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