xref: /llvm-project/libc/test/src/stdio/scanf_core/parser_test.cpp (revision b6bc9d72f65a5086f310f321e969d96e9a559e75)
1 //===-- Unittests for the scanf 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/bitset.h"
11 #include "src/__support/CPP/string_view.h"
12 #include "src/__support/arg_list.h"
13 #include "src/stdio/scanf_core/parser.h"
14 
15 #include <stdarg.h>
16 
17 #include "test/UnitTest/ScanfMatcher.h"
18 #include "test/UnitTest/Test.h"
19 
20 using LIBC_NAMESPACE::cpp::string_view;
21 using LIBC_NAMESPACE::internal::ArgList;
22 
init(const char * __restrict str,...)23 void init(const char *__restrict str, ...) {
24   va_list vlist;
25   va_start(vlist, str);
26   ArgList v(vlist);
27   va_end(vlist);
28 
29   LIBC_NAMESPACE::scanf_core::Parser<ArgList> parser(str, v);
30 }
31 
evaluate(LIBC_NAMESPACE::scanf_core::FormatSection * format_arr,const char * __restrict str,...)32 void evaluate(LIBC_NAMESPACE::scanf_core::FormatSection *format_arr,
33               const char *__restrict str, ...) {
34   va_list vlist;
35   va_start(vlist, str);
36   LIBC_NAMESPACE::internal::ArgList v(vlist);
37   va_end(vlist);
38 
39   LIBC_NAMESPACE::scanf_core::Parser<ArgList> parser(str, v);
40 
41   for (auto cur_section = parser.get_next_section();
42        !cur_section.raw_string.empty();
43        cur_section = parser.get_next_section()) {
44     *format_arr = cur_section;
45     ++format_arr;
46   }
47 }
48 
TEST(LlvmLibcScanfParserTest,Constructor)49 TEST(LlvmLibcScanfParserTest, Constructor) { init("test", 1, 2); }
50 
TEST(LlvmLibcScanfParserTest,EvalRaw)51 TEST(LlvmLibcScanfParserTest, EvalRaw) {
52   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
53   const char *str = "test";
54   evaluate(format_arr, str);
55 
56   LIBC_NAMESPACE::scanf_core::FormatSection expected;
57   expected.has_conv = false;
58 
59   expected.raw_string = str;
60 
61   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
62   // TODO: add checks that the format_arr after the last one has length 0
63 }
64 
TEST(LlvmLibcScanfParserTest,EvalSimple)65 TEST(LlvmLibcScanfParserTest, EvalSimple) {
66   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
67   const char *str = "test %% test";
68   evaluate(format_arr, str);
69 
70   LIBC_NAMESPACE::scanf_core::FormatSection expected0, expected1, expected2;
71   expected0.has_conv = false;
72 
73   expected0.raw_string = {str, 5};
74 
75   ASSERT_SFORMAT_EQ(expected0, format_arr[0]);
76 
77   expected1.has_conv = true;
78 
79   expected1.raw_string = {str + 5, 2};
80   expected1.conv_name = '%';
81 
82   ASSERT_SFORMAT_EQ(expected1, format_arr[1]);
83 
84   expected2.has_conv = false;
85 
86   expected2.raw_string = {str + 7, 5};
87 
88   ASSERT_SFORMAT_EQ(expected2, format_arr[2]);
89 }
90 
TEST(LlvmLibcScanfParserTest,EvalOneArg)91 TEST(LlvmLibcScanfParserTest, EvalOneArg) {
92   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
93   const char *str = "%d";
94   int arg1 = 12345;
95   evaluate(format_arr, str, &arg1);
96 
97   LIBC_NAMESPACE::scanf_core::FormatSection expected;
98   expected.has_conv = true;
99 
100   expected.raw_string = str;
101   expected.output_ptr = &arg1;
102   expected.conv_name = 'd';
103 
104   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
105 }
106 
TEST(LlvmLibcScanfParserTest,EvalBadArg)107 TEST(LlvmLibcScanfParserTest, EvalBadArg) {
108   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
109   const char *str = "%\0abc";
110   int arg1 = 12345;
111   evaluate(format_arr, str, &arg1);
112 
113   LIBC_NAMESPACE::scanf_core::FormatSection expected;
114   expected.has_conv = false;
115   expected.raw_string = {str, 1};
116 
117   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
118 }
119 
TEST(LlvmLibcScanfParserTest,EvalOneArgWithFlag)120 TEST(LlvmLibcScanfParserTest, EvalOneArgWithFlag) {
121   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
122   const char *str = "%*d";
123   // Since NO_WRITE is set, the argument shouldn't be used, but I've included
124   // one anyways because in the case that it doesn't work it's better for it to
125   // have a real argument to check against.
126   int arg1 = 12345;
127   evaluate(format_arr, str, &arg1);
128 
129   LIBC_NAMESPACE::scanf_core::FormatSection expected;
130   expected.has_conv = true;
131 
132   expected.raw_string = str;
133   expected.flags = LIBC_NAMESPACE::scanf_core::FormatFlags::NO_WRITE;
134   expected.conv_name = 'd';
135 
136   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
137 
138   // If NO_WRITE is set, then the equality check ignores the pointer since it's
139   // irrelevant, but in this case I want to make sure that it hasn't been set
140   // and check it separately.
141   ASSERT_EQ(expected.output_ptr, format_arr[0].output_ptr);
142 }
143 
TEST(LlvmLibcScanfParserTest,EvalOneArgWithWidth)144 TEST(LlvmLibcScanfParserTest, EvalOneArgWithWidth) {
145   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
146   const char *str = "%12d";
147   int arg1 = 12345;
148   evaluate(format_arr, str, &arg1);
149 
150   LIBC_NAMESPACE::scanf_core::FormatSection expected;
151   expected.has_conv = true;
152 
153   expected.raw_string = str;
154   expected.max_width = 12;
155   expected.output_ptr = &arg1;
156   expected.conv_name = 'd';
157 
158   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
159 }
160 
TEST(LlvmLibcScanfParserTest,EvalOneArgWithShortLengthModifier)161 TEST(LlvmLibcScanfParserTest, EvalOneArgWithShortLengthModifier) {
162   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
163   const char *str = "%hd";
164   int arg1 = 12345;
165   evaluate(format_arr, str, &arg1);
166 
167   LIBC_NAMESPACE::scanf_core::FormatSection expected;
168   expected.has_conv = true;
169 
170   expected.raw_string = str;
171   expected.length_modifier = LIBC_NAMESPACE::scanf_core::LengthModifier::h;
172   expected.output_ptr = &arg1;
173   expected.conv_name = 'd';
174 
175   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
176 }
177 
TEST(LlvmLibcScanfParserTest,EvalOneArgWithLongLengthModifier)178 TEST(LlvmLibcScanfParserTest, EvalOneArgWithLongLengthModifier) {
179   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
180   const char *str = "%lld";
181   long long arg1 = 12345;
182   evaluate(format_arr, str, &arg1);
183 
184   LIBC_NAMESPACE::scanf_core::FormatSection expected;
185   expected.has_conv = true;
186 
187   expected.raw_string = str;
188   expected.length_modifier = LIBC_NAMESPACE::scanf_core::LengthModifier::ll;
189   expected.output_ptr = &arg1;
190   expected.conv_name = 'd';
191 
192   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
193 }
194 
TEST(LlvmLibcScanfParserTest,EvalOneArgWithAllOptions)195 TEST(LlvmLibcScanfParserTest, EvalOneArgWithAllOptions) {
196   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
197   const char *str = "%*56jd";
198   intmax_t arg1 = 12345;
199   evaluate(format_arr, str, &arg1);
200 
201   LIBC_NAMESPACE::scanf_core::FormatSection expected;
202   expected.has_conv = true;
203 
204   expected.raw_string = str;
205   expected.flags = LIBC_NAMESPACE::scanf_core::FormatFlags::NO_WRITE;
206   expected.max_width = 56;
207   expected.length_modifier = LIBC_NAMESPACE::scanf_core::LengthModifier::j;
208   expected.conv_name = 'd';
209 
210   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
211 }
212 
TEST(LlvmLibcScanfParserTest,EvalSimpleBracketArg)213 TEST(LlvmLibcScanfParserTest, EvalSimpleBracketArg) {
214   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
215   const char *str = "%[abc]";
216   char arg1 = 'a';
217   evaluate(format_arr, str, &arg1);
218 
219   LIBC_NAMESPACE::scanf_core::FormatSection expected;
220   expected.has_conv = true;
221 
222   expected.raw_string = str;
223   expected.conv_name = '[';
224   expected.output_ptr = &arg1;
225 
226   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
227 
228   scan_set.set('a');
229   scan_set.set('b');
230   scan_set.set('c');
231 
232   expected.scan_set = scan_set;
233 
234   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
235 }
236 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRange)237 TEST(LlvmLibcScanfParserTest, EvalBracketArgRange) {
238   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
239   const char *str = "%[A-D]";
240   char arg1 = 'a';
241   evaluate(format_arr, str, &arg1);
242 
243   LIBC_NAMESPACE::scanf_core::FormatSection expected;
244   expected.has_conv = true;
245 
246   expected.raw_string = str;
247   expected.conv_name = '[';
248   expected.output_ptr = &arg1;
249 
250   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
251 
252   scan_set.set('A');
253   scan_set.set('B');
254   scan_set.set('C');
255   scan_set.set('D');
256 
257   expected.scan_set = scan_set;
258 
259   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
260 }
261 
TEST(LlvmLibcScanfParserTest,EvalBracketArgTwoRanges)262 TEST(LlvmLibcScanfParserTest, EvalBracketArgTwoRanges) {
263   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
264   const char *str = "%[A-De-g]";
265   char arg1 = 'a';
266   evaluate(format_arr, str, &arg1);
267 
268   LIBC_NAMESPACE::scanf_core::FormatSection expected;
269   expected.has_conv = true;
270 
271   expected.raw_string = str;
272   expected.conv_name = '[';
273   expected.output_ptr = &arg1;
274 
275   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
276 
277   scan_set.set('A');
278   scan_set.set('B');
279   scan_set.set('C');
280   scan_set.set('D');
281   scan_set.set_range('e', 'g');
282 
283   expected.scan_set = scan_set;
284 
285   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
286 }
287 
TEST(LlvmLibcScanfParserTest,EvalBracketArgJustHyphen)288 TEST(LlvmLibcScanfParserTest, EvalBracketArgJustHyphen) {
289   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
290   const char *str = "%[-]";
291   char arg1 = 'a';
292   evaluate(format_arr, str, &arg1);
293 
294   LIBC_NAMESPACE::scanf_core::FormatSection expected;
295   expected.has_conv = true;
296 
297   expected.raw_string = str;
298   expected.conv_name = '[';
299   expected.output_ptr = &arg1;
300 
301   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
302 
303   scan_set.set('-');
304 
305   expected.scan_set = scan_set;
306 
307   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
308 }
309 
TEST(LlvmLibcScanfParserTest,EvalBracketArgLeftHyphen)310 TEST(LlvmLibcScanfParserTest, EvalBracketArgLeftHyphen) {
311   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
312   const char *str = "%[-A]";
313   char arg1 = 'a';
314   evaluate(format_arr, str, &arg1);
315 
316   LIBC_NAMESPACE::scanf_core::FormatSection expected;
317   expected.has_conv = true;
318 
319   expected.raw_string = str;
320   expected.conv_name = '[';
321   expected.output_ptr = &arg1;
322 
323   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
324 
325   scan_set.set('-');
326   scan_set.set('A');
327 
328   expected.scan_set = scan_set;
329 
330   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
331 }
332 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRightHyphen)333 TEST(LlvmLibcScanfParserTest, EvalBracketArgRightHyphen) {
334   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
335   const char *str = "%[Z-]";
336   char arg1 = 'a';
337   evaluate(format_arr, str, &arg1);
338 
339   LIBC_NAMESPACE::scanf_core::FormatSection expected;
340   expected.has_conv = true;
341 
342   expected.raw_string = str;
343   expected.conv_name = '[';
344   expected.output_ptr = &arg1;
345 
346   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
347 
348   scan_set.set('-');
349   scan_set.set('Z');
350 
351   expected.scan_set = scan_set;
352 
353   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
354 }
355 
TEST(LlvmLibcScanfParserTest,EvalBracketArgInvertSimple)356 TEST(LlvmLibcScanfParserTest, EvalBracketArgInvertSimple) {
357   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
358   const char *str = "%[^abc]";
359   char arg1 = 'a';
360   evaluate(format_arr, str, &arg1);
361 
362   LIBC_NAMESPACE::scanf_core::FormatSection expected;
363   expected.has_conv = true;
364 
365   expected.raw_string = str;
366   expected.conv_name = '[';
367   expected.output_ptr = &arg1;
368 
369   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
370 
371   scan_set.set('a');
372   scan_set.set('b');
373   scan_set.set('c');
374   scan_set.flip();
375 
376   expected.scan_set = scan_set;
377 
378   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
379 }
380 
TEST(LlvmLibcScanfParserTest,EvalBracketArgInvertRange)381 TEST(LlvmLibcScanfParserTest, EvalBracketArgInvertRange) {
382   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
383   const char *str = "%[^0-9]";
384   char arg1 = 'a';
385   evaluate(format_arr, str, &arg1);
386 
387   LIBC_NAMESPACE::scanf_core::FormatSection expected;
388   expected.has_conv = true;
389 
390   expected.raw_string = str;
391   expected.conv_name = '[';
392   expected.output_ptr = &arg1;
393 
394   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
395 
396   scan_set.set_range('0', '9');
397   scan_set.flip();
398 
399   expected.scan_set = scan_set;
400 
401   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
402 }
403 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRightBracket)404 TEST(LlvmLibcScanfParserTest, EvalBracketArgRightBracket) {
405   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
406   const char *str = "%[]]";
407   char arg1 = 'a';
408   evaluate(format_arr, str, &arg1);
409 
410   LIBC_NAMESPACE::scanf_core::FormatSection expected;
411   expected.has_conv = true;
412 
413   expected.raw_string = str;
414   expected.conv_name = '[';
415   expected.output_ptr = &arg1;
416 
417   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
418 
419   scan_set.set(']');
420 
421   expected.scan_set = scan_set;
422 
423   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
424 }
425 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRightBracketRange)426 TEST(LlvmLibcScanfParserTest, EvalBracketArgRightBracketRange) {
427   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
428   const char *str = "%[]-a]";
429   char arg1 = 'a';
430   evaluate(format_arr, str, &arg1);
431 
432   LIBC_NAMESPACE::scanf_core::FormatSection expected;
433   expected.has_conv = true;
434 
435   expected.raw_string = str;
436   expected.conv_name = '[';
437   expected.output_ptr = &arg1;
438 
439   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
440 
441   scan_set.set_range(']', 'a');
442 
443   expected.scan_set = scan_set;
444 
445   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
446 }
447 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRightBracketInvert)448 TEST(LlvmLibcScanfParserTest, EvalBracketArgRightBracketInvert) {
449   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
450   const char *str = "%[^]]";
451   char arg1 = 'a';
452   evaluate(format_arr, str, &arg1);
453 
454   LIBC_NAMESPACE::scanf_core::FormatSection expected;
455   expected.has_conv = true;
456 
457   expected.raw_string = str;
458   expected.conv_name = '[';
459   expected.output_ptr = &arg1;
460 
461   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
462 
463   scan_set.set(']');
464   scan_set.flip();
465 
466   expected.scan_set = scan_set;
467 
468   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
469 }
470 
TEST(LlvmLibcScanfParserTest,EvalBracketArgRightBracketInvertRange)471 TEST(LlvmLibcScanfParserTest, EvalBracketArgRightBracketInvertRange) {
472   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
473   const char *str = "%[^]-^]";
474   char arg1 = 'a';
475   evaluate(format_arr, str, &arg1);
476 
477   LIBC_NAMESPACE::scanf_core::FormatSection expected;
478   expected.has_conv = true;
479 
480   expected.raw_string = str;
481   expected.conv_name = '[';
482   expected.output_ptr = &arg1;
483 
484   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
485 
486   scan_set.set_range(']', '^');
487   scan_set.flip();
488 
489   expected.scan_set = scan_set;
490 
491   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
492 }
493 
494 // This is not part of the standard, but the hyphen's effect is always
495 // implementation defined, and I have defined it such that it will capture the
496 // correct range regardless of the order of the characters.
TEST(LlvmLibcScanfParserTest,EvalBracketArgBackwardsRange)497 TEST(LlvmLibcScanfParserTest, EvalBracketArgBackwardsRange) {
498   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
499   const char *str = "%[9-0]";
500   char arg1 = 'a';
501   evaluate(format_arr, str, &arg1);
502 
503   LIBC_NAMESPACE::scanf_core::FormatSection expected;
504   expected.has_conv = true;
505 
506   expected.raw_string = str;
507   expected.conv_name = '[';
508   expected.output_ptr = &arg1;
509 
510   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
511 
512   scan_set.set_range('0', '9');
513 
514   expected.scan_set = scan_set;
515 
516   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
517 }
518 
TEST(LlvmLibcScanfParserTest,EvalThreeArgs)519 TEST(LlvmLibcScanfParserTest, EvalThreeArgs) {
520   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
521   const char *str = "%d%f%s";
522   int arg1 = 12345;
523   double arg2 = 123.45;
524   const char *arg3 = "12345";
525   evaluate(format_arr, str, &arg1, &arg2, &arg3);
526 
527   LIBC_NAMESPACE::scanf_core::FormatSection expected0, expected1, expected2;
528   expected0.has_conv = true;
529 
530   expected0.raw_string = {str, 2};
531   expected0.output_ptr = &arg1;
532   expected0.conv_name = 'd';
533 
534   ASSERT_SFORMAT_EQ(expected0, format_arr[0]);
535 
536   expected1.has_conv = true;
537 
538   expected1.raw_string = {str + 2, 2};
539   expected1.output_ptr = &arg2;
540   expected1.conv_name = 'f';
541 
542   ASSERT_SFORMAT_EQ(expected1, format_arr[1]);
543 
544   expected2.has_conv = true;
545 
546   expected2.raw_string = {str + 4, 2};
547   expected2.output_ptr = &arg3;
548   expected2.conv_name = 's';
549 
550   ASSERT_SFORMAT_EQ(expected2, format_arr[2]);
551 }
552 
553 #ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE
554 
TEST(LlvmLibcScanfParserTest,IndexModeOneArg)555 TEST(LlvmLibcScanfParserTest, IndexModeOneArg) {
556   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
557   const char *str = "%1$d";
558   int arg1 = 12345;
559   evaluate(format_arr, str, &arg1);
560 
561   LIBC_NAMESPACE::scanf_core::FormatSection expected;
562   expected.has_conv = true;
563 
564   expected.raw_string = {str, 4};
565   expected.output_ptr = &arg1;
566   expected.conv_name = 'd';
567 
568   ASSERT_SFORMAT_EQ(expected, format_arr[0]);
569 }
570 
TEST(LlvmLibcScanfParserTest,IndexModeThreeArgsSequential)571 TEST(LlvmLibcScanfParserTest, IndexModeThreeArgsSequential) {
572   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
573   const char *str = "%1$d%2$f%3$s";
574   int arg1 = 12345;
575   double arg2 = 123.45;
576   const char *arg3 = "12345";
577   evaluate(format_arr, str, &arg1, &arg2, &arg3);
578 
579   LIBC_NAMESPACE::scanf_core::FormatSection expected0, expected1, expected2;
580   expected0.has_conv = true;
581 
582   expected0.raw_string = {str, 4};
583   expected0.output_ptr = &arg1;
584   expected0.conv_name = 'd';
585 
586   ASSERT_SFORMAT_EQ(expected0, format_arr[0]);
587 
588   expected1.has_conv = true;
589 
590   expected1.raw_string = {str + 4, 4};
591   expected1.output_ptr = &arg2;
592   expected1.conv_name = 'f';
593 
594   ASSERT_SFORMAT_EQ(expected1, format_arr[1]);
595 
596   expected2.has_conv = true;
597 
598   expected2.raw_string = {str + 8, 4};
599   expected2.output_ptr = &arg3;
600   expected2.conv_name = 's';
601 
602   ASSERT_SFORMAT_EQ(expected2, format_arr[2]);
603 }
604 
TEST(LlvmLibcScanfParserTest,IndexModeThreeArgsReverse)605 TEST(LlvmLibcScanfParserTest, IndexModeThreeArgsReverse) {
606   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
607   const char *str = "%3$d%2$f%1$s";
608   int arg1 = 12345;
609   double arg2 = 123.45;
610   const char *arg3 = "12345";
611   evaluate(format_arr, str, &arg3, &arg2, &arg1);
612 
613   LIBC_NAMESPACE::scanf_core::FormatSection expected0, expected1, expected2;
614   expected0.has_conv = true;
615 
616   expected0.raw_string = {str, 4};
617   expected0.output_ptr = &arg1;
618   expected0.conv_name = 'd';
619 
620   ASSERT_SFORMAT_EQ(expected0, format_arr[0]);
621 
622   expected1.has_conv = true;
623 
624   expected1.raw_string = {str + 4, 4};
625   expected1.output_ptr = &arg2;
626   expected1.conv_name = 'f';
627 
628   ASSERT_SFORMAT_EQ(expected1, format_arr[1]);
629 
630   expected2.has_conv = true;
631 
632   expected2.raw_string = {str + 8, 4};
633   expected2.output_ptr = &arg3;
634   expected2.conv_name = 's';
635 
636   ASSERT_SFORMAT_EQ(expected2, format_arr[2]);
637 }
638 
TEST(LlvmLibcScanfParserTest,IndexModeTenArgsRandom)639 TEST(LlvmLibcScanfParserTest, IndexModeTenArgsRandom) {
640   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
641   const char *str = "%6$d%3$d%7$d%2$d%8$d%1$d%4$d%9$d%5$d%10$d";
642   uintptr_t args[10] = {6, 4, 2, 7, 9, 1, 3, 5, 8, 10};
643   evaluate(format_arr, str, args[0], args[1], args[2], args[3], args[4],
644            args[5], args[6], args[7], args[8], args[9]);
645 
646   for (size_t i = 0; i < 10; ++i) {
647     LIBC_NAMESPACE::scanf_core::FormatSection expected;
648     expected.has_conv = true;
649 
650     expected.raw_string = {str + (4 * i),
651                            static_cast<size_t>(4 + (i >= 9 ? 1 : 0))};
652     expected.output_ptr = reinterpret_cast<void *>(i + 1);
653     expected.conv_name = 'd';
654     EXPECT_SFORMAT_EQ(expected, format_arr[i]);
655   }
656 }
657 
TEST(LlvmLibcScanfParserTest,IndexModeComplexParsing)658 TEST(LlvmLibcScanfParserTest, IndexModeComplexParsing) {
659   LIBC_NAMESPACE::scanf_core::FormatSection format_arr[11];
660   const char *str = "normal text %3$llu %% %2$*f %4$d %1$1c%5$[123]";
661   char arg1 = '1';
662   double arg2 = 123.45;
663   unsigned long long arg3 = 12345;
664   int arg4 = 10;
665   char arg5 = 'A';
666   evaluate(format_arr, str, &arg1, &arg2, &arg3, &arg4, &arg5);
667 
668   LIBC_NAMESPACE::scanf_core::FormatSection expected0, expected1, expected2,
669       expected3, expected4, expected5, expected6, expected7, expected8,
670       expected9, expected10;
671 
672   expected0.has_conv = false;
673 
674   // "normal text "
675   expected0.raw_string = {str, 12};
676 
677   EXPECT_SFORMAT_EQ(expected0, format_arr[0]);
678 
679   expected1.has_conv = true;
680   // "%3$llu"
681   expected1.raw_string = {str + 12, 6};
682   expected1.length_modifier = LIBC_NAMESPACE::scanf_core::LengthModifier::ll;
683   expected1.output_ptr = &arg3;
684   expected1.conv_name = 'u';
685 
686   EXPECT_SFORMAT_EQ(expected1, format_arr[1]);
687 
688   expected2.has_conv = false;
689   // " "
690   expected2.raw_string = {str + 18, 1};
691 
692   EXPECT_SFORMAT_EQ(expected2, format_arr[2]);
693 
694   expected3.has_conv = true;
695   // "%%"
696   expected3.raw_string = {str + 19, 2};
697   expected3.conv_name = '%';
698 
699   EXPECT_SFORMAT_EQ(expected3, format_arr[3]);
700 
701   expected4.has_conv = false;
702   // " "
703   expected4.raw_string = {str + 21, 1};
704 
705   EXPECT_SFORMAT_EQ(expected4, format_arr[4]);
706 
707   expected5.has_conv = true;
708   // "%2$*f"
709   expected5.raw_string = {str + 22, 5};
710   expected5.flags = LIBC_NAMESPACE::scanf_core::FormatFlags::NO_WRITE;
711   expected5.conv_name = 'f';
712 
713   EXPECT_SFORMAT_EQ(expected5, format_arr[5]);
714 
715   expected6.has_conv = false;
716   // " "
717   expected6.raw_string = {str + 27, 1};
718 
719   EXPECT_SFORMAT_EQ(expected6, format_arr[6]);
720 
721   expected7.has_conv = true;
722 
723   // "%4$d"
724   expected7.raw_string = {str + 28, 4};
725   expected7.output_ptr = &arg4;
726   expected7.conv_name = 'd';
727 
728   EXPECT_SFORMAT_EQ(expected7, format_arr[7]);
729 
730   expected8.has_conv = false;
731   // " "
732   expected8.raw_string = {str + 32, 1};
733 
734   EXPECT_SFORMAT_EQ(expected8, format_arr[8]);
735 
736   expected9.has_conv = true;
737   // "%1$1c"
738   expected9.raw_string = {str + 33, 5};
739   expected9.max_width = 1;
740   expected9.output_ptr = &arg1;
741   expected9.conv_name = 'c';
742 
743   EXPECT_SFORMAT_EQ(expected9, format_arr[9]);
744 
745   expected10.has_conv = true;
746   // "%5$[123]"
747   expected10.raw_string = {str + 38, 8};
748   expected10.output_ptr = &arg5;
749   expected10.conv_name = '[';
750 
751   LIBC_NAMESPACE::cpp::bitset<256> scan_set;
752 
753   scan_set.set_range('1', '3');
754 
755   expected10.scan_set = scan_set;
756 
757   EXPECT_SFORMAT_EQ(expected10, format_arr[10]);
758 }
759 
760 #endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE
761