]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
b9911c2e DL |
2 | /* |
3 | * printfrr() unit test | |
4 | * Copyright (C) 2019 David Lamparter | |
b9911c2e DL |
5 | */ |
6 | ||
7 | #include "zebra.h" | |
8 | ||
9 | #include <math.h> | |
10 | ||
11 | #include "lib/printfrr.h" | |
12 | #include "lib/memory.h" | |
13 | #include "lib/prefix.h" | |
016cfe70 | 14 | #include "lib/nexthop.h" |
b9911c2e DL |
15 | |
16 | static int errors; | |
17 | ||
afb35622 | 18 | static void printcmp(const char *fmt, ...) PRINTFRR(1, 2); |
b9911c2e DL |
19 | static void printcmp(const char *fmt, ...) |
20 | { | |
21 | va_list ap; | |
22 | char buf[256], bufrr[256], *p; | |
23 | int cmp; | |
24 | memset(bufrr, 0xcc, sizeof(bufrr)); | |
25 | ||
26 | va_start(ap, fmt); | |
27 | vsnprintf(buf, sizeof(buf), fmt, ap); | |
28 | va_end(ap); | |
29 | ||
30 | va_start(ap, fmt); | |
31 | vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap); | |
32 | va_end(ap); | |
33 | ||
34 | cmp = strcmp(buf, bufrr); | |
35 | ||
36 | /* OS dependent "+nan" vs. "nan" */ | |
37 | if (cmp && (p = strstr(bufrr, "+nan"))) { | |
38 | p[0] = ' '; | |
39 | if (!strcmp(buf, bufrr)) | |
40 | cmp = 0; | |
41 | p[0] = '+'; | |
42 | } | |
43 | printf("fmt: \"%s\"\nsys: \"%s\"\nfrr: \"%s\"\n%s\n\n", | |
44 | fmt, buf, bufrr, cmp ? "ERROR" : "ok"); | |
45 | ||
46 | if (cmp) | |
47 | errors++; | |
48 | } | |
49 | ||
cb4928ce DL |
50 | static int printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); |
51 | static int printchk(const char *ref, const char *fmt, ...) | |
b9911c2e DL |
52 | { |
53 | va_list ap; | |
54 | char bufrr[256]; | |
212e04e5 DL |
55 | bool truncfail = false; |
56 | size_t i; | |
57 | size_t expectlen; | |
58 | ||
b9911c2e DL |
59 | memset(bufrr, 0xcc, sizeof(bufrr)); |
60 | ||
212e04e5 DL |
61 | va_start(ap, fmt); |
62 | expectlen = vsnprintfrr(NULL, 0, fmt, ap); | |
63 | va_end(ap); | |
64 | ||
65 | va_start(ap, fmt); | |
66 | vsnprintfrr(bufrr, 7, fmt, ap); | |
67 | va_end(ap); | |
68 | ||
69 | if (strnlen(bufrr, 7) == 7) | |
70 | truncfail = true; | |
71 | if (strnlen(bufrr, 7) < 7 && strncmp(ref, bufrr, 6) != 0) | |
72 | truncfail = true; | |
73 | for (i = 7; i < sizeof(bufrr); i++) | |
74 | if (bufrr[i] != (char)0xcc) { | |
75 | truncfail = true; | |
76 | break; | |
77 | } | |
78 | ||
79 | if (truncfail) { | |
80 | printf("truncation test FAILED:\n" | |
81 | "fmt: \"%s\"\nref: \"%s\"\nfrr[:7]: \"%s\"\n%s\n\n", | |
82 | fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); | |
83 | errors++; | |
84 | } | |
85 | ||
487eefcf DL |
86 | struct fmt_outpos outpos[16]; |
87 | struct fbuf fb = { | |
88 | .buf = bufrr, | |
89 | .pos = bufrr, | |
90 | .len = sizeof(bufrr) - 1, | |
91 | .outpos = outpos, | |
92 | .outpos_n = array_size(outpos), | |
93 | }; | |
94 | ||
b9911c2e | 95 | va_start(ap, fmt); |
487eefcf DL |
96 | vbprintfrr(&fb, fmt, ap); |
97 | fb.pos[0] = '\0'; | |
b9911c2e DL |
98 | va_end(ap); |
99 | ||
487eefcf | 100 | printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n", |
b9911c2e DL |
101 | fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); |
102 | if (strcmp(ref, bufrr)) | |
103 | errors++; | |
212e04e5 DL |
104 | if (strlen(bufrr) != expectlen) { |
105 | printf("return value <> length mismatch\n"); | |
106 | errors++; | |
107 | } | |
487eefcf DL |
108 | |
109 | for (size_t i = 0; i < fb.outpos_i; i++) | |
110 | printf("\t[%zu: %u..%u] = \"%.*s\"\n", i, | |
111 | outpos[i].off_start, | |
112 | outpos[i].off_end, | |
113 | (int)(outpos[i].off_end - outpos[i].off_start), | |
114 | bufrr + outpos[i].off_start); | |
115 | printf("\n"); | |
cb4928ce | 116 | return 0; |
b9911c2e DL |
117 | } |
118 | ||
9c4380da DL |
119 | static void test_va(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); |
120 | static void test_va(const char *ref, const char *fmt, ...) | |
121 | { | |
122 | struct va_format vaf; | |
123 | va_list ap; | |
124 | ||
125 | va_start(ap, fmt); | |
126 | vaf.fmt = fmt; | |
127 | vaf.va = ≈ | |
128 | ||
129 | printchk(ref, "VA [%pVA] %s", &vaf, "--"); | |
130 | ||
131 | va_end(ap); | |
132 | } | |
133 | ||
b9911c2e DL |
134 | int main(int argc, char **argv) |
135 | { | |
136 | size_t i; | |
137 | float flts[] = { | |
138 | 123.456789, | |
139 | 23.456789e-30, | |
140 | 3.456789e+30, | |
141 | INFINITY, | |
142 | NAN, | |
143 | }; | |
144 | uint64_t ui64 = 0xfeed1278cafef00d; | |
145 | struct in_addr ip; | |
146 | char *p; | |
147 | char buf[256]; | |
148 | ||
149 | printcmp("%d %u %d %u", 123, 123, -456, -456); | |
150 | printcmp("%lld %llu %lld %llu", 123LL, 123LL, -456LL, -456LL); | |
151 | ||
152 | printcmp("%-20s,%20s,%.20s", "test", "test", "test"); | |
153 | printcmp("%-3s,%3s,%.3s", "test", "test", "test"); | |
154 | printcmp("%-6.3s,%6.3s,%6.3s", "test", "test", "test"); | |
155 | printcmp("%*s,%*s,%.*s", -3, "test", 3, "test", 3, "test"); | |
156 | ||
157 | for (i = 0; i < array_size(flts); i++) { | |
158 | printcmp("%-6.3e,%6.3e,%+06.3e", flts[i], flts[i], flts[i]); | |
159 | printcmp("%-6.3f,%6.3f,%+06.3f", flts[i], flts[i], flts[i]); | |
160 | printcmp("%-6.3g,%6.3g,%+06.3g", flts[i], flts[i], flts[i]); | |
161 | printcmp("%-6.3a,%6.3a,%+06.3a", flts[i], flts[i], flts[i]); | |
162 | } | |
163 | ||
164 | printchk("-77385308584349683 18369358765125201933 feed1278cafef00d", | |
165 | "%Ld %Lu %Lx", ui64, ui64, ui64); | |
166 | ||
167 | inet_aton("192.168.1.2", &ip); | |
168 | printchk("192.168.1.2", "%pI4", &ip); | |
169 | printchk(" 192.168.1.2", "%20pI4", &ip); | |
212e04e5 | 170 | printchk("192.168.1.2 ", "%-20pI4", &ip); |
b9911c2e DL |
171 | |
172 | printcmp("%p", &ip); | |
173 | ||
9c4380da DL |
174 | test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234); |
175 | ||
2c5b4d80 DL |
176 | inet_aton("0.0.0.0", &ip); |
177 | printchk("0.0.0.0", "%pI4", &ip); | |
178 | printchk("*", "%pI4s", &ip); | |
179 | ||
b9911c2e DL |
180 | snprintfrr(buf, sizeof(buf), "test%s", "#1"); |
181 | csnprintfrr(buf, sizeof(buf), "test%s", "#2"); | |
182 | assert(strcmp(buf, "test#1test#2") == 0); | |
183 | ||
184 | p = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), "test%s", "#3"); | |
185 | assert(p == buf); | |
186 | assert(strcmp(buf, "test#3") == 0); | |
187 | ||
188 | p = asnprintfrr(MTYPE_TMP, buf, 4, "test%s", "#4"); | |
189 | assert(p != buf); | |
190 | assert(strcmp(p, "test#4") == 0); | |
191 | XFREE(MTYPE_TMP, p); | |
192 | ||
193 | p = asprintfrr(MTYPE_TMP, "test%s", "#5"); | |
194 | assert(strcmp(p, "test#5") == 0); | |
195 | XFREE(MTYPE_TMP, p); | |
196 | ||
543a2684 DL |
197 | struct prefix pfx; |
198 | ||
199 | str2prefix("192.168.1.23/24", &pfx); | |
200 | printchk("192.168.1.23/24", "%pFX", &pfx); | |
201 | printchk("192.168.1.23", "%pFXh", &pfx); | |
202 | ||
203 | str2prefix("2001:db8::1234/64", &pfx); | |
204 | printchk("2001:db8::1234/64", "%pFX", &pfx); | |
205 | printchk("2001:db8::1234", "%pFXh", &pfx); | |
206 | ||
207 | pfx.family = AF_UNIX; | |
208 | printchk("UNK prefix", "%pFX", &pfx); | |
209 | printchk("{prefix.af=AF_UNIX}", "%pFXh", &pfx); | |
210 | ||
211 | str2prefix_eth("02:ca:fe:f0:0d:1e/48", (struct prefix_eth *)&pfx); | |
212 | printchk("02:ca:fe:f0:0d:1e/48", "%pFX", &pfx); | |
213 | printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx); | |
214 | ||
b9911c2e DL |
215 | struct prefix_sg sg; |
216 | sg.src.s_addr = INADDR_ANY; | |
217 | sg.grp.s_addr = INADDR_ANY; | |
d51f8b0f | 218 | printchk("(*,*)", "%pPSG4", &sg); |
b9911c2e DL |
219 | |
220 | inet_aton("192.168.1.2", &sg.src); | |
d51f8b0f | 221 | printchk("(192.168.1.2,*)", "%pPSG4", &sg); |
b9911c2e DL |
222 | |
223 | inet_aton("224.1.2.3", &sg.grp); | |
d51f8b0f | 224 | printchk("(192.168.1.2,224.1.2.3)", "%pPSG4", &sg); |
b9911c2e DL |
225 | |
226 | sg.src.s_addr = INADDR_ANY; | |
d51f8b0f | 227 | printchk("(*,224.1.2.3)", "%pPSG4", &sg); |
b9911c2e | 228 | |
a4cb97a6 DL |
229 | uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; |
230 | ||
7798203f DL |
231 | FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex)); |
232 | FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.*pHX", | |
233 | (int)sizeof(randhex), randhex)); | |
234 | FMT_NSTD(printchk("12 34 00 ca", "%.4pHX", randhex)); | |
235 | ||
236 | printchk("12 34 00 ca fe 00 aa 55", "%8pHX", randhex); | |
237 | printchk("12 34 00 ca fe 00 aa 55", "%*pHX", | |
a4cb97a6 | 238 | (int)sizeof(randhex), randhex); |
7798203f DL |
239 | printchk("12 34 00 ca", "%4pHX", randhex); |
240 | ||
241 | printchk("", "%pHX", randhex); | |
242 | ||
243 | printchk("12:34:00:ca:fe:00:aa:55", "%8pHXc", randhex); | |
244 | printchk("123400cafe00aa55", "%8pHXn", randhex); | |
245 | ||
246 | printchk("/test/pa\\ th/\\~spe\\ncial\\x01/file.name", "%pSE", | |
247 | "/test/pa th/~spe\ncial\x01/file.name"); | |
248 | printchk("/test/pa\\ th/\\~spe\\n", "%17pSE", | |
249 | "/test/pa th/~spe\ncial\x01/file.name"); | |
250 | ||
251 | char nulltest[] = { 'n', 'u', 0, 'l', 'l' }; | |
252 | ||
253 | printchk("nu\\x00ll", "%5pSE", nulltest); | |
254 | printchk("nu\\x00ll", "%*pSE", 5, nulltest); | |
a4cb97a6 | 255 | |
7798203f DL |
256 | printchk("bl\\\"ah\\x01te[st\\nab]c", "%pSQ", |
257 | "bl\"ah\x01te[st\nab]c"); | |
258 | printchk("\"bl\\\"ah\\x01te[st\\nab]c\"", "%pSQq", | |
259 | "bl\"ah\x01te[st\nab]c"); | |
260 | printchk("\"bl\\\"ah\\x01te[st\\x0aab\\]c\"", "%pSQqs", | |
261 | "bl\"ah\x01te[st\nab]c"); | |
262 | printchk("\"\"", "%pSQqn", ""); | |
263 | printchk("\"\"", "%pSQqn", (char *)NULL); | |
264 | printchk("(null)", "%pSQq", (char *)NULL); | |
a4cb97a6 | 265 | |
016cfe70 PZ |
266 | /* |
267 | * %pNH<foo> tests | |
268 | * | |
269 | * gateway addresses only for now: interfaces require more setup | |
270 | */ | |
fec9fb29 DL |
271 | printchk("(null)", "%pNHcg", (struct nexthop *)NULL); |
272 | printchk("(null)", "%pNHci", (struct nexthop *)NULL); | |
016cfe70 PZ |
273 | |
274 | struct nexthop nh; | |
275 | ||
276 | memset(&nh, 0, sizeof(nh)); | |
277 | ||
278 | nh.type = NEXTHOP_TYPE_IPV4; | |
279 | inet_aton("3.2.1.0", &nh.gate.ipv4); | |
280 | printchk("3.2.1.0", "%pNHcg", &nh); | |
281 | ||
282 | nh.type = NEXTHOP_TYPE_IPV6; | |
283 | inet_pton(AF_INET6, "fe2c::34", &nh.gate.ipv6); | |
284 | printchk("fe2c::34", "%pNHcg", &nh); | |
285 | ||
2c76ba43 DL |
286 | /* time printing */ |
287 | ||
288 | /* need a non-UTC timezone for testing */ | |
289 | setenv("TZ", "TEST-01:00", 1); | |
290 | tzset(); | |
291 | ||
292 | struct timespec ts; | |
293 | struct timeval tv; | |
294 | time_t tt; | |
295 | ||
296 | ts.tv_sec = tv.tv_sec = tt = 1642015880; | |
297 | ts.tv_nsec = 123456789; | |
298 | tv.tv_usec = 234567; | |
299 | ||
300 | printchk("Wed Jan 12 20:31:20 2022", "%pTSR", &ts); | |
301 | printchk("Wed Jan 12 20:31:20 2022", "%pTVR", &tv); | |
302 | printchk("Wed Jan 12 20:31:20 2022", "%pTTR", &tt); | |
303 | ||
304 | FMT_NSTD(printchk("Wed Jan 12 20:31:20 2022", "%.3pTSR", &ts)); | |
305 | ||
306 | printchk("2022-01-12T20:31:20.123", "%pTSRi", &ts); | |
307 | printchk("2022-01-12 20:31:20.123", "%pTSRip", &ts); | |
308 | printchk("2022-01-12 20:31:20.123", "%pTSRpi", &ts); | |
309 | FMT_NSTD(printchk("2022-01-12T20:31:20", "%.0pTSRi", &ts)); | |
310 | FMT_NSTD(printchk("2022-01-12T20:31:20.123456789", "%.9pTSRi", &ts)); | |
311 | FMT_NSTD(printchk("2022-01-12T20:31:20", "%.3pTTRi", &tt)); | |
312 | ||
313 | ts.tv_sec = tv.tv_sec = tt = 9 * 86400 + 12345; | |
314 | ||
315 | printchk("1w 2d 03:25:45.123", "%pTSIp", &ts); | |
316 | printchk("1w2d03:25:45.123", "%pTSI", &ts); | |
317 | printchk("1w2d03:25:45.234", "%pTVI", &tv); | |
318 | printchk("1w2d03:25:45", "%pTTI", &tt); | |
319 | ||
320 | printchk("1w 2d 03h", "%pTVItp", &tv); | |
321 | printchk("1w2d03h", "%pTSIt", &ts); | |
322 | ||
323 | printchk("219:25:45", "%pTVIh", &tv); | |
324 | printchk("13165:45", "%pTVIm", &tv); | |
325 | ||
326 | ts.tv_sec = tv.tv_sec = tt = 1 * 86400 + 12345; | |
327 | ||
328 | printchk("1d 03:25:45.123", "%pTSIp", &ts); | |
329 | printchk("1d03:25:45.234", "%pTVI", &tv); | |
330 | ||
331 | printchk("1d 03h 25m", "%pTVItp", &tv); | |
332 | printchk("1d03h25m", "%pTSIt", &ts); | |
333 | ||
334 | printchk("98745.234", "%pTVId", &tv); | |
335 | ||
336 | printchk("27:25:45", "%pTVIh", &tv); | |
337 | printchk("1645:45", "%pTVIm", &tv); | |
338 | ||
339 | ts.tv_sec = tv.tv_sec = tt = 12345; | |
340 | ||
341 | printchk("03:25:45.123", "%pTSIp", &ts); | |
342 | printchk("03:25:45.123", "%pTSI", &ts); | |
343 | printchk("03:25:45.234", "%pTVI", &tv); | |
344 | printchk("03:25:45", "%pTTI", &tt); | |
345 | ||
346 | printchk("03:25:45", "%pTSItp", &ts); | |
347 | printchk("03:25:45", "%pTVIt", &tv); | |
348 | ||
349 | printchk("12345.234", "%pTVId", &tv); | |
350 | ||
351 | printchk("03:25:45", "%pTVIh", &tv); | |
352 | printchk("205:45", "%pTVIm", &tv); | |
353 | ||
354 | ts.tv_sec = tv.tv_sec = tt = 0; | |
355 | ||
356 | printchk("00:00:00.123", "%pTSIp", &ts); | |
357 | printchk("00:00:00.123", "%pTSI", &ts); | |
358 | printchk("00:00:00.234", "%pTVI", &tv); | |
359 | printchk("00:00:00", "%pTTI", &tt); | |
360 | ||
361 | printchk("00:00:00", "%pTVItp", &tv); | |
362 | printchk("00:00:00", "%pTSIt", &ts); | |
363 | ||
364 | printchk("0.234", "%pTVId", &tv); | |
365 | printchk("0.234", "%pTVIdx", &tv); | |
366 | printchk("-", "%pTTIdx", &tt); | |
367 | ||
368 | printchk("00:00:00", "%pTVIhx", &tv); | |
369 | printchk("--:--:--", "%pTTIhx", &tt); | |
370 | printchk("00:00", "%pTVImx", &tv); | |
371 | printchk("--:--", "%pTTImx", &tt); | |
372 | ||
373 | ts.tv_sec = tv.tv_sec = tt = -10; | |
374 | ||
375 | printchk("-00:00:09.876", "%pTSIp", &ts); | |
376 | printchk("-00:00:09.876", "%pTSI", &ts); | |
377 | printchk("-00:00:09.765", "%pTVI", &tv); | |
378 | printchk("-00:00:10", "%pTTI", &tt); | |
379 | ||
380 | printchk("-00:00:09", "%pTSItp", &ts); | |
381 | printchk("-00:00:09", "%pTSIt", &ts); | |
382 | printchk("-00:00:09", "%pTVIt", &tv); | |
383 | printchk("-00:00:10", "%pTTIt", &tt); | |
384 | ||
385 | printchk("-9.765", "%pTVId", &tv); | |
386 | printchk("-", "%pTVIdx", &tv); | |
387 | ||
388 | printchk("-00:00:09", "%pTSIh", &ts); | |
389 | printchk("--:--:--", "%pTVIhx", &tv); | |
390 | printchk("--:--:--", "%pTTIhx", &tt); | |
391 | ||
392 | printchk("-00:09", "%pTSIm", &ts); | |
393 | printchk("--:--", "%pTVImx", &tv); | |
394 | printchk("--:--", "%pTTImx", &tt); | |
395 | ||
b9911c2e DL |
396 | return !!errors; |
397 | } |