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