]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-json.c
Merge pull request #11375 from daxtens/issue5882
[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 assert_se(json_build(&a, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)),
286 JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL)))),
287 JSON_BUILD_VARIANT(NULL),
288 JSON_BUILD_LITERAL(NULL),
289 JSON_BUILD_STRING(NULL),
290 JSON_BUILD_NULL,
291 JSON_BUILD_INTEGER(77),
292 JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")), JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))),
293 JSON_BUILD_STRV(STRV_MAKE("one", "two", "three", "four")))) >= 0);
294
295 assert_se(json_variant_format(a, 0, &s) >= 0);
296 log_info("GOT: %s\n", s);
297 assert_se(json_parse(s, &b, NULL, NULL) >= 0);
298 assert_se(json_variant_equal(a, b));
299
300 a = json_variant_unref(a);
301 b = json_variant_unref(b);
302
303 assert_se(json_build(&a, JSON_BUILD_REAL(M_PIl)) >= 0);
304
305 s = mfree(s);
306 assert_se(json_variant_format(a, 0, &s) >= 0);
307 log_info("GOT: %s\n", s);
308 assert_se(json_parse(s, &b, NULL, NULL) >= 0);
309 assert_se(json_variant_format(b, 0, &t) >= 0);
310 log_info("GOT: %s\n", t);
311
312 assert_se(streq(s, t));
313
314 a = json_variant_unref(a);
315 b = json_variant_unref(b);
316
317 assert_se(json_build(&a, JSON_BUILD_OBJECT(
318 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
319 JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")),
320 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
321 )) >= 0);
322
323 assert_se(json_build(&b, JSON_BUILD_OBJECT(
324 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
325 JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")),
326 JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")),
327 JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))),
328 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
329 )) >= 0);
330
331 assert_se(json_variant_equal(a, b));
332 }
333
334 static void test_source(void) {
335 static const char data[] =
336 "\n"
337 "\n"
338 "{\n"
339 "\"foo\" : \"bar\", \n"
340 "\"qüüx\" : [ 1, 2, 3,\n"
341 "4,\n"
342 "5 ],\n"
343 "\"miep\" : { \"hallo\" : 1 },\n"
344 "\n"
345 "\"zzzzzz\" \n"
346 ":\n"
347 "[ true, \n"
348 "false, 7.5, {} ]\n"
349 "}\n";
350
351 _cleanup_fclose_ FILE *f = NULL;
352 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
353
354 printf("--- original begin ---\n"
355 "%s"
356 "--- original end ---\n", data);
357
358 assert_se(f = fmemopen((void*) data, strlen(data), "r"));
359
360 assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0);
361
362 printf("--- non-pretty begin ---\n");
363 json_variant_dump(v, 0, stdout, NULL);
364 printf("\n--- non-pretty end ---\n");
365
366 printf("--- pretty begin ---\n");
367 json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, stdout, NULL);
368 printf("--- pretty end ---\n");
369 }
370
371 static void test_depth(void) {
372 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
373 unsigned i;
374 int r;
375
376 v = JSON_VARIANT_STRING_CONST("start");
377
378 /* Let's verify that the maximum depth checks work */
379
380 for (i = 0;; i++) {
381 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
382
383 assert_se(i <= UINT16_MAX);
384 if (i & 1)
385 r = json_variant_new_array(&w, &v, 1);
386 else
387 r = json_variant_new_object(&w, (JsonVariant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2);
388 if (r == -ELNRNG) {
389 log_info("max depth at %u", i);
390 break;
391 }
392
393 assert_se(r >= 0);
394
395 json_variant_unref(v);
396 v = TAKE_PTR(w);
397 }
398
399 json_variant_dump(v, 0, stdout, NULL);
400 fputs("\n", stdout);
401 }
402
403 int main(int argc, char *argv[]) {
404
405 log_set_max_level(LOG_DEBUG);
406 log_parse_environment();
407 log_open();
408
409 test_tokenizer("x", -EINVAL);
410 test_tokenizer("", JSON_TOKEN_END);
411 test_tokenizer(" ", JSON_TOKEN_END);
412 test_tokenizer("0", JSON_TOKEN_UNSIGNED, (uintmax_t) 0, JSON_TOKEN_END);
413 test_tokenizer("-0", JSON_TOKEN_INTEGER, (intmax_t) 0, JSON_TOKEN_END);
414 test_tokenizer("1234", JSON_TOKEN_UNSIGNED, (uintmax_t) 1234, JSON_TOKEN_END);
415 test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
416 test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED, (uintmax_t) UINT64_MAX, JSON_TOKEN_END);
417 test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER, (intmax_t) INT64_MIN, JSON_TOKEN_END);
418 test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (long double) 18446744073709551616.0L, JSON_TOKEN_END);
419 test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (long double) -9223372036854775809.0L, JSON_TOKEN_END);
420 test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
421 test_tokenizer("3.141", JSON_TOKEN_REAL, (long double) 3.141, JSON_TOKEN_END);
422 test_tokenizer("0.0", JSON_TOKEN_REAL, (long double) 0.0, JSON_TOKEN_END);
423 test_tokenizer("7e3", JSON_TOKEN_REAL, (long double) 7e3, JSON_TOKEN_END);
424 test_tokenizer("-7e-3", JSON_TOKEN_REAL, (long double) -7e-3, JSON_TOKEN_END);
425 test_tokenizer("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END);
426 test_tokenizer("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END);
427 test_tokenizer("null", JSON_TOKEN_NULL, JSON_TOKEN_END);
428 test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
429 test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
430 test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
431 test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
432 test_tokenizer("\"\"", JSON_TOKEN_STRING, "", JSON_TOKEN_END);
433 test_tokenizer("\"foo\"", JSON_TOKEN_STRING, "foo", JSON_TOKEN_END);
434 test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING, "foo\nfoo", JSON_TOKEN_END);
435 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);
436 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);
437 test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
438 test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
439 test_tokenizer("\"\\uf\"", -EINVAL);
440 test_tokenizer("\"\\ud800a\"", -EINVAL);
441 test_tokenizer("\"\\udc00\\udc00\"", -EINVAL);
442 test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING, "\xf0\x90\x90\xb7", JSON_TOKEN_END);
443
444 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);
445
446 test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
447 test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2);
448 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);
449
450 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);
451
452 test_build();
453
454 test_source();
455
456 test_depth();
457
458 return 0;
459 }