1 | //===-- Unittests for the basic scanf converters --------------------------===// |
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/string_view.h" |
10 | #include "src/stdio/scanf_core/converter.h" |
11 | #include "src/stdio/scanf_core/core_structs.h" |
12 | #include "src/stdio/scanf_core/reader.h" |
13 | #include "src/stdio/scanf_core/string_reader.h" |
14 | |
15 | #include "test/UnitTest/Test.h" |
16 | |
17 | TEST(LlvmLibcScanfConverterTest, RawMatchBasic) { |
18 | const char *str = "abcdef" ; |
19 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
20 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
21 | |
22 | // Reading "abc" should succeed. |
23 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "abc" ), |
24 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
25 | ASSERT_EQ(reader.chars_read(), size_t(3)); |
26 | |
27 | // Reading nothing should succeed and not advance. |
28 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "" ), |
29 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
30 | ASSERT_EQ(reader.chars_read(), size_t(3)); |
31 | |
32 | // Reading a space where there is none should succeed and not advance. |
33 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, " " ), |
34 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
35 | ASSERT_EQ(reader.chars_read(), size_t(3)); |
36 | |
37 | // Reading "d" should succeed and advance by 1. |
38 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "d" ), |
39 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
40 | ASSERT_EQ(reader.chars_read(), size_t(4)); |
41 | |
42 | // Reading "z" should fail and not advance. |
43 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "z" ), |
44 | static_cast<int>(LIBC_NAMESPACE::scanf_core::MATCHING_FAILURE)); |
45 | ASSERT_EQ(reader.chars_read(), size_t(4)); |
46 | |
47 | // Reading "efgh" should fail but advance to the end. |
48 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "efgh" ), |
49 | static_cast<int>(LIBC_NAMESPACE::scanf_core::MATCHING_FAILURE)); |
50 | ASSERT_EQ(reader.chars_read(), size_t(6)); |
51 | } |
52 | |
53 | TEST(LlvmLibcScanfConverterTest, RawMatchSpaces) { |
54 | const char *str = " a \t\n b cd" ; |
55 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
56 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
57 | |
58 | // Reading "a" should fail and not advance. |
59 | // Since there's nothing in the format string (the second argument to |
60 | // raw_match) to match the space in the buffer it isn't consumed. |
61 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "a" ), |
62 | static_cast<int>(LIBC_NAMESPACE::scanf_core::MATCHING_FAILURE)); |
63 | ASSERT_EQ(reader.chars_read(), size_t(0)); |
64 | |
65 | // Reading " \t\n " should succeed and advance past the space. |
66 | // Any number of space characters in the format string match 0 or more space |
67 | // characters in the buffer. |
68 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, " \t\n " ), |
69 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
70 | ASSERT_EQ(reader.chars_read(), size_t(1)); |
71 | |
72 | // Reading "ab" should fail and only advance past the a |
73 | // The a characters match, but the format string doesn't have anything to |
74 | // consume the spaces in the buffer, so it fails. |
75 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "ab" ), |
76 | static_cast<int>(LIBC_NAMESPACE::scanf_core::MATCHING_FAILURE)); |
77 | ASSERT_EQ(reader.chars_read(), size_t(2)); |
78 | |
79 | // Reading " b" should succeed and advance past the b |
80 | // Any number of space characters in the format string matches 0 or more space |
81 | // characters in the buffer. |
82 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, " b" ), |
83 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
84 | ASSERT_EQ(reader.chars_read(), size_t(7)); |
85 | |
86 | // Reading "\t" should succeed and advance past the spaces to the c |
87 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "\t" ), |
88 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
89 | ASSERT_EQ(reader.chars_read(), size_t(10)); |
90 | |
91 | // Reading "c d" should succeed and advance past the d. |
92 | // Here the space character in the format string is matching 0 space |
93 | // characters in the buffer. |
94 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::raw_match(&reader, "c d" ), |
95 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
96 | ASSERT_EQ(reader.chars_read(), size_t(12)); |
97 | } |
98 | |
99 | TEST(LlvmLibcScanfConverterTest, StringConvSimple) { |
100 | const char *str = "abcDEF123 654LKJihg" ; |
101 | char result[20]; |
102 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
103 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
104 | |
105 | LIBC_NAMESPACE::scanf_core::FormatSection conv; |
106 | conv.has_conv = true; |
107 | conv.conv_name = 's'; |
108 | conv.output_ptr = result; |
109 | |
110 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
111 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
112 | ASSERT_EQ(reader.chars_read(), size_t(9)); |
113 | ASSERT_STREQ(result, "abcDEF123" ); |
114 | |
115 | //%s skips all spaces before beginning to read. |
116 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
117 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
118 | ASSERT_EQ(reader.chars_read(), size_t(19)); |
119 | ASSERT_STREQ(result, "654LKJihg" ); |
120 | } |
121 | |
122 | TEST(LlvmLibcScanfConverterTest, StringConvNoWrite) { |
123 | const char *str = "abcDEF123 654LKJihg" ; |
124 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
125 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
126 | |
127 | LIBC_NAMESPACE::scanf_core::FormatSection conv; |
128 | conv.has_conv = true; |
129 | conv.conv_name = 's'; |
130 | conv.flags = LIBC_NAMESPACE::scanf_core::NO_WRITE; |
131 | |
132 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
133 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
134 | ASSERT_EQ(reader.chars_read(), size_t(9)); |
135 | |
136 | //%s skips all spaces before beginning to read. |
137 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
138 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
139 | ASSERT_EQ(reader.chars_read(), size_t(19)); |
140 | } |
141 | |
142 | TEST(LlvmLibcScanfConverterTest, StringConvWidth) { |
143 | const char *str = "abcDEF123 654LKJihg" ; |
144 | char result[6]; |
145 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
146 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
147 | |
148 | LIBC_NAMESPACE::scanf_core::FormatSection conv; |
149 | conv.has_conv = true; |
150 | conv.conv_name = 's'; |
151 | conv.max_width = 5; // this means the result takes up 6 characters (with \0). |
152 | conv.output_ptr = result; |
153 | |
154 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
155 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
156 | ASSERT_EQ(reader.chars_read(), size_t(5)); |
157 | ASSERT_STREQ(result, "abcDE" ); |
158 | |
159 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
160 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
161 | ASSERT_EQ(reader.chars_read(), size_t(9)); |
162 | ASSERT_STREQ(result, "F123" ); |
163 | |
164 | //%s skips all spaces before beginning to read. |
165 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
166 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
167 | ASSERT_EQ(reader.chars_read(), size_t(15)); |
168 | ASSERT_STREQ(result, "654LK" ); |
169 | |
170 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
171 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
172 | ASSERT_EQ(reader.chars_read(), size_t(19)); |
173 | ASSERT_STREQ(result, "Jihg" ); |
174 | } |
175 | |
176 | TEST(LlvmLibcScanfConverterTest, CharsConv) { |
177 | const char *str = "abcDEF123 654LKJihg MNOpqr&*(" ; |
178 | char result[20]; |
179 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
180 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
181 | |
182 | LIBC_NAMESPACE::scanf_core::FormatSection conv; |
183 | conv.has_conv = true; |
184 | conv.conv_name = 'c'; |
185 | conv.output_ptr = result; |
186 | |
187 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
188 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
189 | ASSERT_EQ(reader.chars_read(), size_t(1)); |
190 | ASSERT_EQ(result[0], 'a'); |
191 | |
192 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
193 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
194 | ASSERT_EQ(reader.chars_read(), size_t(2)); |
195 | ASSERT_EQ(result[0], 'b'); |
196 | |
197 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
198 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
199 | ASSERT_EQ(reader.chars_read(), size_t(3)); |
200 | ASSERT_EQ(result[0], 'c'); |
201 | |
202 | // Switch from character by character to 8 at a time. |
203 | conv.max_width = 8; |
204 | LIBC_NAMESPACE::cpp::string_view result_view(result, 8); |
205 | |
206 | //%c doesn't stop on spaces. |
207 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
208 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
209 | ASSERT_EQ(reader.chars_read(), size_t(11)); |
210 | ASSERT_EQ(result_view, LIBC_NAMESPACE::cpp::string_view("DEF123 6" , 8)); |
211 | |
212 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
213 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
214 | ASSERT_EQ(reader.chars_read(), size_t(19)); |
215 | ASSERT_EQ(result_view, LIBC_NAMESPACE::cpp::string_view("54LKJihg" , 8)); |
216 | |
217 | //%c also doesn't skip spaces at the start. |
218 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
219 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
220 | ASSERT_EQ(reader.chars_read(), size_t(27)); |
221 | ASSERT_EQ(result_view, LIBC_NAMESPACE::cpp::string_view(" MNOpqr&" , 8)); |
222 | |
223 | //%c will stop on a null byte though. |
224 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
225 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
226 | ASSERT_EQ(reader.chars_read(), size_t(29)); |
227 | ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(result, 2), |
228 | LIBC_NAMESPACE::cpp::string_view("*(" , 2)); |
229 | } |
230 | |
231 | TEST(LlvmLibcScanfConverterTest, ScansetConv) { |
232 | const char *str = "abcDEF[123] 654LKJihg" ; |
233 | char result[20]; |
234 | LIBC_NAMESPACE::scanf_core::StringReader str_reader(str); |
235 | LIBC_NAMESPACE::scanf_core::Reader reader(&str_reader); |
236 | |
237 | LIBC_NAMESPACE::scanf_core::FormatSection conv; |
238 | conv.has_conv = true; |
239 | conv.conv_name = '['; |
240 | conv.output_ptr = result; |
241 | |
242 | LIBC_NAMESPACE::cpp::bitset<256> bitset1; |
243 | bitset1.set_range(Start: 'a', End: 'c'); |
244 | bitset1.set_range(Start: 'D', End: 'F'); |
245 | bitset1.set_range(Start: '1', End: '6'); |
246 | bitset1.set('['); |
247 | bitset1.set(']'); |
248 | |
249 | conv.scan_set = bitset1; |
250 | |
251 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
252 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
253 | ASSERT_EQ(reader.chars_read(), size_t(11)); |
254 | ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(result, 11), |
255 | LIBC_NAMESPACE::cpp::string_view("abcDEF[123]" , 11)); |
256 | |
257 | // The scanset conversion doesn't consume leading spaces. If it did it would |
258 | // return "654" here. |
259 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
260 | static_cast<int>(LIBC_NAMESPACE::scanf_core::MATCHING_FAILURE)); |
261 | ASSERT_EQ(reader.chars_read(), size_t(11)); |
262 | |
263 | // This set is everything except for a-g. |
264 | LIBC_NAMESPACE::cpp::bitset<256> bitset2; |
265 | bitset2.set_range(Start: 'a', End: 'g'); |
266 | bitset2.flip(); |
267 | conv.scan_set = bitset2; |
268 | |
269 | conv.max_width = 5; |
270 | |
271 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
272 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
273 | ASSERT_EQ(reader.chars_read(), size_t(16)); |
274 | ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(result, 5), |
275 | LIBC_NAMESPACE::cpp::string_view(" 654L" , 5)); |
276 | |
277 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
278 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
279 | ASSERT_EQ(reader.chars_read(), size_t(20)); |
280 | ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(result, 4), |
281 | LIBC_NAMESPACE::cpp::string_view("KJih" , 4)); |
282 | |
283 | // This set is g and '\0'. |
284 | LIBC_NAMESPACE::cpp::bitset<256> bitset3; |
285 | bitset3.set('g'); |
286 | bitset3.set('\0'); |
287 | conv.scan_set = bitset3; |
288 | |
289 | // Even though '\0' is in the scanset, it should still stop on it. |
290 | ASSERT_EQ(LIBC_NAMESPACE::scanf_core::convert(&reader, conv), |
291 | static_cast<int>(LIBC_NAMESPACE::scanf_core::READ_OK)); |
292 | ASSERT_EQ(reader.chars_read(), size_t(21)); |
293 | ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(result, 1), |
294 | LIBC_NAMESPACE::cpp::string_view("g" , 1)); |
295 | } |
296 | |