]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-json.c
Merge pull request #11608 from taro-yamada/add_persistent_randmized_delay
[thirdparty/systemd.git] / src / test / test-json.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <math.h>
4
5 #include "alloc-util.h"
6 #include "fd-util.h"
7 #include "json-internal.h"
8 #include "json.h"
9 #include "string-util.h"
10 #include "strv.h"
11 #include "util.h"
12
13 static void test_tokenizer(const char *data, ...) {
14 unsigned line = 0, column = 0;
15 void *state = NULL;
16 va_list ap;
17
18 va_start(ap, data);
19
20 for (;;) {
21 unsigned token_line, token_column;
22 _cleanup_free_ char *str = NULL;
23 JsonValue v = JSON_VALUE_NULL;
24 int t, tt;
25
26 t = json_tokenize(&data, &str, &v, &token_line, &token_column, &state, &line, &column);
27 tt = va_arg(ap, int);
28
29 assert_se(t == tt);
30
31 if (t == JSON_TOKEN_END || t < 0)
32 break;
33
34 else if (t == JSON_TOKEN_STRING) {
35 const char *nn;
36
37 nn = va_arg(ap, const char *);
38 assert_se(streq_ptr(nn, str));
39
40 } else if (t == JSON_TOKEN_REAL) {
41 long double d;
42
43 d = va_arg(ap, long double);
44
45 /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit:
46 * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits.
47 * Some architectures might not support long double either.
48 */
49
50 assert_se(fabsl(d - v.real) < 1e-10 ||
51 fabsl((d - v.real) / v.real) < 1e-10);
52
53 } else if (t == JSON_TOKEN_INTEGER) {
54 intmax_t i;
55
56 i = va_arg(ap, intmax_t);
57 assert_se(i == v.integer);
58
59 } else if (t == JSON_TOKEN_UNSIGNED) {
60 uintmax_t u;
61
62 u = va_arg(ap, uintmax_t);
63 assert_se(u == v.unsig);
64
65 } else if (t == JSON_TOKEN_BOOLEAN) {
66 bool b;
67
68 b = va_arg(ap, int);
69 assert_se(b == v.boolean);
70 }
71 }
72
73 va_end(ap);
74 }
75
76 typedef void (*Test)(JsonVariant *);
77
78 static void test_variant(const char *data, Test test) {
79 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
80 _cleanup_free_ char *s = NULL;
81 int r;
82
83 r = json_parse(data, &v, NULL, NULL);
84 assert_se(r == 0);
85 assert_se(v);
86
87 r = json_variant_format(v, 0, &s);
88 assert_se(r >= 0);
89 assert_se(s);
90
91 log_info("formatted normally: %s\n", s);
92
93 r = json_parse(data, &w, NULL, NULL);
94 assert_se(r == 0);
95 assert_se(w);
96 assert_se(json_variant_has_type(v, json_variant_type(w)));
97 assert_se(json_variant_has_type(w, json_variant_type(v)));
98 assert_se(json_variant_equal(v, w));
99
100 s = mfree(s);
101 w = json_variant_unref(w);
102
103 r = json_variant_format(v, JSON_FORMAT_PRETTY, &s);
104 assert_se(r >= 0);
105 assert_se(s);
106
107 log_info("formatted prettily:\n%s", s);
108
109 r = json_parse(data, &w, NULL, NULL);
110 assert_se(r == 0);
111 assert_se(w);
112
113 assert_se(json_variant_has_type(v, json_variant_type(w)));
114 assert_se(json_variant_has_type(w, json_variant_type(v)));
115 assert_se(json_variant_equal(v, w));
116
117 s = mfree(s);
118 r = json_variant_format(v, JSON_FORMAT_COLOR, &s);
119 assert_se(r >= 0);
120 assert_se(s);
121 printf("Normal with color: %s\n", s);
122
123 s = mfree(s);
124 r = json_variant_format(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, &s);
125 assert_se(r >= 0);
126 assert_se(s);
127 printf("Pretty with color:\n%s\n", s);
128
129 if (test)
130 test(v);
131 }
132
133 static void test_1(JsonVariant *v) {
134 JsonVariant *p, *q;
135 unsigned i;
136
137 /* 3 keys + 3 values */
138 assert_se(json_variant_elements(v) == 6);
139
140 /* has k */
141 p = json_variant_by_key(v, "k");
142 assert_se(p && json_variant_type(p) == JSON_VARIANT_STRING);
143
144 /* k equals v */
145 assert_se(streq(json_variant_string(p), "v"));
146
147 /* has foo */
148 p = json_variant_by_key(v, "foo");
149 assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 3);
150
151 /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
152 for (i = 0; i < 3; ++i) {
153 q = json_variant_by_index(p, i);
154 assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == (i+1));
155 assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == (i+1));
156 }
157
158 /* has bar */
159 p = json_variant_by_key(v, "bar");
160 assert_se(p && json_variant_type(p) == JSON_VARIANT_OBJECT && json_variant_elements(p) == 2);
161
162 /* zap is null */
163 q = json_variant_by_key(p, "zap");
164 assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL);
165 }
166
167 static void test_2(JsonVariant *v) {
168 JsonVariant *p, *q;
169
170 /* 2 keys + 2 values */
171 assert_se(json_variant_elements(v) == 4);
172
173 /* has mutant */
174 p = json_variant_by_key(v, "mutant");
175 assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 4);
176
177 /* mutant[0] == 1 */
178 q = json_variant_by_index(p, 0);
179 assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1);
180 assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1);
181
182 /* mutant[1] == null */
183 q = json_variant_by_index(p, 1);
184 assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL);
185
186 /* mutant[2] == "1" */
187 q = json_variant_by_index(p, 2);
188 assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
189
190 /* mutant[3] == JSON_VARIANT_OBJECT */
191 q = json_variant_by_index(p, 3);
192 assert_se(q && json_variant_type(q) == JSON_VARIANT_OBJECT && json_variant_elements(q) == 2);
193
194 /* has 1 */
195 p = json_variant_by_key(q, "1");
196 assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 2);
197
198 /* "1"[0] == 1 */
199 q = json_variant_by_index(p, 0);
200 assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1);
201 assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1);
202
203 /* "1"[1] == "1" */
204 q = json_variant_by_index(p, 1);
205 assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
206
207 /* has thisisaverylongproperty */
208 p = json_variant_by_key(v, "thisisaverylongproperty");
209 assert_se(p && json_variant_type(p) == JSON_VARIANT_REAL && fabsl(json_variant_real(p) - 1.27) < 0.001);
210 }
211
212 static void test_zeroes(JsonVariant *v) {
213 size_t i;
214
215 /* Make sure zero is how we expect it. */
216
217 assert_se(json_variant_elements(v) == 13);
218
219 for (i = 0; i < json_variant_elements(v); i++) {
220 JsonVariant *w;
221 size_t j;
222
223 assert_se(w = json_variant_by_index(v, i));
224
225 assert_se(json_variant_integer(w) == 0);
226 assert_se(json_variant_unsigned(w) == 0U);
227
228 #pragma GCC diagnostic push
229 #pragma GCC diagnostic ignored "-Wfloat-equal"
230 assert_se(json_variant_real(w) == 0.0L);
231 #pragma GCC diagnostic pop
232
233 assert_se(json_variant_is_integer(w));
234 assert_se(json_variant_is_unsigned(w));
235 assert_se(json_variant_is_real(w));
236 assert_se(json_variant_is_number(w));
237
238 assert_se(!json_variant_is_negative(w));
239
240 assert_se(IN_SET(json_variant_type(w), JSON_VARIANT_INTEGER, JSON_VARIANT_UNSIGNED, JSON_VARIANT_REAL));
241
242 for (j = 0; j < json_variant_elements(v); j++) {
243 JsonVariant *q;
244
245 assert_se(q = json_variant_by_index(v, j));
246
247 assert_se(json_variant_equal(w, q));
248 }
249 }
250 }
251
252 static void test_build(void) {
253 _cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL;
254 _cleanup_free_ char *s = NULL, *t = NULL;
255
256 assert_se(json_build(&a, JSON_BUILD_STRING("hallo")) >= 0);
257 assert_se(json_build(&b, JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0);
258 assert_se(json_variant_equal(a, b));
259
260 b = json_variant_unref(b);
261
262 assert_se(json_build(&b, JSON_BUILD_VARIANT(a)) >= 0);
263 assert_se(json_variant_equal(a, b));
264
265 b = json_variant_unref(b);
266 assert_se(json_build(&b, JSON_BUILD_STRING("pief")) >= 0);
267 assert_se(!json_variant_equal(a, b));
268
269 a = json_variant_unref(a);
270 b = json_variant_unref(b);
271
272 assert_se(json_build(&a, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("one", JSON_BUILD_INTEGER(7)),
273 JSON_BUILD_PAIR("two", JSON_BUILD_REAL(2.0)),
274 JSON_BUILD_PAIR("three", JSON_BUILD_INTEGER(0)))) >= 0);
275
276 assert_se(json_build(&b, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("two", JSON_BUILD_INTEGER(2)),
277 JSON_BUILD_PAIR("three", JSON_BUILD_REAL(0)),
278 JSON_BUILD_PAIR("one", JSON_BUILD_REAL(7)))) >= 0);
279
280 assert_se(json_variant_equal(a, b));
281
282 a = json_variant_unref(a);
283 b = json_variant_unref(b);
284
285 const char* arr_1234[] = {"one", "two", "three", "four", NULL};
286 assert_se(json_build(&a, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)),
287 JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL)))),
288 JSON_BUILD_VARIANT(NULL),
289 JSON_BUILD_LITERAL(NULL),
290 JSON_BUILD_STRING(NULL),
291 JSON_BUILD_NULL,
292 JSON_BUILD_INTEGER(77),
293 JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")),
294 JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))),
295 JSON_BUILD_STRV((char**) arr_1234))) >= 0);
296
297 assert_se(json_variant_format(a, 0, &s) >= 0);
298 log_info("GOT: %s\n", s);
299 assert_se(json_parse(s, &b, NULL, NULL) >= 0);
300 assert_se(json_variant_equal(a, b));
301
302 a = json_variant_unref(a);
303 b = json_variant_unref(b);
304
305 assert_se(json_build(&a, JSON_BUILD_REAL(M_PIl)) >= 0);
306
307 s = mfree(s);
308 assert_se(json_variant_format(a, 0, &s) >= 0);
309 log_info("GOT: %s\n", s);
310 assert_se(json_parse(s, &b, NULL, NULL) >= 0);
311 assert_se(json_variant_format(b, 0, &t) >= 0);
312 log_info("GOT: %s\n", t);
313
314 assert_se(streq(s, t));
315
316 a = json_variant_unref(a);
317 b = json_variant_unref(b);
318
319 assert_se(json_build(&a, JSON_BUILD_OBJECT(
320 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
321 JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")),
322 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
323 )) >= 0);
324
325 assert_se(json_build(&b, JSON_BUILD_OBJECT(
326 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
327 JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")),
328 JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")),
329 JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))),
330 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
331 )) >= 0);
332
333 assert_se(json_variant_equal(a, b));
334 }
335
336 static void test_source(void) {
337 static const char data[] =
338 "\n"
339 "\n"
340 "{\n"
341 "\"foo\" : \"bar\", \n"
342 "\"qüüx\" : [ 1, 2, 3,\n"
343 "4,\n"
344 "5 ],\n"
345 "\"miep\" : { \"hallo\" : 1 },\n"
346 "\n"
347 "\"zzzzzz\" \n"
348 ":\n"
349 "[ true, \n"
350 "false, 7.5, {} ]\n"
351 "}\n";
352
353 _cleanup_fclose_ FILE *f = NULL;
354 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
355
356 printf("--- original begin ---\n"
357 "%s"
358 "--- original end ---\n", data);
359
360 assert_se(f = fmemopen((void*) data, strlen(data), "r"));
361
362 assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0);
363
364 printf("--- non-pretty begin ---\n");
365 json_variant_dump(v, 0, stdout, NULL);
366 printf("\n--- non-pretty end ---\n");
367
368 printf("--- pretty begin ---\n");
369 json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, stdout, NULL);
370 printf("--- pretty end ---\n");
371 }
372
373 static void test_depth(void) {
374 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
375 unsigned i;
376 int r;
377
378 v = JSON_VARIANT_STRING_CONST("start");
379
380 /* Let's verify that the maximum depth checks work */
381
382 for (i = 0;; i++) {
383 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
384
385 assert_se(i <= UINT16_MAX);
386 if (i & 1)
387 r = json_variant_new_array(&w, &v, 1);
388 else
389 r = json_variant_new_object(&w, (JsonVariant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2);
390 if (r == -ELNRNG) {
391 log_info("max depth at %u", i);
392 break;
393 }
394
395 assert_se(r >= 0);
396
397 json_variant_unref(v);
398 v = TAKE_PTR(w);
399 }
400
401 json_variant_dump(v, 0, stdout, NULL);
402 fputs("\n", stdout);
403 }
404
405 int main(int argc, char *argv[]) {
406
407 log_set_max_level(LOG_DEBUG);
408 log_parse_environment();
409 log_open();
410
411 test_tokenizer("x", -EINVAL);
412 test_tokenizer("", JSON_TOKEN_END);
413 test_tokenizer(" ", JSON_TOKEN_END);
414 test_tokenizer("0", JSON_TOKEN_UNSIGNED, (uintmax_t) 0, JSON_TOKEN_END);
415 test_tokenizer("-0", JSON_TOKEN_INTEGER, (intmax_t) 0, JSON_TOKEN_END);
416 test_tokenizer("1234", JSON_TOKEN_UNSIGNED, (uintmax_t) 1234, JSON_TOKEN_END);
417 test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
418 test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED, (uintmax_t) UINT64_MAX, JSON_TOKEN_END);
419 test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER, (intmax_t) INT64_MIN, JSON_TOKEN_END);
420 test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (long double) 18446744073709551616.0L, JSON_TOKEN_END);
421 test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (long double) -9223372036854775809.0L, JSON_TOKEN_END);
422 test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
423 test_tokenizer("3.141", JSON_TOKEN_REAL, (long double) 3.141, JSON_TOKEN_END);
424 test_tokenizer("0.0", JSON_TOKEN_REAL, (long double) 0.0, JSON_TOKEN_END);
425 test_tokenizer("7e3", JSON_TOKEN_REAL, (long double) 7e3, JSON_TOKEN_END);
426 test_tokenizer("-7e-3", JSON_TOKEN_REAL, (long double) -7e-3, JSON_TOKEN_END);
427 test_tokenizer("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END);
428 test_tokenizer("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END);
429 test_tokenizer("null", JSON_TOKEN_NULL, JSON_TOKEN_END);
430 test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
431 test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
432 test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
433 test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
434 test_tokenizer("\"\"", JSON_TOKEN_STRING, "", JSON_TOKEN_END);
435 test_tokenizer("\"foo\"", JSON_TOKEN_STRING, "foo", JSON_TOKEN_END);
436 test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING, "foo\nfoo", JSON_TOKEN_END);
437 test_tokenizer("{\"foo\" : \"bar\"}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_STRING, "foo", JSON_TOKEN_COLON, JSON_TOKEN_STRING, "bar", JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
438 test_tokenizer("{\"foo\" : [true, false]}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_STRING, "foo", JSON_TOKEN_COLON, JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_COMMA, JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
439 test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
440 test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
441 test_tokenizer("\"\\uf\"", -EINVAL);
442 test_tokenizer("\"\\ud800a\"", -EINVAL);
443 test_tokenizer("\"\\udc00\\udc00\"", -EINVAL);
444 test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING, "\xf0\x90\x90\xb7", JSON_TOKEN_END);
445
446 test_tokenizer("[1, 2, -3]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_UNSIGNED, (uintmax_t) 1, JSON_TOKEN_COMMA, JSON_TOKEN_UNSIGNED, (uintmax_t) 2, JSON_TOKEN_COMMA, JSON_TOKEN_INTEGER, (intmax_t) -3, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
447
448 test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
449 test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2);
450 test_variant("{\"foo\" : \"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFF\"}", NULL);
451
452 test_variant("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes);
453
454 test_build();
455
456 test_source();
457
458 test_depth();
459
460 return 0;
461 }