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