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 | |
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 | |
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 | |
49 | TEST(LlvmLibcScanfParserTest, Constructor) { init(str: "test" , 1, 2); } |
50 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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(Start: 'e', End: 'g'); |
282 | |
283 | expected.scan_set = scan_set; |
284 | |
285 | ASSERT_SFORMAT_EQ(expected, format_arr[0]); |
286 | } |
287 | |
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 | |
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 | |
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 | |
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 | |
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(Start: '0', End: '9'); |
397 | scan_set.flip(); |
398 | |
399 | expected.scan_set = scan_set; |
400 | |
401 | ASSERT_SFORMAT_EQ(expected, format_arr[0]); |
402 | } |
403 | |
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 | |
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(Start: ']', End: 'a'); |
442 | |
443 | expected.scan_set = scan_set; |
444 | |
445 | ASSERT_SFORMAT_EQ(expected, format_arr[0]); |
446 | } |
447 | |
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 | |
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(Start: ']', End: '^'); |
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. |
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(Start: '0', End: '9'); |
513 | |
514 | expected.scan_set = scan_set; |
515 | |
516 | ASSERT_SFORMAT_EQ(expected, format_arr[0]); |
517 | } |
518 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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(Start: '1', End: '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 | |