1 /*
2 * SysDB - t/unit/utils/strbuf_test.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include "utils/strbuf.h"
29 #include "libsysdb_test.h"
31 #include <check.h>
33 /*
34 * private data types
35 */
37 static sdb_strbuf_t *buf;
39 static void
40 setup(void)
41 {
42 buf = sdb_strbuf_create(0);
43 fail_unless(buf != NULL,
44 "sdb_strbuf_create() = NULL; expected strbuf object");
45 } /* setup */
47 static void
48 teardown(void)
49 {
50 sdb_strbuf_destroy(buf);
51 buf = NULL;
52 } /* teardown */
54 /*
55 * tests
56 */
58 START_TEST(test_null)
59 {
60 sdb_strbuf_t *b = NULL;
61 va_list ap;
63 /* check that methods don't crash */
64 sdb_strbuf_destroy(b);
65 sdb_strbuf_skip(b, 0, 0);
66 sdb_strbuf_skip(b, 0, 10);
67 sdb_strbuf_skip(b, 10, 10);
68 sdb_strbuf_clear(b);
70 /* check that methods return an error */
71 fail_unless(sdb_strbuf_vappend(b, "test", ap) < 0,
72 "sdb_strbuf_vappend(NULL) didn't report failure");
73 fail_unless(sdb_strbuf_append(b, "test") < 0,
74 "sdb_strbuf_append(NULL) didn't report failure");
75 fail_unless(sdb_strbuf_vsprintf(b, "test", ap) < 0,
76 "sdb_strbuf_vsprintf(NULL) didn't report failure");
77 fail_unless(sdb_strbuf_sprintf(b, "test") < 0,
78 "sdb_strbuf_sprintf(NULL) didn't report failure");
79 fail_unless(sdb_strbuf_memcpy(b, "test", 4) < 0,
80 "sdb_strbuf_memcpy(NULL) didn't report failure");
81 fail_unless(sdb_strbuf_memappend(b, "test", 4) < 0,
82 "sdb_strbuf_memappend(NULL) didn't report failure");
83 fail_unless(sdb_strbuf_read(b, 0, 32) < 0,
84 "sdb_strbuf_read(NULL) didn't report failure");
85 fail_unless(sdb_strbuf_chomp(b) < 0,
86 "sdb_strbuf_chomp(NULL) didn't report failure");
87 }
88 END_TEST
90 START_TEST(test_empty)
91 {
92 sdb_strbuf_t *b = sdb_strbuf_create(0);
93 const char *data;
94 size_t len;
96 /* check that methods don't crash */
97 sdb_strbuf_skip(b, 1, 1);
98 sdb_strbuf_clear(b);
99 sdb_strbuf_chomp(b);
101 data = sdb_strbuf_string(b);
102 fail_unless(data && (*data == '\0'),
103 "sdb_strbuf_string(<empty>) = '%s'; expected: ''", data);
104 len = sdb_strbuf_len(b);
105 fail_unless(len == 0,
106 "sdb_strbuf_len(<empty>) = %zu; expected: 0", len);
108 sdb_strbuf_destroy(b);
109 }
110 END_TEST
112 START_TEST(test_create)
113 {
114 sdb_strbuf_t *s;
115 size_t len;
117 s = sdb_strbuf_create(0);
118 fail_unless(s != NULL,
119 "sdb_strbuf_create() = NULL; expected strbuf object");
120 len = sdb_strbuf_len(s);
121 fail_unless(len == 0,
122 "sdb_strbuf_create() created buffer with len = %zu; "
123 "expected: 0", len);
124 sdb_strbuf_destroy(s);
126 s = sdb_strbuf_create(128);
127 fail_unless(s != NULL,
128 "sdb_strbuf_create() = NULL; expected strbuf object");
129 len = sdb_strbuf_len(s);
130 /* len still has to be 0 -- there's no content */
131 fail_unless(len == 0,
132 "sdb_strbuf_create() created buffer with len = %zu; "
133 "expected: 0", len);
134 sdb_strbuf_destroy(s);
135 }
136 END_TEST
138 START_TEST(test_append)
139 {
140 ssize_t n;
141 size_t len, total = 0;
142 const char *test;
144 struct {
145 const char *input;
146 const char *result;
147 } golden_data[] = {
148 { "1234567890", "1234567890" },
149 { "ABCDE", "1234567890ABCDE" },
150 { "", "1234567890ABCDE" },
151 { "-", "1234567890ABCDE-" },
152 /* when adding anything to this array, the last check has to be
153 * updated accordingly */
154 };
156 size_t i;
158 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
159 n = sdb_strbuf_append(buf, golden_data[i].input);
160 fail_unless((size_t)n == strlen(golden_data[i].input),
161 "sdb_strbuf_append() appended %zi bytes; expected: %zu",
162 n, strlen(golden_data[i].input));
163 total += n;
164 len = sdb_strbuf_len(buf);
165 fail_unless(len == total,
166 "sdb_strbuf_append() left behind buffer with len = %zu; "
167 "expected: %zu", len, total);
169 test = sdb_strbuf_string(buf);
170 fail_unless(test[len] == '\0',
171 "sdb_strbuf_append() did not nil-terminate the string");
173 test = sdb_strbuf_string(buf);
174 fail_unless(!strcmp(test, golden_data[i].result),
175 "sdb_strbuf_append() did not correctly concatenate "
176 "the input; got: %s; expected: %s",
177 test, golden_data[i].result);
178 }
180 n = sdb_strbuf_append(buf, "%zu; %5.4f", 42, 4.2);
181 fail_unless(n == 10,
182 "sdb_strbuf_append() appended %zi bytes; expected: 10", n);
183 total += n;
184 len = sdb_strbuf_len(buf);
185 fail_unless(len == total,
186 "sdb_strbuf_append() left behind buffer with len = %zu; "
187 "expected: %zu", len, total);
189 test = sdb_strbuf_string(buf);
190 fail_unless(test[len] == '\0',
191 "sdb_strbuf_append() did not nil-terminate the string");
192 fail_unless(!strcmp(test, "1234567890ABCDE-42; 4.2000"),
193 "sdb_strbuf_append() did not correctly concatenate the input; "
194 "got: %s; expected: 1234567890ABCDE-42; 4.2000", test);
195 }
196 END_TEST
198 START_TEST(test_sprintf)
199 {
200 ssize_t n;
201 size_t len;
202 const char *test;
204 const char *golden_data[] = {
205 "1234567890",
206 "ABCDE",
207 "",
208 "-",
209 };
211 size_t i;
213 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
214 n = sdb_strbuf_sprintf(buf, golden_data[i]);
215 fail_unless((size_t)n == strlen(golden_data[i]),
216 "sdb_strbuf_sprintf() wrote %zi bytes; expected: %zu",
217 n, strlen(golden_data[i]));
218 len = sdb_strbuf_len(buf);
219 fail_unless(len == (size_t)n,
220 "sdb_strbuf_sprintf() left behind buffer with len = %zu; "
221 "expected: %zi", len, n);
223 test = sdb_strbuf_string(buf);
224 fail_unless(test[len] == '\0',
225 "sdb_strbuf_sprintf() did not nil-terminate the string");
226 fail_unless(!strcmp(test, golden_data[i]),
227 "sdb_strbuf_sprintf() did not format string correctly; "
228 "got: %s; expected: %s", test, golden_data[i]);
229 }
231 n = sdb_strbuf_sprintf(buf, "%zu; %5.4f", 42, 4.2);
232 fail_unless(n == 10,
233 "sdb_strbuf_sprintf() wrote %zi bytes; expected: 10", n);
234 len = sdb_strbuf_len(buf);
235 fail_unless(len == 10,
236 "sdb_strbuf_sprintf() left behind buffer with len = %zu; "
237 "expected: 10", len);
239 test = sdb_strbuf_string(buf);
240 fail_unless(test[len] == '\0',
241 "sdb_strbuf_sprintf() did not nil-terminate the string");
242 fail_unless(!strcmp(test, "42; 4.2000"),
243 "sdb_strbuf_sprintf() did not format string correctly; "
244 "got: %s; expected: 42; 4.2000", test);
245 }
246 END_TEST
248 START_TEST(test_incremental)
249 {
250 const char *data;
252 ssize_t n;
253 size_t i;
255 sdb_strbuf_destroy(buf);
256 buf = sdb_strbuf_create(1024);
258 /* fill buffer one by one; leave room for nul-byte */
259 for (i = 0; i < 1023; ++i) {
260 n = sdb_strbuf_append(buf, ".");
261 fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n);
262 }
264 /* write another byte; this has to trigger a resize */
265 n = sdb_strbuf_append(buf, ".");
266 fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n);
268 /* write more bytes; this should trigger at least one more resize but
269 * that's an implementation detail */
270 for (i = 0; i < 1024; ++i) {
271 n = sdb_strbuf_append(buf, ".");
272 fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n);
273 }
275 n = (ssize_t)sdb_strbuf_len(buf);
276 fail_unless(n == 2048, "sdb_strbuf_len() = %zi; expectd: 2048", n);
278 data = sdb_strbuf_string(buf);
279 for (i = 0; i < 2048; ++i)
280 fail_unless(data[i] == '.',
281 "After sdb_strbuf_append(), found character %x "
282 "at position %zi; expected %x (.)",
283 (int)data[i], i, '.');
284 fail_unless(data[i] == '\0',
285 "After sdb_strbuf_append(), found character %x at end of string; "
286 "expected '\\0'", (int)data[i]);
287 }
288 END_TEST
290 /* used by test_memcpy and test_memappend */
291 static struct {
292 const char *input;
293 size_t size;
294 } mem_golden_data[] = {
295 { "abc\0\x10\x42", 6 },
296 { "\0\1\2\3\4", 5 },
297 { "\n\n\0\n\n", 5 },
298 { "", 0 },
299 };
301 START_TEST(test_memcpy)
302 {
303 size_t i;
305 for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) {
306 ssize_t n;
307 const char *check;
309 n = sdb_strbuf_memcpy(buf, mem_golden_data[i].input,
310 mem_golden_data[i].size);
311 fail_unless(n >= 0,
312 "sdb_strbuf_memcpy() = %zi; expected: >=0", n);
313 fail_unless((size_t)n == mem_golden_data[i].size,
314 "sdb_strbuf_memcpy() = %zi; expected: %zu",
315 n, mem_golden_data[i].size);
317 n = (ssize_t)sdb_strbuf_len(buf);
318 fail_unless((size_t)n == mem_golden_data[i].size,
319 "sdb_strbuf_len() = %zu (after memcpy); expected: %zu",
320 n, mem_golden_data[i].size);
322 check = sdb_strbuf_string(buf);
323 fail_unless(check != NULL,
324 "sdb_strbuf_string() = NULL (after memcpy); expected: data");
325 fail_unless(check[mem_golden_data[i].size] == '\0',
326 "sdb_strbuf_memcpy() did not nil-terminate the data");
327 fail_unless(!memcmp(check, mem_golden_data[i].input,
328 mem_golden_data[i].size),
329 "sdb_strbuf_memcpy() did not set the buffer correctly");
330 }
331 }
332 END_TEST
334 START_TEST(test_memappend)
335 {
336 size_t i;
338 for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) {
339 ssize_t n;
340 const char *check;
342 size_t total, j;
344 n = sdb_strbuf_memappend(buf, mem_golden_data[i].input,
345 mem_golden_data[i].size);
346 fail_unless(n >= 0,
347 "sdb_strbuf_memappend() = %zi; expected: >=0", n);
348 fail_unless((size_t)n == mem_golden_data[i].size,
349 "sdb_strbuf_memappend() = %zi; expected: %zu",
350 n, mem_golden_data[i].size);
352 check = sdb_strbuf_string(buf);
353 fail_unless(check != NULL,
354 "sdb_strbuf_string() = NULL (after memappend); "
355 "expected: data");
357 n = (ssize_t)sdb_strbuf_len(buf);
358 total = 0;
359 for (j = 0; j <= i; ++j) {
360 fail_unless(total + mem_golden_data[j].size <= (size_t)n,
361 "sdb_strbuf_len() = %zu (after memappend); "
362 "expected: >=%zu", n, total + mem_golden_data[j].size);
364 fail_unless(!memcmp(check + total, mem_golden_data[j].input,
365 mem_golden_data[j].size),
366 "sdb_strbuf_memappend() did not "
367 "set the buffer correctly");
368 total += mem_golden_data[j].size;
369 }
370 fail_unless((size_t)n == total,
371 "sdb_strbuf_len() = %zu (after memappend); expected: %zu",
372 n, total);
374 fail_unless(check[total] == '\0',
375 "sdb_strbuf_memappend() did not nil-terminate the data");
376 }
377 }
378 END_TEST
380 START_TEST(test_chomp)
381 {
382 struct {
383 const char *input;
384 ssize_t expected;
385 const char *expected_string;
386 } golden_data[] = {
387 { NULL, 0, "" },
388 { "\n", 1, "" },
389 { "\n\n", 2, "" },
390 { "12345\n\n\n", 3, "12345" },
391 { "abcd", 0, "abcd" },
392 };
394 size_t i;
396 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
397 ssize_t n;
398 const char *check;
400 if (golden_data[i].input)
401 sdb_strbuf_sprintf(buf, golden_data[i].input);
403 /* empty buffer */
404 n = sdb_strbuf_chomp(buf);
405 fail_unless(n == golden_data[i].expected,
406 "sdb_strbuf_chomp() = %zi; expected: %zi", n,
407 golden_data[i].expected);
409 check = sdb_strbuf_string(buf);
410 fail_unless(!strcmp(check, golden_data[i].expected_string),
411 "sdb_strbuf_chomp() did not correctly remove newlines; "
412 "got string '%s'; expected: '%s'", check,
413 golden_data[i].expected_string);
414 }
415 }
416 END_TEST
418 START_TEST(test_skip)
419 {
420 const char *input = "1234567890";
421 struct {
422 size_t offset;
423 size_t n;
424 const char *expected;
425 size_t expected_len;
426 } golden_data[] = {
427 { 0, 0, "1234567890", 10 },
428 { 0, 1, "234567890", 9 },
429 { 0, 2, "34567890", 8 },
430 { 0, 9, "0", 1 },
431 { 0, 10, "", 0 },
432 { 0, 11, "", 0 },
433 { 0, 100, "", 0 },
434 { 1, 0, "1234567890", 10 },
435 { 1, 1, "134567890", 9 },
436 { 1, 2, "14567890", 8 },
437 { 2, 0, "1234567890", 10 },
438 { 2, 1, "124567890", 9 },
439 { 2, 2, "12567890", 8 },
440 { 2, 3, "1267890", 7 },
441 { 2, 4, "127890", 6 },
442 { 2, 5, "12890", 5 },
443 { 2, 6, "1290", 4 },
444 { 2, 7, "120", 3 },
445 { 2, 8, "12", 2 },
446 { 2, 9, "12", 2 },
447 { 2, 10, "12", 2 },
448 { 8, 1, "123456780", 9 },
449 { 8, 2, "12345678", 8 },
450 { 8, 3, "12345678", 8 },
451 { 9, 1, "123456789", 9 },
452 { 9, 2, "123456789", 9 },
453 { 10, 1, "1234567890", 10 },
454 { 10, 2, "1234567890", 10 },
455 };
457 size_t i;
459 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
460 const char *check;
461 size_t n;
463 sdb_strbuf_sprintf(buf, input);
464 sdb_strbuf_skip(buf, golden_data[i].offset,
465 golden_data[i].n);
467 n = sdb_strbuf_len(buf);
468 fail_unless(n == golden_data[i].expected_len,
469 "sdb_strbuf_len() = %zu (after skip); expected: %zu",
470 n, golden_data[i].expected_len);
472 check = sdb_strbuf_string(buf);
473 fail_unless(!!check,
474 "sdb_strbuf_string() = NULL (after skip); expected: string");
476 fail_unless(check[n] == '\0',
477 "sdb_strbuf_skip() did not nil-terminate the string");
479 fail_unless(! strcmp(golden_data[i].expected, check),
480 "sdb_strbuf_skip('%s', %zu) did not skip correctly; "
481 "got string '%s'; expected: '%s'", input,
482 golden_data[i].n, check, golden_data[i].expected);
483 }
484 }
485 END_TEST
487 START_TEST(test_clear)
488 {
489 const char *data;
490 size_t len;
492 sdb_strbuf_append(buf, "abc");
493 len = sdb_strbuf_len(buf);
494 fail_unless(len != 0,
495 "sdb_strbuf_len() = %zu; expected: != 0", len);
497 sdb_strbuf_clear(buf);
498 len = sdb_strbuf_len(buf);
499 fail_unless(len == 0,
500 "sdb_strbuf_len() = %zu (after clear); expected: 0", len);
502 data = sdb_strbuf_string(buf);
503 fail_unless(*data == '\0',
504 "sdb_strbuf_string() = '%s' (after clear); expected: ''", data);
505 }
506 END_TEST
508 START_TEST(test_string)
509 {
510 struct {
511 const char *input;
512 const char *expected;
513 } golden_data[] = {
514 { NULL, "" },
515 { "a", "a" },
516 { "abcdef", "abcdef" },
517 };
519 size_t i;
521 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
522 const char *check;
524 if (golden_data[i].input)
525 sdb_strbuf_sprintf(buf, golden_data[i].input);
526 check = sdb_strbuf_string(buf);
527 fail_unless(!strcmp(check, golden_data[i].expected),
528 "sdb_strbuf_string() = '%s'; expected: '%s'",
529 check, golden_data[i].expected);
530 }
531 }
532 END_TEST
534 START_TEST(test_len)
535 {
536 struct {
537 const char *input;
538 size_t expected;
539 } golden_data[] = {
540 { NULL, 0 },
541 { "a", 1 },
542 { "12345", 5 },
543 };
545 size_t i;
547 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
548 size_t check;
550 if (golden_data[i].input)
551 sdb_strbuf_sprintf(buf, golden_data[i].input);
552 check = sdb_strbuf_len(buf);
553 fail_unless(check == golden_data[i].expected,
554 "sdb_strbuf_len() = %zu; expected: %zu",
555 check, golden_data[i].expected);
556 }
557 }
558 END_TEST
560 Suite *
561 util_strbuf_suite(void)
562 {
563 Suite *s = suite_create("utils::strbuf");
564 TCase *tc;
566 tc = tcase_create("empty");
567 tcase_add_test(tc, test_null);
568 tcase_add_test(tc, test_empty);
569 suite_add_tcase(s, tc);
571 tc = tcase_create("core");
572 tcase_add_checked_fixture(tc, setup, teardown);
573 tcase_add_test(tc, test_create);
574 tcase_add_test(tc, test_append);
575 tcase_add_test(tc, test_sprintf);
576 tcase_add_test(tc, test_incremental);
577 tcase_add_test(tc, test_memcpy);
578 tcase_add_test(tc, test_memappend);
579 tcase_add_test(tc, test_chomp);
580 tcase_add_test(tc, test_skip);
581 tcase_add_test(tc, test_clear);
582 tcase_add_test(tc, test_string);
583 tcase_add_test(tc, test_len);
584 suite_add_tcase(s, tc);
586 return s;
587 } /* util_strbuf_suite */
589 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */