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 =
101 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
102 expected.conv_name = 'd';
103
104 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
105}
106
107TEST(LlvmLibcPrintfParserTest, EvalBadArg) {
108 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
109 const char *str = "%\0abc";
110 int arg1 = 12345;
111 evaluate(format_arr, str, arg1);
112
113 LIBC_NAMESPACE::printf_core::FormatSection expected;
114 expected.has_conv = false;
115 expected.raw_string = {str, 1};
116
117 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
118}
119
120TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFlags) {
121 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
122 const char *str = "%+-0 #d";
123 int arg1 = 12345;
124 evaluate(format_arr, str, arg1);
125
126 LIBC_NAMESPACE::printf_core::FormatSection expected;
127 expected.has_conv = true;
128
129 expected.raw_string = {str, 7};
130 expected.flags = static_cast<LIBC_NAMESPACE::printf_core::FormatFlags>(
131 LIBC_NAMESPACE::printf_core::FormatFlags::FORCE_SIGN |
132 LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED |
133 LIBC_NAMESPACE::printf_core::FormatFlags::LEADING_ZEROES |
134 LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX |
135 LIBC_NAMESPACE::printf_core::FormatFlags::ALTERNATE_FORM);
136 expected.conv_val_raw =
137 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
138 expected.conv_name = 'd';
139
140 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
141}
142
143TEST(LlvmLibcPrintfParserTest, EvalOneArgWithWidth) {
144 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
145 const char *str = "%12d";
146 int arg1 = 12345;
147 evaluate(format_arr, str, arg1);
148
149 LIBC_NAMESPACE::printf_core::FormatSection expected;
150 expected.has_conv = true;
151
152 expected.raw_string = {str, 4};
153 expected.min_width = 12;
154 expected.conv_val_raw =
155 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
156 expected.conv_name = 'd';
157
158 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
159}
160
161TEST(LlvmLibcPrintfParserTest, EvalOneArgWithPrecision) {
162 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
163 const char *str = "%.34d";
164 int arg1 = 12345;
165 evaluate(format_arr, str, arg1);
166
167 LIBC_NAMESPACE::printf_core::FormatSection expected;
168 expected.has_conv = true;
169
170 expected.raw_string = {str, 5};
171 expected.precision = 34;
172 expected.conv_val_raw =
173 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
174 expected.conv_name = 'd';
175
176 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
177}
178
179TEST(LlvmLibcPrintfParserTest, EvalOneArgWithTrivialPrecision) {
180 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
181 const char *str = "%.d";
182 int arg1 = 12345;
183 evaluate(format_arr, str, arg1);
184
185 LIBC_NAMESPACE::printf_core::FormatSection expected;
186 expected.has_conv = true;
187
188 expected.raw_string = {str, 3};
189 expected.precision = 0;
190 expected.conv_val_raw =
191 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
192 expected.conv_name = 'd';
193
194 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
195}
196
197TEST(LlvmLibcPrintfParserTest, EvalOneArgWithShortLengthModifier) {
198 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
199 const char *str = "%hd";
200 int arg1 = 12345;
201 evaluate(format_arr, str, arg1);
202
203 LIBC_NAMESPACE::printf_core::FormatSection expected;
204 expected.has_conv = true;
205
206 expected.raw_string = {str, 3};
207 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::h;
208 expected.conv_val_raw =
209 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
210 expected.conv_name = 'd';
211
212 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
213}
214
215TEST(LlvmLibcPrintfParserTest, EvalOneArgWithLongLengthModifier) {
216 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
217 const char *str = "%lld";
218 long long arg1 = 12345;
219 evaluate(format_arr, str, arg1);
220
221 LIBC_NAMESPACE::printf_core::FormatSection expected;
222 expected.has_conv = true;
223
224 expected.raw_string = {str, 4};
225 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::ll;
226 expected.conv_val_raw =
227 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
228 expected.conv_name = 'd';
229
230 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
231}
232
233TEST(LlvmLibcPrintfParserTest, EvalOneArgWithBitWidthLengthModifier) {
234 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
235 const char *str = "%w32d";
236 long long arg1 = 12345;
237 evaluate(format_arr, str, arg1);
238
239 LIBC_NAMESPACE::printf_core::FormatSection expected;
240 expected.has_conv = true;
241
242 expected.raw_string = {str, 5};
243 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::w;
244 expected.bit_width = 32;
245 expected.conv_val_raw =
246 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
247 expected.conv_name = 'd';
248
249 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
250}
251
252TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFastBitWidthLengthModifier) {
253 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
254 const char *str = "%wf32d";
255 long long arg1 = 12345;
256 evaluate(format_arr, str, arg1);
257
258 LIBC_NAMESPACE::printf_core::FormatSection expected;
259 expected.has_conv = true;
260
261 expected.raw_string = {str, 6};
262 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::wf;
263 expected.bit_width = 32;
264 expected.conv_val_raw =
265 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
266 expected.conv_name = 'd';
267
268 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
269}
270
271TEST(LlvmLibcPrintfParserTest, EvalOneArgWithAllOptions) {
272 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
273 const char *str = "% -056.78jd";
274 intmax_t arg1 = 12345;
275 evaluate(format_arr, str, arg1);
276
277 LIBC_NAMESPACE::printf_core::FormatSection expected;
278 expected.has_conv = true;
279
280 expected.raw_string = {str, 11};
281 expected.flags = static_cast<LIBC_NAMESPACE::printf_core::FormatFlags>(
282 LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED |
283 LIBC_NAMESPACE::printf_core::FormatFlags::LEADING_ZEROES |
284 LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX);
285 expected.min_width = 56;
286 expected.precision = 78;
287 expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::j;
288 expected.conv_val_raw =
289 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
290 expected.conv_name = 'd';
291
292 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
293}
294
295TEST(LlvmLibcPrintfParserTest, EvalThreeArgs) {
296 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
297 const char *str = "%d%f%s";
298 int arg1 = 12345;
299 double arg2 = 123.45;
300 const char *arg3 = "12345";
301 evaluate(format_arr, str, arg1, arg2, arg3);
302
303 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
304 expected0.has_conv = true;
305
306 expected0.raw_string = {str, 2};
307 expected0.conv_val_raw =
308 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
309 expected0.conv_name = 'd';
310
311 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
312
313 expected1.has_conv = true;
314
315 expected1.raw_string = {str + 2, 2};
316 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
317 expected1.conv_name = 'f';
318
319 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
320
321 expected2.has_conv = true;
322
323 expected2.raw_string = {str + 4, 2};
324 expected2.conv_val_ptr = const_cast<char *>(arg3);
325 expected2.conv_name = 's';
326
327 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
328}
329
330TEST(LlvmLibcPrintfParserTest, EvalOneArgWithOverflowingWidthAndPrecision) {
331 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
332 const char *str = "%-999999999999.999999999999d";
333 int arg1 = 12345;
334 evaluate(format_arr, str, arg1);
335
336 LIBC_NAMESPACE::printf_core::FormatSection expected;
337 expected.has_conv = true;
338
339 expected.raw_string = {str, 28};
340 expected.flags = LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
341 expected.min_width = INT_MAX;
342 expected.precision = INT_MAX;
343 expected.conv_val_raw =
344 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
345 expected.conv_name = 'd';
346
347 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
348}
349
350TEST(LlvmLibcPrintfParserTest,
351 EvalOneArgWithOverflowingWidthAndPrecisionAsArgs) {
352 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
353 const char *str = "%*.*d";
354 int arg1 = INT_MIN; // INT_MIN = -2147483648 if int is 32 bits.
355 int arg2 = INT_MIN;
356 int arg3 = 12345;
357 evaluate(format_arr, str, arg1, arg2, arg3);
358
359 LIBC_NAMESPACE::printf_core::FormatSection expected;
360 expected.has_conv = true;
361
362 expected.raw_string = {str, 5};
363 expected.flags = LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
364 expected.min_width = INT_MAX;
365 expected.precision = arg2;
366 expected.conv_val_raw =
367 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg3);
368 expected.conv_name = 'd';
369
370 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
371}
372
373#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
374
375TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {
376 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
377 const char *str = "%1$d";
378 int arg1 = 12345;
379 evaluate(format_arr, str, arg1);
380
381 LIBC_NAMESPACE::printf_core::FormatSection expected;
382 expected.has_conv = true;
383
384 expected.raw_string = {str, 4};
385 expected.conv_val_raw =
386 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
387 expected.conv_name = 'd';
388
389 ASSERT_PFORMAT_EQ(expected, format_arr[0]);
390}
391
392TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsSequential) {
393 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
394 const char *str = "%1$d%2$f%3$s";
395 int arg1 = 12345;
396 double arg2 = 123.45;
397 const char *arg3 = "12345";
398 evaluate(format_arr, str, arg1, arg2, arg3);
399
400 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
401 expected0.has_conv = true;
402
403 expected0.raw_string = {str, 4};
404 expected0.conv_val_raw =
405 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
406 expected0.conv_name = 'd';
407
408 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
409
410 expected1.has_conv = true;
411
412 expected1.raw_string = {str + 4, 4};
413 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
414 expected1.conv_name = 'f';
415
416 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
417
418 expected2.has_conv = true;
419
420 expected2.raw_string = {str + 8, 4};
421 expected2.conv_val_ptr = const_cast<char *>(arg3);
422 expected2.conv_name = 's';
423
424 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
425}
426
427TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsReverse) {
428 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
429 const char *str = "%3$d%2$f%1$s";
430 int arg1 = 12345;
431 double arg2 = 123.45;
432 const char *arg3 = "12345";
433 evaluate(format_arr, str, arg3, arg2, arg1);
434
435 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
436 expected0.has_conv = true;
437
438 expected0.raw_string = {str, 4};
439 expected0.conv_val_raw =
440 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
441 expected0.conv_name = 'd';
442
443 ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
444
445 expected1.has_conv = true;
446
447 expected1.raw_string = {str + 4, 4};
448 expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
449 expected1.conv_name = 'f';
450
451 ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
452
453 expected2.has_conv = true;
454
455 expected2.raw_string = {str + 8, 4};
456 expected2.conv_val_ptr = const_cast<char *>(arg3);
457 expected2.conv_name = 's';
458
459 ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
460}
461
462TEST(LlvmLibcPrintfParserTest, IndexModeTenArgsRandom) {
463 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
464 const char *str = "%6$d%3$d%7$d%2$d%8$d%1$d%4$d%9$d%5$d%10$d";
465 int args[10] = {6, 4, 2, 7, 9, 1, 3, 5, 8, 10};
466 evaluate(format_arr, str, args[0], args[1], args[2], args[3], args[4],
467 args[5], args[6], args[7], args[8], args[9]);
468
469 for (size_t i = 0; i < 10; ++i) {
470 LIBC_NAMESPACE::printf_core::FormatSection expected;
471 expected.has_conv = true;
472
473 expected.raw_string = {str + (4 * i),
474 static_cast<size_t>(4 + (i >= 9 ? 1 : 0))};
475 expected.conv_val_raw = i + 1;
476 expected.conv_name = 'd';
477 EXPECT_PFORMAT_EQ(expected, format_arr[i]);
478 }
479}
480
481TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
482 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
483 const char *str = "normal text %3$llu %% %2$ *4$f %2$ .*4$f %1$1.1c";
484 char arg1 = '1';
485 double arg2 = 123.45;
486 unsigned long long arg3 = 12345;
487 int arg4 = 10;
488 evaluate(format_arr, str, arg1, arg2, arg3, arg4);
489
490 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2,
491 expected3, expected4, expected5, expected6, expected7, expected8,
492 expected9;
493
494 expected0.has_conv = false;
495
496 expected0.raw_string = {str, 12};
497
498 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
499
500 expected1.has_conv = true;
501
502 expected1.raw_string = {str + 12, 6};
503 expected1.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::ll;
504 expected1.conv_val_raw =
505 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg3);
506 expected1.conv_name = 'u';
507
508 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
509
510 expected2.has_conv = false;
511
512 expected2.raw_string = {str + 18, 1};
513
514 EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
515
516 expected3.has_conv = true;
517
518 expected3.raw_string = {str + 19, 2};
519 expected3.conv_name = '%';
520
521 EXPECT_PFORMAT_EQ(expected3, format_arr[3]);
522
523 expected4.has_conv = false;
524
525 expected4.raw_string = {str + 21, 1};
526
527 EXPECT_PFORMAT_EQ(expected4, format_arr[4]);
528
529 expected5.has_conv = true;
530
531 expected5.raw_string = {str + 22, 8};
532 expected5.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
533 expected5.min_width = arg4;
534 expected5.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
535 expected5.conv_name = 'f';
536
537 EXPECT_PFORMAT_EQ(expected5, format_arr[5]);
538
539 expected6.has_conv = false;
540
541 expected6.raw_string = {str + 30, 1};
542
543 EXPECT_PFORMAT_EQ(expected6, format_arr[6]);
544
545 expected7.has_conv = true;
546
547 expected7.raw_string = {str + 31, 9};
548 expected7.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
549 expected7.precision = arg4;
550 expected7.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
551 expected7.conv_name = 'f';
552
553 EXPECT_PFORMAT_EQ(expected7, format_arr[7]);
554
555 expected8.has_conv = false;
556
557 expected8.raw_string = {str + 40, 1};
558
559 EXPECT_PFORMAT_EQ(expected8, format_arr[8]);
560
561 expected9.has_conv = true;
562
563 expected9.raw_string = {str + 41, 7};
564 expected9.min_width = 1;
565 expected9.precision = 1;
566 expected9.conv_val_raw =
567 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
568 expected9.conv_name = 'c';
569
570 EXPECT_PFORMAT_EQ(expected9, format_arr[9]);
571}
572
573TEST(LlvmLibcPrintfParserTest, IndexModeGapCheck) {
574 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
575 const char *str = "%1$d%2$d%4$d";
576 int arg1 = 1;
577 int arg2 = 2;
578 int arg3 = 3;
579 int arg4 = 4;
580
581 evaluate(format_arr, str, arg1, arg2, arg3, arg4);
582
583 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
584
585 expected0.has_conv = true;
586 expected0.raw_string = {str, 4};
587 expected0.conv_val_raw =
588 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
589 expected0.conv_name = 'd';
590
591 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
592
593 expected1.has_conv = true;
594 expected1.raw_string = {str + 4, 4};
595 expected1.conv_val_raw =
596 static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg2);
597 expected1.conv_name = 'd';
598
599 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
600
601 expected2.has_conv = false;
602 expected2.raw_string = {str + 8, 4};
603
604 EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
605}
606
607TEST(LlvmLibcPrintfParserTest, IndexModeTrailingPercentCrash) {
608 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
609 const char *str = "%2$d%";
610 evaluate(format_arr, str, 1, 2);
611
612 LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1;
613 expected0.has_conv = false;
614
615 expected0.raw_string = {str, 4};
616 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
617
618 expected1.has_conv = false;
619
620 expected1.raw_string = {str + 4, 1};
621 EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
622}
623
624TEST(LlvmLibcPrintfParserTest, DoublePercentIsAllowedInvalidIndex) {
625 LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
626
627 // Normally this conversion specifier would be raw (due to having a width
628 // defined as an invalid argument) but since it's a % conversion it's allowed
629 // by this specific parser. Any % conversion that is not just "%%" is
630 // undefined, so this is implementation-specific behavior.
631 // The goal is to be consistent. A conversion specifier of "%L%" is also
632 // undefined, but is traditionally displayed as just "%". "%2%" is also
633 // displayed as "%", even though if the width was respected it should be " %".
634 // Finally, "%*%" traditionally is displayed as "%" but also traditionally
635 // consumes an argument, since the * consumes an integer. Therefore, having
636 // "%*2$%" display as "%" is consistent with other printf behavior.
637 const char *str = "%*2$%";
638
639 evaluate(format_arr, str, 1, 2);
640
641 LIBC_NAMESPACE::printf_core::FormatSection expected0;
642 expected0.has_conv = true;
643
644 expected0.raw_string = str;
645 expected0.conv_name = '%';
646 EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
647}
648
649#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
650

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