1 | //===-- Unittests for the printf Converter --------------------------------===// |
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/stdio/printf_core/converter.h" |
10 | #include "src/stdio/printf_core/core_structs.h" |
11 | #include "src/stdio/printf_core/writer.h" |
12 | |
13 | #include "test/UnitTest/Test.h" |
14 | |
15 | class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test { |
16 | protected: |
17 | // void SetUp() override {} |
18 | // void TearDown() override {} |
19 | |
20 | char str[60]; |
21 | LIBC_NAMESPACE::printf_core::WriteBuffer wb = |
22 | LIBC_NAMESPACE::printf_core::WriteBuffer(str, sizeof(str) - 1); |
23 | LIBC_NAMESPACE::printf_core::Writer writer = |
24 | LIBC_NAMESPACE::printf_core::Writer(&wb); |
25 | }; |
26 | |
27 | TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) { |
28 | LIBC_NAMESPACE::printf_core::FormatSection raw_section; |
29 | raw_section.has_conv = false; |
30 | raw_section.raw_string = "abc" ; |
31 | |
32 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: raw_section); |
33 | |
34 | wb.buff[wb.buff_cur] = '\0'; |
35 | |
36 | ASSERT_STREQ(str, "abc" ); |
37 | ASSERT_EQ(writer.get_chars_written(), 3); |
38 | } |
39 | |
40 | TEST_F(LlvmLibcPrintfConverterTest, PercentConversion) { |
41 | LIBC_NAMESPACE::printf_core::FormatSection simple_conv; |
42 | simple_conv.has_conv = true; |
43 | simple_conv.raw_string = "%%" ; |
44 | simple_conv.conv_name = '%'; |
45 | |
46 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: simple_conv); |
47 | |
48 | wb.buff[wb.buff_cur] = '\0'; |
49 | |
50 | ASSERT_STREQ(str, "%" ); |
51 | ASSERT_EQ(writer.get_chars_written(), 1); |
52 | } |
53 | |
54 | TEST_F(LlvmLibcPrintfConverterTest, CharConversionSimple) { |
55 | LIBC_NAMESPACE::printf_core::FormatSection simple_conv; |
56 | simple_conv.has_conv = true; |
57 | // If has_conv is true, the raw string is ignored. They are not being parsed |
58 | // and match the actual conversion taking place so that you can compare these |
59 | // tests with other implmentations. The raw strings are completely optional. |
60 | simple_conv.raw_string = "%c" ; |
61 | simple_conv.conv_name = 'c'; |
62 | simple_conv.conv_val_raw = 'D'; |
63 | |
64 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: simple_conv); |
65 | |
66 | wb.buff[wb.buff_cur] = '\0'; |
67 | |
68 | ASSERT_STREQ(str, "D" ); |
69 | ASSERT_EQ(writer.get_chars_written(), 1); |
70 | } |
71 | |
72 | TEST_F(LlvmLibcPrintfConverterTest, CharConversionRightJustified) { |
73 | LIBC_NAMESPACE::printf_core::FormatSection right_justified_conv; |
74 | right_justified_conv.has_conv = true; |
75 | right_justified_conv.raw_string = "%4c" ; |
76 | right_justified_conv.conv_name = 'c'; |
77 | right_justified_conv.min_width = 4; |
78 | right_justified_conv.conv_val_raw = 'E'; |
79 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: right_justified_conv); |
80 | |
81 | wb.buff[wb.buff_cur] = '\0'; |
82 | |
83 | ASSERT_STREQ(str, " E" ); |
84 | ASSERT_EQ(writer.get_chars_written(), 4); |
85 | } |
86 | |
87 | TEST_F(LlvmLibcPrintfConverterTest, CharConversionLeftJustified) { |
88 | LIBC_NAMESPACE::printf_core::FormatSection left_justified_conv; |
89 | left_justified_conv.has_conv = true; |
90 | left_justified_conv.raw_string = "%-4c" ; |
91 | left_justified_conv.conv_name = 'c'; |
92 | left_justified_conv.flags = |
93 | LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED; |
94 | left_justified_conv.min_width = 4; |
95 | left_justified_conv.conv_val_raw = 'F'; |
96 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: left_justified_conv); |
97 | |
98 | wb.buff[wb.buff_cur] = '\0'; |
99 | |
100 | ASSERT_STREQ(str, "F " ); |
101 | ASSERT_EQ(writer.get_chars_written(), 4); |
102 | } |
103 | |
104 | TEST_F(LlvmLibcPrintfConverterTest, StringConversionSimple) { |
105 | |
106 | LIBC_NAMESPACE::printf_core::FormatSection simple_conv; |
107 | simple_conv.has_conv = true; |
108 | simple_conv.raw_string = "%s" ; |
109 | simple_conv.conv_name = 's'; |
110 | simple_conv.conv_val_ptr = const_cast<char *>("DEF" ); |
111 | |
112 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: simple_conv); |
113 | |
114 | wb.buff[wb.buff_cur] = '\0'; |
115 | |
116 | ASSERT_STREQ(str, "DEF" ); |
117 | ASSERT_EQ(writer.get_chars_written(), 3); |
118 | } |
119 | |
120 | TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionHigh) { |
121 | LIBC_NAMESPACE::printf_core::FormatSection high_precision_conv; |
122 | high_precision_conv.has_conv = true; |
123 | high_precision_conv.raw_string = "%4s" ; |
124 | high_precision_conv.conv_name = 's'; |
125 | high_precision_conv.precision = 4; |
126 | high_precision_conv.conv_val_ptr = const_cast<char *>("456" ); |
127 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: high_precision_conv); |
128 | |
129 | wb.buff[wb.buff_cur] = '\0'; |
130 | |
131 | ASSERT_STREQ(str, "456" ); |
132 | ASSERT_EQ(writer.get_chars_written(), 3); |
133 | } |
134 | |
135 | TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionLow) { |
136 | LIBC_NAMESPACE::printf_core::FormatSection low_precision_conv; |
137 | low_precision_conv.has_conv = true; |
138 | low_precision_conv.raw_string = "%.2s" ; |
139 | low_precision_conv.conv_name = 's'; |
140 | low_precision_conv.precision = 2; |
141 | low_precision_conv.conv_val_ptr = const_cast<char *>("xyz" ); |
142 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: low_precision_conv); |
143 | |
144 | wb.buff[wb.buff_cur] = '\0'; |
145 | |
146 | ASSERT_STREQ(str, "xy" ); |
147 | ASSERT_EQ(writer.get_chars_written(), 2); |
148 | } |
149 | |
150 | TEST_F(LlvmLibcPrintfConverterTest, StringConversionRightJustified) { |
151 | LIBC_NAMESPACE::printf_core::FormatSection right_justified_conv; |
152 | right_justified_conv.has_conv = true; |
153 | right_justified_conv.raw_string = "%4s" ; |
154 | right_justified_conv.conv_name = 's'; |
155 | right_justified_conv.min_width = 4; |
156 | right_justified_conv.conv_val_ptr = const_cast<char *>("789" ); |
157 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: right_justified_conv); |
158 | |
159 | wb.buff[wb.buff_cur] = '\0'; |
160 | |
161 | ASSERT_STREQ(str, " 789" ); |
162 | ASSERT_EQ(writer.get_chars_written(), 4); |
163 | } |
164 | |
165 | TEST_F(LlvmLibcPrintfConverterTest, StringConversionLeftJustified) { |
166 | LIBC_NAMESPACE::printf_core::FormatSection left_justified_conv; |
167 | left_justified_conv.has_conv = true; |
168 | left_justified_conv.raw_string = "%-4s" ; |
169 | left_justified_conv.conv_name = 's'; |
170 | left_justified_conv.flags = |
171 | LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED; |
172 | left_justified_conv.min_width = 4; |
173 | left_justified_conv.conv_val_ptr = const_cast<char *>("ghi" ); |
174 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: left_justified_conv); |
175 | |
176 | wb.buff[wb.buff_cur] = '\0'; |
177 | |
178 | ASSERT_STREQ(str, "ghi " ); |
179 | ASSERT_EQ(writer.get_chars_written(), 4); |
180 | } |
181 | |
182 | TEST_F(LlvmLibcPrintfConverterTest, IntConversionSimple) { |
183 | LIBC_NAMESPACE::printf_core::FormatSection section; |
184 | section.has_conv = true; |
185 | section.raw_string = "%d" ; |
186 | section.conv_name = 'd'; |
187 | section.conv_val_raw = 12345; |
188 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: section); |
189 | |
190 | wb.buff[wb.buff_cur] = '\0'; |
191 | |
192 | ASSERT_STREQ(str, "12345" ); |
193 | ASSERT_EQ(writer.get_chars_written(), 5); |
194 | } |
195 | |
196 | TEST_F(LlvmLibcPrintfConverterTest, HexConversion) { |
197 | LIBC_NAMESPACE::printf_core::FormatSection section; |
198 | section.has_conv = true; |
199 | section.raw_string = "%#018x" ; |
200 | section.conv_name = 'x'; |
201 | section.flags = static_cast<LIBC_NAMESPACE::printf_core::FormatFlags>( |
202 | LIBC_NAMESPACE::printf_core::FormatFlags::ALTERNATE_FORM | |
203 | LIBC_NAMESPACE::printf_core::FormatFlags::LEADING_ZEROES); |
204 | section.min_width = 18; |
205 | section.conv_val_raw = 0x123456ab; |
206 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: section); |
207 | |
208 | wb.buff[wb.buff_cur] = '\0'; |
209 | ASSERT_STREQ(str, "0x00000000123456ab" ); |
210 | ASSERT_EQ(writer.get_chars_written(), 18); |
211 | } |
212 | |
213 | TEST_F(LlvmLibcPrintfConverterTest, BinaryConversion) { |
214 | LIBC_NAMESPACE::printf_core::FormatSection section; |
215 | section.has_conv = true; |
216 | section.raw_string = "%b" ; |
217 | section.conv_name = 'b'; |
218 | section.conv_val_raw = 42; |
219 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: section); |
220 | |
221 | wb.buff[wb.buff_cur] = '\0'; |
222 | |
223 | ASSERT_STREQ(str, "101010" ); |
224 | ASSERT_EQ(writer.get_chars_written(), 6); |
225 | } |
226 | |
227 | TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) { |
228 | |
229 | LIBC_NAMESPACE::printf_core::FormatSection section; |
230 | section.has_conv = true; |
231 | section.raw_string = "%p" ; |
232 | section.conv_name = 'p'; |
233 | section.conv_val_ptr = (void *)(0x123456ab); |
234 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: section); |
235 | |
236 | wb.buff[wb.buff_cur] = '\0'; |
237 | ASSERT_STREQ(str, "0x123456ab" ); |
238 | ASSERT_EQ(writer.get_chars_written(), 10); |
239 | } |
240 | |
241 | TEST_F(LlvmLibcPrintfConverterTest, OctConversion) { |
242 | |
243 | LIBC_NAMESPACE::printf_core::FormatSection section; |
244 | section.has_conv = true; |
245 | section.raw_string = "%o" ; |
246 | section.conv_name = 'o'; |
247 | section.conv_val_raw = 01234; |
248 | LIBC_NAMESPACE::printf_core::convert(writer: &writer, to_conv: section); |
249 | |
250 | wb.buff[wb.buff_cur] = '\0'; |
251 | ASSERT_STREQ(str, "1234" ); |
252 | ASSERT_EQ(writer.get_chars_written(), 4); |
253 | } |
254 | |