chiark / gitweb /
180f062390e3bb3b464e7216e8250d37f9610af2
[elogind.git] / src / test / test-strv.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2013 Thomas H.P. Andersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <string.h>
24
25 #include "util.h"
26 #include "specifier.h"
27 #include "strv.h"
28
29 static void test_specifier_printf(void) {
30         static const Specifier table[] = {
31                 { 'a', specifier_string, (char*) "AAAA" },
32                 { 'b', specifier_string, (char*) "BBBB" },
33                 { 'm', specifier_machine_id, NULL },
34                 { 'B', specifier_boot_id, NULL },
35                 { 'H', specifier_host_name, NULL },
36                 { 'v', specifier_kernel_release, NULL },
37                 {}
38         };
39
40         _cleanup_free_ char *w = NULL;
41         int r;
42
43         r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w);
44         assert_se(r >= 0);
45         assert_se(w);
46
47         puts(w);
48         assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
49
50         free(w);
51         r = specifier_printf("machine=%m, boot=%B, host=%H, version=%v", table, NULL, &w);
52         assert_se(r >= 0);
53         assert_se(w);
54         puts(w);
55 }
56
57 static const char* const input_table_multiple[] = {
58         "one",
59         "two",
60         "three",
61         NULL,
62 };
63
64 static const char* const input_table_one[] = {
65         "one",
66         NULL,
67 };
68
69 static const char* const input_table_none[] = {
70         NULL,
71 };
72
73 static const char* const input_table_quotes[] = {
74         "\"",
75         "'",
76         "\"\"",
77         "\\",
78         "\\\\",
79         NULL,
80 };
81 #define QUOTES_STRING                            \
82         "\"\\\"\" "                              \
83         "\"\\\'\" "                              \
84         "\"\\\"\\\"\" "                          \
85         "\"\\\\\" "                              \
86         "\"\\\\\\\\\""
87
88 static const char * const input_table_spaces[] = {
89         " ",
90         "' '",
91         "\" ",
92         " \"",
93         " \\\\ ",
94         NULL,
95 };
96 #define SPACES_STRING                           \
97         "\" \" "                                \
98         "\"\\' \\'\" "                          \
99         "\"\\\" \" "                            \
100         "\" \\\"\" "                            \
101         "\" \\\\\\\\ \""
102
103 static void test_strv_find(void) {
104         assert_se(strv_find((char **)input_table_multiple, "three"));
105         assert_se(!strv_find((char **)input_table_multiple, "four"));
106 }
107
108 static void test_strv_find_prefix(void) {
109         assert_se(strv_find_prefix((char **)input_table_multiple, "o"));
110         assert_se(strv_find_prefix((char **)input_table_multiple, "one"));
111         assert_se(strv_find_prefix((char **)input_table_multiple, ""));
112         assert_se(!strv_find_prefix((char **)input_table_multiple, "xxx"));
113         assert_se(!strv_find_prefix((char **)input_table_multiple, "onee"));
114 }
115
116 static void test_strv_find_startswith(void) {
117         char *r;
118
119         r = strv_find_startswith((char **)input_table_multiple, "o");
120         assert_se(r && streq(r, "ne"));
121
122         r = strv_find_startswith((char **)input_table_multiple, "one");
123         assert_se(r && streq(r, ""));
124
125         r = strv_find_startswith((char **)input_table_multiple, "");
126         assert_se(r && streq(r, "one"));
127
128         assert_se(!strv_find_startswith((char **)input_table_multiple, "xxx"));
129         assert_se(!strv_find_startswith((char **)input_table_multiple, "onee"));
130 }
131
132 static void test_strv_join(void) {
133         _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL;
134
135         p = strv_join((char **)input_table_multiple, ", ");
136         assert_se(p);
137         assert_se(streq(p, "one, two, three"));
138
139         q = strv_join((char **)input_table_multiple, ";");
140         assert_se(q);
141         assert_se(streq(q, "one;two;three"));
142
143         r = strv_join((char **)input_table_multiple, NULL);
144         assert_se(r);
145         assert_se(streq(r, "one two three"));
146
147         s = strv_join((char **)input_table_one, ", ");
148         assert_se(s);
149         assert_se(streq(s, "one"));
150
151         t = strv_join((char **)input_table_none, ", ");
152         assert_se(t);
153         assert_se(streq(t, ""));
154 }
155
156 static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
157         _cleanup_free_ char *p;
158         _cleanup_strv_free_ char **s;
159         char **t;
160         int r;
161
162         p = strv_join_quoted((char **)split);
163         assert_se(p);
164         printf("-%s- --- -%s-\n", p, quoted); /* fprintf deals with NULL, puts does not */
165         assert_se(p);
166         assert_se(streq(p, quoted));
167
168         r = strv_split_quoted(&s, quoted, false);
169         assert_se(r == 0);
170         assert_se(s);
171         STRV_FOREACH(t, s) {
172                 assert_se(*t);
173                 assert_se(streq(*t, *split));
174                 split++;
175         }
176 }
177
178 static void test_strv_unquote(const char *quoted, const char **list) {
179         _cleanup_strv_free_ char **s;
180         _cleanup_free_ char *j;
181         unsigned i = 0;
182         char **t;
183         int r;
184
185         r = strv_split_quoted(&s, quoted, false);
186         assert_se(r == 0);
187         assert_se(s);
188         j = strv_join(s, " | ");
189         assert_se(j);
190         puts(j);
191
192         STRV_FOREACH(t, s)
193                 assert_se(streq(list[i++], *t));
194
195         assert_se(list[i] == NULL);
196 }
197
198 static void test_invalid_unquote(const char *quoted) {
199         char **s = NULL;
200         int r;
201
202         r = strv_split_quoted(&s, quoted, false);
203         assert_se(s == NULL);
204         assert_se(r == -EINVAL);
205 }
206
207 static void test_strv_split(void) {
208         char **s;
209         unsigned i = 0;
210         _cleanup_strv_free_ char **l = NULL;
211         const char str[] = "one,two,three";
212
213         l = strv_split(str, ",");
214
215         assert_se(l);
216
217         STRV_FOREACH(s, l) {
218                 assert_se(streq(*s, input_table_multiple[i++]));
219         }
220 }
221
222 static void test_strv_split_newlines(void) {
223         unsigned i = 0;
224         char **s;
225         _cleanup_strv_free_ char **l = NULL;
226         const char str[] = "one\ntwo\nthree";
227
228         l = strv_split_newlines(str);
229
230         assert_se(l);
231
232         STRV_FOREACH(s, l) {
233                 assert_se(streq(*s, input_table_multiple[i++]));
234         }
235 }
236
237 static void test_strv_split_nulstr(void) {
238         _cleanup_strv_free_ char **l = NULL;
239         const char nulstr[] = "str0\0str1\0str2\0str3\0";
240
241         l = strv_split_nulstr (nulstr);
242         assert_se(l);
243
244         assert_se(streq(l[0], "str0"));
245         assert_se(streq(l[1], "str1"));
246         assert_se(streq(l[2], "str2"));
247         assert_se(streq(l[3], "str3"));
248 }
249
250 static void test_strv_parse_nulstr(void) {
251         _cleanup_strv_free_ char **l = NULL;
252         const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
253
254         l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
255         assert_se(l);
256         puts("Parse nulstr:");
257         strv_print(l);
258
259         assert_se(streq(l[0], "fuck"));
260         assert_se(streq(l[1], "fuck2"));
261         assert_se(streq(l[2], "fuck3"));
262         assert_se(streq(l[3], ""));
263         assert_se(streq(l[4], "fuck5"));
264         assert_se(streq(l[5], ""));
265         assert_se(streq(l[6], "xxx"));
266 }
267
268 static void test_strv_overlap(void) {
269         const char * const input_table[] = {
270                 "one",
271                 "two",
272                 "three",
273                 NULL
274         };
275         const char * const input_table_overlap[] = {
276                 "two",
277                 NULL
278         };
279         const char * const input_table_unique[] = {
280                 "four",
281                 "five",
282                 "six",
283                 NULL
284         };
285
286         assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap));
287         assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique));
288 }
289
290 static void test_strv_sort(void) {
291         const char* input_table[] = {
292                 "durian",
293                 "apple",
294                 "citrus",
295                  "CAPITAL LETTERS FIRST",
296                 "banana",
297                 NULL
298         };
299
300         strv_sort((char **)input_table);
301
302         assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST"));
303         assert_se(streq(input_table[1], "apple"));
304         assert_se(streq(input_table[2], "banana"));
305         assert_se(streq(input_table[3], "citrus"));
306         assert_se(streq(input_table[4], "durian"));
307 }
308
309 static void test_strv_extend_strv_concat(void) {
310          _cleanup_strv_free_ char **a = NULL, **b = NULL;
311
312         a = strv_new("without", "suffix", NULL);
313         b = strv_new("with", "suffix", NULL);
314         assert_se(a);
315         assert_se(b);
316
317         assert_se(strv_extend_strv_concat(&a, b, "_suffix") >= 0);
318
319         assert_se(streq(a[0], "without"));
320         assert_se(streq(a[1], "suffix"));
321         assert_se(streq(a[2], "with_suffix"));
322         assert_se(streq(a[3], "suffix_suffix"));
323 }
324
325 static void test_strv_extend_strv(void) {
326          _cleanup_strv_free_ char **a = NULL, **b = NULL;
327
328         a = strv_new("abc", "def", "ghi", NULL);
329         b = strv_new("jkl", "mno", "pqr", NULL);
330         assert_se(a);
331         assert_se(b);
332
333         assert_se(strv_extend_strv(&a, b) >= 0);
334
335         assert_se(streq(a[0], "abc"));
336         assert_se(streq(a[1], "def"));
337         assert_se(streq(a[2], "ghi"));
338         assert_se(streq(a[3], "jkl"));
339         assert_se(streq(a[4], "mno"));
340         assert_se(streq(a[5], "pqr"));
341
342         assert_se(strv_length(a) == 6);
343 }
344
345 static void test_strv_extend(void) {
346         _cleanup_strv_free_ char **a = NULL, **b = NULL;
347
348         a = strv_new("test", "test1", NULL);
349         assert_se(a);
350         assert_se(strv_extend(&a, "test2") >= 0);
351         assert_se(strv_extend(&b, "test3") >= 0);
352
353         assert_se(streq(a[0], "test"));
354         assert_se(streq(a[1], "test1"));
355         assert_se(streq(a[2], "test2"));
356         assert_se(streq(b[0], "test3"));
357 }
358
359 static void test_strv_extendf(void) {
360         _cleanup_strv_free_ char **a = NULL, **b = NULL;
361
362         a = strv_new("test", "test1", NULL);
363         assert_se(a);
364         assert_se(strv_extendf(&a, "test2 %s %d %s", "foo", 128, "bar") >= 0);
365         assert_se(strv_extendf(&b, "test3 %s %s %d", "bar", "foo", 128) >= 0);
366
367         assert_se(streq(a[0], "test"));
368         assert_se(streq(a[1], "test1"));
369         assert_se(streq(a[2], "test2 foo 128 bar"));
370         assert_se(streq(b[0], "test3 bar foo 128"));
371 }
372
373 static void test_strv_foreach(void) {
374         _cleanup_strv_free_ char **a;
375         unsigned i = 0;
376         char **check;
377
378         a = strv_new("one", "two", "three", NULL);
379
380         assert_se(a);
381
382         STRV_FOREACH(check, a) {
383                 assert_se(streq(*check, input_table_multiple[i++]));
384         }
385 }
386
387 static void test_strv_foreach_backwards(void) {
388         _cleanup_strv_free_ char **a;
389         unsigned i = 2;
390         char **check;
391
392         a = strv_new("one", "two", "three", NULL);
393
394         assert_se(a);
395
396         STRV_FOREACH_BACKWARDS(check, a) {
397                 assert_se(streq_ptr(*check, input_table_multiple[i--]));
398         }
399 }
400
401 static void test_strv_foreach_pair(void) {
402         _cleanup_strv_free_ char **a = NULL;
403         char **x, **y;
404
405         a = strv_new("pair_one",   "pair_one",
406                      "pair_two",   "pair_two",
407                      "pair_three", "pair_three",
408                      NULL);
409
410         STRV_FOREACH_PAIR(x, y, a) {
411                 assert_se(streq(*x, *y));
412         }
413 }
414
415 static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) {
416         char **j;
417         unsigned i;
418
419         j = strv_from_stdarg_alloca(first);
420
421         for (i = 0;; i++) {
422                 assert_se(streq_ptr(l[i], j[i]));
423
424                 if (!l[i])
425                         break;
426         }
427 }
428
429 static void test_strv_from_stdarg_alloca(void) {
430         test_strv_from_stdarg_alloca_one(STRV_MAKE("foo", "bar"), "foo", "bar", NULL);
431         test_strv_from_stdarg_alloca_one(STRV_MAKE("foo"), "foo", NULL);
432         test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL);
433 }
434
435 static void test_strv_push_prepend(void) {
436         _cleanup_strv_free_ char **a = NULL;
437
438         a = strv_new("foo", "bar", "three", NULL);
439
440         assert_se(strv_push_prepend(&a, strdup("first")) >= 0);
441         assert_se(streq(a[0], "first"));
442         assert_se(streq(a[1], "foo"));
443         assert_se(streq(a[2], "bar"));
444         assert_se(streq(a[3], "three"));
445         assert_se(!a[4]);
446
447         assert_se(strv_consume_prepend(&a, strdup("first2")) >= 0);
448         assert_se(streq(a[0], "first2"));
449         assert_se(streq(a[1], "first"));
450         assert_se(streq(a[2], "foo"));
451         assert_se(streq(a[3], "bar"));
452         assert_se(streq(a[4], "three"));
453         assert_se(!a[5]);
454 }
455
456 int main(int argc, char *argv[]) {
457         test_specifier_printf();
458         test_strv_foreach();
459         test_strv_foreach_backwards();
460         test_strv_foreach_pair();
461         test_strv_find();
462         test_strv_find_prefix();
463         test_strv_find_startswith();
464         test_strv_join();
465
466         test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\"");
467         test_strv_quote_unquote(input_table_one, "\"one\"");
468         test_strv_quote_unquote(input_table_none, "");
469         test_strv_quote_unquote(input_table_quotes, QUOTES_STRING);
470         test_strv_quote_unquote(input_table_spaces, SPACES_STRING);
471
472         test_strv_unquote("    foo=bar     \"waldo\"    zzz    ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL });
473         test_strv_unquote("", (const char*[]) { NULL });
474         test_strv_unquote(" ", (const char*[]) { NULL });
475         test_strv_unquote("   ", (const char*[]) { NULL });
476         test_strv_unquote("   x", (const char*[]) { "x", NULL });
477         test_strv_unquote("x   ", (const char*[]) { "x", NULL });
478         test_strv_unquote("  x   ", (const char*[]) { "x", NULL });
479         test_strv_unquote("  \"x\"   ", (const char*[]) { "x", NULL });
480         test_strv_unquote("  'x'   ", (const char*[]) { "x", NULL });
481         test_strv_unquote("  'x\"'   ", (const char*[]) { "x\"", NULL });
482         test_strv_unquote("  \"x'\"   ", (const char*[]) { "x'", NULL });
483         test_strv_unquote("a  '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL });
484
485         test_invalid_unquote("a  --b='c \"d e\"''");
486         test_invalid_unquote("a  --b='c \"d e\" '\"");
487         test_invalid_unquote("a  --b='c \"d e\"garbage");
488         test_invalid_unquote("'");
489         test_invalid_unquote("\"");
490         test_invalid_unquote("'x'y'g");
491
492         test_strv_split();
493         test_strv_split_newlines();
494         test_strv_split_nulstr();
495         test_strv_parse_nulstr();
496         test_strv_overlap();
497         test_strv_sort();
498         test_strv_extend_strv();
499         test_strv_extend_strv_concat();
500         test_strv_extend();
501         test_strv_extendf();
502         test_strv_from_stdarg_alloca();
503         test_strv_push_prepend();
504
505         return 0;
506 }