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
17TEST(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
53TEST(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
99TEST(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
122TEST(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
142TEST(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
176TEST(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
231TEST(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

source code of libc/test/src/stdio/scanf_core/converter_test.cpp