1 | //===-- Unittests for the printf String Writer ----------------------------===// |
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/printf_core/writer.h" |
11 | |
12 | #include "src/string/memory_utils/inline_memcpy.h" |
13 | |
14 | #include "test/UnitTest/Test.h" |
15 | |
16 | using LIBC_NAMESPACE::cpp::string_view; |
17 | using LIBC_NAMESPACE::printf_core::WriteBuffer; |
18 | using LIBC_NAMESPACE::printf_core::WriteMode; |
19 | using LIBC_NAMESPACE::printf_core::Writer; |
20 | |
21 | TEST(LlvmLibcPrintfWriterTest, Constructor) { |
22 | char str[10]; |
23 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
24 | Writer writer(wb); |
25 | (void)writer; |
26 | } |
27 | |
28 | TEST(LlvmLibcPrintfWriterTest, Write) { |
29 | char str[4] = {'D', 'E', 'F', 'G'}; |
30 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
31 | Writer writer(wb); |
32 | writer.write({"abc" , 3}); |
33 | |
34 | EXPECT_EQ(str[3], 'G'); |
35 | |
36 | // The string must be null terminated manually since the writer cannot tell |
37 | // when it's done. |
38 | wb.buff[wb.buff_cur] = '\0'; |
39 | |
40 | ASSERT_STREQ("abc" , str); |
41 | ASSERT_EQ(writer.get_chars_written(), 3); |
42 | } |
43 | |
44 | TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) { |
45 | char str[10]; |
46 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
47 | Writer writer(wb); |
48 | writer.write({"abc" , 3}); |
49 | writer.write({"DEF" , 3}); |
50 | writer.write({"1234" , 3}); |
51 | |
52 | wb.buff[wb.buff_cur] = '\0'; |
53 | |
54 | ASSERT_STREQ("abcDEF123" , str); |
55 | ASSERT_EQ(writer.get_chars_written(), 9); |
56 | } |
57 | |
58 | TEST(LlvmLibcPrintfWriterTest, WriteChars) { |
59 | char str[4] = {'D', 'E', 'F', 'G'}; |
60 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
61 | Writer writer(wb); |
62 | writer.write('a', 3); |
63 | |
64 | EXPECT_EQ(str[3], 'G'); |
65 | wb.buff[wb.buff_cur] = '\0'; |
66 | |
67 | ASSERT_STREQ("aaa" , str); |
68 | ASSERT_EQ(writer.get_chars_written(), 3); |
69 | } |
70 | |
71 | TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) { |
72 | char str[10]; |
73 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
74 | Writer writer(wb); |
75 | writer.write('a', 3); |
76 | writer.write('D', 3); |
77 | writer.write('1', 3); |
78 | |
79 | wb.buff[wb.buff_cur] = '\0'; |
80 | |
81 | ASSERT_STREQ("aaaDDD111" , str); |
82 | ASSERT_EQ(writer.get_chars_written(), 9); |
83 | } |
84 | |
85 | TEST(LlvmLibcPrintfWriterTest, WriteManyChars) { |
86 | char str[100]; |
87 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
88 | Writer writer(wb); |
89 | writer.write('Z', 99); |
90 | |
91 | wb.buff[wb.buff_cur] = '\0'; |
92 | |
93 | ASSERT_STREQ("ZZZZZZZZZZ" |
94 | "ZZZZZZZZZZ" |
95 | "ZZZZZZZZZZ" |
96 | "ZZZZZZZZZZ" |
97 | "ZZZZZZZZZZ" |
98 | "ZZZZZZZZZZ" |
99 | "ZZZZZZZZZZ" |
100 | "ZZZZZZZZZZ" |
101 | "ZZZZZZZZZZ" |
102 | "ZZZZZZZZZ" , |
103 | str); |
104 | ASSERT_EQ(writer.get_chars_written(), 99); |
105 | } |
106 | |
107 | TEST(LlvmLibcPrintfWriterTest, MixedWrites) { |
108 | char str[13]; |
109 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
110 | Writer writer(wb); |
111 | writer.write('a', 3); |
112 | writer.write({"DEF" , 3}); |
113 | writer.write('1', 3); |
114 | writer.write({"456" , 3}); |
115 | |
116 | wb.buff[wb.buff_cur] = '\0'; |
117 | |
118 | ASSERT_STREQ("aaaDEF111456" , str); |
119 | ASSERT_EQ(writer.get_chars_written(), 12); |
120 | } |
121 | |
122 | TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) { |
123 | char str[11]; |
124 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
125 | Writer writer(wb); |
126 | writer.write({"abcDEF123456" , 12}); |
127 | |
128 | wb.buff[wb.buff_cur] = '\0'; |
129 | |
130 | ASSERT_STREQ("abcDEF1234" , str); |
131 | ASSERT_EQ(writer.get_chars_written(), 12); |
132 | } |
133 | |
134 | TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) { |
135 | char str[11]; |
136 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
137 | Writer writer(wb); |
138 | writer.write('1', 15); |
139 | |
140 | wb.buff[wb.buff_cur] = '\0'; |
141 | |
142 | ASSERT_STREQ("1111111111" , str); |
143 | ASSERT_EQ(writer.get_chars_written(), 15); |
144 | } |
145 | |
146 | TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) { |
147 | char str[11]; |
148 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1); |
149 | |
150 | Writer writer(wb); |
151 | writer.write('a', 3); |
152 | writer.write({"DEF" , 3}); |
153 | writer.write('1', 3); |
154 | writer.write({"456" , 3}); |
155 | |
156 | wb.buff[wb.buff_cur] = '\0'; |
157 | |
158 | ASSERT_STREQ("aaaDEF1114" , str); |
159 | ASSERT_EQ(writer.get_chars_written(), 12); |
160 | } |
161 | |
162 | TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) { |
163 | char str[1]; |
164 | // This is because the max length should be at most 1 less than the size of |
165 | // the buffer it's writing to. |
166 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, 0); |
167 | |
168 | Writer writer(wb); |
169 | writer.write('a', 3); |
170 | writer.write({"DEF" , 3}); |
171 | writer.write('1', 3); |
172 | writer.write({"456" , 3}); |
173 | |
174 | wb.buff[wb.buff_cur] = '\0'; |
175 | |
176 | ASSERT_STREQ("" , str); |
177 | ASSERT_EQ(writer.get_chars_written(), 12); |
178 | } |
179 | |
180 | TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) { |
181 | WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0); |
182 | |
183 | Writer writer(wb); |
184 | writer.write('a', 3); |
185 | writer.write({"DEF" , 3}); |
186 | writer.write('1', 3); |
187 | writer.write({"456" , 3}); |
188 | |
189 | ASSERT_EQ(writer.get_chars_written(), 12); |
190 | } |
191 | |
192 | struct OutBuff { |
193 | char *out_str; |
194 | size_t cur_pos = 0; |
195 | }; |
196 | |
197 | int copy_to_out(string_view new_str, void *raw_out_buff) { |
198 | if (new_str.size() == 0) { |
199 | return 0; |
200 | } |
201 | |
202 | OutBuff *out_buff = reinterpret_cast<OutBuff *>(raw_out_buff); |
203 | |
204 | LIBC_NAMESPACE::inline_memcpy(out_buff->out_str + out_buff->cur_pos, |
205 | new_str.data(), new_str.size()); |
206 | |
207 | out_buff->cur_pos += new_str.size(); |
208 | return 0; |
209 | } |
210 | |
211 | TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) { |
212 | char str[16]; |
213 | |
214 | OutBuff out_buff = {str, 0}; |
215 | |
216 | char wb_buff[8]; |
217 | WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb( |
218 | wb_buff, sizeof(wb_buff), ©_to_out, |
219 | reinterpret_cast<void *>(&out_buff)); |
220 | Writer writer(wb); |
221 | writer.write({"abcDEF123456" , 12}); |
222 | |
223 | // Flush the buffer |
224 | wb.overflow_write("" ); |
225 | str[out_buff.cur_pos] = '\0'; |
226 | |
227 | ASSERT_STREQ("abcDEF123456" , str); |
228 | ASSERT_EQ(writer.get_chars_written(), 12); |
229 | } |
230 | |
231 | TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) { |
232 | char str[16]; |
233 | |
234 | OutBuff out_buff = {str, 0}; |
235 | |
236 | char wb_buff[8]; |
237 | WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb( |
238 | wb_buff, sizeof(wb_buff), ©_to_out, |
239 | reinterpret_cast<void *>(&out_buff)); |
240 | Writer writer(wb); |
241 | writer.write('1', 15); |
242 | |
243 | // Flush the buffer |
244 | wb.overflow_write("" ); |
245 | str[out_buff.cur_pos] = '\0'; |
246 | |
247 | ASSERT_STREQ("111111111111111" , str); |
248 | ASSERT_EQ(writer.get_chars_written(), 15); |
249 | } |
250 | |
251 | TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) { |
252 | char str[16]; |
253 | |
254 | OutBuff out_buff = {str, 0}; |
255 | |
256 | char wb_buff[8]; |
257 | WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb( |
258 | wb_buff, sizeof(wb_buff), ©_to_out, |
259 | reinterpret_cast<void *>(&out_buff)); |
260 | Writer writer(wb); |
261 | writer.write('a', 3); |
262 | writer.write({"DEF" , 3}); |
263 | writer.write('1', 3); |
264 | writer.write({"456" , 3}); |
265 | |
266 | // Flush the buffer |
267 | wb.overflow_write("" ); |
268 | str[out_buff.cur_pos] = '\0'; |
269 | |
270 | ASSERT_STREQ("aaaDEF111456" , str); |
271 | ASSERT_EQ(writer.get_chars_written(), 12); |
272 | } |
273 | |
274 | TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) { |
275 | char str[16]; |
276 | |
277 | OutBuff out_buff = {str, 0}; |
278 | |
279 | char wb_buff[1]; |
280 | WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb( |
281 | wb_buff, 0, ©_to_out, reinterpret_cast<void *>(&out_buff)); |
282 | |
283 | Writer writer(wb); |
284 | writer.write('a', 3); |
285 | writer.write({"DEF" , 3}); |
286 | writer.write('1', 3); |
287 | writer.write({"456" , 3}); |
288 | |
289 | // Flush the buffer |
290 | wb.overflow_write("" ); |
291 | str[out_buff.cur_pos] = '\0'; |
292 | |
293 | ASSERT_STREQ("aaaDEF111456" , str); |
294 | ASSERT_EQ(writer.get_chars_written(), 12); |
295 | } |
296 | |
297 | TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) { |
298 | char str[16]; |
299 | |
300 | OutBuff out_buff = {str, 0}; |
301 | |
302 | WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb( |
303 | nullptr, 0, ©_to_out, reinterpret_cast<void *>(&out_buff)); |
304 | |
305 | Writer writer(wb); |
306 | writer.write('a', 3); |
307 | writer.write({"DEF" , 3}); |
308 | writer.write('1', 3); |
309 | writer.write({"456" , 3}); |
310 | |
311 | wb.overflow_write("" ); |
312 | str[out_buff.cur_pos] = '\0'; |
313 | |
314 | ASSERT_EQ(writer.get_chars_written(), 12); |
315 | ASSERT_STREQ("aaaDEF111456" , str); |
316 | } |
317 | |