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) \
362 zassert_true(prf_check(expected, rv, __FILE__, __LINE__), \
363 NULL)
364
ZTEST(prf,test_pct)365 ZTEST(prf, test_pct)
366 {
367 int rc;
368
369 TEST_PRF(&rc, "/%%/%c/", 'a');
370
371 PRF_CHECK("/%/a/", rc);
372 }
373
ZTEST(prf,test_c)374 ZTEST(prf, test_c)
375 {
376 int rc;
377
378 TEST_PRF(&rc, "%c", 'a');
379 PRF_CHECK("a", rc);
380
381 rc = prf(NULL, "/%256c/", 'a');
382
383 const char *bp = buf;
384 size_t spaces = 255;
385
386 zassert_equal(rc, 258, "len %d", rc);
387 zassert_equal(*bp, '/');
388 ++bp;
389 while (spaces-- > 0) {
390 zassert_equal(*bp, ' ');
391 ++bp;
392 }
393 zassert_equal(*bp, 'a');
394 ++bp;
395 zassert_equal(*bp, '/');
396
397 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
398 TC_PRINT("short test for nano\n");
399 return;
400 }
401
402 TEST_PRF(&rc, "%lc", (wint_t)'a');
403 if (ENABLED_USE_LIBC) {
404 PRF_CHECK("a", rc);
405 } else {
406 PRF_CHECK("%lc", rc);
407 }
408 }
409
ZTEST(prf,test_s)410 ZTEST(prf, test_s)
411 {
412 const char *s = "123";
413 static wchar_t ws[] = L"abc";
414 int rc;
415
416 TEST_PRF(&rc, "/%s/", s);
417 PRF_CHECK("/123/", rc);
418
419 TEST_PRF(&rc, "/%6s/%-6s/%2s/", s, s, s);
420 PRF_CHECK("/ 123/123 /123/", rc);
421
422 TEST_PRF(&rc, "/%.6s/%.2s/%.s/", s, s, s);
423 PRF_CHECK("/123/12//", rc);
424
425 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
426 TC_PRINT("short test for nano\n");
427 return;
428 }
429
430 TEST_PRF(&rc, "%ls", ws);
431 if (ENABLED_USE_LIBC) {
432 PRF_CHECK("abc", rc);
433 } else {
434 PRF_CHECK("%ls", rc);
435 }
436 }
437
ZTEST(prf,test_v_c)438 ZTEST(prf, test_v_c)
439 {
440 int rc;
441
442 reset_out();
443 buf[1] = 'b';
444 rc = rawprf("%c", 'a');
445 zassert_equal(rc, 1);
446 zassert_equal(buf[0], 'a');
447 if (!ENABLED_USE_LIBC) {
448 zassert_equal(buf[1], 'b', "wth %x", buf[1]);
449 }
450 }
451
ZTEST(prf,test_d_length)452 ZTEST(prf, test_d_length)
453 {
454 int min = -1234567890;
455 int max = 1876543210;
456 long long svll = 123LL << 48;
457 long long svll2 = -2LL;
458 unsigned long long uvll = 4000000000LLU;
459 int rc;
460
461 TEST_PRF(&rc, "%d/%d", min, max);
462 PRF_CHECK("-1234567890/1876543210", rc);
463
464 TEST_PRF(&rc, "%u/%u", min, max);
465 PRF_CHECK("3060399406/1876543210", rc);
466
467 if (!IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
468 TEST_PRF(&rc, "%hd/%hd", (short) min, (short) max);
469 PRF_CHECK("-722/-14614", rc);
470
471 TEST_PRF(&rc, "%hhd/%hhd", (char) min, (char) max);
472 PRF_CHECK("46/-22", rc);
473 }
474
475 TEST_PRF(&rc, "%ld/%ld/%lu/", (long)min, (long)max, 4000000000UL);
476 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
477 || (sizeof(long) <= 4)
478 || IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
479 PRF_CHECK("-1234567890/1876543210/4000000000/", rc);
480 } else {
481 PRF_CHECK("%ld/%ld/%lu/", rc);
482 }
483
484 TEST_PRF(&rc, "/%lld/%lld/%lld/%llu/", svll, -svll, svll2, uvll);
485 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
486 PRF_CHECK("/34621422135410688/-34621422135410688/-2/4000000000/", rc);
487 } else if (IS_ENABLED(CONFIG_CBPRINTF_COMPLETE)) {
488 PRF_CHECK("/%lld/%lld/%lld/%llu/", rc);
489 } else if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
490 PRF_CHECK("/ERR/ERR/-2/4000000000/", rc);
491 } else {
492 zassert_true(false, "Missed case!");
493 }
494
495 TEST_PRF(&rc, "%lld/%lld", (long long)min, (long long)max);
496 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
497 PRF_CHECK("-1234567890/1876543210", rc);
498 } else if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
499 PRF_CHECK("-1234567890/1876543210", rc);
500 } else {
501 PRF_CHECK("%lld/%lld", rc);
502 }
503
504 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
505 TC_PRINT("short test for nano\n");
506 return;
507 }
508
509 TEST_PRF(&rc, "%jd/%jd", (intmax_t)min, (intmax_t)max);
510 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
511 PRF_CHECK("-1234567890/1876543210", rc);
512 } else {
513 PRF_CHECK("%jd/%jd", rc);
514 }
515
516 TEST_PRF(&rc, "%zd/%td/%td", (size_t)min, (ptrdiff_t)min,
517 (ptrdiff_t)max);
518 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
519 || (sizeof(size_t) <= 4)) {
520 PRF_CHECK("-1234567890/-1234567890/1876543210", rc);
521 } else {
522 PRF_CHECK("%zd/%td/%td", rc);
523 }
524
525 /* These have to be tested without the format validation
526 * attribute because they produce diagnostics, but we have
527 * intended behavior so we have to test them.
528 */
529 reset_out();
530 rc = rawprf("/%Ld/", max);
531 zassert_equal(rc, 5, "len %d", rc);
532 zassert_equal(strncmp("/%Ld/", buf, rc), 0);
533 }
534
ZTEST(prf,test_d_flags)535 ZTEST(prf, test_d_flags)
536 {
537 int sv = 123;
538 int rc;
539
540 /* Stuff related to sign */
541 TEST_PRF(&rc, "/%d/%-d/%+d/% d/",
542 sv, sv, sv, sv);
543 PRF_CHECK("/123/123/+123/ 123/", rc);
544
545 /* Stuff related to width padding */
546 TEST_PRF(&rc, "/%1d/%4d/%-4d/%04d/%15d/%-15d/",
547 sv, sv, sv, sv, sv, sv);
548 PRF_CHECK("/123/ 123/123 /0123/"
549 " 123/123 /", rc);
550
551 /* Stuff related to precision */
552 TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv);
553 PRF_CHECK("/000123/ 0123/", rc);
554
555 /* Now with negative values */
556 sv = -sv;
557 TEST_PRF(&rc, "/%d/%-d/%+d/% d/",
558 sv, sv, sv, sv);
559 PRF_CHECK("/-123/-123/-123/-123/", rc);
560
561 TEST_PRF(&rc, "/%1d/%6d/%-6d/%06d/%13d/%-13d/",
562 sv, sv, sv, sv, sv, sv);
563 PRF_CHECK("/-123/ -123/-123 /-00123/"
564 " -123/-123 /", rc);
565
566 TEST_PRF(&rc, "/%.6d/%6.4d/", sv, sv);
567 PRF_CHECK("/-000123/ -0123/", rc);
568
569 /* These have to be tested without the format validation
570 * attribute because they produce diagnostics, but the
571 * standard specifies behavior so we have to test them.
572 */
573 sv = 123;
574 reset_out();
575 rc = rawprf("/%#d/% +d/%-04d/%06.4d/", sv, sv, sv, sv);
576 zassert_equal(rc, 22, "rc %d", rc);
577 zassert_equal(strncmp("/123/+123/123 / 0123/",
578 buf, rc), 0, NULL);
579 }
580
ZTEST(prf,test_x_length)581 ZTEST(prf, test_x_length)
582 {
583 unsigned int min = 0x4c3c2c1c;
584 unsigned int max = 0x4d3d2d1d;
585 int rc;
586
587 TEST_PRF(&rc, "%x/%X", min, max);
588 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
589
590 TEST_PRF(&rc, "%lx/%lX", (unsigned long)min, (unsigned long)max);
591 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
592 || (sizeof(long) <= 4)
593 || IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
594 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
595 } else {
596 PRF_CHECK("%lx/%lX", rc);
597 }
598
599 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
600 TC_PRINT("short test for nano\n");
601 return;
602 }
603
604 TEST_PRF(&rc, "%hx/%hX", (short) min, (short) max);
605 PRF_CHECK("2c1c/2D1D", rc);
606
607 TEST_PRF(&rc, "%hhx/%hhX", (char) min, (char) max);
608 PRF_CHECK("1c/1D", rc);
609
610 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
611 TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min,
612 (unsigned long long)max);
613 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
614
615 TEST_PRF(&rc, "%jx/%jX", (uintmax_t)min, (uintmax_t)max);
616 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
617 }
618
619 TEST_PRF(&rc, "%zx/%zX", (size_t)min, (size_t)max);
620 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
621 || (sizeof(size_t) <= 4)) {
622 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
623 } else {
624 PRF_CHECK("%zx/%zX", rc);
625 }
626
627 TEST_PRF(&rc, "%tx/%tX", (ptrdiff_t)min, (ptrdiff_t)max);
628 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
629 || (sizeof(ptrdiff_t) <= 4)) {
630 PRF_CHECK("4c3c2c1c/4D3D2D1D", rc);
631 } else {
632 PRF_CHECK("%tx/%tX", rc);
633 }
634
635 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)
636 && (sizeof(long long) > sizeof(int))) {
637 unsigned long long min = 0x8c7c6c5c4c3c2c1cULL;
638 unsigned long long max = 0x8d7d6d5d4d3d2d1dULL;
639
640 TEST_PRF(&rc, "%llx/%llX", (unsigned long long)min,
641 (unsigned long long)max);
642 PRF_CHECK("8c7c6c5c4c3c2c1c/8D7D6D5D4D3D2D1D", rc);
643 }
644 }
645
ZTEST(prf,test_x_flags)646 ZTEST(prf, test_x_flags)
647 {
648 unsigned int sv = 0x123;
649 int rc;
650
651 /* Stuff related to sign flags, which have no effect on
652 * unsigned conversions, and alternate form
653 */
654 TEST_PRF(&rc, "/%x/%-x/%#x/",
655 sv, sv, sv);
656 PRF_CHECK("/123/123/0x123/", rc);
657
658 /* Stuff related to width and padding */
659 TEST_PRF(&rc, "/%1x/%4x/%-4x/%04x/%#15x/%-15x/",
660 sv, sv, sv, sv, sv, sv);
661 PRF_CHECK("/123/ 123/123 /0123/"
662 " 0x123/123 /", rc);
663
664 /* These have to be tested without the format validation
665 * attribute because they produce diagnostics, but the
666 * standard specifies behavior so we have to test them.
667 */
668 reset_out();
669 rc = rawprf("/%+x/% x/", sv, sv);
670 zassert_equal(rc, 9, "rc %d", rc);
671 zassert_equal(strncmp("/123/123/", buf, rc), 0);
672 }
673
ZTEST(prf,test_o)674 ZTEST(prf, test_o)
675 {
676 unsigned int v = 01234567;
677 int rc;
678
679 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
680 TC_PRINT("skipped test for nano\n");
681 return;
682 }
683
684 TEST_PRF(&rc, "%o", v);
685 PRF_CHECK("1234567", rc);
686 TEST_PRF(&rc, "%#o", v);
687 PRF_CHECK("01234567", rc);
688 }
689
ZTEST(prf,test_fp_value)690 ZTEST(prf, test_fp_value)
691 {
692 if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
693 TC_PRINT("skipping unsupported feature\n");
694 return;
695 }
696
697 double dv = 1234.567;
698 int rc;
699
700 TEST_PRF(&rc, "/%f/%F/", dv, dv);
701 PRF_CHECK("/1234.567000/1234.567000/", rc);
702 TEST_PRF(&rc, "%g", dv);
703 PRF_CHECK("1234.57", rc);
704 TEST_PRF(&rc, "%e", dv);
705 PRF_CHECK("1.234567e+03", rc);
706 TEST_PRF(&rc, "%E", dv);
707 PRF_CHECK("1.234567E+03", rc);
708 TEST_PRF(&rc, "%a", dv);
709 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
710 PRF_CHECK("0x1.34a449ba5e354p+10", rc);
711 } else {
712 PRF_CHECK("%a", rc);
713 }
714
715 dv = 1E3;
716 TEST_PRF(&rc, "%.2f", dv);
717 PRF_CHECK("1000.00", rc);
718
719 dv = 1E20;
720 TEST_PRF(&rc, "%.0f", dv);
721 PRF_CHECK("100000000000000000000", rc);
722 TEST_PRF(&rc, "%.20e", dv);
723 PRF_CHECK("1.00000000000000000000e+20", rc);
724
725 dv = 1E-3;
726 TEST_PRF(&rc, "%.3e", dv);
727 PRF_CHECK("1.000e-03", rc);
728
729 dv = 1E-3;
730 TEST_PRF(&rc, "%g", dv);
731 PRF_CHECK("0.001", rc);
732
733 dv = 1234567.89;
734 TEST_PRF(&rc, "%g", dv);
735 PRF_CHECK("1.23457e+06", rc);
736
737 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
738 dv = (double)BIT64(40);
739 TEST_PRF(&rc, "/%a/%.4a/%.20a/", dv, dv, dv);
740 PRF_CHECK("/0x1p+40/0x1.0000p+40/"
741 "0x1.00000000000000000000p+40/", rc);
742
743 dv += (double)BIT64(32);
744 TEST_PRF(&rc, "%a", dv);
745 PRF_CHECK("0x1.01p+40", rc);
746 }
747
748 dv = INFINITY;
749 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
750 dv, dv, dv, dv, dv, dv, dv, dv);
751 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
752 PRF_CHECK("inf.f INF.F inf.e INF.E "
753 "inf.g INF.g inf.a INF.A", rc);
754 } else {
755 PRF_CHECK("inf.f INF.F inf.e INF.E "
756 "inf.g INF.g %a.a %A.A", rc);
757 }
758
759 dv = -INFINITY;
760 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
761 dv, dv, dv, dv, dv, dv, dv, dv);
762 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
763 PRF_CHECK("-inf.f -INF.F -inf.e -INF.E "
764 "-inf.g -INF.g -inf.a -INF.A", rc);
765 } else {
766 PRF_CHECK("-inf.f -INF.F -inf.e -INF.E "
767 "-inf.g -INF.g %a.a %A.A", rc);
768 }
769
770 dv = NAN;
771 TEST_PRF(&rc, "%f.f %F.F %e.e %E.E %g.g %G.g %a.a %A.A",
772 dv, dv, dv, dv, dv, dv, dv, dv);
773 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
774 PRF_CHECK("nan.f NAN.F nan.e NAN.E "
775 "nan.g NAN.g nan.a NAN.A", rc);
776 } else {
777 PRF_CHECK("nan.f NAN.F nan.e NAN.E "
778 "nan.g NAN.g %a.a %A.A", rc);
779 }
780
781 dv = DBL_MIN;
782 TEST_PRF(&rc, "%a %e", dv, dv);
783 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
784 PRF_CHECK("0x1p-1022 2.225074e-308", rc);
785 } else {
786 PRF_CHECK("%a 2.225074e-308", rc);
787 }
788
789 dv /= 4;
790 TEST_PRF(&rc, "%a %e", dv, dv);
791 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
792 PRF_CHECK("0x0.4p-1022 5.562685e-309", rc);
793 } else {
794 PRF_CHECK("%a 5.562685e-309", rc);
795 }
796
797 /*
798 * The following tests are tailored to exercise edge cases in
799 * lib/os/cbprintf_complete.c:encode_float() and related functions.
800 */
801
802 dv = 0x1.0p-3;
803 TEST_PRF(&rc, "%.16g", dv);
804 PRF_CHECK("0.125", rc);
805
806 dv = 0x1.0p-4;
807 TEST_PRF(&rc, "%.16g", dv);
808 PRF_CHECK("0.0625", rc);
809
810 dv = 0x1.8p-4;
811 TEST_PRF(&rc, "%.16g", dv);
812 PRF_CHECK("0.09375", rc);
813
814 dv = 0x1.cp-4;
815 TEST_PRF(&rc, "%.16g", dv);
816 PRF_CHECK("0.109375", rc);
817
818 dv = 0x1.9999999800000p-7;
819 TEST_PRF(&rc, "%.16g", dv);
820 PRF_CHECK("0.01249999999708962", rc);
821
822 dv = 0x1.9999999ffffffp-8;
823 TEST_PRF(&rc, "%.16g", dv);
824 PRF_CHECK("0.006250000005820765", rc);
825
826 dv = 0x1.0p+0;
827 TEST_PRF(&rc, "%.16g", dv);
828 PRF_CHECK("1", rc);
829
830 dv = 0x1.fffffffffffffp-1022;
831 TEST_PRF(&rc, "%.16g", dv);
832 PRF_CHECK("4.450147717014402e-308", rc);
833
834 dv = 0x1.ffffffffffffep-1022;
835 TEST_PRF(&rc, "%.16g", dv);
836 PRF_CHECK("4.450147717014402e-308", rc);
837
838 dv = 0x1.ffffffffffffdp-1022;
839 TEST_PRF(&rc, "%.16g", dv);
840 PRF_CHECK("4.450147717014401e-308", rc);
841
842 dv = 0x1.0000000000001p-1022;
843 TEST_PRF(&rc, "%.16g", dv);
844 PRF_CHECK("2.225073858507202e-308", rc);
845
846 dv = 0x1p-1022;
847 TEST_PRF(&rc, "%.16g", dv);
848 PRF_CHECK("2.225073858507201e-308", rc);
849
850 dv = 0x0.fffffffffffffp-1022;
851 TEST_PRF(&rc, "%.16g", dv);
852 PRF_CHECK("2.225073858507201e-308", rc);
853
854 dv = 0x0.0000000000001p-1022;
855 TEST_PRF(&rc, "%.16g", dv);
856 PRF_CHECK("4.940656458412465e-324", rc);
857
858 dv = 0x1.1fa182c40c60dp-1019;
859 TEST_PRF(&rc, "%.16g", dv);
860 PRF_CHECK("2e-307", rc);
861
862 dv = 0x1.fffffffffffffp+1023;
863 TEST_PRF(&rc, "%.16g", dv);
864 PRF_CHECK("1.797693134862316e+308", rc);
865
866 dv = 0x1.ffffffffffffep+1023;
867 TEST_PRF(&rc, "%.16g", dv);
868 PRF_CHECK("1.797693134862316e+308", rc);
869
870 dv = 0x1.ffffffffffffdp+1023;
871 TEST_PRF(&rc, "%.16g", dv);
872 PRF_CHECK("1.797693134862315e+308", rc);
873
874 dv = 0x1.0000000000001p+1023;
875 TEST_PRF(&rc, "%.16g", dv);
876 PRF_CHECK("8.988465674311582e+307", rc);
877
878 dv = 0x1p+1023;
879 TEST_PRF(&rc, "%.16g", dv);
880 PRF_CHECK("8.98846567431158e+307", rc);
881 }
882
ZTEST(prf,test_fp_length)883 ZTEST(prf, test_fp_length)
884 {
885 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
886 TC_PRINT("skipped test for nano\n");
887 return;
888 }
889
890 double dv = 1.2345;
891 int rc;
892
893 TEST_PRF(&rc, "/%g/", dv);
894 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
895 PRF_CHECK("/1.2345/", rc);
896 } else {
897 PRF_CHECK("/%g/", rc);
898 }
899
900 TEST_PRF(&rc, "/%lg/", dv);
901 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
902 PRF_CHECK("/1.2345/", rc);
903 } else {
904 PRF_CHECK("/%lg/", rc);
905 }
906
907 TEST_PRF_LONG_DOUBLE(&rc, "/%Lg/", (long double)dv);
908 if (ENABLED_USE_LIBC) {
909 PRF_CHECK("/1.2345/", rc);
910 } else {
911 PRF_CHECK("/%Lg/", rc);
912 }
913
914 /* These have to be tested without the format validation
915 * attribute because they produce diagnostics, but we have
916 * intended behavior so we have to test them.
917 */
918 reset_out();
919 rc = rawprf("/%hf/", dv);
920 zassert_equal(rc, 5, "len %d", rc);
921 zassert_equal(strncmp("/%hf/", buf, rc), 0);
922 }
923
ZTEST(prf,test_fp_flags)924 ZTEST(prf, test_fp_flags)
925 {
926 if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
927 TC_PRINT("skipping unsupported feature\n");
928 return;
929 }
930
931 double dv = 1.23;
932 int rc;
933
934 TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv);
935 PRF_CHECK("/1.23/ 1.23/+1.23/", rc);
936
937 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
938 TEST_PRF(&rc, "/%a/%.1a/%.2a/", dv, dv, dv);
939 PRF_CHECK("/0x1.3ae147ae147aep+0/"
940 "0x1.4p+0/0x1.3bp+0/", rc);
941 }
942
943 dv = -dv;
944 TEST_PRF(&rc, "/%g/% g/%+g/", dv, dv, dv);
945 PRF_CHECK("/-1.23/-1.23/-1.23/", rc);
946
947 dv = 23;
948 TEST_PRF(&rc, "/%g/%#g/%.0f/%#.0f/", dv, dv, dv, dv);
949 PRF_CHECK("/23/23.0000/23/23./", rc);
950
951 rc = prf(NULL, "% .380f", 0x1p-400);
952 zassert_equal(rc, 383);
953 zassert_equal(strncmp(buf, " 0.000", 6), 0);
954 zassert_equal(strncmp(&buf[119], "00003872", 8), 0);
955 }
956
ZTEST(prf,test_star_width)957 ZTEST(prf, test_star_width)
958 {
959 int rc;
960
961 TEST_PRF(&rc, "/%3c/%-3c/", 'a', 'a');
962 PRF_CHECK("/ a/a /", rc);
963
964 TEST_PRF(&rc, "/%*c/%*c/", 3, 'a', -3, 'a');
965 PRF_CHECK("/ a/a /", rc);
966 }
967
ZTEST(prf,test_star_precision)968 ZTEST(prf, test_star_precision)
969 {
970 int rc;
971
972 TEST_PRF(&rc, "/%.*x/%10.*x/",
973 5, 0x12, 5, 0x12);
974 PRF_CHECK("/00012/ 00012/", rc);
975
976 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
977 TC_PRINT("short test for nano\n");
978 return;
979 }
980
981 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
982 double dv = 1.2345678;
983
984 TEST_PRF(&rc, "/%.3g/%.5g/%.8g/%g/",
985 dv, dv, dv, dv);
986 PRF_CHECK("/1.23/1.2346/1.2345678/1.23457/", rc);
987
988 TEST_PRF(&rc, "/%.*g/%.*g/%.*g/%.*g/",
989 3, dv,
990 5, dv,
991 8, dv,
992 -3, dv);
993 PRF_CHECK("/1.23/1.2346/1.2345678/1.23457/", rc);
994 }
995 }
996
ZTEST(prf,test_n)997 ZTEST(prf, test_n)
998 {
999 if (!IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
1000 TC_PRINT("skipping unsupported feature\n");
1001 return;
1002 }
1003 if (IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
1004 TC_PRINT("skipped test for nano\n");
1005 return;
1006 }
1007
1008 char l_hh = 0;
1009 short l_h = 0;
1010 int l = 0;
1011 long l_l = 0;
1012 long long l_ll = 0;
1013 intmax_t l_j = 0;
1014 size_t l_z = 0;
1015 ptrdiff_t l_t = 0;
1016 int rc;
1017
1018 rc = prf(NULL, "12345%n", &l);
1019 zassert_equal(l, rc, "%d != %d", l, rc);
1020 zassert_equal(rc, 5);
1021
1022
1023 rc = prf(NULL, "12345%hn", &l_h);
1024 zassert_equal(l_h, rc);
1025
1026 rc = prf(NULL, "12345%hhn", &l_hh);
1027 zassert_equal(l_hh, rc);
1028
1029 rc = prf(NULL, "12345%ln", &l_l);
1030 zassert_equal(l_l, rc);
1031
1032 rc = prf(NULL, "12345%lln", &l_ll);
1033 zassert_equal(l_ll, rc);
1034
1035 rc = prf(NULL, "12345%jn", &l_j);
1036 zassert_equal(l_j, rc);
1037
1038 rc = prf(NULL, "12345%zn", &l_z);
1039 zassert_equal(l_z, rc);
1040
1041 rc = prf(NULL, "12345%tn", &l_t);
1042 zassert_equal(l_t, rc);
1043 }
1044
1045 #define EXPECTED_1ARG(_t) (IS_ENABLED(CONFIG_CBPRINTF_NANO) \
1046 ? 1U : (sizeof(_t) / sizeof(int)))
1047
ZTEST(prf,test_p)1048 ZTEST(prf, test_p)
1049 {
1050 if (ENABLED_USE_LIBC) {
1051 TC_PRINT("skipping on libc\n");
1052 return;
1053 }
1054
1055 uintptr_t uip = 0xcafe21;
1056 void *ptr = (void *)uip;
1057 int rc;
1058
1059 TEST_PRF(&rc, "%p", ptr);
1060 PRF_CHECK("0xcafe21", rc);
1061 TEST_PRF(&rc, "%p", NULL);
1062 PRF_CHECK("(nil)", rc);
1063
1064 reset_out();
1065 rc = rawprf("/%12p/", ptr);
1066 zassert_equal(rc, 14);
1067 zassert_equal(strncmp("/ 0xcafe21/", buf, rc), 0);
1068
1069 reset_out();
1070 rc = rawprf("/%12p/", NULL);
1071 zassert_equal(rc, 14);
1072 zassert_equal(strncmp("/ (nil)/", buf, rc), 0);
1073
1074 reset_out();
1075 rc = rawprf("/%-12p/", ptr);
1076 zassert_equal(rc, 14);
1077 zassert_equal(strncmp("/0xcafe21 /", buf, rc), 0);
1078
1079 reset_out();
1080 rc = rawprf("/%-12p/", NULL);
1081 zassert_equal(rc, 14);
1082 zassert_equal(strncmp("/(nil) /", buf, rc), 0);
1083
1084 reset_out();
1085 rc = rawprf("/%.8p/", ptr);
1086 zassert_equal(rc, 12);
1087 zassert_equal(strncmp("/0x00cafe21/", buf, rc), 0);
1088 }
1089
out_counter(int c,void * ctx)1090 static int out_counter(int c,
1091 void *ctx)
1092 {
1093 size_t *count = ctx;
1094
1095 ++*count;
1096 return c;
1097 }
1098
out_e42(int c,void * ctx)1099 static int out_e42(int c,
1100 void *ctx)
1101 {
1102 return -42;
1103 }
1104
ZTEST(prf,test_libc_substs)1105 ZTEST(prf, test_libc_substs)
1106 {
1107 if (!IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
1108 TC_PRINT("not enabled\n");
1109 return;
1110 }
1111
1112 char lbuf[8];
1113 char full_flag = 0xbf;
1114 size_t count = 0;
1115 size_t const len = sizeof(lbuf) - 1U;
1116 int rc;
1117
1118 lbuf[len] = full_flag;
1119
1120 rc = snprintfcb(lbuf, len, "%06d", 1);
1121 zassert_equal(rc, 6);
1122 zassert_equal(strncmp("000001", lbuf, rc), 0);
1123 zassert_equal(lbuf[7], full_flag);
1124
1125 rc = snprintfcb(lbuf, len, "%07d", 1);
1126 zassert_equal(rc, 7);
1127 zassert_equal(strncmp("000000", lbuf, rc), 0);
1128 zassert_equal(lbuf[7], full_flag);
1129
1130 rc = snprintfcb(lbuf, len, "%020d", 1);
1131 zassert_equal(rc, 20, "rc %d", rc);
1132 zassert_equal(lbuf[7], full_flag);
1133 zassert_equal(strncmp("000000", lbuf, rc), 0);
1134
1135 rc = cbprintf(out_counter, &count, "%020d", 1);
1136 zassert_equal(rc, 20, "rc %d", rc);
1137 zassert_equal(count, 20);
1138
1139 if (!IS_ENABLED(CONFIG_CBPRINTF_NANO)) {
1140 rc = cbprintf(out_e42, NULL, "%020d", 1);
1141 zassert_equal(rc, -42, "rc %d", rc);
1142 }
1143 }
1144
ZTEST(prf,test_cbprintf_package)1145 ZTEST(prf, test_cbprintf_package)
1146 {
1147 if (!ENABLED_USE_PACKAGED) {
1148 TC_PRINT("disabled\n");
1149 return;
1150 }
1151
1152 int rc;
1153 char fmt[] = "/%i/"; /* not const */
1154
1155 /* Verify we can calculate length without storing */
1156 rc = cbprintf_package(NULL, PKG_ALIGN_OFFSET, PACKAGE_FLAGS, fmt, 3);
1157 zassert_true(rc > sizeof(int));
1158
1159 /* Capture the base package information for future tests. */
1160 size_t len = rc;
1161 /* Create a buffer aligned to max argument. */
1162 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) buf[len + PKG_ALIGN_OFFSET];
1163
1164 /* Verify we get same length when storing. Pass buffer which may be
1165 * unaligned. Same alignment offset was used for space calculation.
1166 */
1167 rc = cbprintf_package(&buf[PKG_ALIGN_OFFSET], len, PACKAGE_FLAGS, fmt, 3);
1168 zassert_equal(rc, len);
1169
1170 /* Verify we get an error if can't store */
1171 len -= 1;
1172 rc = cbprintf_package(&buf[PKG_ALIGN_OFFSET], len, PACKAGE_FLAGS, fmt, 3);
1173 zassert_equal(rc, -ENOSPC);
1174 }
1175
1176 /* Test using @ref CBPRINTF_PACKAGE_ADD_STRING_IDXS flag.
1177 * Note that only static packaging is tested here because ro string detection
1178 * does not work on host testing.
1179 */
ZTEST(prf,test_cbprintf_package_rw_string_indexes)1180 ZTEST(prf, test_cbprintf_package_rw_string_indexes)
1181 {
1182 if (!ENABLED_USE_PACKAGED) {
1183 TC_PRINT("disabled\n");
1184 return;
1185 }
1186
1187 if (!Z_C_GENERIC) {
1188 /* runtime packaging will not detect ro strings. */
1189 return;
1190 }
1191
1192 int len0, len1;
1193 static const char *test_str = "test %d %s";
1194 static const char *test_str1 = "lorem ipsum";
1195 uint8_t str_idx;
1196 char *addr;
1197
1198 CBPRINTF_STATIC_PACKAGE(NULL, 0, len0, 0, CBPRINTF_PACKAGE_CONST_CHAR_RO,
1199 test_str, 100, test_str1);
1200 CBPRINTF_STATIC_PACKAGE(NULL, 0, len1, 0,
1201 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1202 test_str, 100, test_str1);
1203 /* package with string indexes will contain two more bytes holding indexes
1204 * of string parameter locations.
1205 */
1206 zassert_equal(len0 + 2, len1);
1207
1208 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package0[len0];
1209 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package1[len1];
1210
1211 CBPRINTF_STATIC_PACKAGE(package0, sizeof(package0), len0, 0,
1212 CBPRINTF_PACKAGE_CONST_CHAR_RO,
1213 test_str, 100, test_str1);
1214 CBPRINTF_STATIC_PACKAGE(package1, sizeof(package1), len1, 0,
1215 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1216 test_str, 100, test_str1);
1217
1218 union cbprintf_package_hdr *desc0 = (union cbprintf_package_hdr *)package0;
1219 union cbprintf_package_hdr *desc1 = (union cbprintf_package_hdr *)package1;
1220
1221 /* Compare descriptor content. Second package has one ro string index. */
1222 zassert_equal(desc0->desc.ro_str_cnt, 0);
1223 zassert_equal(desc1->desc.ro_str_cnt, 2);
1224 zassert_equal(len0 + 2, len1);
1225
1226 int *p = (int *)package1;
1227
1228 str_idx = package1[len0];
1229 addr = *(char **)&p[str_idx];
1230 zassert_equal(addr, test_str);
1231
1232 str_idx = package1[len0 + 1];
1233 addr = *(char **)&p[str_idx];
1234 zassert_equal(addr, test_str1);
1235 }
1236
fsc_package_cb(int c,void * ctx)1237 static int fsc_package_cb(int c, void *ctx)
1238 {
1239 char **p = ctx;
1240
1241 (*p)[0] = c;
1242 *p = *p + 1;
1243
1244 return c;
1245 }
1246
1247 /* Test for validating conversion to fully self-contained package. */
ZTEST(prf,test_cbprintf_fsc_package)1248 ZTEST(prf, test_cbprintf_fsc_package)
1249 {
1250 if (!ENABLED_USE_PACKAGED) {
1251 TC_PRINT("disabled\n");
1252 return;
1253 }
1254
1255 if (!Z_C_GENERIC) {
1256 /* runtime packaging will not detect ro strings. */
1257 return;
1258 }
1259
1260 char test_str[] = "test %d %s";
1261 const char *test_str1 = "lorem ipsum";
1262 char exp_str0[256];
1263 char exp_str1[256];
1264 char out_str[256];
1265 char *pout;
1266 int len;
1267 int fsc_len;
1268 int err;
1269
1270 snprintf(exp_str0, sizeof(exp_str0), test_str, 100, test_str1);
1271
1272 CBPRINTF_STATIC_PACKAGE(NULL, 0, len, 0,
1273 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1274 test_str, 100, test_str1);
1275
1276 zassert_true(len > 0);
1277 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
1278
1279 CBPRINTF_STATIC_PACKAGE(package, sizeof(package), len, 0,
1280 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
1281 test_str, 100, test_str1);
1282
1283 /* Get length of fsc package. */
1284 fsc_len = cbprintf_fsc_package(package, len, NULL, 0);
1285
1286 int exp_len = len + (int)strlen(test_str) + 1 + (int)strlen(test_str1) + 1;
1287
1288 zassert_equal(exp_len, fsc_len);
1289
1290 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) fsc_package[fsc_len];
1291
1292 err = cbprintf_fsc_package(package, len, fsc_package, fsc_len - 1);
1293 zassert_equal(err, -ENOSPC);
1294
1295 err = cbprintf_fsc_package(package, len, fsc_package, fsc_len);
1296 zassert_equal(err, fsc_len);
1297
1298 /* Now overwrite a char in original string, confirm that fsc package
1299 * contains string without that change because ro string is copied into
1300 * the package.
1301 */
1302 test_str[0] = 'w';
1303 snprintf(exp_str1, sizeof(exp_str1), test_str, 100, test_str1);
1304
1305 pout = out_str;
1306 cbpprintf(fsc_package_cb, &pout, package);
1307 *pout = '\0';
1308
1309 zassert_equal(strcmp(out_str, exp_str1), 0);
1310 zassert_true(strcmp(exp_str0, exp_str1) != 0);
1311
1312 /* FSC package contains original content. */
1313 pout = out_str;
1314 cbpprintf(fsc_package_cb, &pout, fsc_package);
1315 *pout = '\0';
1316 zassert_equal(strcmp(out_str, exp_str0), 0);
1317 }
1318
ZTEST(prf,test_cbpprintf)1319 ZTEST(prf, test_cbpprintf)
1320 {
1321 if (!ENABLED_USE_PACKAGED) {
1322 TC_PRINT("disabled\n");
1323 return;
1324 }
1325
1326 int rc;
1327
1328 /* This only checks error conditions. Formatting is checked
1329 * by diverting prf() and related helpers to use the packaged
1330 * version.
1331 */
1332 reset_out();
1333 rc = cbpprintf(out, &outbuf, NULL);
1334 zassert_equal(rc, -EINVAL);
1335 }
1336
ZTEST(prf,test_nop)1337 ZTEST(prf, test_nop)
1338 {
1339 }
1340
cbprintf_setup(void)1341 static void *cbprintf_setup(void)
1342 {
1343 if (sizeof(int) == 4) {
1344 pfx_str += 8U;
1345 sfx_str += 8U;
1346 }
1347
1348 TC_PRINT("Opts: " COND_CODE_1(M64_MODE, ("m64"), ("m32")) "\n");
1349 if (ENABLED_USE_LIBC) {
1350 TC_PRINT(" LIBC");
1351 }
1352 if (IS_ENABLED(CONFIG_CBPRINTF_COMPLETE)) {
1353 TC_PRINT(" COMPLETE");
1354 } else {
1355 TC_PRINT(" NANO\n");
1356 }
1357 if (ENABLED_USE_PACKAGED) {
1358 TC_PRINT(" PACKAGED %s C11 _Generic\n",
1359 Z_C_GENERIC ? "with" : "without");
1360 } else {
1361 TC_PRINT(" VA_LIST\n");
1362 }
1363 if (IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
1364 TC_PRINT(" FULL_INTEGRAL\n");
1365 } else {
1366 TC_PRINT(" REDUCED_INTEGRAL\n");
1367 }
1368 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
1369 TC_PRINT(" FP_SUPPORT\n");
1370 }
1371 if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
1372 TC_PRINT(" FP_A_SUPPORT\n");
1373 }
1374 if (IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
1375 TC_PRINT(" FP_N_SPECIFIER\n");
1376 }
1377 if (IS_ENABLED(CONFIG_CBPRINTF_LIBC_SUBSTS)) {
1378 TC_PRINT(" LIBC_SUBSTS\n");
1379 }
1380
1381 printf("sizeof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
1382 sizeof(int), sizeof(long), sizeof(void *), sizeof(long long),
1383 sizeof(double), sizeof(long double));
1384 printf("alignof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
1385 __alignof__(int), __alignof__(long), __alignof__(void *),
1386 __alignof__(long long), __alignof__(double), __alignof__(long double));
1387 #ifdef CONFIG_CBPRINTF_COMPLETE
1388 printf("sizeof(conversion) = %zu\n", sizeof(struct conversion));
1389 #endif
1390
1391 #ifdef USE_PACKAGED
1392 printf("package alignment offset = %zu\n", PKG_ALIGN_OFFSET);
1393 #endif
1394
1395 return NULL;
1396 }
1397
1398 ZTEST_SUITE(prf, NULL, cbprintf_setup, NULL, NULL, NULL);
1399