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/arg_list.h"
11 #include "src/stdio/printf_core/parser.h"
12 
13 #include <stdarg.h>
14 
15 #include "utils/UnitTest/PrintfMatcher.h"
16 #include "utils/UnitTest/Test.h"
17 
init(const char * __restrict str,...)18 void init(const char *__restrict str, ...) {
19   va_list vlist;
20   va_start(vlist, str);
21   __llvm_libc::internal::ArgList v(vlist);
22   va_end(vlist);
23 
24   __llvm_libc::printf_core::Parser parser(str, v);
25 }
26 
evaluate(__llvm_libc::printf_core::FormatSection * format_arr,const char * __restrict str,...)27 void evaluate(__llvm_libc::printf_core::FormatSection *format_arr,
28               const char *__restrict str, ...) {
29   va_list vlist;
30   va_start(vlist, str);
31   __llvm_libc::internal::ArgList v(vlist);
32   va_end(vlist);
33 
34   __llvm_libc::printf_core::Parser parser(str, v);
35 
36   for (auto cur_section = parser.get_next_section(); cur_section.raw_len > 0;
37        cur_section = parser.get_next_section()) {
38     *format_arr = cur_section;
39     ++format_arr;
40   }
41 }
42 
TEST(LlvmLibcPrintfParserTest,Constructor)43 TEST(LlvmLibcPrintfParserTest, Constructor) { init("test", 1, 2); }
44 
TEST(LlvmLibcPrintfParserTest,EvalRaw)45 TEST(LlvmLibcPrintfParserTest, EvalRaw) {
46   __llvm_libc::printf_core::FormatSection format_arr[10];
47   const char *str = "test";
48   evaluate(format_arr, str);
49 
50   __llvm_libc::printf_core::FormatSection expected;
51   expected.has_conv = false;
52   expected.raw_len = 4;
53   expected.raw_string = str;
54 
55   ASSERT_FORMAT_EQ(expected, format_arr[0]);
56   // TODO: add checks that the format_arr after the last one has length 0
57 }
58 
TEST(LlvmLibcPrintfParserTest,EvalSimple)59 TEST(LlvmLibcPrintfParserTest, EvalSimple) {
60   __llvm_libc::printf_core::FormatSection format_arr[10];
61   const char *str = "test %% test";
62   evaluate(format_arr, str);
63 
64   __llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
65   expected0.has_conv = false;
66   expected0.raw_len = 5;
67   expected0.raw_string = str;
68 
69   ASSERT_FORMAT_EQ(expected0, format_arr[0]);
70 
71   expected1.has_conv = true;
72   expected1.raw_len = 2;
73   expected1.raw_string = str + 5;
74   expected1.conv_name = '%';
75 
76   ASSERT_FORMAT_EQ(expected1, format_arr[1]);
77 
78   expected2.has_conv = false;
79   expected2.raw_len = 5;
80   expected2.raw_string = str + 7;
81 
82   ASSERT_FORMAT_EQ(expected2, format_arr[2]);
83 }
84 
TEST(LlvmLibcPrintfParserTest,EvalOneArg)85 TEST(LlvmLibcPrintfParserTest, EvalOneArg) {
86   __llvm_libc::printf_core::FormatSection format_arr[10];
87   const char *str = "%d";
88   int arg1 = 12345;
89   evaluate(format_arr, str, arg1);
90 
91   __llvm_libc::printf_core::FormatSection expected;
92   expected.has_conv = true;
93   expected.raw_len = 2;
94   expected.raw_string = str;
95   expected.conv_val_raw = arg1;
96   expected.conv_name = 'd';
97 
98   ASSERT_FORMAT_EQ(expected, format_arr[0]);
99 }
100 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithFlags)101 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFlags) {
102   __llvm_libc::printf_core::FormatSection format_arr[10];
103   const char *str = "%+-0 #d";
104   int arg1 = 12345;
105   evaluate(format_arr, str, arg1);
106 
107   __llvm_libc::printf_core::FormatSection expected;
108   expected.has_conv = true;
109   expected.raw_len = 7;
110   expected.raw_string = str;
111   expected.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
112       __llvm_libc::printf_core::FormatFlags::FORCE_SIGN |
113       __llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED |
114       __llvm_libc::printf_core::FormatFlags::LEADING_ZEROES |
115       __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX |
116       __llvm_libc::printf_core::FormatFlags::ALTERNATE_FORM);
117   expected.conv_val_raw = arg1;
118   expected.conv_name = 'd';
119 
120   ASSERT_FORMAT_EQ(expected, format_arr[0]);
121 }
122 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithWidth)123 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithWidth) {
124   __llvm_libc::printf_core::FormatSection format_arr[10];
125   const char *str = "%12d";
126   int arg1 = 12345;
127   evaluate(format_arr, str, arg1);
128 
129   __llvm_libc::printf_core::FormatSection expected;
130   expected.has_conv = true;
131   expected.raw_len = 4;
132   expected.raw_string = str;
133   expected.min_width = 12;
134   expected.conv_val_raw = arg1;
135   expected.conv_name = 'd';
136 
137   ASSERT_FORMAT_EQ(expected, format_arr[0]);
138 }
139 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithPrecision)140 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithPrecision) {
141   __llvm_libc::printf_core::FormatSection format_arr[10];
142   const char *str = "%.34d";
143   int arg1 = 12345;
144   evaluate(format_arr, str, arg1);
145 
146   __llvm_libc::printf_core::FormatSection expected;
147   expected.has_conv = true;
148   expected.raw_len = 5;
149   expected.raw_string = str;
150   expected.precision = 34;
151   expected.conv_val_raw = arg1;
152   expected.conv_name = 'd';
153 
154   ASSERT_FORMAT_EQ(expected, format_arr[0]);
155 }
156 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithTrivialPrecision)157 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithTrivialPrecision) {
158   __llvm_libc::printf_core::FormatSection format_arr[10];
159   const char *str = "%.d";
160   int arg1 = 12345;
161   evaluate(format_arr, str, arg1);
162 
163   __llvm_libc::printf_core::FormatSection expected;
164   expected.has_conv = true;
165   expected.raw_len = 3;
166   expected.raw_string = str;
167   expected.precision = 0;
168   expected.conv_val_raw = arg1;
169   expected.conv_name = 'd';
170 
171   ASSERT_FORMAT_EQ(expected, format_arr[0]);
172 }
173 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithShortLengthModifier)174 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithShortLengthModifier) {
175   __llvm_libc::printf_core::FormatSection format_arr[10];
176   const char *str = "%hd";
177   int arg1 = 12345;
178   evaluate(format_arr, str, arg1);
179 
180   __llvm_libc::printf_core::FormatSection expected;
181   expected.has_conv = true;
182   expected.raw_len = 3;
183   expected.raw_string = str;
184   expected.length_modifier = __llvm_libc::printf_core::LengthModifier::h;
185   expected.conv_val_raw = arg1;
186   expected.conv_name = 'd';
187 
188   ASSERT_FORMAT_EQ(expected, format_arr[0]);
189 }
190 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithLongLengthModifier)191 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithLongLengthModifier) {
192   __llvm_libc::printf_core::FormatSection format_arr[10];
193   const char *str = "%lld";
194   int arg1 = 12345;
195   evaluate(format_arr, str, arg1);
196 
197   __llvm_libc::printf_core::FormatSection expected;
198   expected.has_conv = true;
199   expected.raw_len = 4;
200   expected.raw_string = str;
201   expected.length_modifier = __llvm_libc::printf_core::LengthModifier::ll;
202   expected.conv_val_raw = arg1;
203   expected.conv_name = 'd';
204 
205   ASSERT_FORMAT_EQ(expected, format_arr[0]);
206 }
207 
TEST(LlvmLibcPrintfParserTest,EvalOneArgWithAllOptions)208 TEST(LlvmLibcPrintfParserTest, EvalOneArgWithAllOptions) {
209   __llvm_libc::printf_core::FormatSection format_arr[10];
210   const char *str = "% -056.78jd";
211   int arg1 = 12345;
212   evaluate(format_arr, str, arg1);
213 
214   __llvm_libc::printf_core::FormatSection expected;
215   expected.has_conv = true;
216   expected.raw_len = 11;
217   expected.raw_string = str;
218   expected.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
219       __llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED |
220       __llvm_libc::printf_core::FormatFlags::LEADING_ZEROES |
221       __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX);
222   expected.min_width = 56;
223   expected.precision = 78;
224   expected.length_modifier = __llvm_libc::printf_core::LengthModifier::j;
225   expected.conv_val_raw = arg1;
226   expected.conv_name = 'd';
227 
228   ASSERT_FORMAT_EQ(expected, format_arr[0]);
229 }
230 
TEST(LlvmLibcPrintfParserTest,EvalThreeArgs)231 TEST(LlvmLibcPrintfParserTest, EvalThreeArgs) {
232   __llvm_libc::printf_core::FormatSection format_arr[10];
233   const char *str = "%d%f%s";
234   int arg1 = 12345;
235   double arg2 = 123.45;
236   const char *arg3 = "12345";
237   evaluate(format_arr, str, arg1, arg2, arg3);
238 
239   __llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
240   expected0.has_conv = true;
241   expected0.raw_len = 2;
242   expected0.raw_string = str;
243   expected0.conv_val_raw = arg1;
244   expected0.conv_name = 'd';
245 
246   ASSERT_FORMAT_EQ(expected0, format_arr[0]);
247 
248   expected1.has_conv = true;
249   expected1.raw_len = 2;
250   expected1.raw_string = str + 2;
251   expected1.conv_val_raw = __llvm_libc::bit_cast<uint64_t>(arg2);
252   expected1.conv_name = 'f';
253 
254   ASSERT_FORMAT_EQ(expected1, format_arr[1]);
255 
256   expected2.has_conv = true;
257   expected2.raw_len = 2;
258   expected2.raw_string = str + 4;
259   expected2.conv_val_ptr = const_cast<char *>(arg3);
260   expected2.conv_name = 's';
261 
262   ASSERT_FORMAT_EQ(expected2, format_arr[2]);
263 }
264 
265 #ifndef LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
266 
TEST(LlvmLibcPrintfParserTest,IndexModeOneArg)267 TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {
268   __llvm_libc::printf_core::FormatSection format_arr[10];
269   const char *str = "%1$d";
270   int arg1 = 12345;
271   evaluate(format_arr, str, arg1);
272 
273   __llvm_libc::printf_core::FormatSection expected;
274   expected.has_conv = true;
275   expected.raw_len = 4;
276   expected.raw_string = str;
277   expected.conv_val_raw = arg1;
278   expected.conv_name = 'd';
279 
280   ASSERT_FORMAT_EQ(expected, format_arr[0]);
281 }
282 
TEST(LlvmLibcPrintfParserTest,IndexModeThreeArgsSequential)283 TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsSequential) {
284   __llvm_libc::printf_core::FormatSection format_arr[10];
285   const char *str = "%1$d%2$f%3$s";
286   int arg1 = 12345;
287   double arg2 = 123.45;
288   const char *arg3 = "12345";
289   evaluate(format_arr, str, arg1, arg2, arg3);
290 
291   __llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
292   expected0.has_conv = true;
293   expected0.raw_len = 4;
294   expected0.raw_string = str;
295   expected0.conv_val_raw = arg1;
296   expected0.conv_name = 'd';
297 
298   ASSERT_FORMAT_EQ(expected0, format_arr[0]);
299 
300   expected1.has_conv = true;
301   expected1.raw_len = 4;
302   expected1.raw_string = str + 4;
303   expected1.conv_val_raw = __llvm_libc::bit_cast<uint64_t>(arg2);
304   expected1.conv_name = 'f';
305 
306   ASSERT_FORMAT_EQ(expected1, format_arr[1]);
307 
308   expected2.has_conv = true;
309   expected2.raw_len = 4;
310   expected2.raw_string = str + 8;
311   expected2.conv_val_ptr = const_cast<char *>(arg3);
312   expected2.conv_name = 's';
313 
314   ASSERT_FORMAT_EQ(expected2, format_arr[2]);
315 }
316 
TEST(LlvmLibcPrintfParserTest,IndexModeThreeArgsReverse)317 TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsReverse) {
318   __llvm_libc::printf_core::FormatSection format_arr[10];
319   const char *str = "%3$d%2$f%1$s";
320   int arg1 = 12345;
321   double arg2 = 123.45;
322   const char *arg3 = "12345";
323   evaluate(format_arr, str, arg3, arg2, arg1);
324 
325   __llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
326   expected0.has_conv = true;
327   expected0.raw_len = 4;
328   expected0.raw_string = str;
329   expected0.conv_val_raw = arg1;
330   expected0.conv_name = 'd';
331 
332   ASSERT_FORMAT_EQ(expected0, format_arr[0]);
333 
334   expected1.has_conv = true;
335   expected1.raw_len = 4;
336   expected1.raw_string = str + 4;
337   expected1.conv_val_raw = __llvm_libc::bit_cast<uint64_t>(arg2);
338   expected1.conv_name = 'f';
339 
340   ASSERT_FORMAT_EQ(expected1, format_arr[1]);
341 
342   expected2.has_conv = true;
343   expected2.raw_len = 4;
344   expected2.raw_string = str + 8;
345   expected2.conv_val_ptr = const_cast<char *>(arg3);
346   expected2.conv_name = 's';
347 
348   ASSERT_FORMAT_EQ(expected2, format_arr[2]);
349 }
350 
TEST(LlvmLibcPrintfParserTest,IndexModeTenArgsRandom)351 TEST(LlvmLibcPrintfParserTest, IndexModeTenArgsRandom) {
352   __llvm_libc::printf_core::FormatSection format_arr[10];
353   const char *str = "%6$d%3$d%7$d%2$d%8$d%1$d%4$d%9$d%5$d%10$d";
354   int args[10] = {6, 4, 2, 7, 9, 1, 3, 5, 8, 10};
355   evaluate(format_arr, str, args[0], args[1], args[2], args[3], args[4],
356            args[5], args[6], args[7], args[8], args[9]);
357 
358   for (size_t i = 0; i < 10; ++i) {
359     __llvm_libc::printf_core::FormatSection expected;
360     expected.has_conv = true;
361     expected.raw_len = 4 + (i >= 9 ? 1 : 0);
362     expected.raw_string = str + (4 * i);
363     expected.conv_val_raw = i + 1;
364     expected.conv_name = 'd';
365     EXPECT_FORMAT_EQ(expected, format_arr[i]);
366   }
367 }
368 
TEST(LlvmLibcPrintfParserTest,IndexModeComplexParsing)369 TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
370   __llvm_libc::printf_core::FormatSection format_arr[10];
371   const char *str = "normal text %3$llu %% %2$ *4$f %2$ .*4$f %1$1.1c";
372   char arg1 = '1';
373   double arg2 = 123.45;
374   unsigned long long arg3 = 12345;
375   int arg4 = 10;
376   evaluate(format_arr, str, arg1, arg2, arg3, arg4);
377 
378   __llvm_libc::printf_core::FormatSection expected0, expected1, expected2,
379       expected3, expected4, expected5, expected6, expected7, expected8,
380       expected9;
381 
382   expected0.has_conv = false;
383   expected0.raw_len = 12;
384   expected0.raw_string = str;
385 
386   EXPECT_FORMAT_EQ(expected0, format_arr[0]);
387 
388   expected1.has_conv = true;
389   expected1.raw_len = 6;
390   expected1.raw_string = str + 12;
391   expected1.length_modifier = __llvm_libc::printf_core::LengthModifier::ll;
392   expected1.conv_val_raw = arg3;
393   expected1.conv_name = 'u';
394 
395   EXPECT_FORMAT_EQ(expected1, format_arr[1]);
396 
397   expected2.has_conv = false;
398   expected2.raw_len = 1;
399   expected2.raw_string = str + 18;
400 
401   EXPECT_FORMAT_EQ(expected2, format_arr[2]);
402 
403   expected3.has_conv = true;
404   expected3.raw_len = 2;
405   expected3.raw_string = str + 19;
406   expected3.conv_name = '%';
407 
408   EXPECT_FORMAT_EQ(expected3, format_arr[3]);
409 
410   expected4.has_conv = false;
411   expected4.raw_len = 1;
412   expected4.raw_string = str + 21;
413 
414   EXPECT_FORMAT_EQ(expected4, format_arr[4]);
415 
416   expected5.has_conv = true;
417   expected5.raw_len = 8;
418   expected5.raw_string = str + 22;
419   expected5.flags = __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX;
420   expected5.min_width = arg4;
421   expected5.conv_val_raw = __llvm_libc::bit_cast<uint64_t>(arg2);
422   expected5.conv_name = 'f';
423 
424   EXPECT_FORMAT_EQ(expected5, format_arr[5]);
425 
426   expected6.has_conv = false;
427   expected6.raw_len = 1;
428   expected6.raw_string = str + 30;
429 
430   EXPECT_FORMAT_EQ(expected6, format_arr[6]);
431 
432   expected7.has_conv = true;
433   expected7.raw_len = 9;
434   expected7.raw_string = str + 31;
435   expected7.flags = __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX;
436   expected7.precision = arg4;
437   expected7.conv_val_raw = __llvm_libc::bit_cast<uint64_t>(arg2);
438   expected7.conv_name = 'f';
439 
440   EXPECT_FORMAT_EQ(expected7, format_arr[7]);
441 
442   expected8.has_conv = false;
443   expected8.raw_len = 1;
444   expected8.raw_string = str + 40;
445 
446   EXPECT_FORMAT_EQ(expected8, format_arr[8]);
447 
448   expected9.has_conv = true;
449   expected9.raw_len = 7;
450   expected9.raw_string = str + 41;
451   expected9.min_width = 1;
452   expected9.precision = 1;
453   expected9.conv_val_raw = arg1;
454   expected9.conv_name = 'c';
455 
456   EXPECT_FORMAT_EQ(expected9, format_arr[9]);
457 }
458 
459 #endif // LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
460