xref: /llvm-project/libc/test/src/stdio/printf_core/parser_test.cpp (revision a21fc4c0a681000c23089301e8935f579517b96a)
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 
19 using LIBC_NAMESPACE::cpp::string_view;
20 using LIBC_NAMESPACE::internal::ArgList;
21 
22 void 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 
31 void 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 
48 TEST(LlvmLibcPrintfParserTest, Constructor) { init("test", 1, 2); }
49 
50 TEST(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 
64 TEST(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 
90 TEST(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 
106 TEST(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 
119 TEST(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 
141 TEST(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 
158 TEST(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 
175 TEST(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 
192 TEST(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 
209 TEST(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 
226 TEST(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 
244 TEST(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 
262 TEST(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 
285 TEST(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>(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 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithOverflowingWidthAndPrecision) {
320   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
321   const char *str = "%-999999999999.999999999999d";
322   int arg1 = 12345;
323   evaluate(format_arr, str, arg1);
324 
325   LIBC_NAMESPACE::printf_core::FormatSection expected;
326   expected.has_conv = true;
327 
328   expected.raw_string = {str, 28};
329   expected.flags = LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
330   expected.min_width = INT_MAX;
331   expected.precision = INT_MAX;
332   expected.conv_val_raw = arg1;
333   expected.conv_name = 'd';
334 
335   ASSERT_PFORMAT_EQ(expected, format_arr[0]);
336 }
337 
338 TEST(LlvmLibcPrintfParserTest,
339      EvalOneArgWithOverflowingWidthAndPrecisionAsArgs) {
340   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
341   const char *str = "%*.*d";
342   int arg1 = INT_MIN; // INT_MIN = -2147483648 if int is 32 bits.
343   int arg2 = INT_MIN;
344   int arg3 = 12345;
345   evaluate(format_arr, str, arg1, arg2, arg3);
346 
347   LIBC_NAMESPACE::printf_core::FormatSection expected;
348   expected.has_conv = true;
349 
350   expected.raw_string = {str, 5};
351   expected.flags = LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
352   expected.min_width = INT_MAX;
353   expected.precision = arg2;
354   expected.conv_val_raw = arg3;
355   expected.conv_name = 'd';
356 
357   ASSERT_PFORMAT_EQ(expected, format_arr[0]);
358 }
359 
360 #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
361 
362 TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {
363   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
364   const char *str = "%1$d";
365   int arg1 = 12345;
366   evaluate(format_arr, str, arg1);
367 
368   LIBC_NAMESPACE::printf_core::FormatSection expected;
369   expected.has_conv = true;
370 
371   expected.raw_string = {str, 4};
372   expected.conv_val_raw = arg1;
373   expected.conv_name = 'd';
374 
375   ASSERT_PFORMAT_EQ(expected, format_arr[0]);
376 }
377 
378 TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsSequential) {
379   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
380   const char *str = "%1$d%2$f%3$s";
381   int arg1 = 12345;
382   double arg2 = 123.45;
383   const char *arg3 = "12345";
384   evaluate(format_arr, str, arg1, arg2, arg3);
385 
386   LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
387   expected0.has_conv = true;
388 
389   expected0.raw_string = {str, 4};
390   expected0.conv_val_raw = arg1;
391   expected0.conv_name = 'd';
392 
393   ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
394 
395   expected1.has_conv = true;
396 
397   expected1.raw_string = {str + 4, 4};
398   expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
399   expected1.conv_name = 'f';
400 
401   ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
402 
403   expected2.has_conv = true;
404 
405   expected2.raw_string = {str + 8, 4};
406   expected2.conv_val_ptr = const_cast<char *>(arg3);
407   expected2.conv_name = 's';
408 
409   ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
410 }
411 
412 TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsReverse) {
413   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
414   const char *str = "%3$d%2$f%1$s";
415   int arg1 = 12345;
416   double arg2 = 123.45;
417   const char *arg3 = "12345";
418   evaluate(format_arr, str, arg3, arg2, arg1);
419 
420   LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
421   expected0.has_conv = true;
422 
423   expected0.raw_string = {str, 4};
424   expected0.conv_val_raw = arg1;
425   expected0.conv_name = 'd';
426 
427   ASSERT_PFORMAT_EQ(expected0, format_arr[0]);
428 
429   expected1.has_conv = true;
430 
431   expected1.raw_string = {str + 4, 4};
432   expected1.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
433   expected1.conv_name = 'f';
434 
435   ASSERT_PFORMAT_EQ(expected1, format_arr[1]);
436 
437   expected2.has_conv = true;
438 
439   expected2.raw_string = {str + 8, 4};
440   expected2.conv_val_ptr = const_cast<char *>(arg3);
441   expected2.conv_name = 's';
442 
443   ASSERT_PFORMAT_EQ(expected2, format_arr[2]);
444 }
445 
446 TEST(LlvmLibcPrintfParserTest, IndexModeTenArgsRandom) {
447   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
448   const char *str = "%6$d%3$d%7$d%2$d%8$d%1$d%4$d%9$d%5$d%10$d";
449   int args[10] = {6, 4, 2, 7, 9, 1, 3, 5, 8, 10};
450   evaluate(format_arr, str, args[0], args[1], args[2], args[3], args[4],
451            args[5], args[6], args[7], args[8], args[9]);
452 
453   for (size_t i = 0; i < 10; ++i) {
454     LIBC_NAMESPACE::printf_core::FormatSection expected;
455     expected.has_conv = true;
456 
457     expected.raw_string = {str + (4 * i),
458                            static_cast<size_t>(4 + (i >= 9 ? 1 : 0))};
459     expected.conv_val_raw = i + 1;
460     expected.conv_name = 'd';
461     EXPECT_PFORMAT_EQ(expected, format_arr[i]);
462   }
463 }
464 
465 TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
466   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
467   const char *str = "normal text %3$llu %% %2$ *4$f %2$ .*4$f %1$1.1c";
468   char arg1 = '1';
469   double arg2 = 123.45;
470   unsigned long long arg3 = 12345;
471   int arg4 = 10;
472   evaluate(format_arr, str, arg1, arg2, arg3, arg4);
473 
474   LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2,
475       expected3, expected4, expected5, expected6, expected7, expected8,
476       expected9;
477 
478   expected0.has_conv = false;
479 
480   expected0.raw_string = {str, 12};
481 
482   EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
483 
484   expected1.has_conv = true;
485 
486   expected1.raw_string = {str + 12, 6};
487   expected1.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::ll;
488   expected1.conv_val_raw = arg3;
489   expected1.conv_name = 'u';
490 
491   EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
492 
493   expected2.has_conv = false;
494 
495   expected2.raw_string = {str + 18, 1};
496 
497   EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
498 
499   expected3.has_conv = true;
500 
501   expected3.raw_string = {str + 19, 2};
502   expected3.conv_name = '%';
503 
504   EXPECT_PFORMAT_EQ(expected3, format_arr[3]);
505 
506   expected4.has_conv = false;
507 
508   expected4.raw_string = {str + 21, 1};
509 
510   EXPECT_PFORMAT_EQ(expected4, format_arr[4]);
511 
512   expected5.has_conv = true;
513 
514   expected5.raw_string = {str + 22, 8};
515   expected5.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
516   expected5.min_width = arg4;
517   expected5.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
518   expected5.conv_name = 'f';
519 
520   EXPECT_PFORMAT_EQ(expected5, format_arr[5]);
521 
522   expected6.has_conv = false;
523 
524   expected6.raw_string = {str + 30, 1};
525 
526   EXPECT_PFORMAT_EQ(expected6, format_arr[6]);
527 
528   expected7.has_conv = true;
529 
530   expected7.raw_string = {str + 31, 9};
531   expected7.flags = LIBC_NAMESPACE::printf_core::FormatFlags::SPACE_PREFIX;
532   expected7.precision = arg4;
533   expected7.conv_val_raw = LIBC_NAMESPACE::cpp::bit_cast<uint64_t>(arg2);
534   expected7.conv_name = 'f';
535 
536   EXPECT_PFORMAT_EQ(expected7, format_arr[7]);
537 
538   expected8.has_conv = false;
539 
540   expected8.raw_string = {str + 40, 1};
541 
542   EXPECT_PFORMAT_EQ(expected8, format_arr[8]);
543 
544   expected9.has_conv = true;
545 
546   expected9.raw_string = {str + 41, 7};
547   expected9.min_width = 1;
548   expected9.precision = 1;
549   expected9.conv_val_raw = arg1;
550   expected9.conv_name = 'c';
551 
552   EXPECT_PFORMAT_EQ(expected9, format_arr[9]);
553 }
554 
555 TEST(LlvmLibcPrintfParserTest, IndexModeGapCheck) {
556   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
557   const char *str = "%1$d%2$d%4$d";
558   int arg1 = 1;
559   int arg2 = 2;
560   int arg3 = 3;
561   int arg4 = 4;
562 
563   evaluate(format_arr, str, arg1, arg2, arg3, arg4);
564 
565   LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1, expected2;
566 
567   expected0.has_conv = true;
568   expected0.raw_string = {str, 4};
569   expected0.conv_val_raw = arg1;
570   expected0.conv_name = 'd';
571 
572   EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
573 
574   expected1.has_conv = true;
575   expected1.raw_string = {str + 4, 4};
576   expected1.conv_val_raw = arg2;
577   expected1.conv_name = 'd';
578 
579   EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
580 
581   expected2.has_conv = false;
582   expected2.raw_string = {str + 8, 4};
583 
584   EXPECT_PFORMAT_EQ(expected2, format_arr[2]);
585 }
586 
587 TEST(LlvmLibcPrintfParserTest, IndexModeTrailingPercentCrash) {
588   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
589   const char *str = "%2$d%";
590   evaluate(format_arr, str, 1, 2);
591 
592   LIBC_NAMESPACE::printf_core::FormatSection expected0, expected1;
593   expected0.has_conv = false;
594 
595   expected0.raw_string = {str, 4};
596   EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
597 
598   expected1.has_conv = false;
599 
600   expected1.raw_string = {str + 4, 1};
601   EXPECT_PFORMAT_EQ(expected1, format_arr[1]);
602 }
603 
604 TEST(LlvmLibcPrintfParserTest, DoublePercentIsAllowedInvalidIndex) {
605   LIBC_NAMESPACE::printf_core::FormatSection format_arr[10];
606 
607   // Normally this conversion specifier would be raw (due to having a width
608   // defined as an invalid argument) but since it's a % conversion it's allowed
609   // by this specific parser. Any % conversion that is not just "%%" is
610   // undefined, so this is implementation-specific behavior.
611   // The goal is to be consistent. A conversion specifier of "%L%" is also
612   // undefined, but is traditionally displayed as just "%". "%2%" is also
613   // displayed as "%", even though if the width was respected it should be " %".
614   // Finally, "%*%" traditionally is displayed as "%" but also traditionally
615   // consumes an argument, since the * consumes an integer. Therefore, having
616   // "%*2$%" display as "%" is consistent with other printf behavior.
617   const char *str = "%*2$%";
618 
619   evaluate(format_arr, str, 1, 2);
620 
621   LIBC_NAMESPACE::printf_core::FormatSection expected0;
622   expected0.has_conv = true;
623 
624   expected0.raw_string = str;
625   expected0.conv_name = '%';
626   EXPECT_PFORMAT_EQ(expected0, format_arr[0]);
627 }
628 
629 #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
630