1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2016 Zbigniew Jędrzejewski-Szmek
11 #include "string-util.h"
15 static void test_strv_env_delete(void) {
16 _cleanup_strv_free_
char **a
= NULL
, **b
= NULL
, **c
= NULL
, **d
= NULL
;
18 a
= strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL
);
21 b
= strv_new("PIEP", "FOO", NULL
);
24 c
= strv_new("SCHLUMPF", NULL
);
27 d
= strv_env_delete(a
, 2, b
, c
);
30 assert_se(streq(d
[0], "WALDO=WALDO"));
31 assert_se(streq(d
[1], "WALDO="));
32 assert_se(strv_length(d
) == 2);
35 static void test_strv_env_get(void) {
38 l
= STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
40 assert_se(streq(strv_env_get(l
, "ONE_OR_TWO"), "2"));
41 assert_se(streq(strv_env_get(l
, "THREE"), "3"));
42 assert_se(streq(strv_env_get(l
, "FOUR"), "4"));
45 static void test_strv_env_unset(void) {
46 _cleanup_strv_free_
char **l
= NULL
;
48 l
= strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
51 assert_se(strv_env_unset(l
, "SCHLUMPF") == l
);
53 assert_se(streq(l
[0], "PIEP"));
54 assert_se(streq(l
[1], "NANANANA=YES"));
55 assert_se(strv_length(l
) == 2);
58 static void test_strv_env_set(void) {
59 _cleanup_strv_free_
char **l
= NULL
, **r
= NULL
;
61 l
= strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
64 r
= strv_env_set(l
, "WALDO=WALDO");
67 assert_se(streq(r
[0], "PIEP"));
68 assert_se(streq(r
[1], "SCHLUMPF=SMURFF"));
69 assert_se(streq(r
[2], "NANANANA=YES"));
70 assert_se(streq(r
[3], "WALDO=WALDO"));
71 assert_se(strv_length(r
) == 4);
74 static void test_strv_env_merge(void) {
75 _cleanup_strv_free_
char **a
= NULL
, **b
= NULL
, **r
= NULL
;
77 a
= strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL
);
80 b
= strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
83 r
= strv_env_merge(2, a
, b
);
85 assert_se(streq(r
[0], "FOO="));
86 assert_se(streq(r
[1], "WALDO="));
87 assert_se(streq(r
[2], "PIEP"));
88 assert_se(streq(r
[3], "SCHLUMPF=SMURFF"));
89 assert_se(streq(r
[4], "PIEP="));
90 assert_se(streq(r
[5], "NANANANA=YES"));
91 assert_se(strv_length(r
) == 6);
93 assert_se(strv_env_clean(r
) == r
);
94 assert_se(streq(r
[0], "FOO="));
95 assert_se(streq(r
[1], "WALDO="));
96 assert_se(streq(r
[2], "SCHLUMPF=SMURFF"));
97 assert_se(streq(r
[3], "PIEP="));
98 assert_se(streq(r
[4], "NANANANA=YES"));
99 assert_se(strv_length(r
) == 5);
102 static void test_env_strv_get_n(void) {
103 const char *_env
[] = {
110 char **env
= (char**) _env
;
112 assert_se(streq(strv_env_get_n(env
, "FOO__", 3, 0), "BAR BAR"));
113 assert_se(streq(strv_env_get_n(env
, "FOO__", 3, REPLACE_ENV_USE_ENVIRONMENT
), "BAR BAR"));
114 assert_se(streq(strv_env_get_n(env
, "FOO", 3, 0), "BAR BAR"));
115 assert_se(streq(strv_env_get_n(env
, "FOO", 3, REPLACE_ENV_USE_ENVIRONMENT
), "BAR BAR"));
117 assert_se(streq(strv_env_get_n(env
, "PATH__", 4, 0), "unset"));
118 assert_se(streq(strv_env_get_n(env
, "PATH", 4, 0), "unset"));
119 assert_se(streq(strv_env_get_n(env
, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT
), "unset"));
120 assert_se(streq(strv_env_get_n(env
, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT
), "unset"));
122 env
[3] = NULL
; /* kill our $PATH */
124 assert_se(!strv_env_get_n(env
, "PATH__", 4, 0));
125 assert_se(!strv_env_get_n(env
, "PATH", 4, 0));
126 assert_se(streq(strv_env_get_n(env
, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT
),
128 assert_se(streq(strv_env_get_n(env
, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT
),
132 static void test_replace_env(bool braceless
) {
133 const char *env
[] = {
138 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *q
= NULL
, *r
= NULL
, *p
= NULL
;
139 unsigned flags
= REPLACE_ENV_ALLOW_BRACELESS
*braceless
;
141 t
= replace_env("FOO=$FOO=${FOO}", (char**) env
, flags
);
142 assert_se(streq(t
, braceless
? "FOO=BAR BAR=BAR BAR" : "FOO=$FOO=BAR BAR"));
144 s
= replace_env("BAR=$BAR=${BAR}", (char**) env
, flags
);
145 assert_se(streq(s
, braceless
? "BAR=waldo=waldo" : "BAR=$BAR=waldo"));
147 q
= replace_env("BARBAR=$BARBAR=${BARBAR}", (char**) env
, flags
);
148 assert_se(streq(q
, braceless
? "BARBAR==" : "BARBAR=$BARBAR="));
150 r
= replace_env("BAR=$BAR$BAR${BAR}${BAR}", (char**) env
, flags
);
151 assert_se(streq(r
, braceless
? "BAR=waldowaldowaldowaldo" : "BAR=$BAR$BARwaldowaldo"));
153 p
= replace_env("${BAR}$BAR$BAR", (char**) env
, flags
);
154 assert_se(streq(p
, braceless
? "waldowaldowaldo" : "waldo$BAR$BAR"));
157 static void test_replace_env2(bool extended
) {
158 const char *env
[] = {
163 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *q
= NULL
, *r
= NULL
, *p
= NULL
, *x
= NULL
;
164 unsigned flags
= REPLACE_ENV_ALLOW_EXTENDED
*extended
;
166 t
= replace_env("FOO=${FOO:-${BAR}}", (char**) env
, flags
);
167 assert_se(streq(t
, extended
? "FOO=foo" : "FOO=${FOO:-bar}"));
169 s
= replace_env("BAR=${XXX:-${BAR}}", (char**) env
, flags
);
170 assert_se(streq(s
, extended
? "BAR=bar" : "BAR=${XXX:-bar}"));
172 q
= replace_env("XXX=${XXX:+${BAR}}", (char**) env
, flags
);
173 assert_se(streq(q
, extended
? "XXX=" : "XXX=${XXX:+bar}"));
175 r
= replace_env("FOO=${FOO:+${BAR}}", (char**) env
, flags
);
176 assert_se(streq(r
, extended
? "FOO=bar" : "FOO=${FOO:+bar}"));
178 p
= replace_env("FOO=${FOO:-${BAR}post}", (char**) env
, flags
);
179 assert_se(streq(p
, extended
? "FOO=foo" : "FOO=${FOO:-barpost}"));
181 x
= replace_env("XXX=${XXX:+${BAR}post}", (char**) env
, flags
);
182 assert_se(streq(x
, extended
? "XXX=" : "XXX=${XXX:+barpost}"));
185 static void test_replace_env_argv(void) {
186 const char *env
[] = {
191 const char *line
[] = {
211 _cleanup_strv_free_
char **r
= NULL
;
213 r
= replace_env_argv((char**) line
, (char**) env
);
215 assert_se(streq(r
[0], "FOO$FOO"));
216 assert_se(streq(r
[1], "FOO$FOOFOO"));
217 assert_se(streq(r
[2], "FOOBAR BAR$FOO"));
218 assert_se(streq(r
[3], "FOOBAR BAR"));
219 assert_se(streq(r
[4], "BAR BAR"));
220 assert_se(streq(r
[5], "BAR"));
221 assert_se(streq(r
[6], "BAR"));
222 assert_se(streq(r
[7], "BAR BARwaldo"));
223 assert_se(streq(r
[8], "${FOO"));
224 assert_se(streq(r
[9], "FOO$BAR BAR"));
225 assert_se(streq(r
[10], "$FOOBAR BAR"));
226 assert_se(streq(r
[11], "${FOO:-waldo}"));
227 assert_se(streq(r
[12], "${QUUX:-BAR BAR}"));
228 assert_se(streq(r
[13], "${FOO:+waldo}"));
229 assert_se(streq(r
[14], "${QUUX:+waldo}"));
230 assert_se(streq(r
[15], "${FOO:+|waldo|}}"));
231 assert_se(streq(r
[16], "${FOO:+|waldo{|}"));
232 assert_se(strv_length(r
) == 17);
235 static void test_env_clean(void) {
236 _cleanup_strv_free_
char **e
;
238 e
= strv_new("FOOBAR=WALDO",
256 assert_se(!strv_env_is_valid(e
));
257 assert_se(strv_env_clean(e
) == e
);
258 assert_se(strv_env_is_valid(e
));
260 assert_se(streq(e
[0], "FOOBAR=WALDO"));
261 assert_se(streq(e
[1], "X="));
262 assert_se(streq(e
[2], "F=F"));
263 assert_se(streq(e
[3], "abcd=äöüß"));
264 assert_se(streq(e
[4], "xyz=xyz\n"));
265 assert_se(streq(e
[5], "another=final one"));
266 assert_se(e
[6] == NULL
);
269 static void test_env_name_is_valid(void) {
270 assert_se(env_name_is_valid("test"));
272 assert_se(!env_name_is_valid(NULL
));
273 assert_se(!env_name_is_valid(""));
274 assert_se(!env_name_is_valid("xxx\a"));
275 assert_se(!env_name_is_valid("xxx\007b"));
276 assert_se(!env_name_is_valid("\007\009"));
277 assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
278 assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
281 static void test_env_value_is_valid(void) {
282 assert_se(env_value_is_valid(""));
283 assert_se(env_value_is_valid("głąb kapuściany"));
284 assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
285 assert_se(env_value_is_valid("tab\tcharacter"));
286 assert_se(env_value_is_valid("new\nline"));
289 static void test_env_assignment_is_valid(void) {
290 assert_se(env_assignment_is_valid("a="));
291 assert_se(env_assignment_is_valid("b=głąb kapuściany"));
292 assert_se(env_assignment_is_valid("c=\\007\\009\\011"));
293 assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
294 assert_se(env_assignment_is_valid("f=tab\tcharacter"));
295 assert_se(env_assignment_is_valid("g=new\nline"));
297 assert_se(!env_assignment_is_valid("="));
298 assert_se(!env_assignment_is_valid("a b="));
299 assert_se(!env_assignment_is_valid("a ="));
300 assert_se(!env_assignment_is_valid(" b="));
301 /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
302 assert_se(!env_assignment_is_valid("a.b="));
303 assert_se(!env_assignment_is_valid("a-b="));
304 assert_se(!env_assignment_is_valid("\007=głąb kapuściany"));
305 assert_se(!env_assignment_is_valid("c\009=\007\009\011"));
306 assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
309 static void test_deserialize_environment(void) {
310 _cleanup_strv_free_
char **env
= strv_new("A=1", NULL
);
312 assert_se(deserialize_environment(&env
, "env=B=2") >= 0);
313 assert_se(deserialize_environment(&env
, "env=FOO%%=a\\177b\\nc\\td e") >= 0);
315 assert_se(strv_equal(env
, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
317 assert_se(deserialize_environment(&env
, "env=foo\\") < 0);
318 assert_se(deserialize_environment(&env
, "env=bar\\_baz") < 0);
321 static void test_serialize_environment(void) {
322 char fn
[] = "/tmp/test-env-util.XXXXXXX";
324 _cleanup_fclose_
FILE *f
= NULL
;
326 _cleanup_strv_free_
char **env
= strv_new("A=1",
330 "FOO%%=a\177b\nc\td e",
332 _cleanup_strv_free_
char **env2
= NULL
;
334 fd
= mkostemp_safe(fn
);
337 assert_se(f
= fdopen(fd
, "r+"));
339 assert_se(serialize_environment(f
, env
) == 0);
340 assert_se(fflush_and_check(f
) == 0);
348 if (!fgets(line
, sizeof line
, f
))
354 r
= deserialize_environment(&env2
, l
);
359 assert_se(strv_equal(env
, env2
));
364 int main(int argc
, char *argv
[]) {
365 test_strv_env_delete();
367 test_strv_env_unset();
369 test_strv_env_merge();
370 test_env_strv_get_n();
371 test_replace_env(false);
372 test_replace_env(true);
373 test_replace_env2(false);
374 test_replace_env2(true);
375 test_replace_env_argv();
377 test_env_name_is_valid();
378 test_env_value_is_valid();
379 test_env_assignment_is_valid();
380 test_deserialize_environment();
381 test_serialize_environment();