1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "cx/test.h"
30 #include "util_allocator.h"
31
32 #include "cx/printf.h"
33 #include "cx/buffer.h"
34
35 #define ASSERT_ZERO_TERMINATED(str)
CX_TEST_ASSERTM((str).ptr[(str).length] ==
'\0', \
36 #str " is not zero terminated")
37
38 static size_t test_printf_write_func(
39 const void *src,
40 size_t esize,
41 size_t ecount,
42 void *target
43 ) {
44 memcpy(target, src, esize * ecount);
45 return esize * ecount;
46 }
47
48 CX_TEST(test_bprintf) {
49 CxTestingAllocator talloc;
50 cx_testing_allocator_init(&talloc);
51 CxAllocator *alloc = &talloc.base;
52 CX_TEST_DO {
53 CxBuffer buf;
54 cxBufferInit(&buf,
NULL,
64, alloc,
0);
55 size_t r = cx_bprintf(&buf,
"This %s aged %u years in a %2XSK.",
"Test",
10,
0xca);
56 CX_TEST_ASSERT(r ==
34);
57 CX_TEST_ASSERT(buf.size ==
34);
58 buf.space[r] =
'\0';
59 CX_TEST_ASSERT(
0 == strcmp(buf.space,
"This Test aged 10 years in a CASK."));
60 cxBufferDestroy(&buf);
61 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
62 }
63 cx_testing_allocator_destroy(&talloc);
64 }
65
66 CX_TEST(test_bprintf_large_string) {
67 unsigned len = cx_printf_sbo_size;
68 CxTestingAllocator talloc;
69 cx_testing_allocator_init(&talloc);
70 CxAllocator *alloc = &talloc.base;
71 char *aaa = malloc(len);
72 char *bbb = malloc(len);
73 char *expected = malloc(
2*len
+16);
74 memset(aaa,
'a', len
-1);
75 aaa[len
-1] =
0;
76 memset(bbb,
'b', len
-1);
77 bbb[len
-1] =
0;
78 sprintf(expected,
"After %s comes %s.", aaa, bbb);
79 CX_TEST_DO {
80 CxBuffer buf;
81 cxBufferInit(&buf,
NULL,
64, alloc,
CX_BUFFER_AUTO_EXTEND);
82 size_t r = cx_bprintf(&buf,
"After %s comes %s.", aaa, bbb);
83 size_t er =
2*len
-2+14;
84 CX_TEST_ASSERT(r == er);
85 CX_TEST_ASSERT(buf.size == er);
86 cxBufferPut(&buf,
0);
87 CX_TEST_ASSERT(
0 == strcmp(expected, buf.space));
88 cxBufferDestroy(&buf);
89 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
90 }
91 free(aaa);
92 free(bbb);
93 free(expected);
94 cx_testing_allocator_destroy(&talloc);
95 }
96
97 CX_TEST(test_bprintf_nocap) {
98 CxTestingAllocator talloc;
99 cx_testing_allocator_init(&talloc);
100 CxAllocator *alloc = &talloc.base;
101 char space[
20];
102 memset(space,
'a',
20);
103 CX_TEST_DO {
104 CxBuffer buf;
105 cxBufferInit(&buf, space,
16, alloc,
0);
106 size_t r = cx_bprintf(&buf,
"Hello %s with more than %d chars.",
"string",
16);
107 CX_TEST_ASSERT(r ==
16);
108 CX_TEST_ASSERT(buf.size ==
16);
109 CX_TEST_ASSERT(
0 == memcmp(space,
"Hello string witaaaa",
20));
110 cxBufferDestroy(&buf);
111 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
112 }
113 cx_testing_allocator_destroy(&talloc);
114 }
115
116 CX_TEST(test_fprintf) {
117 const char *h =
"Hello";
118 char buf[
32];
119 size_t r;
120 CX_TEST_DO {
121 r = cx_fprintf(buf, test_printf_write_func,
"teststring");
122 CX_TEST_ASSERT(r ==
10);
123 CX_TEST_ASSERT(
0 == memcmp(buf,
"teststring", r));
124
125 r = cx_fprintf(buf, test_printf_write_func,
"[%10s]", h);
126 CX_TEST_ASSERT(r ==
12);
127 CX_TEST_ASSERT(
0 == memcmp(buf,
"[ Hello]", r));
128
129 r = cx_fprintf(buf, test_printf_write_func,
"[%-10s]", h);
130 CX_TEST_ASSERT(r ==
12);
131 CX_TEST_ASSERT(
0 == memcmp(buf,
"[Hello ]", r));
132
133 r = cx_fprintf(buf, test_printf_write_func,
"[%*s]",
10, h);
134 CX_TEST_ASSERT(r ==
12);
135 CX_TEST_ASSERT(
0 == memcmp(buf,
"[ Hello]", r));
136
137 r = cx_fprintf(buf, test_printf_write_func,
"[%-10.*s]",
4, h);
138 CX_TEST_ASSERT(r ==
12);
139 CX_TEST_ASSERT(
0 == memcmp(buf,
"[Hell ]", r));
140
141 r = cx_fprintf(buf, test_printf_write_func,
"[%-*.*s]",
10,
4, h);
142 CX_TEST_ASSERT(r ==
12);
143 CX_TEST_ASSERT(
0 == memcmp(buf,
"[Hell ]", r));
144
145 r = cx_fprintf(buf, test_printf_write_func,
"%c",
'A');
146 CX_TEST_ASSERT(r ==
1);
147 CX_TEST_ASSERT(
0 == memcmp(buf,
"A", r));
148
149 r = cx_fprintf(buf, test_printf_write_func,
"%i %d %.6i %i %.0i %+i %i",
1,
2,
3,
0,
0,
4,
-4);
150 CX_TEST_ASSERT(r ==
19);
151 CX_TEST_ASSERT(
0 == memcmp(buf,
"1 2 000003 0 +4 -4", r));
152
153 r = cx_fprintf(buf, test_printf_write_func,
"%x %x %X %#x",
5,
10,
10,
6);
154 CX_TEST_ASSERT(r ==
9);
155 CX_TEST_ASSERT(
0 == memcmp(buf,
"5 a A 0x6", r));
156
157 r = cx_fprintf(buf, test_printf_write_func,
"%o %#o %#o",
10,
10,
4);
158 CX_TEST_ASSERT(r ==
9);
159 CX_TEST_ASSERT(
0 == memcmp(buf,
"12 012 04", r));
160
161 r = cx_fprintf(buf, test_printf_write_func,
"%05.2f %.2f %5.2f",
1.5,
1.5,
1.5);
162 CX_TEST_ASSERT(r ==
16);
163 CX_TEST_ASSERT(
0 == memcmp(buf,
"01.50 1.50 1.50", r));
164
165 r = cx_fprintf(buf, test_printf_write_func,
"''%*c''",
5,
'x');
166 CX_TEST_ASSERT(r ==
7);
167 CX_TEST_ASSERT(
0 == memcmp(buf,
"'' x''", r));
168
169 r = cx_fprintf(buf, test_printf_write_func,
"''%*c''",
-5,
'x');
170 CX_TEST_ASSERT(r ==
7);
171 CX_TEST_ASSERT(
0 == memcmp(buf,
"''x ''", r));
172 }
173 }
174
175 CX_TEST(test_asprintf) {
176 CxTestingAllocator talloc;
177 cx_testing_allocator_init(&talloc);
178 CxAllocator *alloc = &talloc.base;
179
180 const char *h =
"Hello";
181
182 cxmutstr r[
13];
183 size_t specimen_count = cx_nmemb(r);
184 size_t specimen =
0;
185
186 CX_TEST_DO {
187 r[specimen] = cx_asprintf_a(alloc,
"teststring");
188 CX_TEST_ASSERT(r[specimen].length ==
10);
189 ASSERT_ZERO_TERMINATED(r[specimen]);
190 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"teststring"));
191 specimen++;
192
193 r[specimen] = cx_asprintf_a(alloc,
"[%10s]", h);
194 CX_TEST_ASSERT(r[specimen].length ==
12);
195 ASSERT_ZERO_TERMINATED(r[specimen]);
196 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"[ Hello]"));
197 specimen++;
198
199 r[specimen] = cx_asprintf_a(alloc,
"[%-10s]", h);
200 CX_TEST_ASSERT(r[specimen].length ==
12);
201 ASSERT_ZERO_TERMINATED(r[specimen]);
202 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"[Hello ]"));
203 specimen++;
204
205 r[specimen] = cx_asprintf_a(alloc,
"[%*s]",
10, h);
206 CX_TEST_ASSERT(r[specimen].length ==
12);
207 ASSERT_ZERO_TERMINATED(r[specimen]);
208 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"[ Hello]"));
209 specimen++;
210
211 r[specimen] = cx_asprintf_a(alloc,
"[%-10.*s]",
4, h);
212 CX_TEST_ASSERT(r[specimen].length ==
12);
213 ASSERT_ZERO_TERMINATED(r[specimen]);
214 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"[Hell ]"));
215 specimen++;
216
217 r[specimen] = cx_asprintf_a(alloc,
"[%-*.*s]",
10,
4, h);
218 CX_TEST_ASSERT(r[specimen].length ==
12);
219 ASSERT_ZERO_TERMINATED(r[specimen]);
220 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"[Hell ]"));
221 specimen++;
222
223 r[specimen] = cx_asprintf_a(alloc,
"%c",
'A');
224 CX_TEST_ASSERT(r[specimen].length ==
1);
225 ASSERT_ZERO_TERMINATED(r[specimen]);
226 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"A"));
227 specimen++;
228
229 r[specimen] = cx_asprintf_a(alloc,
"%i %d %.6i %i %.0i %+i %i",
1,
2,
3,
0,
0,
4,
-4);
230 CX_TEST_ASSERT(r[specimen].length ==
19);
231 ASSERT_ZERO_TERMINATED(r[specimen]);
232 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"1 2 000003 0 +4 -4"));
233 specimen++;
234
235 r[specimen] = cx_asprintf_a(alloc,
"%x %x %X %#x",
5,
10,
10,
6);
236 CX_TEST_ASSERT(r[specimen].length ==
9);
237 ASSERT_ZERO_TERMINATED(r[specimen]);
238 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"5 a A 0x6"));
239 specimen++;
240
241 r[specimen] = cx_asprintf_a(alloc,
"%o %#o %#o",
10,
10,
4);
242 CX_TEST_ASSERT(r[specimen].length ==
9);
243 ASSERT_ZERO_TERMINATED(r[specimen]);
244 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"12 012 04"));
245 specimen++;
246
247 r[specimen] = cx_asprintf_a(alloc,
"%05.2f %.2f %5.2f",
1.5,
1.5,
1.5);
248 CX_TEST_ASSERT(r[specimen].length ==
16);
249 ASSERT_ZERO_TERMINATED(r[specimen]);
250 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"01.50 1.50 1.50"));
251 specimen++;
252
253 r[specimen] = cx_asprintf_a(alloc,
"''%*c''",
5,
'x');
254 CX_TEST_ASSERT(r[specimen].length ==
7);
255 ASSERT_ZERO_TERMINATED(r[specimen]);
256 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"'' x''"));
257 specimen++;
258
259 r[specimen] = cx_asprintf_a(alloc,
"''%*c''",
-5,
'x');
260 CX_TEST_ASSERT(r[specimen].length ==
7);
261 ASSERT_ZERO_TERMINATED(r[specimen]);
262 CX_TEST_ASSERT(
0 == strcmp(r[specimen].ptr,
"''x ''"));
263 specimen++;
264
265 CX_TEST_ASSERT(specimen == specimen_count);
266
267 for (
size_t i =
0; i < specimen_count; i++) {
268 cx_strfree_a(alloc, &r[i]);
269 }
270 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
271 }
272 cx_testing_allocator_destroy(&talloc);
273 }
274
275 CX_TEST(test_asprintf_large_string) {
276 unsigned len = cx_printf_sbo_size;
277 char *aaa = malloc(len);
278 char *bbb = malloc(len);
279 char *expected = malloc(
2*len
+16);
280 memset(aaa,
'a', len
-1);
281 aaa[len
-1] =
0;
282 memset(bbb,
'b', len
-1);
283 bbb[len
-1] =
0;
284 sprintf(expected,
"After %s comes %s.", aaa, bbb);
285 CX_TEST_DO {
286 cxmutstr r = cx_asprintf(
"After %s comes %s.", aaa, bbb);
287 CX_TEST_ASSERT(r.length ==
2*len
-2+14);
288 ASSERT_ZERO_TERMINATED(r);
289 CX_TEST_ASSERT(
0 == strcmp(r.ptr, expected));
290 cx_strfree(&r);
291 }
292 free(aaa);
293 free(bbb);
294 free(expected);
295 }
296
297 CX_TEST(test_sprintf_no_realloc) {
298 char *buf = malloc(
16);
299 CxTestingAllocator talloc;
300 cx_testing_allocator_init(&talloc);
301 CxAllocator *alloc = &talloc.base;
302 CX_TEST_DO {
303 char *oldbuf = buf;
304 size_t buflen =
16;
305 size_t len = cx_sprintf_a(alloc, &buf, &buflen,
"Test %d %s",
47,
"string");
306 CX_TEST_ASSERT(oldbuf == buf);
307 CX_TEST_ASSERT(len ==
14);
308 CX_TEST_ASSERT(buflen ==
16);
309 CX_TEST_ASSERT(
0 == memcmp(buf,
"Test 47 string",
15));
310 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
311 }
312 cx_testing_allocator_destroy(&talloc);
313 free(buf);
314 }
315
316 CX_TEST(test_sprintf_realloc) {
317 CxTestingAllocator talloc;
318 cx_testing_allocator_init(&talloc);
319 CxAllocator *alloc = &talloc.base;
320 char *buf = cxMalloc(alloc,
8);
321 CX_TEST_DO {
322 size_t buflen =
8;
323 size_t len = cx_sprintf_a(alloc, &buf, &buflen,
"Test %d %s",
47,
"foobar");
324 CX_TEST_ASSERT(len ==
14);
325 CX_TEST_ASSERT(buflen ==
15);
326 CX_TEST_ASSERT(
0 == memcmp(buf,
"Test 47 foobar",
15));
327 cxFree(alloc, buf);
328 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
329 }
330 cx_testing_allocator_destroy(&talloc);
331 }
332
333 CX_TEST(test_sprintf_realloc_to_fit_terminator) {
334 CxTestingAllocator talloc;
335 cx_testing_allocator_init(&talloc);
336 CxAllocator *alloc = &talloc.base;
337
338 char *buf = cxMalloc(alloc,
14);
339 CX_TEST_DO {
340 size_t buflen =
14;
341 size_t len = cx_sprintf_a(alloc, &buf, &buflen,
"Test %d %s",
13,
"string");
342 CX_TEST_ASSERT(len ==
14);
343 CX_TEST_ASSERT(buflen ==
15);
344 CX_TEST_ASSERT(
0 == memcmp(buf,
"Test 13 string",
15));
345 cxFree(alloc, buf);
346 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
347 }
348 cx_testing_allocator_destroy(&talloc);
349 }
350
351 CX_TEST(test_sprintf_s_no_alloc) {
352 char buf[
16];
353 CxTestingAllocator talloc;
354 cx_testing_allocator_init(&talloc);
355 CxAllocator *alloc = &talloc.base;
356 CX_TEST_DO {
357 char *str;
358 size_t buflen =
16;
359 size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str,
"Test %d %s",
47,
"string");
360 CX_TEST_ASSERT(str == buf);
361 CX_TEST_ASSERT(buflen ==
16);
362 CX_TEST_ASSERT(len ==
14);
363 CX_TEST_ASSERT(
0 == memcmp(buf,
"Test 47 string",
15));
364 CX_TEST_ASSERT(
0 == memcmp(str,
"Test 47 string",
15));
365 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
366 }
367 cx_testing_allocator_destroy(&talloc);
368 }
369
370 CX_TEST(test_sprintf_s_alloc) {
371 char buf[
16];
372 memcpy(buf,
"0123456789abcdef",
16);
373 CxTestingAllocator talloc;
374 cx_testing_allocator_init(&talloc);
375 CxAllocator *alloc = &talloc.base;
376 CX_TEST_DO {
377 char *str;
378 size_t buflen =
16;
379 size_t len = cx_sprintf_sa(alloc, buf, &buflen, &str,
"Hello %d %s",
4711,
"larger string");
380 CX_TEST_ASSERT(str != buf);
381 CX_TEST_ASSERT(buflen ==
25);
382 CX_TEST_ASSERT(len ==
24);
383 CX_TEST_ASSERT(
0 == memcmp(str,
"Hello 4711 larger string",
25));
384 cxFree(alloc, str);
385 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
386 }
387 cx_testing_allocator_destroy(&talloc);
388 }
389
390 CX_TEST(test_sprintf_s_alloc_to_fit_terminator) {
391 char buf[
16];
392 memcpy(buf,
"0123456789abcdef",
16);
393 CxTestingAllocator talloc;
394 cx_testing_allocator_init(&talloc);
395 CxAllocator *alloc = &talloc.base;
396 CX_TEST_DO {
397 char *str;
398 size_t buflen =
16;
399 size_t len = cx_sprintf_sa(alloc, buf,&buflen, &str,
"Hello %d %s",
112,
"string");
400 CX_TEST_ASSERT(str != buf);
401 CX_TEST_ASSERT(len ==
16);
402 CX_TEST_ASSERT(buflen ==
17);
403 CX_TEST_ASSERT(
0 == memcmp(str,
"Hello 112 string",
17));
404 cxFree(alloc, str);
405 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
406 }
407 cx_testing_allocator_destroy(&talloc);
408 }
409
410 CxTestSuite *cx_test_suite_printf(
void) {
411 CxTestSuite *suite = cx_test_suite_new(
"printf");
412
413 cx_test_register(suite, test_bprintf);
414 cx_test_register(suite, test_bprintf_large_string);
415 cx_test_register(suite, test_bprintf_nocap);
416 cx_test_register(suite, test_fprintf);
417 cx_test_register(suite, test_asprintf);
418 cx_test_register(suite, test_asprintf_large_string);
419 cx_test_register(suite, test_sprintf_no_realloc);
420 cx_test_register(suite, test_sprintf_realloc);
421 cx_test_register(suite, test_sprintf_realloc_to_fit_terminator);
422 cx_test_register(suite, test_sprintf_s_no_alloc);
423 cx_test_register(suite, test_sprintf_s_alloc);
424 cx_test_register(suite, test_sprintf_s_alloc_to_fit_terminator);
425
426 return suite;
427 }
428