chiark / gitweb /
machine: make sure unpriviliged "machinectl status" can show the machine's OS version
[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_join(void) {
117         _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL;
118
119         p = strv_join((char **)input_table_multiple, ", ");
120         assert_se(p);
121         assert_se(streq(p, "one, two, three"));
122
123         q = strv_join((char **)input_table_multiple, ";");
124         assert_se(q);
125         assert_se(streq(q, "one;two;three"));
126
127         r = strv_join((char **)input_table_multiple, NULL);
128         assert_se(r);
129         assert_se(streq(r, "one two three"));
130
131         s = strv_join((char **)input_table_one, ", ");
132         assert_se(s);
133         assert_se(streq(s, "one"));
134
135         t = strv_join((char **)input_table_none, ", ");
136         assert_se(t);
137         assert_se(streq(t, ""));
138 }
139
140 static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
141         _cleanup_free_ char *p;
142         _cleanup_strv_free_ char **s;
143         char **t;
144         int r;
145
146         p = strv_join_quoted((char **)split);
147         assert_se(p);
148         printf("-%s- --- -%s-\n", p, quoted); /* fprintf deals with NULL, puts does not */
149         assert_se(p);
150         assert_se(streq(p, quoted));
151
152         r = strv_split_quoted(&s, quoted);
153         assert_se(r == 0);
154         assert_se(s);
155         STRV_FOREACH(t, s) {
156                 assert_se(*t);
157                 assert_se(streq(*t, *split));
158                 split++;
159         }
160 }
161
162 static void test_strv_unquote(const char *quoted, const char **list) {
163         _cleanup_strv_free_ char **s;
164         _cleanup_free_ char *j;
165         unsigned i = 0;
166         char **t;
167         int r;
168
169         r = strv_split_quoted(&s, quoted);
170         assert_se(r == 0);
171         assert_se(s);
172         j = strv_join(s, " | ");
173         assert(j);
174         puts(j);
175
176         STRV_FOREACH(t, s)
177                 assert_se(streq(list[i++], *t));
178
179         assert_se(list[i] == NULL);
180 }
181
182 static void test_invalid_unquote(const char *quoted) {
183         char **s = NULL;
184         int r;
185
186         r = strv_split_quoted(&s, quoted);
187         assert(s == NULL);
188         assert(r == -EINVAL);
189 }
190
191 static void test_strv_split(void) {
192         char **s;
193         unsigned i = 0;
194         _cleanup_strv_free_ char **l = NULL;
195         const char str[] = "one,two,three";
196
197         l = strv_split(str, ",");
198
199         assert(l);
200
201         STRV_FOREACH(s, l) {
202                 assert_se(streq(*s, input_table_multiple[i++]));
203         }
204 }
205
206 static void test_strv_split_newlines(void) {
207         unsigned i = 0;
208         char **s;
209         _cleanup_strv_free_ char **l = NULL;
210         const char str[] = "one\ntwo\nthree";
211
212         l = strv_split_newlines(str);
213
214         assert(l);
215
216         STRV_FOREACH(s, l) {
217                 assert_se(streq(*s, input_table_multiple[i++]));
218         }
219 }
220
221 static void test_strv_split_nulstr(void) {
222         _cleanup_strv_free_ char **l = NULL;
223         const char nulstr[] = "str0\0str1\0str2\0str3\0";
224
225         l = strv_split_nulstr (nulstr);
226         assert_se(l);
227
228         assert_se(streq(l[0], "str0"));
229         assert_se(streq(l[1], "str1"));
230         assert_se(streq(l[2], "str2"));
231         assert_se(streq(l[3], "str3"));
232 }
233
234 static void test_strv_parse_nulstr(void) {
235         _cleanup_strv_free_ char **l = NULL;
236         const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
237
238         l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
239         assert_se(l);
240         puts("Parse nulstr:");
241         strv_print(l);
242
243         assert_se(streq(l[0], "fuck"));
244         assert_se(streq(l[1], "fuck2"));
245         assert_se(streq(l[2], "fuck3"));
246         assert_se(streq(l[3], ""));
247         assert_se(streq(l[4], "fuck5"));
248         assert_se(streq(l[5], ""));
249         assert_se(streq(l[6], "xxx"));
250 }
251
252 static void test_strv_overlap(void) {
253         const char * const input_table[] = {
254                 "one",
255                 "two",
256                 "three",
257                 NULL
258         };
259         const char * const input_table_overlap[] = {
260                 "two",
261                 NULL
262         };
263         const char * const input_table_unique[] = {
264                 "four",
265                 "five",
266                 "six",
267                 NULL
268         };
269
270         assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap));
271         assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique));
272 }
273
274 static void test_strv_sort(void) {
275         const char* input_table[] = {
276                 "durian",
277                 "apple",
278                 "citrus",
279                  "CAPITAL LETTERS FIRST",
280                 "banana",
281                 NULL
282         };
283
284         strv_sort((char **)input_table);
285
286         assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST"));
287         assert_se(streq(input_table[1], "apple"));
288         assert_se(streq(input_table[2], "banana"));
289         assert_se(streq(input_table[3], "citrus"));
290         assert_se(streq(input_table[4], "durian"));
291 }
292
293 static void test_strv_extend_strv_concat(void) {
294          _cleanup_strv_free_ char **a = NULL, **b = NULL;
295
296         a = strv_new("without", "suffix", NULL);
297         b = strv_new("with", "suffix", NULL);
298         assert_se(a);
299         assert_se(b);
300
301         assert_se(strv_extend_strv_concat(&a, b, "_suffix") >= 0);
302
303         assert_se(streq(a[0], "without"));
304         assert_se(streq(a[1], "suffix"));
305         assert_se(streq(a[2], "with_suffix"));
306         assert_se(streq(a[3], "suffix_suffix"));
307 }
308
309 static void test_strv_extend_strv(void) {
310          _cleanup_strv_free_ char **a = NULL, **b = NULL;
311
312         a = strv_new("abc", "def", "ghi", NULL);
313         b = strv_new("jkl", "mno", "pqr", NULL);
314         assert_se(a);
315         assert_se(b);
316
317         assert_se(strv_extend_strv(&a, b) >= 0);
318
319         assert_se(streq(a[0], "abc"));
320         assert_se(streq(a[1], "def"));
321         assert_se(streq(a[2], "ghi"));
322         assert_se(streq(a[3], "jkl"));
323         assert_se(streq(a[4], "mno"));
324         assert_se(streq(a[5], "pqr"));
325
326         assert_se(strv_length(a) == 6);
327 }
328
329 static void test_strv_extend(void) {
330         _cleanup_strv_free_ char **a = NULL, **b = NULL;
331
332         a = strv_new("test", "test1", NULL);
333         assert_se(a);
334         assert_se(strv_extend(&a, "test2") >= 0);
335         assert_se(strv_extend(&b, "test3") >= 0);
336
337         assert_se(streq(a[0], "test"));
338         assert_se(streq(a[1], "test1"));
339         assert_se(streq(a[2], "test2"));
340         assert_se(streq(b[0], "test3"));
341 }
342
343 static void test_strv_extendf(void) {
344         _cleanup_strv_free_ char **a = NULL, **b = NULL;
345
346         a = strv_new("test", "test1", NULL);
347         assert_se(a);
348         assert_se(strv_extendf(&a, "test2 %s %d %s", "foo", 128, "bar") >= 0);
349         assert_se(strv_extendf(&b, "test3 %s %s %d", "bar", "foo", 128) >= 0);
350
351         assert_se(streq(a[0], "test"));
352         assert_se(streq(a[1], "test1"));
353         assert_se(streq(a[2], "test2 foo 128 bar"));
354         assert_se(streq(b[0], "test3 bar foo 128"));
355 }
356
357 static void test_strv_foreach(void) {
358         _cleanup_strv_free_ char **a;
359         unsigned i = 0;
360         char **check;
361
362         a = strv_new("one", "two", "three", NULL);
363
364         assert_se(a);
365
366         STRV_FOREACH(check, a) {
367                 assert_se(streq(*check, input_table_multiple[i++]));
368         }
369 }
370
371 static void test_strv_foreach_backwards(void) {
372         _cleanup_strv_free_ char **a;
373         unsigned i = 2;
374         char **check;
375
376         a = strv_new("one", "two", "three", NULL);
377
378         assert_se(a);
379
380         STRV_FOREACH_BACKWARDS(check, a) {
381                 assert_se(streq_ptr(*check, input_table_multiple[i--]));
382         }
383 }
384
385 static void test_strv_foreach_pair(void) {
386         _cleanup_strv_free_ char **a = NULL;
387         char **x, **y;
388
389         a = strv_new("pair_one",   "pair_one",
390                      "pair_two",   "pair_two",
391                      "pair_three", "pair_three",
392                      NULL);
393
394         STRV_FOREACH_PAIR(x, y, a) {
395                 assert_se(streq(*x, *y));
396         }
397 }
398
399 static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) {
400         char **j;
401         unsigned i;
402
403         j = strv_from_stdarg_alloca(first);
404
405         for (i = 0;; i++) {
406                 assert_se(streq_ptr(l[i], j[i]));
407
408                 if (!l[i])
409                         break;
410         }
411 }
412
413 static void test_strv_from_stdarg_alloca(void) {
414         test_strv_from_stdarg_alloca_one(STRV_MAKE("foo", "bar"), "foo", "bar", NULL);
415         test_strv_from_stdarg_alloca_one(STRV_MAKE("foo"), "foo", NULL);
416         test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL);
417 }
418
419 int main(int argc, char *argv[]) {
420         test_specifier_printf();
421         test_strv_foreach();
422         test_strv_foreach_backwards();
423         test_strv_foreach_pair();
424         test_strv_find();
425         test_strv_find_prefix();
426         test_strv_join();
427
428         test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\"");
429         test_strv_quote_unquote(input_table_one, "\"one\"");
430         test_strv_quote_unquote(input_table_none, "");
431         test_strv_quote_unquote(input_table_quotes, QUOTES_STRING);
432         test_strv_quote_unquote(input_table_spaces, SPACES_STRING);
433
434         test_strv_unquote("    foo=bar     \"waldo\"    zzz    ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL });
435         test_strv_unquote("", (const char*[]) { NULL });
436         test_strv_unquote(" ", (const char*[]) { NULL });
437         test_strv_unquote("   ", (const char*[]) { NULL });
438         test_strv_unquote("   x", (const char*[]) { "x", NULL });
439         test_strv_unquote("x   ", (const char*[]) { "x", NULL });
440         test_strv_unquote("  x   ", (const char*[]) { "x", NULL });
441         test_strv_unquote("  \"x\"   ", (const char*[]) { "x", NULL });
442         test_strv_unquote("  'x'   ", (const char*[]) { "x", NULL });
443         test_strv_unquote("  'x\"'   ", (const char*[]) { "x\"", NULL });
444         test_strv_unquote("  \"x'\"   ", (const char*[]) { "x'", NULL });
445         test_strv_unquote("a  '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL });
446
447         test_invalid_unquote("a  --b='c \"d e\"'");
448         test_invalid_unquote("a  --b='c \"d e\" '");
449         test_invalid_unquote("a  --b='c \"d e\"garbage");
450         test_invalid_unquote("'");
451         test_invalid_unquote("\"");
452         test_invalid_unquote("'x'y");
453
454         test_strv_split();
455         test_strv_split_newlines();
456         test_strv_split_nulstr();
457         test_strv_parse_nulstr();
458         test_strv_overlap();
459         test_strv_sort();
460         test_strv_extend_strv();
461         test_strv_extend_strv_concat();
462         test_strv_extend();
463         test_strv_extendf();
464         test_strv_from_stdarg_alloca();
465
466         return 0;
467 }