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
16using LIBC_NAMESPACE::cpp::string_view;
17using LIBC_NAMESPACE::printf_core::WriteBuffer;
18using LIBC_NAMESPACE::printf_core::Writer;
19
20TEST(LlvmLibcPrintfWriterTest, Constructor) {
21 char str[10];
22 WriteBuffer wb(str, sizeof(str) - 1);
23 Writer writer(&wb);
24 (void)writer;
25}
26
27TEST(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
43TEST(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
57TEST(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
70TEST(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
84TEST(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
106TEST(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
121TEST(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
133TEST(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
145TEST(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
161TEST(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
179TEST(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
191struct OutBuff {
192 char *out_str;
193 size_t cur_pos = 0;
194};
195
196int 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
210TEST(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), &copy_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
229TEST(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), &copy_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
248TEST(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), &copy_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
270TEST(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, &copy_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
292TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) {
293 char str[16];
294
295 OutBuff out_buff = {.out_str: str, .cur_pos: 0};
296
297 WriteBuffer wb(nullptr, 0, &copy_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

source code of libc/test/src/stdio/printf_core/writer_test.cpp