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
16TEST(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
51TEST(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
96TEST(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
118TEST(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
137TEST(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
170TEST(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
224TEST(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

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