1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define CONFIG_CBPRINTF_LIBC_SUBSTS 1
8
9 #include <zephyr/ztest.h>
10 #include <float.h>
11 #include <limits.h>
12 #include <math.h>
13 #include <stdarg.h>
14 #include <wctype.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <zephyr/sys/util.h>
18
19 #define CBPRINTF_VIA_UNIT_TEST
20
21 /* Unit testing doesn't use Kconfig, so if we're not building from
22 * twister force selection of all features. If we are use flags to
23 * determine which features are desired. Yes, this is a mess.
24 */
25 #ifndef VIA_TWISTER
26 /* Set this to truthy to use libc's snprintf as external validation.
27 * This should be used with all options enabled.
28 */
29 #define USE_LIBC 0
30 #define USE_PACKAGED 0
31
32 #else /* VIA_TWISTER */
33 #if (VIA_TWISTER & 0x200) != 0
34 #define USE_PACKAGED 1
35 #else
36 #define USE_PACKAGED 0
37 #endif
38 #if (VIA_TWISTER & 0x800) != 0
39 #define AVOID_C_GENERIC 1
40 #endif
41 #if (VIA_TWISTER & 0x1000) != 0
42 #define PKG_ALIGN_OFFSET sizeof(void *)
43 #endif
44
45 #if (VIA_TWISTER & 0x2000) != 0
46 #define PACKAGE_FLAGS CBPRINTF_PACKAGE_ADD_STRING_IDXS
47 #endif
48
49 #endif /* VIA_TWISTER */
50
51 /* Can't use IS_ENABLED on symbols that don't start with CONFIG_
52 * without checkpatch complaints, so do something else.
53 */
54 #if USE_LIBC
55 #define ENABLED_USE_LIBC true
56 #else
57 #define ENABLED_USE_LIBC false
58 #endif
59
60 #if USE_PACKAGED
61 #define ENABLED_USE_PACKAGED true
62 #else
63 #define ENABLED_USE_PACKAGED false
64 #endif
65
66 #if AVOID_C_GENERIC
67 #define Z_C_GENERIC 0
68 #endif
69
70 #ifndef PACKAGE_FLAGS
71 #define PACKAGE_FLAGS 0
72 #endif
73
74 #ifdef CONFIG_LOG
75 #undef CONFIG_LOG
76 #define CONFIG_LOG 0
77 #endif
78
79 #include <zephyr/sys/cbprintf.h>
80 #include "../../../lib/os/cbprintf.c"
81
82 #if defined(CONFIG_CBPRINTF_COMPLETE)
83 #include "../../../lib/os/cbprintf_complete.c"
84 #elif defined(CONFIG_CBPRINTF_NANO)
85 #include "../../../lib/os/cbprintf_nano.c"
86 #endif
87
88 #if USE_PACKAGED
89 #include "../../../lib/os/cbprintf_packaged.c"
90 #endif
91
92 #ifndef PKG_ALIGN_OFFSET
93 #define PKG_ALIGN_OFFSET (size_t)0
94 #endif
95
96 /* We can't determine at build-time whether int is 64-bit, so assume
97 * it is. If not the values are truncated at build time, and the str
98 * pointers will be updated during test initialization.
99 */
100 static const unsigned int pfx_val = (unsigned int)0x7b6b5b4b3b2b1b0b;
101 static const char pfx_str64[] = "7b6b5b4b3b2b1b0b";
102 static const char *pfx_str = pfx_str64;
103 static const unsigned int sfx_val = (unsigned int)0xe7e6e5e4e3e2e1e0;
104 static const char sfx_str64[] = "e7e6e5e4e3e2e1e0";
105 static const char *sfx_str = sfx_str64;
106
107 /* Buffer adequate to hold packaged state for all tested
108 * configurations.
109 */
110 #if USE_PACKAGED
__aligned(CBPRINTF_PACKAGE_ALIGNMENT)111 static uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) packaged[256];
112 #endif
113
114 #define WRAP_FMT(_fmt) "%x" _fmt "%x"
115 #define PASS_ARG(...) pfx_val, __VA_ARGS__, sfx_val
116
117 static inline int match_str(const char **strp,
118 const char *expected,
119 size_t len)
120 {
121 const char *str = *strp;
122 int rv = strncmp(str, expected, len);
123
124 *strp += len;
125 return rv;
126 }
127
match_pfx(const char ** ptr)128 static inline int match_pfx(const char **ptr)
129 {
130 return match_str(ptr, pfx_str, 2U * sizeof(pfx_val));
131 }
132
match_sfx(const char ** ptr)133 static inline int match_sfx(const char **ptr)
134 {
135 return match_str(ptr, sfx_str, 2U * sizeof(sfx_val));
136 }
137
138 /* This has to be more than 255 so we can test over-sized widths. */
139 static char buf[512];
140
141 struct out_buffer {
142 char *buf;
143 size_t idx;
144 size_t size;
145 };
146
147 static struct out_buffer outbuf;
148
reset_out(void)149 static inline void reset_out(void)
150 {
151 outbuf.buf = buf;
152 outbuf.size = ARRAY_SIZE(buf);
153 outbuf.idx = 0;
154 }
155
outbuf_null_terminate(struct out_buffer * outbuf)156 static void outbuf_null_terminate(struct out_buffer *outbuf)
157 {
158 int idx = outbuf->idx - ((outbuf->idx == outbuf->size) ? 1 : 0);
159
160 outbuf->buf[idx] = 0;
161 }
162
out(int c,void * dest)163 static int out(int c, void *dest)
164 {
165 int rv = EOF;
166 struct out_buffer *buf = dest;
167
168 if (buf->idx < buf->size) {
169 buf->buf[buf->idx++] = (char)(unsigned char)c;
170 rv = (int)(unsigned char)c;
171 }
172 return rv;
173 }
174
175 __printf_like(2, 3)
prf(char * static_package_str,const char * format,...)176 static int prf(char *static_package_str, const char *format, ...)
177 {
178 va_list ap;
179 int rv;
180
181 reset_out();
182 va_start(ap, format);
183 #if USE_LIBC
184 rv = vsnprintf(buf, sizeof(buf), format, ap);
185 #else
186 #if USE_PACKAGED
187 rv = cbvprintf_package(packaged, sizeof(packaged), PACKAGE_FLAGS, format, ap);
188 if (rv >= 0) {
189 rv = cbpprintf(out, &outbuf, packaged);
190 if (rv == 0 && static_package_str) {
191 rv = strcmp(static_package_str, outbuf.buf);
192 }
193 }
194 #else
195 rv = cbvprintf(out, &outbuf, format, ap);
196 #endif
197 outbuf_null_terminate(&outbuf);
198 #endif
199 va_end(ap);
200 return rv;
201 }
202
rawprf(const char * format,...)203 static int rawprf(const char *format, ...)
204 {
205 va_list ap;
206 int rv;
207
208 va_start(ap, format);
209 #if USE_PACKAGED
210 va_list ap2;
211 int len;
212 uint8_t *pkg_buf = &packaged[PKG_ALIGN_OFFSET];
213
214 va_copy(ap2, ap);
215 len = cbvprintf_package(NULL, PKG_ALIGN_OFFSET, PACKAGE_FLAGS, format, ap2);
216 va_end(ap2);
217
218 if (len >= 0) {
219 rv = cbvprintf_package(pkg_buf, len, PACKAGE_FLAGS, format, ap);
220 } else {
221 rv = len;
222 }
223 if (rv >= 0) {
224 rv = cbpprintf(out, &outbuf, pkg_buf);
225 }
226 #else
227 rv = cbvprintf(out, &outbuf, format, ap);
228 #endif
229 va_end(ap);
230
231 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)
232 && !IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
233 zassert_equal(rv, 0);
234 rv = outbuf.idx;
235 }
236 return rv;
237 }
238
239 #define TEST_PRF2(rc, _fmt, ...) do { \
240 char _buf[512]; \
241 char *sp_buf = NULL; /* static package buffer */\
242 if (USE_PACKAGED && !CBPRINTF_MUST_RUNTIME_PACKAGE(0, 0, _fmt, __VA_ARGS__)) { \
243 int rv = 0; \
244 size_t _len; \
245 struct out_buffer package_buf = { \
246 .buf = _buf, .size = ARRAY_SIZE(_buf), .idx = 0 \
247 }; \
248 CBPRINTF_STATIC_PACKAGE(NULL, 0, _len, PKG_ALIGN_OFFSET, \
249 PACKAGE_FLAGS, _fmt, __VA_ARGS__); \
250 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) \
251 package[_len + PKG_ALIGN_OFFSET]; \
252 int st_pkg_rv; \
253 CBPRINTF_STATIC_PACKAGE(&package[PKG_ALIGN_OFFSET], _len - 1, \
254 st_pkg_rv, PKG_ALIGN_OFFSET, \
255 PACKAGE_FLAGS, _fmt, __VA_ARGS__); \
256 zassert_equal(st_pkg_rv, -ENOSPC); \
257 CBPRINTF_STATIC_PACKAGE(&package[PKG_ALIGN_OFFSET], _len, \
258 st_pkg_rv, PKG_ALIGN_OFFSET, \
259 PACKAGE_FLAGS, _fmt, __VA_ARGS__); \
260 zassert_equal(st_pkg_rv, _len); \
261 rv = cbpprintf(out, &package_buf, &package[PKG_ALIGN_OFFSET]); \
262 if (rv >= 0) { \
263 sp_buf = _buf; \
264 } \
265 } \
266 *rc = prf(sp_buf, _fmt, __VA_ARGS__); \
267 } while (0)
268
269 #define TEST_PRF(rc, _fmt, ...) \
270 TEST_PRF2(rc, WRAP_FMT(_fmt), PASS_ARG(__VA_ARGS__))
271
272 #ifdef CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE
273 #define TEST_PRF_LONG_DOUBLE(rc, _fmt, ...) \
274 TEST_PRF(rc, _fmt, __VA_ARGS__)
275 #else
276 /* Skip testing of static packaging if long double support not enabled. */
277 #define TEST_PRF_LONG_DOUBLE(rc, _fmt, ...) \
278 *rc = prf(NULL, WRAP_FMT(_fmt), PASS_ARG(__VA_ARGS__))
279 #endif
280
281 struct context {
282 const char *expected;
283 const char *got;
284 const char *file;
285 unsigned int line;
286 };
287
288 __printf_like(3, 4)
prf_failed(const struct context * ctx,const char * cp,const char * format,...)289 static bool prf_failed(const struct context *ctx,
290 const char *cp,
291 const char *format,
292 ...)
293 {
294 va_list ap;
295
296 va_start(ap, format);
297 printf("%s:%u for '%s'\n", ctx->file, ctx->line, ctx->expected);
298 printf("in: %s\nat: %*c%s\n", ctx->got,
299 (unsigned int)(cp - ctx->got), '>', ctx->expected);
300 vprintf(format, ap);
301 va_end(ap);
302 return false;
303 }
304
prf_check(const char * expected,int rv,const char * file,unsigned int line)305 static inline bool prf_check(const char *expected,
306 int rv,
307 const char *file,
308 unsigned int line)
309 {
310 const struct context ctx = {
311 .expected = expected,
312 .got = buf,
313 .file = file,
314 .line = line,
315 };
316
317 const char *str = buf;
318 const char *sp;
319 int rc;
320
321 sp = str;
322 rc = match_pfx(&str);
323 if (rc != 0) {
324 return prf_failed(&ctx, sp, "pfx mismatch %d\n", rc);
325 }
326
327 sp = str;
328 rc = match_str(&str, expected, strlen(expected));
329 if (rc != 0) {
330 return prf_failed(&ctx, sp, "str mismatch %d\n", rc);
331 }
332
333 sp = str;
334 rc = match_sfx(&str);
335 if (rc != 0) {
336 return prf_failed(&ctx, sp, "sfx mismatch, %d\n", rc);
337 }
338
339 rc = (*str != 0);
340 if (rc != 0) {
341 return prf_failed(&ctx, str, "no eos %02x\n", *str);
342 }
343
344 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)
345 && !IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
346 if (rv != 0) {
347 return prf_failed(&ctx, str, "nano rv %d != 0\n", rc);
348 }
349 } else {
350 int len = (int)(str - buf);
351
352 if (rv != len) {
353 return prf_failed(&ctx, str, "rv %d != expected %d\n",
354 rv, len);
355 }
356 }
357
358 return true;
359 }
360
361 #define PRF_CHECK(expected, rv) zassert_true(prf_check(expected, rv, __FILE__, __LINE__))
362
ZTEST(prf,test_pct)363 ZTEST(prf, test_pct)
364 {
365 int rc;
366
367 TEST_PRF(&rc, "/%%/%c/", 'a');
368
369 PRF_CHECK("/%/a/", rc);
370 }
371
ZTEST(prf,test_c)372 ZTEST(prf, test_c)
373 {
374 int rc;
375
376 TEST_PRF(&rc, "%c", 'a');
377 PRF_CHECK("a", rc);
378
379 rc = prf(NULL, "/%256c/", 'a');
380
381 const char *bp = buf;
382 size_t spaces = 255;
383
384 zassert_equal(rc, 258, "len %d", rc);
385 zassert_equal(*bp, '/');
386 ++bp;
387 while (spaces-- > 0) {
388 zassert_equal(*bp, ' ');
389 ++bp;
390 }
391 zassert_equal(*bp, 'a');
392 ++bp;
393 zassert_equal(*bp, '/');
394
395 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
396 TC_PRINT("short test for nano\n");
397 return;
398 }
399
400 TEST_PRF(&rc, "%lc", (wint_t)'a');
401 if (ENABLED_USE_LIBC) {
402 PRF_CHECK("a", rc);
403 } else {
404 PRF_CHECK("%lc", rc);
405 }
406 }
407
ZTEST(prf,test_s)408 ZTEST(prf, test_s)
409 {
410 const char *s = "123";
411 static wchar_t ws[] = L"abc";
412 int rc;
413
414 TEST_PRF(&rc, "/%s/", s);
415 PRF_CHECK("/123/", rc);
416
417 TEST_PRF(&rc, "/%6s/%-6s/%2s/", s, s, s);
418 PRF_CHECK("/ 123/123 /123/", rc);
419
420 TEST_PRF(&rc, "/%.6s/%.2s/%.s/", s, s, s);
421 PRF_CHECK("/123/12//", rc);
422
423 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
424 TC_PRINT("short test for nano\n");
425 return;
426 }
427
428 TEST_PRF(&rc, "%ls", ws);
429 if (ENABLED_USE_LIBC) {
430 PRF_CHECK("abc", rc);
431 } else {
432 PRF_CHECK("%ls", rc);
433 }
434 }
435
ZTEST(prf,test_v_c)436 ZTEST(prf, test_v_c)
437 {
438 int rc;
439
440 reset_out();
441 buf[1] = 'b';
442 rc = rawprf("%c", 'a');
443 zassert_equal(rc, 1);
444 zassert_equal(buf[0], 'a');
445 if (!ENABLED_USE_LIBC) {
446 zassert_equal(buf[1], 'b', "wth %x", buf[1]);
447 }
448 }
449
ZTEST(prf,test_d_length)450 ZTEST(prf, test_d_length)
451 {
452 int min = -1234567890;
453 int max = 1876543210;
454 long long svll = 123LL << 48;
455 long long svll2 = -2LL;
456 unsigned long long uvll = 4000000000LLU;
457 int rc;
458
459 TEST_PRF(&rc, "%d/%d", min, max);
460 PRF_CHECK("-1234567890/1876543210", rc);
461
462 TEST_PRF(&rc, "%u/%u", min, max);
463 PRF_CHECK("3060399406/1876543210", rc);
464
465 if (!IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
466 TEST_PRF(&rc, "%hd/%hd", (short) min, (short) max);
467 PRF_CHECK("-722/-14614", rc);
468
469 TEST_PRF(&rc, "%hhd/%hhd", (char) min, (char) max);
470 PRF_CHECK("46/-22", rc);
471 }
472
473 TEST_PRF(&rc, "%ld/%ld/%lu/", (long)min, (long)max, 4000000000UL);
474 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
475 || (sizeof(long) <= 4)
476 || IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
477 PRF_CHECK("-1234567890/1876543210/4000000000/", rc);
478 } else {
479 PRF_CHECK("%ld/%ld/%lu/", rc);
480 }
481
482 TEST_PRF(&rc, "/%lld/%lld/%lld/%llu/", svll, -svll, svll2, uvll);
483 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
484 PRF_CHECK("/34621422135410688/-34621422135410688/-2/4000000000/", rc);
485 } else if (IS_ENABLED(CONFIG_CBPRINTF_COMPLETE)) {
486 PRF_CHECK("/%lld/%lld/%lld/%llu/", rc);
487 } else if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
488 PRF_CHECK("/ERR/ERR/-2/4000000000/", rc);
489 } else {
490 zassert_true(false, "Missed case!");
491 }
492
493 TEST_PRF(&rc, "%lld/%lld", (long long)min, (long long)max);
494 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
495 PRF_CHECK("-1234567890/1876543210", rc);
496 } else if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
497 PRF_CHECK("-1234567890/1876543210", rc);
498 } else {
499 PRF_CHECK("%lld/%lld", rc);
500 }
501
502 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
503 TC_PRINT("short test for nano\n");
504 return;
505 }
506
507 TEST_PRF(&rc, "%jd/%jd", (intmax_t)min, (intmax_t)max);
508 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
509 PRF_CHECK("-1234567890/1876543210", rc);
510 } else {
511 PRF_CHECK("%jd/%jd", rc);
512 }
513
514 TEST_PRF(&rc, "%zd/%td/%td", (size_t)min, (ptrdiff_t)min,
515 (ptrdiff_t)max);
516 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
517 || (sizeof(size_t) <= 4)) {
518 PRF_CHECK("-1234567890/-1234567890/1876543210", rc);
519 } else {
520 PRF_CHECK("%zd/%td/%td", rc);
521 }
522
523 /* These have to be tested without the format validation
524 * attribute because they produce diagnostics, but we have
525 * intended behavior so we have to test them.
526 */
527 reset_out();
528 rc = rawprf("/%Ld/", max);
529 zassert_equal(rc, 5, "len %d", rc);
530 zassert_equal(strncmp("/%Ld/", buf, rc), 0);
531 }
532
ZTEST(prf,test_d_flags)533 ZTEST(prf, test_d_flags)
534 {
535 int sv = 123;
536 int rc;
537
538 /* Stuff related to sign */
539 TEST_PRF(&rc, "/%d/%-d/%+d/% d/",
540 sv, sv, sv, sv);
541 PRF_CHECK("/123/123/+123/ 123/", rc);
542
543 /* Stuff related to width padding */
544 TEST_PRF(&rc, "/%1d/%4d/%-4d/%04d/%15d/%-15d/",
545 sv, sv, sv, sv, sv, sv);
546 PRF_CHECK("/123/ 123/123 /0123/"
547 " 123/123 /", rc);
548
549 /* Stuff related to precision */
550 TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv);
551 PRF_CHECK("/000123/ 0123/", rc);
552
553 /* Now with negative values */
554 sv = -sv;
555 TEST_PRF(&rc, "/%d/%-d/%+d/% d/",
556 sv, sv, sv, sv);
557 PRF_CHECK("/-123/-123/-123/-123/", rc);
558
559 TEST_PRF(&rc, "/%1d/%6d/%-6d/%06d/%13d/%-13d/",
560 sv, sv, sv, sv, sv, sv);
561 PRF_CHECK("/-123/ -123/-123 /-00123/"
562 " -123/-123 /", rc);
563
564 TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv);
565 PRF_CHECK("/-000123/ -0123/", rc);
566
567 /* These have to be tested without the format validation
568 * attribute because they produce diagnostics, but the
569 * standard specifies behavior so we have to test them.
570 */
571 sv = 123;
572 reset_out();
573 rc = rawprf("/%#d/% +d/%-04d/%06.4d/", sv, sv, sv, sv);
574 zassert_equal(rc, 22, "rc %d", rc);
575 zassert_equal(strncmp("/123/+123/123 / 0123/", buf, rc), 0);
576 }
577
ZTEST(prf,test_x_length)578 ZTEST(prf, test_x_length)
579 {
580 unsigned int min = 0x4c3c2c1c;
581 unsigned int max = 0x4d3d2d1d;
582 int rc;
583
584 TEST_PRF(&rc, "%x/%X", min, max);
585 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
586
587 TEST_PRF(&rc, "%lx/%lX", (unsigned long)min, (unsigned long)max);
588 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
589 || (sizeof(long) <= 4)
590 || IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
591 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
592 } else {
593 PRF_CHECK("%lx/%lX", rc);
594 }
595
596 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
597 TC_PRINT("short test for nano\n");
598 return;
599 }
600
601 TEST_PRF(&rc, "%hx/%hX", (short) min, (short) max);
602 PRF_CHECK("2c1c/2D1D", rc);
603
604 TEST_PRF(&rc, "%hhx/%hhX", (char) min, (char) max);
605 PRF_CHECK("1c/1D", rc);
606
607 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
608 TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min,
609 (unsigned long long)max);
610 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
611
612 TEST_PRF(&rc, "%jx/%jX", (uintmax_t)min, (uintmax_t)max);
613 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
614 }
615
616 TEST_PRF(&rc, "%zx/%zX", (size_t)min, (size_t)max);
617 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
618 || (sizeof(size_t) <= 4)) {
619 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
620 } else {
621 PRF_CHECK("%zx/%zX", rc);
622 }
623
624 TEST_PRF(&rc, "%tx/%tX", (ptrdiff_t)min, (ptrdiff_t)max);
625 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
626 || (sizeof(ptrdiff_t) <= 4)) {
627 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
628 } else {
629 PRF_CHECK("%tx/%tX", rc);
630 }
631
632 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
633 && (sizeof(long long) > sizeof(int))) {
634 unsigned long long min = 0x8c7c6c5c4c3c2c1cULL;
635 unsigned long long max = 0x8d7d6d5d4d3d2d1dULL;
636
637 TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min,
638 (unsigned long long)max);
639 PRF_CHECK("8c7c6c5c4c3c2c1c/8D7D6D5D4D3D2D1D", rc);
640 }
641 }
642
ZTEST(prf,test_x_flags)643 ZTEST(prf, test_x_flags)
644 {
645 unsigned int sv = 0x123;
646 int rc;
647
648 /* Stuff related to sign flags, which have no effect on
649 * unsigned conversions, and alternate form
650 */
651 TEST_PRF(&rc, "/%x/%-x/%#x/",
652 sv, sv, sv);
653 PRF_CHECK("/123/123/0x123/", rc);
654
655 /* Stuff related to width and padding */
656 TEST_PRF(&rc, "/%1x/%4x/%-4x/%04x/%#15x/%-15x/",
657 sv, sv, sv, sv, sv, sv);
658 PRF_CHECK("/123/ 123/123 /0123/"
659 " 0x123/123 /", rc);
660
661 /* These have to be tested without the format validation
662 * attribute because they produce diagnostics, but the
663 * standard specifies behavior so we have to test them.
664 */
665 reset_out();
666 rc = rawprf("/%+x/% x/", sv, sv);
667 zassert_equal(rc, 9, "rc %d", rc);
668 zassert_equal(strncmp("/123/123/", buf, rc), 0);
669 }
670
ZTEST(prf,test_o)671 ZTEST(prf, test_o)
672 {
673 unsigned int v = 01234567;
674 int rc;
675
676 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
677 TC_PRINT("skipped test for nano\n");
678 return;
679 }
680
681 TEST_PRF(&rc, "%o", v);
682 PRF_CHECK("1234567", rc);
683 TEST_PRF(&rc, "%#o", v);
684 PRF_CHECK("01234567", rc);
685 }
686
ZTEST(prf,test_fp_value)687 ZTEST(prf, test_fp_value)
688 {
689 if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
690 TC_PRINT("skipping unsupported feature\n");
691 return;
692 }
693
694 double dv = 1234.567;
695 int rc;
696
697 TEST_PRF(&rc, "/%f/%F/", dv, dv);
698 PRF_CHECK("/1234.567000/1234.567000/", rc);
699 TEST_PRF(&rc, "%g", dv);
700 PRF_CHECK("1234.57", rc);
701 TEST_PRF(&rc, "%e", dv);
702 PRF_CHECK("1.234567e+03", rc);
703 TEST_PRF(&rc, "%E", dv);
704 PRF_CHECK("1.234567E+03", rc);
705 TEST_PRF(&rc, "%a", dv);
706 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
707 PRF_CHECK("0x1.34a449ba5e354p+10", rc);
708 } else {
709 PRF_CHECK("%a", rc);
710 }
711
712 dv = 1E3;
713 TEST_PRF(&rc, "%.2f", dv);
714 PRF_CHECK("1000.00", rc);
715
716 dv = 1E20;
717 TEST_PRF(&rc, "%.0f", dv);
718 PRF_CHECK("100000000000000000000", rc);
719 TEST_PRF(&rc, "%.20e", dv);
720 PRF_CHECK("1.00000000000000000000e+20", rc);
721
722 dv = 1E-3;
723 TEST_PRF(&rc, "%.3e", dv);
724 PRF_CHECK("1.000e-03", rc);
725
726 dv = 1E-3;
727 TEST_PRF(&rc, "%g", dv);
728 PRF_CHECK("0.001", rc);
729
730 dv = 1234567.89;
731 TEST_PRF(&rc, "%g", dv);
732 PRF_CHECK("1.23457e+06", rc);
733
734 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
735 dv = (double)BIT64(40);
736 TEST_PRF(&rc, "/%a/%.4a/%.20a/", dv, dv, dv);
737 PRF_CHECK("/0x1p+40/0x1.0000p+40/"
738 "0x1.00000000000000000000p+40/", rc);
739
740 dv += (double)BIT64(32);
741 TEST_PRF(&rc, "%a", dv);
742 PRF_CHECK("0x1.01p+40", rc);
743 }
744
745 dv = INFINITY;
746 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
747 dv, dv, dv, dv, dv, dv, dv, dv);
748 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
749 PRF_CHECK("inf.f INF.F inf.e INF.E "
750 "inf.g INF.g inf.a INF.A", rc);
751 } else {
752 PRF_CHECK("inf.f INF.F inf.e INF.E "
753 "inf.g INF.g %a.a %A.A", rc);
754 }
755
756 dv = -INFINITY;
757 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
758 dv, dv, dv, dv, dv, dv, dv, dv);
759 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
760 PRF_CHECK("-inf.f -INF.F -inf.e -INF.E "
761 "-inf.g -INF.g -inf.a -INF.A", rc);
762 } else {
763 PRF_CHECK("-inf.f -INF.F -inf.e -INF.E "
764 "-inf.g -INF.g %a.a %A.A", rc);
765 }
766
767 dv = NAN;
768 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
769 dv, dv, dv, dv, dv, dv, dv, dv);
770 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
771 PRF_CHECK("nan.f NAN.F nan.e NAN.E "
772 "nan.g NAN.g nan.a NAN.A", rc);
773 } else {
774 PRF_CHECK("nan.f NAN.F nan.e NAN.E "
775 "nan.g NAN.g %a.a %A.A", rc);
776 }
777
778 dv = DBL_MIN;
779 TEST_PRF(&rc, "%a %e", dv, dv);
780 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
781 PRF_CHECK("0x1p-1022 2.225074e-308", rc);
782 } else {
783 PRF_CHECK("%a 2.225074e-308", rc);
784 }
785
786 dv /= 4;
787 TEST_PRF(&rc, "%a %e", dv, dv);
788 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
789 PRF_CHECK("0x0.4p-1022 5.562685e-309", rc);
790 } else {
791 PRF_CHECK("%a 5.562685e-309", rc);
792 }
793
794 /*
795 * The following tests are tailored to exercise edge cases in
796 * lib/os/cbprintf_complete.c:encode_float() and related functions.
797 */
798
799 dv = 0x1.0p-3;
800 TEST_PRF(&rc, "%.16g", dv);
801 PRF_CHECK("0.125", rc);
802
803 dv = 0x1.0p-4;
804 TEST_PRF(&rc, "%.16g", dv);
805 PRF_CHECK("0.0625", rc);
806
807 dv = 0x1.8p-4;
808 TEST_PRF(&rc, "%.16g", dv);
809 PRF_CHECK("0.09375", rc);
810
811 dv = 0x1.cp-4;
812 TEST_PRF(&rc, "%.16g", dv);
813 PRF_CHECK("0.109375", rc);
814
815 dv = 0x1.9999999800000p-7;
816 TEST_PRF(&rc, "%.16g", dv);
817 PRF_CHECK("0.01249999999708962", rc);
818
819 dv = 0x1.9999999ffffffp-8;
820 TEST_PRF(&rc, "%.16g", dv);
821 PRF_CHECK("0.006250000005820765", rc);
822
823 dv = 0x1.0p+0;
824 TEST_PRF(&rc, "%.16g", dv);
825 PRF_CHECK("1", rc);
826
827 dv = 0x1.fffffffffffffp-1022;
828 TEST_PRF(&rc, "%.16g", dv);
829 PRF_CHECK("4.450147717014402e-308", rc);
830
831 dv = 0x1.ffffffffffffep-1022;
832 TEST_PRF(&rc, "%.16g", dv);
833 PRF_CHECK("4.450147717014402e-308", rc);
834
835 dv = 0x1.ffffffffffffdp-1022;
836 TEST_PRF(&rc, "%.16g", dv);
837 PRF_CHECK("4.450147717014401e-308", rc);
838
839 dv = 0x1.0000000000001p-1022;
840 TEST_PRF(&rc, "%.16g", dv);
841 PRF_CHECK("2.225073858507202e-308", rc);
842
843 dv = 0x1p-1022;
844 TEST_PRF(&rc, "%.16g", dv);
845 PRF_CHECK("2.225073858507201e-308", rc);
846
847 dv = 0x0.fffffffffffffp-1022;
848 TEST_PRF(&rc, "%.16g", dv);
849 PRF_CHECK("2.225073858507201e-308", rc);
850
851 dv = 0x0.0000000000001p-1022;
852 TEST_PRF(&rc, "%.16g", dv);
853 PRF_CHECK("4.940656458412465e-324", rc);
854
855 dv = 0x1.1fa182c40c60dp-1019;
856 TEST_PRF(&rc, "%.16g", dv);
857 PRF_CHECK("2e-307", rc);
858
859 dv = 0x1.fffffffffffffp+1023;
860 TEST_PRF(&rc, "%.16g", dv);
861 PRF_CHECK("1.797693134862316e+308", rc);
862
863 dv = 0x1.ffffffffffffep+1023;
864 TEST_PRF(&rc, "%.16g", dv);
865 PRF_CHECK("1.797693134862316e+308", rc);
866
867 dv = 0x1.ffffffffffffdp+1023;
868 TEST_PRF(&rc, "%.16g", dv);
869 PRF_CHECK("1.797693134862315e+308", rc);
870
871 dv = 0x1.0000000000001p+1023;
872 TEST_PRF(&rc, "%.16g", dv);
873 PRF_CHECK("8.988465674311582e+307", rc);
874
875 dv = 0x1p+1023;
876 TEST_PRF(&rc, "%.16g", dv);
877 PRF_CHECK("8.98846567431158e+307", rc);
878 }
879
ZTEST(prf,test_fp_length)880 ZTEST(prf, test_fp_length)
881 {
882 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
883 TC_PRINT("skipped test for nano\n");
884 return;
885 }
886
887 double dv = 1.2345;
888 int rc;
889
890 TEST_PRF(&rc, "/%g/", dv);
891 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
892 PRF_CHECK("/1.2345/", rc);
893 } else {
894 PRF_CHECK("/%g/", rc);
895 }
896
897 TEST_PRF(&rc, "/%lg/", dv);
898 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
899 PRF_CHECK("/1.2345/", rc);
900 } else {
901 PRF_CHECK("/%lg/", rc);
902 }
903
904 TEST_PRF_LONG_DOUBLE(&rc, "/%Lg/", (long double)dv);
905 if (ENABLED_USE_LIBC) {
906 PRF_CHECK("/1.2345/", rc);
907 } else {
908 PRF_CHECK("/%Lg/", rc);
909 }
910
911 /* These have to be tested without the format validation
912 * attribute because they produce diagnostics, but we have
913 * intended behavior so we have to test them.
914 */
915 reset_out();
916 rc = rawprf("/%hf/", dv);
917 zassert_equal(rc, 5, "len %d", rc);
918 zassert_equal(strncmp("/%hf/", buf, rc), 0);
919 }
920
ZTEST(prf,test_fp_flags)921 ZTEST(prf, test_fp_flags)
922 {
923 if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
924 TC_PRINT("skipping unsupported feature\n");
925 return;
926 }
927
928 double dv = 1.23;
929 int rc;
930
931 TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv);
932 PRF_CHECK("/1.23/ 1.23/+1.23/", rc);
933
934 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
935 TEST_PRF(&rc, "/%a/%.1a/%.2a/", dv, dv, dv);
936 PRF_CHECK("/0x1.3ae147ae147aep+0/"
937 "0x1.4p+0/0x1.3bp+0/", rc);
938 }
939
940 dv = -dv;
941 TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv);
942 PRF_CHECK("/-1.23/-1.23/-1.23/", rc);
943
944 dv = 23;
945 TEST_PRF(&rc, "/%g/%#g/%.0f/%#.0f/", dv, dv, dv, dv);
946 PRF_CHECK("/23/23.0000/23/23./", rc);
947
948 rc = prf(NULL, "% .380f", 0x1p-400);
949 zassert_equal(rc, 383);
950 zassert_equal(strncmp(buf, " 0.000", 6), 0);
951 zassert_equal(strncmp(&buf[119], "00003872", 8), 0);
952 }
953
ZTEST(prf,test_star_width)954 ZTEST(prf, test_star_width)
955 {
956 int rc;
957
958 TEST_PRF(&rc, "/%3c/%-3c/", 'a', 'a');
959 PRF_CHECK("/ a/a /", rc);
960
961 TEST_PRF(&rc, "/%*c/%*c/", 3, 'a', -3, 'a');
962 PRF_CHECK("/ a/a /", rc);
963 }
964
ZTEST(prf,test_star_precision)965 ZTEST(prf, test_star_precision)
966 {
967 int rc;
968
969 TEST_PRF(&rc, "/%.*x/%10.*x/",
970 5, 0x12, 5, 0x12);
971 PRF_CHECK("/00012/ 00012/", rc);
972
973 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
974 TC_PRINT("short test for nano\n");
975 return;
976 }
977
978 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
979 double dv = 1.2345678;
980
981 TEST_PRF(&rc, "/%.3g/%.5g/%.8g/%g/",
982 dv, dv, dv, dv);
983 PRF_CHECK("/1.23/1.2346/1.2345678/1.23457/", rc);
984
985 TEST_PRF(&rc, "/%.*g/%.*g/%.*g/%.*g/",
986 3, dv,
987 5, dv,
988 8, dv,
989 -3, dv);
990 PRF_CHECK("/1.23/1.2346/1.2345678/1.23457/", rc);
991 }
992 }
993
ZTEST(prf,test_n)994 ZTEST(prf, test_n)
995 {
996 if (!IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
997 TC_PRINT("skipping unsupported feature\n");
998 return;
999 }
1000 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
1001 TC_PRINT("skipped test for nano\n");
1002 return;
1003 }
1004
1005 char l_hh = 0;
1006 short l_h = 0;
1007 int l = 0;
1008 long l_l = 0;
1009 long long l_ll = 0;
1010 intmax_t l_j = 0;
1011 size_t l_z = 0;
1012 ptrdiff_t l_t = 0;
1013 int rc;
1014
1015 rc = prf(NULL, "12345%n", &l);
1016 zassert_equal(l, rc, "%d != %d", l, rc);
1017 zassert_equal(rc, 5);
1018
1019
1020 rc = prf(NULL, "12345%hn", &l_h);
1021 zassert_equal(l_h, rc);
1022
1023 rc = prf(NULL, "12345%hhn", &l_hh);
1024 zassert_equal(l_hh, rc);
1025
1026 rc = prf(NULL, "12345%ln", &l_l);
1027 zassert_equal(l_l, rc);
1028
1029 rc = prf(NULL, "12345%lln", &l_ll);
1030 zassert_equal(l_ll, rc);
1031
1032 rc = prf(NULL, "12345%jn", &l_j);
1033 zassert_equal(l_j, rc);
1034
1035 rc = prf(NULL, "12345%zn", &l_z);
1036 zassert_equal(l_z, rc);
1037
1038 rc = prf(NULL, "12345%tn", &l_t);
1039 zassert_equal(l_t, rc);
1040 }
1041
1042 #define EXPECTED_1ARG(_t) (IS_ENABLED(CONFIG_CBPRINTF_NANO) \
1043 ? 1U : (sizeof(_t) / sizeof(int)))
1044
ZTEST(prf,test_p)1045 ZTEST(prf, test_p)
1046 {
1047 if (ENABLED_USE_LIBC) {
1048 TC_PRINT("skipping on libc\n");
1049 return;
1050 }
1051
1052 uintptr_t uip = 0xcafe21;
1053 void *ptr = (void *)uip;
1054 int rc;
1055
1056 TEST_PRF(&rc, "%p", ptr);
1057 PRF_CHECK("0xcafe21", rc);
1058 TEST_PRF(&rc, "%p", NULL);
1059 PRF_CHECK("(nil)", rc);
1060
1061 reset_out();
1062 rc = rawprf("/%12p/", ptr);
1063 zassert_equal(rc, 14);
1064 zassert_equal(strncmp("/ 0xcafe21/", buf, rc), 0);
1065
1066 reset_out();
1067 rc = rawprf("/%12p/", NULL);
1068 zassert_equal(rc, 14);
1069 zassert_equal(strncmp("/ (nil)/", buf, rc), 0);
1070
1071 reset_out();
1072 rc = rawprf("/%-12p/", ptr);
1073 zassert_equal(rc, 14);
1074 zassert_equal(strncmp("/0xcafe21 /", buf, rc), 0);
1075
1076 reset_out();
1077 rc = rawprf("/%-12p/", NULL);
1078 zassert_equal(rc, 14);
1079 zassert_equal(strncmp("/(nil) /", buf, rc), 0);
1080
1081 reset_out();
1082 rc = rawprf("/%.8p/", ptr);
1083 zassert_equal(rc, 12);
1084 zassert_equal(strncmp("/0x00cafe21/", buf, rc), 0);
1085 }
1086
out_counter(int c,void * ctx)1087 static int out_counter(int c,
1088 void *ctx)
1089 {
1090 size_t *count = ctx;
1091
1092 ++*count;
1093 return c;
1094 }
1095
out_e42(int c,void * ctx)1096 static int out_e42(int c,
1097 void *ctx)
1098 {
1099 return -42;
1100 }
1101
ZTEST(prf,test_libc_substs)1102 ZTEST(prf, test_libc_substs)
1103 {
1104 if (!IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
1105 TC_PRINT("not enabled\n");
1106 return;
1107 }
1108
1109 char lbuf[8];
1110 char full_flag = 0xbf;
1111 size_t count = 0;
1112 size_t const len = sizeof(lbuf) - 1U;
1113 int rc;
1114
1115 lbuf[len] = full_flag;
1116
1117 rc = snprintfcb(lbuf, len, "%06d", 1);
1118 zassert_equal(rc, 6);
1119 zassert_equal(strncmp("000001", lbuf, rc), 0);
1120 zassert_equal(lbuf[7], full_flag);
1121
1122 rc = snprintfcb(lbuf, len, "%07d", 1);
1123 zassert_equal(rc, 7);
1124 zassert_equal(strncmp("000000", lbuf, rc), 0);
1125 zassert_equal(lbuf[7], full_flag);
1126
1127 rc = snprintfcb(lbuf, len, "%020d", 1);
1128 zassert_equal(rc, 20, "rc %d", rc);
1129 zassert_equal(lbuf[7], full_flag);
1130 zassert_equal(strncmp("000000", lbuf, rc), 0);
1131
1132 rc = cbprintf(out_counter, &count, "%020d", 1);
1133 zassert_equal(rc, 20, "rc %d", rc);
1134 zassert_equal(count, 20);
1135
1136 if (!IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
1137 rc = cbprintf(out_e42, NULL, "%020d", 1);
1138 zassert_equal(rc, -42, "rc %d", rc);
1139 }
1140 }
1141
ZTEST(prf,test_cbprintf_package)1142 ZTEST(prf, test_cbprintf_package)
1143 {
1144 if (!ENABLED_USE_PACKAGED) {
1145 TC_PRINT("disabled\n");
1146 return;
1147 }
1148
1149 int rc;
1150 char fmt[] = "/%i/"; /* not const */
1151
1152 /* Verify we can calculate length without storing */
1153 rc = cbprintf_package(NULL, PKG_ALIGN_OFFSET, PACKAGE_FLAGS, fmt, 3);
1154 zassert_true(rc > sizeof(int));
1155
1156 /* Capture the base package information for future tests. */
1157 size_t len = rc;
1158 /* Create a buffer aligned to max argument. */
1159 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) buf[len + PKG_ALIGN_OFFSET];
1160
1161 /* Verify we get same length when storing. Pass buffer which may be
1162 * unaligned. Same alignment offset was used for space calculation.
1163 */
1164 rc = cbprintf_package(&buf[PKG_ALIGN_OFFSET], len, PACKAGE_FLAGS, fmt, 3);
1165 zassert_equal(rc, len);
1166
1167 /* Verify we get an error if can't store */
1168 len -= 1;
1169 rc = cbprintf_package(&buf[PKG_ALIGN_OFFSET], len, PACKAGE_FLAGS, fmt, 3);
1170 zassert_equal(rc, -ENOSPC);
1171 }
1172
1173 /* Test using @ref CBPRINTF_PACKAGE_ADD_STRING_IDXS flag.
1174 * Note that only static packaging is tested here because ro string detection
1175 * does not work on host testing.
1176 */
ZTEST(prf,test_cbprintf_package_rw_string_indexes)1177 ZTEST(prf, test_cbprintf_package_rw_string_indexes)
1178 {
1179 if (!ENABLED_USE_PACKAGED) {
1180 TC_PRINT("disabled\n");
1181 return;
1182 }
1183
1184 if (!Z_C_GENERIC) {
1185 /* runtime packaging will not detect ro strings. */
1186 return;
1187 }
1188
1189 int len0, len1;
1190 static const char *test_str = "test %d %s";
1191 static const char *test_str1 = "lorem ipsum";
1192 uint8_t str_idx;
1193 char *addr;
1194
1195 CBPRINTF_STATIC_PACKAGE(NULL, 0, len0, 0, CBPRINTF_PACKAGE_CONST_CHAR_RO,
1196 test_str, 100, test_str1);
1197 CBPRINTF_STATIC_PACKAGE(NULL, 0, len1, 0,
1198 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1199 test_str, 100, test_str1);
1200 /* package with string indexes will contain two more bytes holding indexes
1201 * of string parameter locations.
1202 */
1203 zassert_equal(len0 + 2, len1);
1204
1205 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package0[len0];
1206 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package1[len1];
1207
1208 CBPRINTF_STATIC_PACKAGE(package0, sizeof(package0), len0, 0,
1209 CBPRINTF_PACKAGE_CONST_CHAR_RO,
1210 test_str, 100, test_str1);
1211 CBPRINTF_STATIC_PACKAGE(package1, sizeof(package1), len1, 0,
1212 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1213 test_str, 100, test_str1);
1214
1215 union cbprintf_package_hdr *desc0 = (union cbprintf_package_hdr *)package0;
1216 union cbprintf_package_hdr *desc1 = (union cbprintf_package_hdr *)package1;
1217
1218 /* Compare descriptor content. Second package has one ro string index. */
1219 zassert_equal(desc0->desc.ro_str_cnt, 0);
1220 zassert_equal(desc1->desc.ro_str_cnt, 2);
1221 zassert_equal(len0 + 2, len1);
1222
1223 int *p = (int *)package1;
1224
1225 str_idx = package1[len0];
1226 addr = *(char **)&p[str_idx];
1227 zassert_equal(addr, test_str);
1228
1229 str_idx = package1[len0 + 1];
1230 addr = *(char **)&p[str_idx];
1231 zassert_equal(addr, test_str1);
1232 }
1233
fsc_package_cb(int c,void * ctx)1234 static int fsc_package_cb(int c, void *ctx)
1235 {
1236 char **p = ctx;
1237
1238 (*p)[0] = c;
1239 *p = *p + 1;
1240
1241 return c;
1242 }
1243
1244 /* Test for validating conversion to fully self-contained package. */
ZTEST(prf,test_cbprintf_fsc_package)1245 ZTEST(prf, test_cbprintf_fsc_package)
1246 {
1247 if (!ENABLED_USE_PACKAGED) {
1248 TC_PRINT("disabled\n");
1249 return;
1250 }
1251
1252 if (!Z_C_GENERIC) {
1253 /* runtime packaging will not detect ro strings. */
1254 return;
1255 }
1256
1257 char test_str[] = "test %d %s";
1258 const char *test_str1 = "lorem ipsum";
1259 char exp_str0[256];
1260 char exp_str1[256];
1261 char out_str[256];
1262 char *pout;
1263 int len;
1264 int fsc_len;
1265 int err;
1266
1267 snprintf(exp_str0, sizeof(exp_str0), test_str, 100, test_str1);
1268
1269 CBPRINTF_STATIC_PACKAGE(NULL, 0, len, 0,
1270 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1271 test_str, 100, test_str1);
1272
1273 zassert_true(len > 0);
1274 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
1275
1276 CBPRINTF_STATIC_PACKAGE(package, sizeof(package), len, 0,
1277 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1278 test_str, 100, test_str1);
1279
1280 /* Get length of fsc package. */
1281 fsc_len = cbprintf_fsc_package(package, len, NULL, 0);
1282
1283 int exp_len = len + (int)strlen(test_str) + 1 + (int)strlen(test_str1) + 1;
1284
1285 zassert_equal(exp_len, fsc_len);
1286
1287 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) fsc_package[fsc_len];
1288
1289 err = cbprintf_fsc_package(package, len, fsc_package, fsc_len - 1);
1290 zassert_equal(err, -ENOSPC);
1291
1292 err = cbprintf_fsc_package(package, len, fsc_package, fsc_len);
1293 zassert_equal(err, fsc_len);
1294
1295 /* Now overwrite a char in original string, confirm that fsc package
1296 * contains string without that change because ro string is copied into
1297 * the package.
1298 */
1299 test_str[0] = 'w';
1300 snprintf(exp_str1, sizeof(exp_str1), test_str, 100, test_str1);
1301
1302 pout = out_str;
1303 cbpprintf(fsc_package_cb, &pout, package);
1304 *pout = '\0';
1305
1306 zassert_str_equal(out_str, exp_str1);
1307 zassert_true(strcmp(exp_str0, exp_str1) != 0);
1308
1309 /* FSC package contains original content. */
1310 pout = out_str;
1311 cbpprintf(fsc_package_cb, &pout, fsc_package);
1312 *pout = '\0';
1313 zassert_str_equal(out_str, exp_str0);
1314 }
1315
ZTEST(prf,test_cbpprintf)1316 ZTEST(prf, test_cbpprintf)
1317 {
1318 if (!ENABLED_USE_PACKAGED) {
1319 TC_PRINT("disabled\n");
1320 return;
1321 }
1322
1323 int rc;
1324
1325 /* This only checks error conditions. Formatting is checked
1326 * by diverting prf() and related helpers to use the packaged
1327 * version.
1328 */
1329 reset_out();
1330 rc = cbpprintf(out, &outbuf, NULL);
1331 zassert_equal(rc, -EINVAL);
1332 }
1333
ZTEST(prf,test_nop)1334 ZTEST(prf, test_nop)
1335 {
1336 }
1337
ZTEST(prf,test_is_none_char_ptr)1338 ZTEST(prf, test_is_none_char_ptr)
1339 {
1340 char c = 0;
1341 const char cc = 0;
1342 volatile char vc = 0;
1343 volatile const char vcc = 0;
1344
1345 unsigned char uc = 0;
1346 const unsigned char cuc = 0;
1347 volatile unsigned char vuc = 0;
1348 volatile const unsigned char vcuc = 0;
1349
1350 short s = 0;
1351 unsigned short us = 0;
1352
1353 int i = 0;
1354 unsigned int ui = 0;
1355
1356 long l = 0;
1357 unsigned long ul = 0;
1358
1359 long long ll = 0;
1360 unsigned long long ull = 0;
1361
1362 float f = 0.1;
1363 double d = 0.1;
1364
1365 TOOLCHAIN_DISABLE_GCC_WARNING(TOOLCHAIN_WARNING_POINTER_ARITH);
1366 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(c), 0);
1367 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cc), 0);
1368 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vc), 0);
1369 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcc), 0);
1370
1371 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&c), 0);
1372 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cc), 0);
1373 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vc), 0);
1374 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcc), 0);
1375
1376 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(uc), 0);
1377 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(cuc), 0);
1378 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vuc), 0);
1379 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(vcuc), 0);
1380
1381 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&uc), 0);
1382 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&cuc), 0);
1383 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vuc), 0);
1384 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&vcuc), 0);
1385
1386 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(s), 0);
1387 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(us), 0);
1388 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&s), 1);
1389 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&us), 1);
1390
1391 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(i), 0);
1392 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ui), 0);
1393 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&i), 1);
1394 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ui), 1);
1395
1396 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(l), 0);
1397 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ul), 0);
1398 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&l), 1);
1399 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ul), 1);
1400
1401 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ll), 0);
1402 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(ull), 0);
1403 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ll), 1);
1404 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&ull), 1);
1405
1406 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(f), 0);
1407 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(d), 0);
1408 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&f), 1);
1409 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR(&d), 1);
1410
1411 zassert_equal(Z_CBPRINTF_IS_NONE_CHAR_PTR((void *)&c), 1);
1412
1413 TOOLCHAIN_ENABLE_GCC_WARNING(TOOLCHAIN_WARNING_POINTER_ARITH);
1414 }
1415
ZTEST(prf,test_p_count)1416 ZTEST(prf, test_p_count)
1417 {
1418 zassert_equal(Z_CBPRINTF_P_COUNT("no pointers"), 0);
1419 zassert_equal(Z_CBPRINTF_P_COUNT("no %%p pointers"), 0);
1420
1421 zassert_equal(Z_CBPRINTF_P_COUNT("%d %%p %x %s %p %f"), 1);
1422 zassert_equal(Z_CBPRINTF_P_COUNT("%p %p %llx %p "), 3);
1423 }
1424
ZTEST(prf,test_pointers_validate)1425 ZTEST(prf, test_pointers_validate)
1426 {
1427 TOOLCHAIN_DISABLE_GCC_WARNING(TOOLCHAIN_WARNING_POINTER_ARITH);
1428 zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("no arguments"), true);
1429 /* const char fails validation */
1430 zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", "string"), false);
1431 zassert_equal(Z_CBPRINTF_POINTERS_VALIDATE("%p", (void *)"string"), true);
1432 TOOLCHAIN_ENABLE_GCC_WARNING(TOOLCHAIN_WARNING_POINTER_ARITH);
1433 }
1434
cbprintf_setup(void)1435 static void *cbprintf_setup(void)
1436 {
1437 if (sizeof(int) == 4) {
1438 pfx_str += 8U;
1439 sfx_str += 8U;
1440 }
1441
1442 TC_PRINT("Opts: " COND_CODE_1(M64_MODE, ("m64"), ("m32")) "\n");
1443 if (ENABLED_USE_LIBC) {
1444 TC_PRINT(" LIBC");
1445 }
1446 if (IS_ENABLED(CONFIG_CBPRINTF_COMPLETE)) {
1447 TC_PRINT(" COMPLETE");
1448 } else {
1449 TC_PRINT(" NANO\n");
1450 }
1451 if (ENABLED_USE_PACKAGED) {
1452 TC_PRINT(" PACKAGED %s C11 _Generic\n",
1453 Z_C_GENERIC ? "with" : "without");
1454 } else {
1455 TC_PRINT(" VA_LIST\n");
1456 }
1457 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
1458 TC_PRINT(" FULL_INTEGRAL\n");
1459 } else {
1460 TC_PRINT(" REDUCED_INTEGRAL\n");
1461 }
1462 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
1463 TC_PRINT(" FP_SUPPORT\n");
1464 }
1465 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
1466 TC_PRINT(" FP_A_SUPPORT\n");
1467 }
1468 if (IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
1469 TC_PRINT(" FP_N_SPECIFIER\n");
1470 }
1471 if (IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
1472 TC_PRINT(" LIBC_SUBSTS\n");
1473 }
1474
1475 printf("sizeof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
1476 sizeof(int), sizeof(long), sizeof(void *), sizeof(long long),
1477 sizeof(double), sizeof(long double));
1478 printf("alignof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
1479 __alignof__(int), __alignof__(long), __alignof__(void *),
1480 __alignof__(long long), __alignof__(double), __alignof__(long double));
1481 #ifdef CONFIG_CBPRINTF_COMPLETE
1482 printf("sizeof(conversion) = %zu\n", sizeof(struct conversion));
1483 #endif
1484
1485 #ifdef USE_PACKAGED
1486 printf("package alignment offset = %zu\n", PKG_ALIGN_OFFSET);
1487 #endif
1488
1489 return NULL;
1490 }
1491
1492 ZTEST_SUITE(prf, NULL, cbprintf_setup, NULL, NULL, NULL);
1493