chiark / gitweb /
util: rework safe_atod() to be locale-independent
[elogind.git] / src / test / test-util.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 #include <unistd.h>
25 #include <fcntl.h>
26 #include <locale.h>
27
28 #include "util.h"
29
30 static void test_streq_ptr(void) {
31         assert_se(streq_ptr(NULL, NULL));
32         assert_se(!streq_ptr("abc", "cdef"));
33 }
34
35 static void test_first_word(void) {
36         assert_se(first_word("Hello", ""));
37         assert_se(first_word("Hello", "Hello"));
38         assert_se(first_word("Hello world", "Hello"));
39         assert_se(first_word("Hello\tworld", "Hello"));
40         assert_se(first_word("Hello\nworld", "Hello"));
41         assert_se(first_word("Hello\rworld", "Hello"));
42         assert_se(first_word("Hello ", "Hello"));
43
44         assert_se(!first_word("Hello", "Hellooo"));
45         assert_se(!first_word("Hello", "xxxxx"));
46         assert_se(!first_word("Hellooo", "Hello"));
47 }
48
49 static void test_close_many(void) {
50         int fds[3];
51         char name0[] = "/tmp/test-close-many.XXXXXX";
52         char name1[] = "/tmp/test-close-many.XXXXXX";
53         char name2[] = "/tmp/test-close-many.XXXXXX";
54
55         fds[0] = mkstemp(name0);
56         fds[1] = mkstemp(name1);
57         fds[2] = mkstemp(name2);
58
59         close_many(fds, 2);
60
61         assert_se(fcntl(fds[0], F_GETFD) == -1);
62         assert_se(fcntl(fds[1], F_GETFD) == -1);
63         assert_se(fcntl(fds[2], F_GETFD) >= 0);
64
65         close_nointr_nofail(fds[2]);
66
67         unlink(name0);
68         unlink(name1);
69         unlink(name2);
70 }
71
72 static void test_parse_boolean(void) {
73         assert_se(parse_boolean("1") == 1);
74         assert_se(parse_boolean("y") == 1);
75         assert_se(parse_boolean("Y") == 1);
76         assert_se(parse_boolean("yes") == 1);
77         assert_se(parse_boolean("YES") == 1);
78         assert_se(parse_boolean("true") == 1);
79         assert_se(parse_boolean("TRUE") == 1);
80         assert_se(parse_boolean("on") == 1);
81         assert_se(parse_boolean("ON") == 1);
82
83         assert_se(parse_boolean("0") == 0);
84         assert_se(parse_boolean("n") == 0);
85         assert_se(parse_boolean("N") == 0);
86         assert_se(parse_boolean("no") == 0);
87         assert_se(parse_boolean("NO") == 0);
88         assert_se(parse_boolean("false") == 0);
89         assert_se(parse_boolean("FALSE") == 0);
90         assert_se(parse_boolean("off") == 0);
91         assert_se(parse_boolean("OFF") == 0);
92
93         assert_se(parse_boolean("garbage") < 0);
94         assert_se(parse_boolean("") < 0);
95 }
96
97 static void test_parse_pid(void) {
98         int r;
99         pid_t pid;
100
101         r = parse_pid("100", &pid);
102         assert_se(r == 0);
103         assert_se(pid == 100);
104
105         r = parse_pid("0x7FFFFFFF", &pid);
106         assert_se(r == 0);
107         assert_se(pid == 2147483647);
108
109         pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
110         r = parse_pid("0", &pid);
111         assert_se(r == -ERANGE);
112         assert_se(pid == 65);
113
114         pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
115         r = parse_pid("-100", &pid);
116         assert_se(r == -ERANGE);
117         assert_se(pid == 65);
118
119         pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
120         r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
121         assert(r == -ERANGE);
122         assert_se(pid == 65);
123 }
124
125 static void test_parse_uid(void) {
126         int r;
127         uid_t uid;
128
129         r = parse_uid("100", &uid);
130         assert_se(r == 0);
131         assert_se(uid == 100);
132 }
133
134 static void test_safe_atolli(void) {
135         int r;
136         long long l;
137
138         r = safe_atolli("12345", &l);
139         assert_se(r == 0);
140         assert_se(l == 12345);
141
142         r = safe_atolli("junk", &l);
143         assert_se(r == -EINVAL);
144 }
145
146 static void test_safe_atod(void) {
147         int r;
148         double d;
149         char *e;
150
151         r = safe_atod("junk", &d);
152         assert_se(r == -EINVAL);
153
154         r = safe_atod("0.2244", &d);
155         assert_se(r == 0);
156         assert_se(abs(d - 0.2244) < 0.000001);
157
158         r = safe_atod("0,5", &d);
159         assert_se(r == -EINVAL);
160
161         errno = 0;
162         strtod("0,5", &e);
163         assert_se(*e == ',');
164
165         /* Check if this really is locale independent */
166         setlocale(LC_NUMERIC, "de_DE.utf8");
167
168         r = safe_atod("0.2244", &d);
169         assert_se(r == 0);
170         assert_se(abs(d - 0.2244) < 0.000001);
171
172         r = safe_atod("0,5", &d);
173         assert_se(r == -EINVAL);
174
175         errno = 0;
176         assert_se(abs(strtod("0,5", &e) - 0.5) < 0.00001);
177
178         /* And check again, reset */
179         setlocale(LC_NUMERIC, "C");
180
181         r = safe_atod("0.2244", &d);
182         assert_se(r == 0);
183         assert_se(abs(d - 0.2244) < 0.000001);
184
185         r = safe_atod("0,5", &d);
186         assert_se(r == -EINVAL);
187
188         errno = 0;
189         strtod("0,5", &e);
190         assert_se(*e == ',');
191 }
192
193 static void test_strappend(void) {
194        _cleanup_free_ char *t1, *t2, *t3, *t4;
195
196        t1 = strappend(NULL, NULL);
197        assert_se(streq(t1, ""));
198
199        t2 = strappend(NULL, "suf");
200        assert_se(streq(t2, "suf"));
201
202        t3 = strappend("pre", NULL);
203        assert_se(streq(t3, "pre"));
204
205        t4 = strappend("pre", "suf");
206        assert_se(streq(t4, "presuf"));
207 }
208
209 static void test_strstrip(void) {
210        char *r;
211        char input[] = "   hello, waldo.   ";
212
213        r = strstrip(input);
214        assert_se(streq(r, "hello, waldo."));
215
216 }
217
218 static void test_delete_chars(void) {
219        char *r;
220        char input[] = "   hello, waldo.   abc";
221
222        r = delete_chars(input, WHITESPACE);
223        assert_se(streq(r, "hello,waldo.abc"));
224 }
225
226 static void test_in_charset(void) {
227       assert_se(in_charset("dddaaabbbcccc", "abcd"));
228       assert_se(!in_charset("dddaaabbbcccc", "abc f"));
229 }
230
231 static void test_hexchar(void) {
232         assert_se(hexchar(0xa) == 'a');
233         assert_se(hexchar(0x0) == '0');
234 }
235
236 static void test_unhexchar(void) {
237         assert_se(unhexchar('a') == 0xA);
238         assert_se(unhexchar('A') == 0xA);
239         assert_se(unhexchar('0') == 0x0);
240 }
241
242 static void test_octchar(void) {
243         assert_se(octchar(00) == '0');
244         assert_se(octchar(07) == '7');
245 }
246
247 static void test_unoctchar(void) {
248         assert_se(unoctchar('0') == 00);
249         assert_se(unoctchar('7') == 07);
250 }
251
252 static void test_decchar(void) {
253         assert_se(decchar(0) == '0');
254         assert_se(decchar(9) == '9');
255 }
256
257 static void test_undecchar(void) {
258         assert_se(undecchar('0') == 0);
259         assert_se(undecchar('9') == 9);
260 }
261
262 static void test_foreach_word(void) {
263         char *w, *state;
264         size_t l;
265         int i = 0;
266         const char test[] = "test abc d\te   f   ";
267         const char * const expected[] = {
268                 "test",
269                 "abc",
270                 "d",
271                 "e",
272                 "f",
273                 "",
274                 NULL
275         };
276
277         FOREACH_WORD(w, l, test, state) {
278                 assert_se(strneq(expected[i++], w, l));
279         }
280 }
281
282 static void test_foreach_word_quoted(void) {
283         char *w, *state;
284         size_t l;
285         int i = 0;
286         const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\"";
287         const char * const expected[] = {
288                 "test",
289                 "a",
290                 "b",
291                 "c",
292                 "d",
293                 "e",
294                 "",
295                 "",
296                 "hhh",
297                 "",
298                 "",
299                 "a b c",
300                 NULL
301         };
302
303         printf("<%s>\n", test);
304         FOREACH_WORD_QUOTED(w, l, test, state) {
305                 _cleanup_free_ char *t = NULL;
306
307                 assert_se(t = strndup(w, l));
308                 assert_se(strneq(expected[i++], w, l));
309                 printf("<%s>\n", t);
310         }
311 }
312
313 static void test_default_term_for_tty(void) {
314         puts(default_term_for_tty("/dev/tty23"));
315         puts(default_term_for_tty("/dev/ttyS23"));
316         puts(default_term_for_tty("/dev/tty0"));
317         puts(default_term_for_tty("/dev/pty0"));
318         puts(default_term_for_tty("/dev/pts/0"));
319         puts(default_term_for_tty("/dev/console"));
320         puts(default_term_for_tty("tty23"));
321         puts(default_term_for_tty("ttyS23"));
322         puts(default_term_for_tty("tty0"));
323         puts(default_term_for_tty("pty0"));
324         puts(default_term_for_tty("pts/0"));
325         puts(default_term_for_tty("console"));
326 }
327
328 static void test_memdup_multiply(void) {
329         int org[] = {1, 2, 3};
330         int *dup;
331
332         dup = (int*)memdup_multiply(org, sizeof(int), 3);
333
334         assert_se(dup);
335         assert_se(dup[0] == 1);
336         assert_se(dup[1] == 2);
337         assert_se(dup[2] == 3);
338         free(dup);
339 }
340
341 static void test_bus_path_escape_one(const char *a, const char *b) {
342         _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
343
344         assert_se(t = bus_path_escape(a));
345         assert_se(streq(t, b));
346
347         assert_se(x = bus_path_unescape(t));
348         assert_se(streq(a, x));
349
350         assert_se(y = bus_path_unescape(b));
351         assert_se(streq(a, y));
352 }
353
354 static void test_bus_path_escape(void) {
355         test_bus_path_escape_one("foo123bar", "foo123bar");
356         test_bus_path_escape_one("foo.bar", "foo_2ebar");
357         test_bus_path_escape_one("foo_2ebar", "foo_5f2ebar");
358         test_bus_path_escape_one("", "_");
359         test_bus_path_escape_one("_", "_5f");
360         test_bus_path_escape_one("1", "_31");
361         test_bus_path_escape_one(":1", "_3a1");
362 }
363
364 static void test_hostname_is_valid(void) {
365         assert(hostname_is_valid("foobar"));
366         assert(hostname_is_valid("foobar.com"));
367         assert(!hostname_is_valid("fööbar"));
368         assert(!hostname_is_valid(""));
369         assert(!hostname_is_valid("."));
370         assert(!hostname_is_valid(".."));
371         assert(!hostname_is_valid("foobar."));
372         assert(!hostname_is_valid(".foobar"));
373         assert(!hostname_is_valid("foo..bar"));
374         assert(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
375 }
376
377 static void test_u64log2(void) {
378         assert(u64log2(0) == 0);
379         assert(u64log2(8) == 3);
380         assert(u64log2(9) == 3);
381         assert(u64log2(15) == 3);
382         assert(u64log2(16) == 4);
383         assert(u64log2(1024*1024) == 20);
384         assert(u64log2(1024*1024+5) == 20);
385 }
386
387 static void test_get_process_comm(void) {
388         _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
389         unsigned long long b;
390         pid_t e;
391         uid_t u;
392         gid_t g;
393         dev_t h;
394         int r;
395
396         assert_se(get_process_comm(1, &a) >= 0);
397         log_info("pid1 comm: '%s'", a);
398
399         assert_se(get_starttime_of_pid(1, &b) >= 0);
400         log_info("pid1 starttime: '%llu'", b);
401
402         assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
403         log_info("pid1 cmdline: '%s'", c);
404
405         assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
406         log_info("pid1 cmdline truncated: '%s'", d);
407
408         assert_se(get_parent_of_pid(1, &e) >= 0);
409         log_info("pid1 ppid: '%llu'", (unsigned long long) e);
410         assert_se(e == 0);
411
412         assert_se(is_kernel_thread(1) == 0);
413
414         r = get_process_exe(1, &f);
415         assert_se(r >= 0 || r == -EACCES);
416         log_info("pid1 exe: '%s'", strna(f));
417
418         assert_se(get_process_uid(1, &u) == 0);
419         log_info("pid1 uid: '%llu'", (unsigned long long) u);
420         assert_se(u == 0);
421
422         assert_se(get_process_gid(1, &g) == 0);
423         log_info("pid1 gid: '%llu'", (unsigned long long) g);
424         assert_se(g == 0);
425
426         assert(get_ctty_devnr(1, &h) == -ENOENT);
427
428         getenv_for_pid(1, "PATH", &i);
429         log_info("pid1 $PATH: '%s'", strna(i));
430 }
431
432 int main(int argc, char *argv[]) {
433         test_streq_ptr();
434         test_first_word();
435         test_close_many();
436         test_parse_boolean();
437         test_parse_pid();
438         test_parse_uid();
439         test_safe_atolli();
440         test_safe_atod();
441         test_strappend();
442         test_strstrip();
443         test_delete_chars();
444         test_in_charset();
445         test_hexchar();
446         test_unhexchar();
447         test_octchar();
448         test_unoctchar();
449         test_decchar();
450         test_undecchar();
451         test_foreach_word();
452         test_foreach_word_quoted();
453         test_default_term_for_tty();
454         test_memdup_multiply();
455         test_bus_path_escape();
456         test_hostname_is_valid();
457         test_u64log2();
458         test_get_process_comm();
459
460         return 0;
461 }