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