1//===-- Unittests for the printf Parser -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/__support/CPP/bit.h"
10#include "src/__support/CPP/string_view.h"
11#include "src/__support/arg_list.h"
12#include "src/stdio/printf_core/parser.h"
13
14#include <stdarg.h>
15
16#include "test/UnitTest/PrintfMatcher.h"
17#include "test/UnitTest/Test.h"
18
19using LIBC_NAMESPACE::cpp::string_view;
20using LIBC_NAMESPACE::internal::ArgList;
21
22void init(const char *__restrict str, ...) {
23 va_list vlist;
24 va_start(vlist, str);
25 ArgList v(vlist);
26 va_end(vlist);
27
28 LIBC_NAMESPACE::printf_core::Parser<ArgList> parser(str, v);
29}
30
31void evaluate(LIBC_NAMESPACE::printf_core::FormatSection *format_arr,
32 const char *__restrict str, ...) {
33 va_list vlist;
34 va_start(vlist, str);
35 ArgList v(vlist);
36 va_end(vlist);
37
38 LIBC_NAMESPACE::printf_core::Parser<ArgList> parser(str, v);
39
40 for (auto cur_section = parser.get_next_section();
41 !cur_section.raw_string.empty();
42 cur_section = parser.get_next_section()) {
43 *format_arr = cur_section;
44 ++format_arr;
45 }
46}
47
48TEST(LlvmLibcPrintfParserTest, Constructor) { init(str: "test", 1, 2); }
49
50TEST(LlvmLibcPrintfParserTest, EvalRaw) {
51 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
52 const char *str = "test";
53 evaluate(format_arr, str);
54
55 LIBC_NAMESPACE::printf_core::FormatSection expected;
56 expected.has_conv = false;
57
58 expected.raw_string = {str, 4};
59
60 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
61 // TODO: add checks that the format_arr after the last one has length 0
62}
63
64TEST(LlvmLibcPrintfParserTest, EvalSimple) {
65 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
66 const char *str = "test %% test";
67 evaluate(format_arr, str);
68
69 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
70 expected0.has_conv = false;
71
72 expected0.raw_string = {str, 5};
73
74 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
75
76 expected1.has_conv = true;
77
78 expected1.raw_string = {str + 5, 2};
79 expected1.conv_name = '%';
80
81 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
82
83 expected2.has_conv = false;
84
85 expected2.raw_string = {str + 7, 5};
86
87 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
88}
89
90TEST(LlvmLibcPrintfParserTest, EvalOneArg) {
91 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
92 const char *str = "%d";
93 int arg1 = 12345;
94 evaluate(format_arr, str, arg1);
95
96 LIBC_NAMESPACE::printf_core::FormatSection expected;
97 expected.has_conv = true;
98
99 expected.raw_string = {str, 2};
100 expected.conv_val_raw = arg1;
101 expected.conv_name = 'd';
102
103 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
104}
105
106TEST(LlvmLibcPrintfParserTest, EvalBadArg) {
107 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
108 const char *str = "%\0abc";
109 int arg1 = 12345;
110 evaluate(format_arr, str, arg1);
111
112 LIBC_NAMESPACE::printf_core::FormatSection expected;
113 expected.has_conv = false;
114 expected.raw_string = {str, 1};
115
116 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
117}
118
119TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFlags) {
120 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
121 const char *str = "%+-0 #d";
122 int arg1 = 12345;
123 evaluate(format_arr, str, arg1);
124
125 LIBC_NAMESPACE::printf_core::FormatSection expected;
126 expected.has_conv = true;
127
128 expected.raw_string = {str, 7};
129 expected.flags = static_cast<LIBC_NAMESPACE::printf_core::FormatFlags>(
130 LIBC_NAMESPACE::printf_core::FormatFlags::FORCE_SIGN |
131 LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED |
132 LIBC_NAMESPACE::printf_core::FormatFlags::LEADING_ZEROES |
133 LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX |
134 LIBC_NAMESPACE::printf_core::FormatFlags::ALTERNATE_FORM);
135 expected.conv_val_raw = arg1;
136 expected.conv_name = 'd';
137
138 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
139}
140
141TEST(LlvmLibcPrintfParserTest, EvalOneArgWithWidth) {
142 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
143 const char *str = "%12d";
144 int arg1 = 12345;
145 evaluate(format_arr, str, arg1);
146
147 LIBC_NAMESPACE::printf_core::FormatSection expected;
148 expected.has_conv = true;
149
150 expected.raw_string = {str, 4};
151 expected.min_width = 12;
152 expected.conv_val_raw = arg1;
153 expected.conv_name = 'd';
154
155 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
156}
157
158TEST(LlvmLibcPrintfParserTest, EvalOneArgWithPrecision) {
159 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
160 const char *str = "%.34d";
161 int arg1 = 12345;
162 evaluate(format_arr, str, arg1);
163
164 LIBC_NAMESPACE::printf_core::FormatSection expected;
165 expected.has_conv = true;
166
167 expected.raw_string = {str, 5};
168 expected.precision = 34;
169 expected.conv_val_raw = arg1;
170 expected.conv_name = 'd';
171
172 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
173}
174
175TEST(LlvmLibcPrintfParserTest, EvalOneArgWithTrivialPrecision) {
176 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
177 const char *str = "%.d";
178 int arg1 = 12345;
179 evaluate(format_arr, str, arg1);
180
181 LIBC_NAMESPACE::printf_core::FormatSection expected;
182 expected.has_conv = true;
183
184 expected.raw_string = {str, 3};
185 expected.precision = 0;
186 expected.conv_val_raw = arg1;
187 expected.conv_name = 'd';
188
189 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
190}
191
192TEST(LlvmLibcPrintfParserTest, EvalOneArgWithShortLengthModifier) {
193 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
194 const char *str = "%hd";
195 int arg1 = 12345;
196 evaluate(format_arr, str, arg1);
197
198 LIBC_NAMESPACE::printf_core::FormatSection expected;
199 expected.has_conv = true;
200
201 expected.raw_string = {str, 3};
202 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::h;
203 expected.conv_val_raw = arg1;
204 expected.conv_name = 'd';
205
206 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
207}
208
209TEST(LlvmLibcPrintfParserTest, EvalOneArgWithLongLengthModifier) {
210 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
211 const char *str = "%lld";
212 long long arg1 = 12345;
213 evaluate(format_arr, str, arg1);
214
215 LIBC_NAMESPACE::printf_core::FormatSection expected;
216 expected.has_conv = true;
217
218 expected.raw_string = {str, 4};
219 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::ll;
220 expected.conv_val_raw = arg1;
221 expected.conv_name = 'd';
222
223 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
224}
225
226TEST(LlvmLibcPrintfParserTest, EvalOneArgWithBitWidthLengthModifier) {
227 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
228 const char *str = "%w32d";
229 long long arg1 = 12345;
230 evaluate(format_arr, str, arg1);
231
232 LIBC_NAMESPACE::printf_core::FormatSection expected;
233 expected.has_conv = true;
234
235 expected.raw_string = {str, 5};
236 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::w;
237 expected.bit_width = 32;
238 expected.conv_val_raw = arg1;
239 expected.conv_name = 'd';
240
241 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
242}
243
244TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFastBitWidthLengthModifier) {
245 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
246 const char *str = "%wf32d";
247 long long arg1 = 12345;
248 evaluate(format_arr, str, arg1);
249
250 LIBC_NAMESPACE::printf_core::FormatSection expected;
251 expected.has_conv = true;
252
253 expected.raw_string = {str, 6};
254 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::wf;
255 expected.bit_width = 32;
256 expected.conv_val_raw = arg1;
257 expected.conv_name = 'd';
258
259 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
260}
261
262TEST(LlvmLibcPrintfParserTest, EvalOneArgWithAllOptions) {
263 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
264 const char *str = "% -056.78jd";
265 intmax_t arg1 = 12345;
266 evaluate(format_arr, str, arg1);
267
268 LIBC_NAMESPACE::printf_core::FormatSection expected;
269 expected.has_conv = true;
270
271 expected.raw_string = {str, 11};
272 expected.flags = static_cast<LIBC_NAMESPACE::printf_core::FormatFlags>(
273 LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED |
274 LIBC_NAMESPACE::printf_core::FormatFlags::LEADING_ZEROES |
275 LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX);
276 expected.min_width = 56;
277 expected.precision = 78;
278 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::j;
279 expected.conv_val_raw = arg1;
280 expected.conv_name = 'd';
281
282 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
283}
284
285TEST(LlvmLibcPrintfParserTest, EvalThreeArgs) {
286 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
287 const char *str = "%d%f%s";
288 int arg1 = 12345;
289 double arg2 = 123.45;
290 const char *arg3 = "12345";
291 evaluate(format_arr, str, arg1, arg2, arg3);
292
293 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
294 expected0.has_conv = true;
295
296 expected0.raw_string = {str, 2};
297 expected0.conv_val_raw = arg1;
298 expected0.conv_name = 'd';
299
300 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
301
302 expected1.has_conv = true;
303
304 expected1.raw_string = {str + 2, 2};
305 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(from: arg2);
306 expected1.conv_name = 'f';
307
308 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
309
310 expected2.has_conv = true;
311
312 expected2.raw_string = {str + 4, 2};
313 expected2.conv_val_ptr = const_cast<char *>(arg3);
314 expected2.conv_name = 's';
315
316 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
317}
318
319#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
320
321TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {
322 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
323 const char *str = "%1$d";
324 int arg1 = 12345;
325 evaluate(format_arr, str, arg1);
326
327 LIBC_NAMESPACE::printf_core::FormatSection expected;
328 expected.has_conv = true;
329
330 expected.raw_string = {str, 4};
331 expected.conv_val_raw = arg1;
332 expected.conv_name = 'd';
333
334 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
335}
336
337TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsSequential) {
338 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
339 const char *str = "%1$d%2$f%3$s";
340 int arg1 = 12345;
341 double arg2 = 123.45;
342 const char *arg3 = "12345";
343 evaluate(format_arr, str, arg1, arg2, arg3);
344
345 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
346 expected0.has_conv = true;
347
348 expected0.raw_string = {str, 4};
349 expected0.conv_val_raw = arg1;
350 expected0.conv_name = 'd';
351
352 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
353
354 expected1.has_conv = true;
355
356 expected1.raw_string = {str + 4, 4};
357 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(from: arg2);
358 expected1.conv_name = 'f';
359
360 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
361
362 expected2.has_conv = true;
363
364 expected2.raw_string = {str + 8, 4};
365 expected2.conv_val_ptr = const_cast<char *>(arg3);
366 expected2.conv_name = 's';
367
368 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
369}
370
371TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsReverse) {
372 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
373 const char *str = "%3$d%2$f%1$s";
374 int arg1 = 12345;
375 double arg2 = 123.45;
376 const char *arg3 = "12345";
377 evaluate(format_arr, str, arg3, arg2, arg1);
378
379 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
380 expected0.has_conv = true;
381
382 expected0.raw_string = {str, 4};
383 expected0.conv_val_raw = arg1;
384 expected0.conv_name = 'd';
385
386 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
387
388 expected1.has_conv = true;
389
390 expected1.raw_string = {str + 4, 4};
391 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(from: arg2);
392 expected1.conv_name = 'f';
393
394 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
395
396 expected2.has_conv = true;
397
398 expected2.raw_string = {str + 8, 4};
399 expected2.conv_val_ptr = const_cast<char *>(arg3);
400 expected2.conv_name = 's';
401
402 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
403}
404
405TEST(LlvmLibcPrintfParserTest, IndexModeTenArgsRandom) {
406 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
407 const char *str = "%6$d%3$d%7$d%2$d%8$d%1$d%4$d%9$d%5$d%10$d";
408 int args[10] = {6, 4, 2, 7, 9, 1, 3, 5, 8, 10};
409 evaluate(format_arr, str, args[0], args[1], args[2], args[3], args[4],
410 args[5], args[6], args[7], args[8], args[9]);
411
412 for (size_t i = 0; i < 10; ++i) {
413 LIBC_NAMESPACE::printf_core::FormatSection expected;
414 expected.has_conv = true;
415
416 expected.raw_string = {str + (4 * i),
417 static_cast<size_t>(4 + (i >= 9 ? 1 : 0))};
418 expected.conv_val_raw = i + 1;
419 expected.conv_name = 'd';
420 EXPECT_PFORMAT_EQ(expected, format_arr[i]);
421 }
422}
423
424TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
425 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
426 const char *str = "normal text %3$llu %% %2$ *4$f %2$ .*4$f %1$1.1c";
427 char arg1 = '1';
428 double arg2 = 123.45;
429 unsigned long long arg3 = 12345;
430 int arg4 = 10;
431 evaluate(format_arr, str, arg1, arg2, arg3, arg4);
432
433 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2,
434 expected3, expected4, expected5, expected6, expected7, expected8,
435 expected9;
436
437 expected0.has_conv = false;
438
439 expected0.raw_string = {str, 12};
440
441 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
442
443 expected1.has_conv = true;
444
445 expected1.raw_string = {str + 12, 6};
446 expected1.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::ll;
447 expected1.conv_val_raw = arg3;
448 expected1.conv_name = 'u';
449
450 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
451
452 expected2.has_conv = false;
453
454 expected2.raw_string = {str + 18, 1};
455
456 EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
457
458 expected3.has_conv = true;
459
460 expected3.raw_string = {str + 19, 2};
461 expected3.conv_name = '%';
462
463 EXPECT_PFORMAT_EQ(expected3, format_arr[3]);
464
465 expected4.has_conv = false;
466
467 expected4.raw_string = {str + 21, 1};
468
469 EXPECT_PFORMAT_EQ(expected4, format_arr[4]);
470
471 expected5.has_conv = true;
472
473 expected5.raw_string = {str + 22, 8};
474 expected5.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
475 expected5.min_width = arg4;
476 expected5.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(from: arg2);
477 expected5.conv_name = 'f';
478
479 EXPECT_PFORMAT_EQ(expected5, format_arr[5]);
480
481 expected6.has_conv = false;
482
483 expected6.raw_string = {str + 30, 1};
484
485 EXPECT_PFORMAT_EQ(expected6, format_arr[6]);
486
487 expected7.has_conv = true;
488
489 expected7.raw_string = {str + 31, 9};
490 expected7.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
491 expected7.precision = arg4;
492 expected7.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(from: arg2);
493 expected7.conv_name = 'f';
494
495 EXPECT_PFORMAT_EQ(expected7, format_arr[7]);
496
497 expected8.has_conv = false;
498
499 expected8.raw_string = {str + 40, 1};
500
501 EXPECT_PFORMAT_EQ(expected8, format_arr[8]);
502
503 expected9.has_conv = true;
504
505 expected9.raw_string = {str + 41, 7};
506 expected9.min_width = 1;
507 expected9.precision = 1;
508 expected9.conv_val_raw = arg1;
509 expected9.conv_name = 'c';
510
511 EXPECT_PFORMAT_EQ(expected9, format_arr[9]);
512}
513
514TEST(LlvmLibcPrintfParserTest, IndexModeGapCheck) {
515 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
516 const char *str = "%1$d%2$d%4$d";
517 int arg1 = 1;
518 int arg2 = 2;
519 int arg3 = 3;
520 int arg4 = 4;
521
522 evaluate(format_arr, str, arg1, arg2, arg3, arg4);
523
524 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
525
526 expected0.has_conv = true;
527 expected0.raw_string = {str, 4};
528 expected0.conv_val_raw = arg1;
529 expected0.conv_name = 'd';
530
531 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
532
533 expected1.has_conv = true;
534 expected1.raw_string = {str + 4, 4};
535 expected1.conv_val_raw = arg2;
536 expected1.conv_name = 'd';
537
538 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
539
540 expected2.has_conv = false;
541 expected2.raw_string = {str + 8, 4};
542
543 EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
544}
545
546TEST(LlvmLibcPrintfParserTest, IndexModeTrailingPercentCrash) {
547 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
548 const char *str = "%2$d%";
549 evaluate(format_arr, str, 1, 2);
550
551 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1;
552 expected0.has_conv = false;
553
554 expected0.raw_string = {str, 4};
555 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
556
557 expected1.has_conv = false;
558
559 expected1.raw_string = {str + 4, 1};
560 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
561}
562
563TEST(LlvmLibcPrintfParserTest, DoublePercentIsAllowedInvalidIndex) {
564 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
565
566 // Normally this conversion specifier would be raw (due to having a width
567 // defined as an invalid argument) but since it's a % conversion it's allowed
568 // by this specific parser. Any % conversion that is not just "%%" is
569 // undefined, so this is implementation-specific behavior.
570 // The goal is to be consistent. A conversion specifier of "%L%" is also
571 // undefined, but is traditionally displayed as just "%". "%2%" is also
572 // displayed as "%", even though if the width was respected it should be " %".
573 // Finally, "%*%" traditionally is displayed as "%" but also traditionally
574 // consumes an argument, since the * consumes an integer. Therefore, having
575 // "%*2$%" display as "%" is consistent with other printf behavior.
576 const char *str = "%*2$%";
577
578 evaluate(format_arr, str, 1, 2);
579
580 LIBC_NAMESPACE::printf_core::FormatSection expected0;
581 expected0.has_conv = true;
582
583 expected0.raw_string = str;
584 expected0.conv_name = '%';
585 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
586}
587
588#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
589

source code of libc/test/src/stdio/printf_core/parser_test.cpp