43a477db5d92cbbf84b9176678256dbd89b03355
[platform/upstream/multipath-tools.git] / tests / strbuf.c
1 /*
2  * Copyright (c) 2021 SUSE LLC
3  * SPDX-License-Identifier: GPL-2.0-only
4  */
5
6 #define _GNU_SOURCE
7 #include <stdbool.h>
8 #include <stdarg.h>
9 #include <stddef.h>
10 #include <setjmp.h>
11 #include <stdlib.h>
12 #include <stdbool.h>
13 #include <cmocka.h>
14 #include <errno.h>
15 #include "strbuf.h"
16 #include "debug.h"
17 #include "globals.c"
18
19 void *__real_realloc(void *ptr, size_t size);
20
21 static bool mock_realloc = false;
22 void *__wrap_realloc(void *ptr, size_t size)
23 {
24         void *p;
25         if (!mock_realloc)
26                 return __real_realloc(ptr, size);
27
28         p = mock_ptr_type(void *);
29         condlog(4, "%s: %p, %zu -> %p", __func__, ptr, size, p);
30         return p;
31 }
32
33 static void test_strbuf_00(void **state)
34 {
35         STRBUF_ON_STACK(buf);
36         char *p;
37
38         assert_ptr_equal(buf.buf, NULL);
39         assert_int_equal(buf.size, 0);
40         assert_int_equal(buf.offs, 0);
41         assert_int_equal(get_strbuf_len(&buf), 0);
42         assert_string_equal(get_strbuf_str(&buf), "");
43         p = steal_strbuf_str(&buf);
44         assert_ptr_equal(p, NULL);
45
46         assert_ptr_equal(buf.buf, NULL);
47         assert_int_equal(buf.size, 0);
48         assert_int_equal(buf.offs, 0);
49         assert_int_equal(get_strbuf_len(&buf), 0);
50         assert_string_equal(get_strbuf_str(&buf), "");
51
52         assert_int_equal(append_strbuf_str(&buf, "moin"), 4);
53         assert_int_equal(get_strbuf_len(&buf), 4);
54         assert_in_range(buf.size, 5, SIZE_MAX);
55         assert_string_equal(get_strbuf_str(&buf), "moin");
56         p = steal_strbuf_str(&buf);
57         assert_string_equal(p, "moin");
58         free(p);
59
60         assert_ptr_equal(buf.buf, NULL);
61         assert_int_equal(buf.size, 0);
62         assert_int_equal(buf.offs, 0);
63         assert_int_equal(get_strbuf_len(&buf), 0);
64         assert_string_equal(get_strbuf_str(&buf), "");
65
66         assert_int_equal(append_strbuf_str(&buf, NULL), -EINVAL);
67         assert_int_equal(buf.size, 0);
68         assert_int_equal(buf.offs, 0);
69         assert_int_equal(get_strbuf_len(&buf), 0);
70         assert_string_equal(get_strbuf_str(&buf), "");
71
72         assert_int_equal(append_strbuf_str(&buf, ""), 0);
73         /* appending a 0-length string allocates memory */
74         assert_in_range(buf.size, 1, SIZE_MAX);
75         assert_int_equal(buf.offs, 0);
76         assert_int_equal(get_strbuf_len(&buf), 0);
77         assert_string_equal(get_strbuf_str(&buf), "");
78         p = steal_strbuf_str(&buf);
79         assert_string_equal(p, "");
80         free(p);
81
82         assert_int_equal(__append_strbuf_str(&buf, "x", 0), 0);
83         /* appending a 0-length string allocates memory */
84         assert_in_range(buf.size, 1, SIZE_MAX);
85         assert_int_equal(buf.offs, 0);
86         assert_int_equal(get_strbuf_len(&buf), 0);
87         assert_string_equal(get_strbuf_str(&buf), "");
88 }
89
90 static void test_strbuf_alloc_err(void **state)
91 {
92         STRBUF_ON_STACK(buf);
93         size_t sz, ofs;
94         int rc;
95
96         mock_realloc = true;
97         will_return(__wrap_realloc, NULL);
98         assert_int_equal(append_strbuf_str(&buf, "moin"), -ENOMEM);
99         assert_int_equal(buf.size, 0);
100         assert_int_equal(buf.offs, 0);
101         assert_int_equal(get_strbuf_len(&buf), 0);
102         assert_string_equal(get_strbuf_str(&buf), "");
103
104         mock_realloc = false;
105         assert_int_equal(append_strbuf_str(&buf, "moin"), 4);
106         sz = buf.size;
107         assert_in_range(sz, 5, SIZE_MAX);
108         assert_int_equal(buf.offs, 4);
109         assert_int_equal(get_strbuf_len(&buf), 4);
110         assert_string_equal(get_strbuf_str(&buf), "moin");
111
112         mock_realloc = true;
113         will_return(__wrap_realloc, NULL);
114         ofs = get_strbuf_len(&buf);
115         while ((rc = append_strbuf_str(&buf, " hello")) >= 0) {
116                 condlog(3, "%s", get_strbuf_str(&buf));
117                 assert_int_equal(rc, 6);
118                 assert_int_equal(get_strbuf_len(&buf), ofs + 6);
119                 assert_memory_equal(get_strbuf_str(&buf), "moin", 4);
120                 assert_string_equal(get_strbuf_str(&buf) + ofs, " hello");
121                 ofs = get_strbuf_len(&buf);
122         }
123         assert_int_equal(rc, -ENOMEM);
124         assert_int_equal(buf.size, sz);
125         assert_int_equal(get_strbuf_len(&buf), ofs);
126         assert_memory_equal(get_strbuf_str(&buf), "moin", 4);
127         assert_string_equal(get_strbuf_str(&buf) + ofs - 6, " hello");
128
129         reset_strbuf(&buf);
130         assert_ptr_equal(buf.buf, NULL);
131         assert_int_equal(buf.size, 0);
132         assert_int_equal(buf.offs, 0);
133         assert_int_equal(get_strbuf_len(&buf), 0);
134         assert_string_equal(get_strbuf_str(&buf), "");
135
136         mock_realloc = false;
137 }
138
139 static void test_strbuf_overflow(void **state)
140 {
141         STRBUF_ON_STACK(buf);
142
143         assert_int_equal(append_strbuf_str(&buf, "x"), 1);
144         /* fake huge buffer */
145         buf.size = SIZE_MAX - 1;
146         buf.offs = buf.size - 1;
147         assert_int_equal(append_strbuf_str(&buf, "x"), -EOVERFLOW);
148 }
149
150 static void test_strbuf_big(void **state)
151 {
152         STRBUF_ON_STACK(buf);
153         const char big[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n";
154         char *bbig;
155         int i;
156
157         /* Under valgrind, 30000 iterations need ca. 30s on my laptop */
158         for (i = 0; i < 30000; i++) {
159                 if (i % 1000 == 0)
160                         condlog(4, "%d", i);
161                 assert_int_equal(append_strbuf_str(&buf, big), sizeof(big) - 1);
162                 assert_int_equal(get_strbuf_len(&buf), (sizeof(big) - 1) * (i + 1));
163                 assert_memory_equal(get_strbuf_str(&buf), big, sizeof(big) - 1);
164                 assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf)
165                                     - (sizeof(big) - 1), big);
166         };
167         bbig = steal_strbuf_str(&buf);
168
169         assert_ptr_equal(buf.buf, NULL);
170         assert_int_equal(buf.size, 0);
171         assert_int_equal(buf.offs, 0);
172         assert_int_equal(get_strbuf_len(&buf), 0);
173         assert_string_equal(get_strbuf_str(&buf), "");
174
175         assert_int_equal(strlen(bbig), i * (sizeof(big) - 1));
176         assert_memory_equal(bbig, big, sizeof(big) - 1);
177         free(bbig);
178 }
179
180 static void test_strbuf_nul(void **state)
181 {
182         STRBUF_ON_STACK(buf);
183         char greet[] = "hello, sir!";
184
185         assert_int_equal(__append_strbuf_str(&buf, greet, 6), 6);
186         assert_string_equal(get_strbuf_str(&buf), "hello,");
187         assert_int_equal(__append_strbuf_str(&buf, greet, 6), 6);
188         assert_string_equal(get_strbuf_str(&buf), "hello,hello,");
189
190         /* overwrite comma with NUL; append_strbuf_str() stops at NUL byte */
191         greet[5] = '\0';
192         reset_strbuf(&buf);
193         assert_int_equal(append_strbuf_str(&buf, greet), 5);
194         assert_int_equal(get_strbuf_len(&buf), 5);
195         assert_string_equal(get_strbuf_str(&buf), "hello");
196         assert_int_equal(append_strbuf_str(&buf, greet), 5);
197         assert_int_equal(get_strbuf_len(&buf), 10);
198         assert_string_equal(get_strbuf_str(&buf), "hellohello");
199
200         /* __append_strbuf_str() appends full memory, including NUL bytes */
201         reset_strbuf(&buf);
202         assert_int_equal(__append_strbuf_str(&buf, greet, sizeof(greet) - 1),
203                          sizeof(greet) - 1);
204         assert_int_equal(get_strbuf_len(&buf), sizeof(greet) - 1);
205         assert_string_equal(get_strbuf_str(&buf), "hello");
206         assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf) - 5, " sir!");
207         assert_int_equal(__append_strbuf_str(&buf, greet, sizeof(greet) - 1),
208                          sizeof(greet) - 1);
209         assert_string_equal(get_strbuf_str(&buf), "hello");
210         assert_int_equal(get_strbuf_len(&buf), 2 * (sizeof(greet) - 1));
211         assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf) - 5, " sir!");
212 }
213
214 static void test_strbuf_quoted(void **state)
215 {
216         STRBUF_ON_STACK(buf);
217         const char said[] = "She said ";
218         const char greet[] = "hi, man!";
219         char *p;
220         size_t n;
221
222         assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
223         assert_int_equal(append_strbuf_quoted(&buf, greet), sizeof(greet) + 1);
224         assert_string_equal(get_strbuf_str(&buf), "She said \"hi, man!\"");
225         n = get_strbuf_len(&buf);
226         p = steal_strbuf_str(&buf);
227         assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
228         assert_int_equal(append_strbuf_quoted(&buf, p), n + 4);
229         assert_string_equal(get_strbuf_str(&buf),
230                             "She said \"She said \"\"hi, man!\"\"\"");
231         free(p);
232         n = get_strbuf_len(&buf);
233         p = steal_strbuf_str(&buf);
234         assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
235         assert_int_equal(append_strbuf_quoted(&buf, p), n + 8);
236         assert_string_equal(get_strbuf_str(&buf),
237                             "She said \"She said \"\"She said \"\"\"\"hi, man!\"\"\"\"\"\"\"");
238         free(p);
239 }
240
241 static void test_strbuf_escaped(void **state)
242 {
243         STRBUF_ON_STACK(buf);
244         const char said[] = "She said \"hi, man\"";
245
246         assert_int_equal(append_strbuf_quoted(&buf, said), sizeof(said) + 3);
247         assert_string_equal(get_strbuf_str(&buf),
248                             "\"She said \"\"hi, man\"\"\"");
249
250         reset_strbuf(&buf);
251         assert_int_equal(append_strbuf_quoted(&buf, "\""), 4);
252         assert_string_equal(get_strbuf_str(&buf), "\"\"\"\"");
253
254         reset_strbuf(&buf);
255         assert_int_equal(append_strbuf_quoted(&buf, "\"\""), 6);
256         assert_string_equal(get_strbuf_str(&buf), "\"\"\"\"\"\"");
257
258         reset_strbuf(&buf);
259         assert_int_equal(append_strbuf_quoted(&buf, "\"Hi\""), 8);
260         assert_string_equal(get_strbuf_str(&buf), "\"\"\"Hi\"\"\"");
261 }
262
263 #define SENTENCE "yields, preceded by itself, falsehood"
264 static void test_print_strbuf(void **state)
265 {
266         STRBUF_ON_STACK(buf);
267         char sentence[] = SENTENCE;
268
269         assert_int_equal(print_strbuf(&buf, "\"%s\" %s.", sentence, sentence),
270                          2 * (sizeof(sentence) - 1) + 4);
271         assert_string_equal(get_strbuf_str(&buf),
272                             "\"" SENTENCE "\" " SENTENCE ".");
273         condlog(3, "%s", get_strbuf_str(&buf));
274
275         reset_strbuf(&buf);
276         assert_int_equal(print_strbuf(&buf, "0x%08x", 0xdeadbeef), 10);
277         assert_string_equal(get_strbuf_str(&buf), "0xdeadbeef");
278
279         reset_strbuf(&buf);
280         assert_int_equal(print_strbuf(&buf, "%d%% of %d is %0.2f",
281                                       5, 100, 0.05), 17);
282         assert_string_equal(get_strbuf_str(&buf), "5% of 100 is 0.05");
283 }
284
285 static void test_truncate_strbuf(void **state)
286 {
287         STRBUF_ON_STACK(buf);
288         const char str[] = "hello my dear!\n";
289         size_t sz, sz1;
290
291         assert_int_equal(truncate_strbuf(&buf, 1), -EFAULT);
292         assert_int_equal(truncate_strbuf(&buf, 0), -EFAULT);
293
294         assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
295         assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
296         assert_string_equal(get_strbuf_str(&buf), str);
297
298         assert_int_equal(truncate_strbuf(&buf, sizeof(str)), -ERANGE);
299         assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
300         assert_string_equal(get_strbuf_str(&buf), str);
301
302         assert_int_equal(truncate_strbuf(&buf, sizeof(str) - 1), 0);
303         assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
304         assert_string_equal(get_strbuf_str(&buf), str);
305
306         assert_int_equal(truncate_strbuf(&buf, sizeof(str) - 2), 0);
307         assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 2);
308         assert_string_not_equal(get_strbuf_str(&buf), str);
309         assert_memory_equal(get_strbuf_str(&buf), str, sizeof(str) - 2);
310
311         assert_int_equal(truncate_strbuf(&buf, 5), 0);
312         assert_int_equal(get_strbuf_len(&buf), 5);
313         assert_string_not_equal(get_strbuf_str(&buf), str);
314         assert_string_equal(get_strbuf_str(&buf), "hello");
315
316         reset_strbuf(&buf);
317         assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
318
319         sz = buf.size;
320         while (buf.size == sz)
321                 assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
322
323         sz1  = buf.size;
324         assert_in_range(get_strbuf_len(&buf), sz + 1, SIZE_MAX);
325         assert_string_equal(get_strbuf_str(&buf) +
326                             get_strbuf_len(&buf) - (sizeof(str) - 1), str);
327         assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf) + 1),
328                          -ERANGE);
329         assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf)), 0);
330         assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf)
331                                          - (sizeof(str) - 1)), 0);
332         assert_in_range(get_strbuf_len(&buf), 1, sz);
333         assert_string_equal(get_strbuf_str(&buf) +
334                             get_strbuf_len(&buf) - (sizeof(str) - 1), str);
335         assert_int_equal(buf.size, sz1);
336
337         assert_int_equal(truncate_strbuf(&buf, 5), 0);
338         assert_int_equal(get_strbuf_len(&buf), 5);
339         assert_string_equal(get_strbuf_str(&buf), "hello");
340         assert_int_equal(buf.size, sz1);
341
342         assert_int_equal(truncate_strbuf(&buf, 0), 0);
343         assert_int_equal(get_strbuf_len(&buf), 0);
344         assert_string_equal(get_strbuf_str(&buf), "");
345         assert_int_equal(buf.size, sz1);
346 }
347
348 static void test_fill_strbuf(void **state)
349 {
350         STRBUF_ON_STACK(buf);
351         int i;
352         char *p;
353
354         assert_int_equal(fill_strbuf(&buf, '+', -5), -EINVAL);
355
356         assert_int_equal(fill_strbuf(&buf, '+', 0), 0);
357         assert_int_equal(get_strbuf_len(&buf), 0);
358         assert_string_equal(get_strbuf_str(&buf), "");
359
360         assert_int_equal(fill_strbuf(&buf, '+', 1), 1);
361         assert_int_equal(get_strbuf_len(&buf), 1);
362         assert_string_equal(get_strbuf_str(&buf), "+");
363
364         assert_int_equal(fill_strbuf(&buf, '-', 3), 3);
365         assert_int_equal(get_strbuf_len(&buf), 4);
366         assert_string_equal(get_strbuf_str(&buf), "+---");
367
368         assert_int_equal(fill_strbuf(&buf, '\0', 3), 3);
369         assert_int_equal(get_strbuf_len(&buf), 7);
370         assert_string_equal(get_strbuf_str(&buf), "+---");
371
372         truncate_strbuf(&buf, 4);
373         assert_int_equal(fill_strbuf(&buf, '+', 4), 4);
374         assert_int_equal(get_strbuf_len(&buf), 8);
375         assert_string_equal(get_strbuf_str(&buf), "+---++++");
376
377         reset_strbuf(&buf);
378         assert_int_equal(fill_strbuf(&buf, 'x', 30000), 30000);
379         assert_int_equal(get_strbuf_len(&buf), 30000);
380         p = steal_strbuf_str(&buf);
381         assert_int_equal(strlen(p), 30000);
382         for (i = 0; i < 30000; i++)
383                 assert_int_equal(p[i], 'x');
384         free(p);
385 }
386
387 static int test_strbuf(void)
388 {
389         const struct CMUnitTest tests[] = {
390                 cmocka_unit_test(test_strbuf_00),
391                 cmocka_unit_test(test_strbuf_alloc_err),
392                 cmocka_unit_test(test_strbuf_overflow),
393                 cmocka_unit_test(test_strbuf_big),
394                 cmocka_unit_test(test_strbuf_nul),
395                 cmocka_unit_test(test_strbuf_quoted),
396                 cmocka_unit_test(test_strbuf_escaped),
397                 cmocka_unit_test(test_print_strbuf),
398                 cmocka_unit_test(test_truncate_strbuf),
399                 cmocka_unit_test(test_fill_strbuf),
400         };
401
402         return cmocka_run_group_tests(tests, NULL, NULL);
403 }
404
405 int main(void)
406 {
407         int ret = 0;
408
409         init_test_verbosity(-1);
410         ret += test_strbuf();
411         return ret;
412 }