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