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