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