Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <string.h>
4 :
5 : #include "alloc-util.h"
6 : #include "escape.h"
7 : #include "nulstr-util.h"
8 : #include "specifier.h"
9 : #include "string-util.h"
10 : #include "strv.h"
11 :
12 1 : static void test_specifier_printf(void) {
13 : static const Specifier table[] = {
14 : { 'a', specifier_string, (char*) "AAAA" },
15 : { 'b', specifier_string, (char*) "BBBB" },
16 : { 'm', specifier_machine_id, NULL },
17 : { 'B', specifier_boot_id, NULL },
18 : { 'H', specifier_host_name, NULL },
19 : { 'v', specifier_kernel_release, NULL },
20 : {}
21 : };
22 :
23 1 : _cleanup_free_ char *w = NULL;
24 : int r;
25 :
26 1 : log_info("/* %s */", __func__);
27 :
28 1 : r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w);
29 1 : assert_se(r >= 0);
30 1 : assert_se(w);
31 :
32 1 : puts(w);
33 1 : assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
34 :
35 1 : free(w);
36 1 : r = specifier_printf("machine=%m, boot=%B, host=%H, version=%v", table, NULL, &w);
37 1 : assert_se(r >= 0);
38 1 : assert_se(w);
39 1 : puts(w);
40 1 : }
41 :
42 1 : static void test_str_in_set(void) {
43 1 : log_info("/* %s */", __func__);
44 :
45 1 : assert_se(STR_IN_SET("x", "x", "y", "z"));
46 1 : assert_se(!STR_IN_SET("X", "x", "y", "z"));
47 1 : assert_se(!STR_IN_SET("", "x", "y", "z"));
48 1 : assert_se(STR_IN_SET("x", "w", "x"));
49 1 : }
50 :
51 1 : static void test_strptr_in_set(void) {
52 1 : log_info("/* %s */", __func__);
53 :
54 1 : assert_se(STRPTR_IN_SET("x", "x", "y", "z"));
55 1 : assert_se(!STRPTR_IN_SET("X", "x", "y", "z"));
56 1 : assert_se(!STRPTR_IN_SET("", "x", "y", "z"));
57 1 : assert_se(STRPTR_IN_SET("x", "w", "x"));
58 :
59 1 : assert_se(!STRPTR_IN_SET(NULL, "x", "y", "z"));
60 1 : assert_se(!STRPTR_IN_SET(NULL, ""));
61 : /* strv cannot contain a null, hence the result below */
62 1 : assert_se(!STRPTR_IN_SET(NULL, NULL));
63 1 : }
64 :
65 1 : static void test_startswith_set(void) {
66 1 : log_info("/* %s */", __func__);
67 :
68 4 : assert_se(!STARTSWITH_SET("foo", "bar", "baz", "waldo"));
69 2 : assert_se(!STARTSWITH_SET("foo", "bar"));
70 :
71 1 : assert_se(STARTSWITH_SET("abc", "a", "ab", "abc"));
72 2 : assert_se(STARTSWITH_SET("abc", "ax", "ab", "abc"));
73 3 : assert_se(STARTSWITH_SET("abc", "ax", "abx", "abc"));
74 4 : assert_se(!STARTSWITH_SET("abc", "ax", "abx", "abcx"));
75 :
76 3 : assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "foo", "zzz"), "bar"));
77 3 : assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "", "zzz"), "foobar"));
78 4 : assert_se(streq_ptr(STARTSWITH_SET("", "hhh", "kkk", "zzz", ""), ""));
79 1 : }
80 :
81 : static const char* const input_table_multiple[] = {
82 : "one",
83 : "two",
84 : "three",
85 : NULL,
86 : };
87 :
88 : static const char* const input_table_quoted[] = {
89 : "one",
90 : " two\t three ",
91 : " four five",
92 : NULL,
93 : };
94 :
95 : static const char* const input_table_one[] = {
96 : "one",
97 : NULL,
98 : };
99 :
100 : static const char* const input_table_none[] = {
101 : NULL,
102 : };
103 :
104 : static const char* const input_table_two_empties[] = {
105 : "",
106 : "",
107 : NULL,
108 : };
109 :
110 : static const char* const input_table_one_empty[] = {
111 : "",
112 : NULL,
113 : };
114 :
115 1 : static void test_strv_find(void) {
116 1 : log_info("/* %s */", __func__);
117 :
118 1 : assert_se(strv_find((char **)input_table_multiple, "three"));
119 1 : assert_se(!strv_find((char **)input_table_multiple, "four"));
120 1 : }
121 :
122 1 : static void test_strv_find_prefix(void) {
123 1 : log_info("/* %s */", __func__);
124 :
125 1 : assert_se(strv_find_prefix((char **)input_table_multiple, "o"));
126 1 : assert_se(strv_find_prefix((char **)input_table_multiple, "one"));
127 1 : assert_se(strv_find_prefix((char **)input_table_multiple, ""));
128 1 : assert_se(!strv_find_prefix((char **)input_table_multiple, "xxx"));
129 1 : assert_se(!strv_find_prefix((char **)input_table_multiple, "onee"));
130 1 : }
131 :
132 1 : static void test_strv_find_startswith(void) {
133 : char *r;
134 :
135 1 : log_info("/* %s */", __func__);
136 :
137 1 : r = strv_find_startswith((char **)input_table_multiple, "o");
138 1 : assert_se(r && streq(r, "ne"));
139 :
140 1 : r = strv_find_startswith((char **)input_table_multiple, "one");
141 1 : assert_se(r && streq(r, ""));
142 :
143 1 : r = strv_find_startswith((char **)input_table_multiple, "");
144 1 : assert_se(r && streq(r, "one"));
145 :
146 1 : assert_se(!strv_find_startswith((char **)input_table_multiple, "xxx"));
147 1 : assert_se(!strv_find_startswith((char **)input_table_multiple, "onee"));
148 1 : }
149 :
150 1 : static void test_strv_join(void) {
151 1 : _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
152 :
153 1 : log_info("/* %s */", __func__);
154 :
155 1 : p = strv_join((char **)input_table_multiple, ", ");
156 1 : assert_se(p);
157 1 : assert_se(streq(p, "one, two, three"));
158 :
159 1 : q = strv_join((char **)input_table_multiple, ";");
160 1 : assert_se(q);
161 1 : assert_se(streq(q, "one;two;three"));
162 :
163 1 : r = strv_join((char **)input_table_multiple, NULL);
164 1 : assert_se(r);
165 1 : assert_se(streq(r, "one two three"));
166 :
167 1 : s = strv_join((char **)input_table_one, ", ");
168 1 : assert_se(s);
169 1 : assert_se(streq(s, "one"));
170 :
171 1 : t = strv_join((char **)input_table_none, ", ");
172 1 : assert_se(t);
173 1 : assert_se(streq(t, ""));
174 :
175 1 : v = strv_join((char **)input_table_two_empties, ", ");
176 1 : assert_se(v);
177 1 : assert_se(streq(v, ", "));
178 :
179 1 : w = strv_join((char **)input_table_one_empty, ", ");
180 1 : assert_se(w);
181 1 : assert_se(streq(w, ""));
182 1 : }
183 :
184 1 : static void test_strv_join_prefix(void) {
185 1 : _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
186 :
187 1 : log_info("/* %s */", __func__);
188 :
189 1 : p = strv_join_prefix((char **)input_table_multiple, ", ", "foo");
190 1 : assert_se(p);
191 1 : assert_se(streq(p, "fooone, footwo, foothree"));
192 :
193 1 : q = strv_join_prefix((char **)input_table_multiple, ";", "foo");
194 1 : assert_se(q);
195 1 : assert_se(streq(q, "fooone;footwo;foothree"));
196 :
197 1 : r = strv_join_prefix((char **)input_table_multiple, NULL, "foo");
198 1 : assert_se(r);
199 1 : assert_se(streq(r, "fooone footwo foothree"));
200 :
201 1 : s = strv_join_prefix((char **)input_table_one, ", ", "foo");
202 1 : assert_se(s);
203 1 : assert_se(streq(s, "fooone"));
204 :
205 1 : t = strv_join_prefix((char **)input_table_none, ", ", "foo");
206 1 : assert_se(t);
207 1 : assert_se(streq(t, ""));
208 :
209 1 : v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo");
210 1 : assert_se(v);
211 1 : assert_se(streq(v, "foo, foo"));
212 :
213 1 : w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo");
214 1 : assert_se(w);
215 1 : assert_se(streq(w, "foo"));
216 1 : }
217 :
218 13 : static void test_strv_unquote(const char *quoted, char **list) {
219 13 : _cleanup_strv_free_ char **s;
220 13 : _cleanup_free_ char *j;
221 13 : unsigned i = 0;
222 : char **t;
223 : int r;
224 :
225 13 : log_info("/* %s */", __func__);
226 :
227 13 : r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE);
228 13 : assert_se(r == (int) strv_length(list));
229 13 : assert_se(s);
230 13 : j = strv_join(s, " | ");
231 13 : assert_se(j);
232 13 : puts(j);
233 :
234 26 : STRV_FOREACH(t, s)
235 13 : assert_se(streq(list[i++], *t));
236 :
237 13 : assert_se(list[i] == NULL);
238 13 : }
239 :
240 7 : static void test_invalid_unquote(const char *quoted) {
241 7 : char **s = NULL;
242 : int r;
243 :
244 7 : log_info("/* %s */", __func__);
245 :
246 7 : r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_UNQUOTE);
247 7 : assert_se(s == NULL);
248 7 : assert_se(r == -EINVAL);
249 7 : }
250 :
251 1 : static void test_strv_split(void) {
252 1 : _cleanup_(strv_free_erasep) char **l = NULL;
253 1 : const char str[] = "one,two,three";
254 :
255 1 : log_info("/* %s */", __func__);
256 :
257 1 : l = strv_split(str, ",");
258 1 : assert_se(l);
259 1 : assert_se(strv_equal(l, (char**) input_table_multiple));
260 :
261 1 : strv_free_erase(l);
262 :
263 1 : l = strv_split(" one two\t three", WHITESPACE);
264 1 : assert_se(l);
265 1 : assert_se(strv_equal(l, (char**) input_table_multiple));
266 :
267 1 : strv_free_erase(l);
268 :
269 : /* Setting NULL for separator is equivalent to WHITESPACE */
270 1 : l = strv_split(" one two\t three", NULL);
271 1 : assert_se(l);
272 1 : assert_se(strv_equal(l, (char**) input_table_multiple));
273 :
274 1 : strv_free_erase(l);
275 :
276 1 : l = strv_split_full(" one two\t three", NULL, 0);
277 1 : assert_se(l);
278 1 : assert_se(strv_equal(l, (char**) input_table_multiple));
279 :
280 1 : strv_free_erase(l);
281 :
282 1 : l = strv_split_full(" 'one' \" two\t three \" ' four five'", NULL, SPLIT_QUOTES);
283 1 : assert_se(l);
284 1 : assert_se(strv_equal(l, (char**) input_table_quoted));
285 :
286 1 : strv_free_erase(l);
287 :
288 : /* missing last quote ignores the last element. */
289 1 : l = strv_split_full(" 'one' \" two\t three \" ' four five' ' ignored element ", NULL, SPLIT_QUOTES);
290 1 : assert_se(l);
291 1 : assert_se(strv_equal(l, (char**) input_table_quoted));
292 :
293 1 : strv_free_erase(l);
294 :
295 : /* missing last quote, but the last element is _not_ ignored with SPLIT_RELAX. */
296 1 : l = strv_split_full(" 'one' \" two\t three \" ' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX);
297 1 : assert_se(l);
298 1 : assert_se(strv_equal(l, (char**) input_table_quoted));
299 :
300 1 : strv_free_erase(l);
301 :
302 : /* missing separator between */
303 1 : l = strv_split_full(" 'one' \" two\t three \"' four five'", NULL, SPLIT_QUOTES | SPLIT_RELAX);
304 1 : assert_se(l);
305 1 : assert_se(strv_equal(l, (char**) input_table_quoted));
306 :
307 1 : strv_free_erase(l);
308 :
309 1 : l = strv_split_full(" 'one' \" two\t three \"' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX);
310 1 : assert_se(l);
311 1 : assert_se(strv_equal(l, (char**) input_table_quoted));
312 1 : }
313 :
314 1 : static void test_strv_split_empty(void) {
315 1 : _cleanup_strv_free_ char **l = NULL;
316 :
317 1 : log_info("/* %s */", __func__);
318 :
319 1 : l = strv_split("", WHITESPACE);
320 1 : assert_se(l);
321 1 : assert_se(strv_isempty(l));
322 :
323 1 : strv_free(l);
324 1 : l = strv_split("", NULL);
325 1 : assert_se(l);
326 1 : assert_se(strv_isempty(l));
327 :
328 1 : strv_free(l);
329 1 : l = strv_split_full("", NULL, 0);
330 1 : assert_se(l);
331 1 : assert_se(strv_isempty(l));
332 :
333 1 : strv_free(l);
334 1 : l = strv_split_full("", NULL, SPLIT_QUOTES);
335 1 : assert_se(l);
336 1 : assert_se(strv_isempty(l));
337 :
338 1 : strv_free(l);
339 1 : l = strv_split_full("", WHITESPACE, SPLIT_QUOTES);
340 1 : assert_se(l);
341 1 : assert_se(strv_isempty(l));
342 :
343 1 : strv_free(l);
344 1 : l = strv_split_full("", WHITESPACE, SPLIT_QUOTES | SPLIT_RELAX);
345 1 : assert_se(l);
346 1 : assert_se(strv_isempty(l));
347 :
348 1 : strv_free(l);
349 1 : l = strv_split(" ", WHITESPACE);
350 1 : assert_se(l);
351 1 : assert_se(strv_isempty(l));
352 :
353 1 : strv_free(l);
354 1 : l = strv_split(" ", NULL);
355 1 : assert_se(l);
356 1 : assert_se(strv_isempty(l));
357 :
358 1 : strv_free(l);
359 1 : l = strv_split_full(" ", NULL, 0);
360 1 : assert_se(l);
361 1 : assert_se(strv_isempty(l));
362 :
363 1 : strv_free(l);
364 1 : l = strv_split_full(" ", WHITESPACE, SPLIT_QUOTES);
365 1 : assert_se(l);
366 1 : assert_se(strv_isempty(l));
367 :
368 1 : strv_free(l);
369 1 : l = strv_split_full(" ", NULL, SPLIT_QUOTES);
370 1 : assert_se(l);
371 1 : assert_se(strv_isempty(l));
372 :
373 1 : strv_free(l);
374 1 : l = strv_split_full(" ", NULL, SPLIT_QUOTES | SPLIT_RELAX);
375 1 : assert_se(l);
376 1 : assert_se(strv_isempty(l));
377 1 : }
378 :
379 1 : static void test_strv_split_extract(void) {
380 1 : _cleanup_strv_free_ char **l = NULL;
381 1 : const char *str = ":foo\\:bar::waldo:";
382 : int r;
383 :
384 1 : log_info("/* %s */", __func__);
385 :
386 1 : r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
387 1 : assert_se(r == (int) strv_length(l));
388 1 : assert_se(streq_ptr(l[0], ""));
389 1 : assert_se(streq_ptr(l[1], "foo:bar"));
390 1 : assert_se(streq_ptr(l[2], ""));
391 1 : assert_se(streq_ptr(l[3], "waldo"));
392 1 : assert_se(streq_ptr(l[4], ""));
393 1 : assert_se(streq_ptr(l[5], NULL));
394 1 : }
395 :
396 1 : static void test_strv_split_newlines(void) {
397 1 : unsigned i = 0;
398 : char **s;
399 1 : _cleanup_strv_free_ char **l = NULL;
400 1 : const char str[] = "one\ntwo\nthree";
401 :
402 1 : log_info("/* %s */", __func__);
403 :
404 1 : l = strv_split_newlines(str);
405 1 : assert_se(l);
406 :
407 4 : STRV_FOREACH(s, l) {
408 3 : assert_se(streq(*s, input_table_multiple[i++]));
409 : }
410 1 : }
411 :
412 1 : static void test_strv_split_nulstr(void) {
413 1 : _cleanup_strv_free_ char **l = NULL;
414 1 : const char nulstr[] = "str0\0str1\0str2\0str3\0";
415 :
416 1 : log_info("/* %s */", __func__);
417 :
418 1 : l = strv_split_nulstr (nulstr);
419 1 : assert_se(l);
420 :
421 1 : assert_se(streq(l[0], "str0"));
422 1 : assert_se(streq(l[1], "str1"));
423 1 : assert_se(streq(l[2], "str2"));
424 1 : assert_se(streq(l[3], "str3"));
425 1 : }
426 :
427 1 : static void test_strv_parse_nulstr(void) {
428 1 : _cleanup_strv_free_ char **l = NULL;
429 1 : const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
430 :
431 1 : log_info("/* %s */", __func__);
432 :
433 1 : l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
434 1 : assert_se(l);
435 1 : puts("Parse nulstr:");
436 1 : strv_print(l);
437 :
438 1 : assert_se(streq(l[0], "hoge"));
439 1 : assert_se(streq(l[1], "hoge2"));
440 1 : assert_se(streq(l[2], "hoge3"));
441 1 : assert_se(streq(l[3], ""));
442 1 : assert_se(streq(l[4], "hoge5"));
443 1 : assert_se(streq(l[5], ""));
444 1 : assert_se(streq(l[6], "xxx"));
445 1 : }
446 :
447 1 : static void test_strv_overlap(void) {
448 1 : const char * const input_table[] = {
449 : "one",
450 : "two",
451 : "three",
452 : NULL
453 : };
454 1 : const char * const input_table_overlap[] = {
455 : "two",
456 : NULL
457 : };
458 1 : const char * const input_table_unique[] = {
459 : "four",
460 : "five",
461 : "six",
462 : NULL
463 : };
464 :
465 1 : log_info("/* %s */", __func__);
466 :
467 1 : assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap));
468 1 : assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique));
469 1 : }
470 :
471 1 : static void test_strv_sort(void) {
472 1 : const char* input_table[] = {
473 : "durian",
474 : "apple",
475 : "citrus",
476 : "CAPITAL LETTERS FIRST",
477 : "banana",
478 : NULL
479 : };
480 :
481 1 : log_info("/* %s */", __func__);
482 :
483 1 : strv_sort((char **)input_table);
484 :
485 1 : assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST"));
486 1 : assert_se(streq(input_table[1], "apple"));
487 1 : assert_se(streq(input_table[2], "banana"));
488 1 : assert_se(streq(input_table[3], "citrus"));
489 1 : assert_se(streq(input_table[4], "durian"));
490 1 : }
491 :
492 1 : static void test_strv_extend_strv_concat(void) {
493 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL;
494 :
495 1 : log_info("/* %s */", __func__);
496 :
497 1 : a = strv_new("without", "suffix");
498 1 : b = strv_new("with", "suffix");
499 1 : assert_se(a);
500 1 : assert_se(b);
501 :
502 1 : assert_se(strv_extend_strv_concat(&a, b, "_suffix") >= 0);
503 :
504 1 : assert_se(streq(a[0], "without"));
505 1 : assert_se(streq(a[1], "suffix"));
506 1 : assert_se(streq(a[2], "with_suffix"));
507 1 : assert_se(streq(a[3], "suffix_suffix"));
508 1 : }
509 :
510 1 : static void test_strv_extend_strv(void) {
511 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL;
512 :
513 1 : log_info("/* %s */", __func__);
514 :
515 1 : a = strv_new("abc", "def", "ghi");
516 1 : b = strv_new("jkl", "mno", "abc", "pqr");
517 1 : assert_se(a);
518 1 : assert_se(b);
519 :
520 1 : assert_se(strv_extend_strv(&a, b, true) == 3);
521 :
522 1 : assert_se(streq(a[0], "abc"));
523 1 : assert_se(streq(a[1], "def"));
524 1 : assert_se(streq(a[2], "ghi"));
525 1 : assert_se(streq(a[3], "jkl"));
526 1 : assert_se(streq(a[4], "mno"));
527 1 : assert_se(streq(a[5], "pqr"));
528 1 : assert_se(strv_length(a) == 6);
529 :
530 1 : assert_se(strv_extend_strv(&n, b, false) >= 0);
531 1 : assert_se(streq(n[0], "jkl"));
532 1 : assert_se(streq(n[1], "mno"));
533 1 : assert_se(streq(n[2], "abc"));
534 1 : assert_se(streq(n[3], "pqr"));
535 1 : assert_se(strv_length(n) == 4);
536 1 : }
537 :
538 1 : static void test_strv_extend(void) {
539 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL;
540 :
541 1 : log_info("/* %s */", __func__);
542 :
543 1 : a = strv_new("test", "test1");
544 1 : assert_se(a);
545 1 : assert_se(strv_extend(&a, "test2") >= 0);
546 1 : assert_se(strv_extend(&b, "test3") >= 0);
547 :
548 1 : assert_se(streq(a[0], "test"));
549 1 : assert_se(streq(a[1], "test1"));
550 1 : assert_se(streq(a[2], "test2"));
551 1 : assert_se(streq(b[0], "test3"));
552 1 : }
553 :
554 1 : static void test_strv_extendf(void) {
555 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL;
556 :
557 1 : log_info("/* %s */", __func__);
558 :
559 1 : a = strv_new("test", "test1");
560 1 : assert_se(a);
561 1 : assert_se(strv_extendf(&a, "test2 %s %d %s", "foo", 128, "bar") >= 0);
562 1 : assert_se(strv_extendf(&b, "test3 %s %s %d", "bar", "foo", 128) >= 0);
563 :
564 1 : assert_se(streq(a[0], "test"));
565 1 : assert_se(streq(a[1], "test1"));
566 1 : assert_se(streq(a[2], "test2 foo 128 bar"));
567 1 : assert_se(streq(b[0], "test3 bar foo 128"));
568 1 : }
569 :
570 1 : static void test_strv_foreach(void) {
571 1 : _cleanup_strv_free_ char **a;
572 1 : unsigned i = 0;
573 : char **check;
574 :
575 1 : log_info("/* %s */", __func__);
576 :
577 1 : a = strv_new("one", "two", "three");
578 1 : assert_se(a);
579 :
580 4 : STRV_FOREACH(check, a)
581 3 : assert_se(streq(*check, input_table_multiple[i++]));
582 1 : }
583 :
584 1 : static void test_strv_foreach_backwards(void) {
585 1 : _cleanup_strv_free_ char **a;
586 1 : unsigned i = 2;
587 : char **check;
588 :
589 1 : log_info("/* %s */", __func__);
590 :
591 1 : a = strv_new("one", "two", "three");
592 :
593 1 : assert_se(a);
594 :
595 4 : STRV_FOREACH_BACKWARDS(check, a)
596 3 : assert_se(streq_ptr(*check, input_table_multiple[i--]));
597 :
598 1 : STRV_FOREACH_BACKWARDS(check, (char**) NULL)
599 : assert_not_reached("Let's see that we check empty strv right, too.");
600 :
601 1 : STRV_FOREACH_BACKWARDS(check, (char**) { NULL })
602 : assert_not_reached("Let's see that we check empty strv right, too.");
603 1 : }
604 :
605 1 : static void test_strv_foreach_pair(void) {
606 1 : _cleanup_strv_free_ char **a = NULL;
607 : char **x, **y;
608 :
609 1 : log_info("/* %s */", __func__);
610 :
611 1 : a = strv_new("pair_one", "pair_one",
612 : "pair_two", "pair_two",
613 : "pair_three", "pair_three");
614 4 : STRV_FOREACH_PAIR(x, y, a)
615 3 : assert_se(streq(*x, *y));
616 1 : }
617 :
618 3 : static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) {
619 : char **j;
620 : unsigned i;
621 :
622 3 : log_info("/* %s */", __func__);
623 :
624 5 : j = strv_from_stdarg_alloca(first);
625 :
626 3 : for (i = 0;; i++) {
627 6 : assert_se(streq_ptr(l[i], j[i]));
628 :
629 6 : if (!l[i])
630 3 : break;
631 : }
632 3 : }
633 :
634 1 : static void test_strv_from_stdarg_alloca(void) {
635 1 : log_info("/* %s */", __func__);
636 :
637 1 : test_strv_from_stdarg_alloca_one(STRV_MAKE("foo", "bar"), "foo", "bar", NULL);
638 1 : test_strv_from_stdarg_alloca_one(STRV_MAKE("foo"), "foo", NULL);
639 1 : test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL);
640 1 : }
641 :
642 1 : static void test_strv_insert(void) {
643 1 : _cleanup_strv_free_ char **a = NULL;
644 :
645 1 : log_info("/* %s */", __func__);
646 :
647 1 : assert_se(strv_insert(&a, 0, strdup("first")) == 0);
648 1 : assert_se(streq(a[0], "first"));
649 1 : assert_se(!a[1]);
650 :
651 1 : assert_se(strv_insert(&a, 0, NULL) == 0);
652 1 : assert_se(streq(a[0], "first"));
653 1 : assert_se(!a[1]);
654 :
655 1 : assert_se(strv_insert(&a, 1, strdup("two")) == 0);
656 1 : assert_se(streq(a[0], "first"));
657 1 : assert_se(streq(a[1], "two"));
658 1 : assert_se(!a[2]);
659 :
660 1 : assert_se(strv_insert(&a, 4, strdup("tri")) == 0);
661 1 : assert_se(streq(a[0], "first"));
662 1 : assert_se(streq(a[1], "two"));
663 1 : assert_se(streq(a[2], "tri"));
664 1 : assert_se(!a[3]);
665 :
666 1 : assert_se(strv_insert(&a, 1, strdup("duo")) == 0);
667 1 : assert_se(streq(a[0], "first"));
668 1 : assert_se(streq(a[1], "duo"));
669 1 : assert_se(streq(a[2], "two"));
670 1 : assert_se(streq(a[3], "tri"));
671 1 : assert_se(!a[4]);
672 1 : }
673 :
674 1 : static void test_strv_push_prepend(void) {
675 1 : _cleanup_strv_free_ char **a = NULL;
676 :
677 1 : log_info("/* %s */", __func__);
678 :
679 1 : a = strv_new("foo", "bar", "three");
680 :
681 1 : assert_se(strv_push_prepend(&a, strdup("first")) >= 0);
682 1 : assert_se(streq(a[0], "first"));
683 1 : assert_se(streq(a[1], "foo"));
684 1 : assert_se(streq(a[2], "bar"));
685 1 : assert_se(streq(a[3], "three"));
686 1 : assert_se(!a[4]);
687 :
688 1 : assert_se(strv_consume_prepend(&a, strdup("first2")) >= 0);
689 1 : assert_se(streq(a[0], "first2"));
690 1 : assert_se(streq(a[1], "first"));
691 1 : assert_se(streq(a[2], "foo"));
692 1 : assert_se(streq(a[3], "bar"));
693 1 : assert_se(streq(a[4], "three"));
694 1 : assert_se(!a[5]);
695 1 : }
696 :
697 1 : static void test_strv_push(void) {
698 1 : _cleanup_strv_free_ char **a = NULL;
699 : char *i, *j;
700 :
701 1 : log_info("/* %s */", __func__);
702 :
703 1 : assert_se(i = strdup("foo"));
704 1 : assert_se(strv_push(&a, i) >= 0);
705 :
706 1 : assert_se(i = strdup("a"));
707 1 : assert_se(j = strdup("b"));
708 1 : assert_se(strv_push_pair(&a, i, j) >= 0);
709 :
710 1 : assert_se(streq_ptr(a[0], "foo"));
711 1 : assert_se(streq_ptr(a[1], "a"));
712 1 : assert_se(streq_ptr(a[2], "b"));
713 1 : assert_se(streq_ptr(a[3], NULL));
714 1 : }
715 :
716 1 : static void test_strv_equal(void) {
717 1 : _cleanup_strv_free_ char **a = NULL;
718 1 : _cleanup_strv_free_ char **b = NULL;
719 1 : _cleanup_strv_free_ char **c = NULL;
720 :
721 1 : log_info("/* %s */", __func__);
722 :
723 1 : a = strv_new("one", "two", "three");
724 1 : assert_se(a);
725 1 : b = strv_new("one", "two", "three");
726 1 : assert_se(a);
727 1 : c = strv_new("one", "two", "three", "four");
728 1 : assert_se(a);
729 :
730 1 : assert_se(strv_equal(a, a));
731 1 : assert_se(strv_equal(a, b));
732 1 : assert_se(strv_equal(NULL, NULL));
733 :
734 1 : assert_se(!strv_equal(a, c));
735 1 : assert_se(!strv_equal(b, c));
736 1 : assert_se(!strv_equal(b, NULL));
737 1 : }
738 :
739 1 : static void test_strv_is_uniq(void) {
740 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
741 :
742 1 : log_info("/* %s */", __func__);
743 :
744 1 : a = strv_new(NULL);
745 1 : assert_se(a);
746 1 : assert_se(strv_is_uniq(a));
747 :
748 1 : b = strv_new("foo");
749 1 : assert_se(b);
750 1 : assert_se(strv_is_uniq(b));
751 :
752 1 : c = strv_new("foo", "bar");
753 1 : assert_se(c);
754 1 : assert_se(strv_is_uniq(c));
755 :
756 1 : d = strv_new("foo", "bar", "waldo", "bar", "piep");
757 1 : assert_se(d);
758 1 : assert_se(!strv_is_uniq(d));
759 1 : }
760 :
761 1 : static void test_strv_reverse(void) {
762 1 : _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
763 :
764 1 : log_info("/* %s */", __func__);
765 :
766 1 : a = strv_new(NULL);
767 1 : assert_se(a);
768 :
769 1 : strv_reverse(a);
770 1 : assert_se(strv_isempty(a));
771 :
772 1 : b = strv_new("foo");
773 1 : assert_se(b);
774 1 : strv_reverse(b);
775 1 : assert_se(streq_ptr(b[0], "foo"));
776 1 : assert_se(streq_ptr(b[1], NULL));
777 :
778 1 : c = strv_new("foo", "bar");
779 1 : assert_se(c);
780 1 : strv_reverse(c);
781 1 : assert_se(streq_ptr(c[0], "bar"));
782 1 : assert_se(streq_ptr(c[1], "foo"));
783 1 : assert_se(streq_ptr(c[2], NULL));
784 :
785 1 : d = strv_new("foo", "bar", "waldo");
786 1 : assert_se(d);
787 1 : strv_reverse(d);
788 1 : assert_se(streq_ptr(d[0], "waldo"));
789 1 : assert_se(streq_ptr(d[1], "bar"));
790 1 : assert_se(streq_ptr(d[2], "foo"));
791 1 : assert_se(streq_ptr(d[3], NULL));
792 1 : }
793 :
794 1 : static void test_strv_shell_escape(void) {
795 1 : _cleanup_strv_free_ char **v = NULL;
796 :
797 1 : log_info("/* %s */", __func__);
798 :
799 1 : v = strv_new("foo:bar", "bar,baz", "wal\\do");
800 1 : assert_se(v);
801 1 : assert_se(strv_shell_escape(v, ",:"));
802 1 : assert_se(streq_ptr(v[0], "foo\\:bar"));
803 1 : assert_se(streq_ptr(v[1], "bar\\,baz"));
804 1 : assert_se(streq_ptr(v[2], "wal\\\\do"));
805 1 : assert_se(streq_ptr(v[3], NULL));
806 1 : }
807 :
808 12 : static void test_strv_skip_one(char **a, size_t n, char **b) {
809 12 : a = strv_skip(a, n);
810 12 : assert_se(strv_equal(a, b));
811 12 : }
812 :
813 1 : static void test_strv_skip(void) {
814 1 : log_info("/* %s */", __func__);
815 :
816 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz"));
817 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz"));
818 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz"));
819 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL));
820 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL));
821 1 : test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL));
822 :
823 1 : test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux"));
824 1 : test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL));
825 1 : test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL));
826 :
827 1 : test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL));
828 1 : test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL));
829 1 : test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL));
830 1 : }
831 :
832 1 : static void test_strv_extend_n(void) {
833 1 : _cleanup_strv_free_ char **v = NULL;
834 :
835 1 : log_info("/* %s */", __func__);
836 :
837 1 : v = strv_new("foo", "bar");
838 1 : assert_se(v);
839 :
840 1 : assert_se(strv_extend_n(&v, "waldo", 3) >= 0);
841 1 : assert_se(strv_extend_n(&v, "piep", 2) >= 0);
842 :
843 1 : assert_se(streq(v[0], "foo"));
844 1 : assert_se(streq(v[1], "bar"));
845 1 : assert_se(streq(v[2], "waldo"));
846 1 : assert_se(streq(v[3], "waldo"));
847 1 : assert_se(streq(v[4], "waldo"));
848 1 : assert_se(streq(v[5], "piep"));
849 1 : assert_se(streq(v[6], "piep"));
850 1 : assert_se(v[7] == NULL);
851 :
852 1 : v = strv_free(v);
853 :
854 1 : assert_se(strv_extend_n(&v, "foo", 1) >= 0);
855 1 : assert_se(strv_extend_n(&v, "bar", 0) >= 0);
856 :
857 1 : assert_se(streq(v[0], "foo"));
858 1 : assert_se(v[1] == NULL);
859 1 : }
860 :
861 5 : static void test_strv_make_nulstr_one(char **l) {
862 5 : _cleanup_free_ char *b = NULL, *c = NULL;
863 5 : _cleanup_strv_free_ char **q = NULL;
864 5 : const char *s = NULL;
865 : size_t n, m;
866 5 : unsigned i = 0;
867 :
868 5 : log_info("/* %s */", __func__);
869 :
870 5 : assert_se(strv_make_nulstr(l, &b, &n) >= 0);
871 5 : assert_se(q = strv_parse_nulstr(b, n));
872 5 : assert_se(strv_equal(l, q));
873 :
874 5 : assert_se(strv_make_nulstr(q, &c, &m) >= 0);
875 5 : assert_se(m == n);
876 5 : assert_se(memcmp(b, c, m) == 0);
877 :
878 11 : NULSTR_FOREACH(s, b)
879 6 : assert_se(streq(s, l[i++]));
880 5 : assert_se(i == strv_length(l));
881 5 : }
882 :
883 1 : static void test_strv_make_nulstr(void) {
884 1 : log_info("/* %s */", __func__);
885 :
886 1 : test_strv_make_nulstr_one(NULL);
887 1 : test_strv_make_nulstr_one(STRV_MAKE(NULL));
888 1 : test_strv_make_nulstr_one(STRV_MAKE("foo"));
889 1 : test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
890 1 : test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
891 1 : }
892 :
893 1 : static void test_strv_free_free(void) {
894 : char ***t;
895 :
896 1 : log_info("/* %s */", __func__);
897 :
898 1 : assert_se(t = new(char**, 3));
899 1 : assert_se(t[0] = strv_new("a", "b"));
900 1 : assert_se(t[1] = strv_new("c", "d", "e"));
901 1 : t[2] = NULL;
902 :
903 1 : t = strv_free_free(t);
904 1 : }
905 :
906 1 : static void test_foreach_string(void) {
907 1 : const char * const t[] = {
908 : "foo",
909 : "bar",
910 : "waldo",
911 : NULL
912 : };
913 : const char *x;
914 1 : unsigned i = 0;
915 :
916 1 : log_info("/* %s */", __func__);
917 :
918 4 : FOREACH_STRING(x, "foo", "bar", "waldo")
919 3 : assert_se(streq_ptr(t[i++], x));
920 :
921 1 : assert_se(i == 3);
922 :
923 2 : FOREACH_STRING(x, "zzz")
924 1 : assert_se(streq(x, "zzz"));
925 1 : }
926 :
927 1 : static void test_strv_fnmatch(void) {
928 1 : _cleanup_strv_free_ char **v = NULL;
929 :
930 1 : log_info("/* %s */", __func__);
931 :
932 1 : assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0));
933 :
934 1 : v = strv_new("*\\*");
935 1 : assert_se(!strv_fnmatch(v, "\\", 0));
936 1 : assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE));
937 1 : }
938 :
939 1 : int main(int argc, char *argv[]) {
940 1 : test_specifier_printf();
941 1 : test_str_in_set();
942 1 : test_strptr_in_set();
943 1 : test_startswith_set();
944 1 : test_strv_foreach();
945 1 : test_strv_foreach_backwards();
946 1 : test_strv_foreach_pair();
947 1 : test_strv_find();
948 1 : test_strv_find_prefix();
949 1 : test_strv_find_startswith();
950 1 : test_strv_join();
951 1 : test_strv_join_prefix();
952 :
953 1 : test_strv_unquote(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz"));
954 1 : test_strv_unquote("", STRV_MAKE_EMPTY);
955 1 : test_strv_unquote(" ", STRV_MAKE_EMPTY);
956 1 : test_strv_unquote(" ", STRV_MAKE_EMPTY);
957 1 : test_strv_unquote(" x", STRV_MAKE("x"));
958 1 : test_strv_unquote("x ", STRV_MAKE("x"));
959 1 : test_strv_unquote(" x ", STRV_MAKE("x"));
960 1 : test_strv_unquote(" \"x\" ", STRV_MAKE("x"));
961 1 : test_strv_unquote(" 'x' ", STRV_MAKE("x"));
962 1 : test_strv_unquote(" 'x\"' ", STRV_MAKE("x\""));
963 1 : test_strv_unquote(" \"x'\" ", STRV_MAKE("x'"));
964 1 : test_strv_unquote("a '--b=c \"d e\"'", STRV_MAKE("a", "--b=c \"d e\""));
965 :
966 : /* trailing backslashes */
967 1 : test_strv_unquote(" x\\\\", STRV_MAKE("x\\"));
968 1 : test_invalid_unquote(" x\\");
969 :
970 1 : test_invalid_unquote("a --b='c \"d e\"''");
971 1 : test_invalid_unquote("a --b='c \"d e\" '\"");
972 1 : test_invalid_unquote("a --b='c \"d e\"garbage");
973 1 : test_invalid_unquote("'");
974 1 : test_invalid_unquote("\"");
975 1 : test_invalid_unquote("'x'y'g");
976 :
977 1 : test_strv_split();
978 1 : test_strv_split_empty();
979 1 : test_strv_split_extract();
980 1 : test_strv_split_newlines();
981 1 : test_strv_split_nulstr();
982 1 : test_strv_parse_nulstr();
983 1 : test_strv_overlap();
984 1 : test_strv_sort();
985 1 : test_strv_extend_strv();
986 1 : test_strv_extend_strv_concat();
987 1 : test_strv_extend();
988 1 : test_strv_extendf();
989 1 : test_strv_from_stdarg_alloca();
990 1 : test_strv_insert();
991 1 : test_strv_push_prepend();
992 1 : test_strv_push();
993 1 : test_strv_equal();
994 1 : test_strv_is_uniq();
995 1 : test_strv_reverse();
996 1 : test_strv_shell_escape();
997 1 : test_strv_skip();
998 1 : test_strv_extend_n();
999 1 : test_strv_make_nulstr();
1000 1 : test_strv_free_free();
1001 :
1002 1 : test_foreach_string();
1003 1 : test_strv_fnmatch();
1004 :
1005 1 : return 0;
1006 : }
|