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