]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-json.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
7 #include "json-internal.h"
9 #include "string-util.h"
14 static void test_tokenizer(const char *data
, ...) {
15 unsigned line
= 0, column
= 0;
22 unsigned token_line
, token_column
;
23 _cleanup_free_
char *str
= NULL
;
24 JsonValue v
= JSON_VALUE_NULL
;
27 t
= json_tokenize(&data
, &str
, &v
, &token_line
, &token_column
, &state
, &line
, &column
);
32 if (t
== JSON_TOKEN_END
|| t
< 0)
35 else if (t
== JSON_TOKEN_STRING
) {
38 nn
= va_arg(ap
, const char *);
39 assert_se(streq_ptr(nn
, str
));
41 } else if (t
== JSON_TOKEN_REAL
) {
44 d
= va_arg(ap
, long double);
46 /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit:
47 * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits.
48 * Some architectures might not support long double either.
51 assert_se(fabsl(d
- v
.real
) < 1e-10 ||
52 fabsl((d
- v
.real
) / v
.real
) < 1e-10);
54 } else if (t
== JSON_TOKEN_INTEGER
) {
57 i
= va_arg(ap
, intmax_t);
58 assert_se(i
== v
.integer
);
60 } else if (t
== JSON_TOKEN_UNSIGNED
) {
63 u
= va_arg(ap
, uintmax_t);
64 assert_se(u
== v
.unsig
);
66 } else if (t
== JSON_TOKEN_BOOLEAN
) {
70 assert_se(b
== v
.boolean
);
77 typedef void (*Test
)(JsonVariant
*);
79 static void test_variant(const char *data
, Test test
) {
80 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
81 _cleanup_free_
char *s
= NULL
;
84 r
= json_parse(data
, &v
, NULL
, NULL
);
88 r
= json_variant_format(v
, 0, &s
);
92 log_info("formatted normally: %s\n", s
);
94 r
= json_parse(data
, &w
, NULL
, NULL
);
97 assert_se(json_variant_has_type(v
, json_variant_type(w
)));
98 assert_se(json_variant_has_type(w
, json_variant_type(v
)));
99 assert_se(json_variant_equal(v
, w
));
102 w
= json_variant_unref(w
);
104 r
= json_variant_format(v
, JSON_FORMAT_PRETTY
, &s
);
108 log_info("formatted prettily:\n%s", s
);
110 r
= json_parse(data
, &w
, NULL
, NULL
);
114 assert_se(json_variant_has_type(v
, json_variant_type(w
)));
115 assert_se(json_variant_has_type(w
, json_variant_type(v
)));
116 assert_se(json_variant_equal(v
, w
));
119 r
= json_variant_format(v
, JSON_FORMAT_COLOR
, &s
);
122 printf("Normal with color: %s\n", s
);
125 r
= json_variant_format(v
, JSON_FORMAT_COLOR
|JSON_FORMAT_PRETTY
, &s
);
128 printf("Pretty with color:\n%s\n", s
);
134 static void test_1(JsonVariant
*v
) {
138 /* 3 keys + 3 values */
139 assert_se(json_variant_elements(v
) == 6);
142 p
= json_variant_by_key(v
, "k");
143 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_STRING
);
146 assert_se(streq(json_variant_string(p
), "v"));
149 p
= json_variant_by_key(v
, "foo");
150 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 3);
152 /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
153 for (i
= 0; i
< 3; ++i
) {
154 q
= json_variant_by_index(p
, i
);
155 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == (i
+1));
156 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == (i
+1));
160 p
= json_variant_by_key(v
, "bar");
161 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_OBJECT
&& json_variant_elements(p
) == 2);
164 q
= json_variant_by_key(p
, "zap");
165 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_NULL
);
168 static void test_2(JsonVariant
*v
) {
171 /* 2 keys + 2 values */
172 assert_se(json_variant_elements(v
) == 4);
175 p
= json_variant_by_key(v
, "mutant");
176 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 4);
179 q
= json_variant_by_index(p
, 0);
180 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == 1);
181 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == 1);
183 /* mutant[1] == null */
184 q
= json_variant_by_index(p
, 1);
185 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_NULL
);
187 /* mutant[2] == "1" */
188 q
= json_variant_by_index(p
, 2);
189 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_STRING
&& streq(json_variant_string(q
), "1"));
191 /* mutant[3] == JSON_VARIANT_OBJECT */
192 q
= json_variant_by_index(p
, 3);
193 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_OBJECT
&& json_variant_elements(q
) == 2);
196 p
= json_variant_by_key(q
, "1");
197 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 2);
200 q
= json_variant_by_index(p
, 0);
201 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == 1);
202 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == 1);
205 q
= json_variant_by_index(p
, 1);
206 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_STRING
&& streq(json_variant_string(q
), "1"));
208 /* has thisisaverylongproperty */
209 p
= json_variant_by_key(v
, "thisisaverylongproperty");
210 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_REAL
&& fabsl(json_variant_real(p
) - 1.27) < 0.001);
213 static void test_zeroes(JsonVariant
*v
) {
216 /* Make sure zero is how we expect it. */
218 assert_se(json_variant_elements(v
) == 13);
220 for (i
= 0; i
< json_variant_elements(v
); i
++) {
224 assert_se(w
= json_variant_by_index(v
, i
));
226 assert_se(json_variant_integer(w
) == 0);
227 assert_se(json_variant_unsigned(w
) == 0U);
229 #pragma GCC diagnostic push
230 #pragma GCC diagnostic ignored "-Wfloat-equal"
231 assert_se(json_variant_real(w
) == 0.0L);
232 #pragma GCC diagnostic pop
234 assert_se(json_variant_is_integer(w
));
235 assert_se(json_variant_is_unsigned(w
));
236 assert_se(json_variant_is_real(w
));
237 assert_se(json_variant_is_number(w
));
239 assert_se(!json_variant_is_negative(w
));
241 assert_se(IN_SET(json_variant_type(w
), JSON_VARIANT_INTEGER
, JSON_VARIANT_UNSIGNED
, JSON_VARIANT_REAL
));
243 for (j
= 0; j
< json_variant_elements(v
); j
++) {
246 assert_se(q
= json_variant_by_index(v
, j
));
248 assert_se(json_variant_equal(w
, q
));
253 static void test_build(void) {
254 _cleanup_(json_variant_unrefp
) JsonVariant
*a
= NULL
, *b
= NULL
;
255 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
257 assert_se(json_build(&a
, JSON_BUILD_STRING("hallo")) >= 0);
258 assert_se(json_build(&b
, JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0);
259 assert_se(json_variant_equal(a
, b
));
261 b
= json_variant_unref(b
);
263 assert_se(json_build(&b
, JSON_BUILD_VARIANT(a
)) >= 0);
264 assert_se(json_variant_equal(a
, b
));
266 b
= json_variant_unref(b
);
267 assert_se(json_build(&b
, JSON_BUILD_STRING("pief")) >= 0);
268 assert_se(!json_variant_equal(a
, b
));
270 a
= json_variant_unref(a
);
271 b
= json_variant_unref(b
);
273 assert_se(json_build(&a
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("one", JSON_BUILD_INTEGER(7)),
274 JSON_BUILD_PAIR("two", JSON_BUILD_REAL(2.0)),
275 JSON_BUILD_PAIR("three", JSON_BUILD_INTEGER(0)))) >= 0);
277 assert_se(json_build(&b
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("two", JSON_BUILD_INTEGER(2)),
278 JSON_BUILD_PAIR("three", JSON_BUILD_REAL(0)),
279 JSON_BUILD_PAIR("one", JSON_BUILD_REAL(7)))) >= 0);
281 assert_se(json_variant_equal(a
, b
));
283 a
= json_variant_unref(a
);
284 b
= json_variant_unref(b
);
286 const char* arr_1234
[] = {"one", "two", "three", "four", NULL
};
287 assert_se(json_build(&a
, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)),
288 JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL
)))),
289 JSON_BUILD_VARIANT(NULL
),
290 JSON_BUILD_LITERAL(NULL
),
291 JSON_BUILD_STRING(NULL
),
293 JSON_BUILD_INTEGER(77),
294 JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")),
295 JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))),
296 JSON_BUILD_STRV((char**) arr_1234
))) >= 0);
298 assert_se(json_variant_format(a
, 0, &s
) >= 0);
299 log_info("GOT: %s\n", s
);
300 assert_se(json_parse(s
, &b
, NULL
, NULL
) >= 0);
301 assert_se(json_variant_equal(a
, b
));
303 a
= json_variant_unref(a
);
304 b
= json_variant_unref(b
);
306 assert_se(json_build(&a
, JSON_BUILD_REAL(M_PIl
)) >= 0);
309 assert_se(json_variant_format(a
, 0, &s
) >= 0);
310 log_info("GOT: %s\n", s
);
311 assert_se(json_parse(s
, &b
, NULL
, NULL
) >= 0);
312 assert_se(json_variant_format(b
, 0, &t
) >= 0);
313 log_info("GOT: %s\n", t
);
315 assert_se(streq(s
, t
));
317 a
= json_variant_unref(a
);
318 b
= json_variant_unref(b
);
320 assert_se(json_build(&a
, JSON_BUILD_OBJECT(
321 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
322 JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")),
323 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
326 assert_se(json_build(&b
, JSON_BUILD_OBJECT(
327 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
328 JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")),
329 JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")),
330 JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))),
331 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
334 assert_se(json_variant_equal(a
, b
));
337 static void test_source(void) {
338 static const char data
[] =
342 "\"foo\" : \"bar\", \n"
343 "\"qüüx\" : [ 1, 2, 3,\n"
346 "\"miep\" : { \"hallo\" : 1 },\n"
354 _cleanup_fclose_
FILE *f
= NULL
;
355 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
357 printf("--- original begin ---\n"
359 "--- original end ---\n", data
);
361 assert_se(f
= fmemopen((void*) data
, strlen(data
), "r"));
363 assert_se(json_parse_file(f
, "waldo", &v
, NULL
, NULL
) >= 0);
365 printf("--- non-pretty begin ---\n");
366 json_variant_dump(v
, 0, stdout
, NULL
);
367 printf("\n--- non-pretty end ---\n");
369 printf("--- pretty begin ---\n");
370 json_variant_dump(v
, JSON_FORMAT_PRETTY
|JSON_FORMAT_COLOR
|JSON_FORMAT_SOURCE
, stdout
, NULL
);
371 printf("--- pretty end ---\n");
374 static void test_depth(void) {
375 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
379 v
= JSON_VARIANT_STRING_CONST("start");
381 /* Let's verify that the maximum depth checks work */
384 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
386 assert_se(i
<= UINT16_MAX
);
388 r
= json_variant_new_array(&w
, &v
, 1);
390 r
= json_variant_new_object(&w
, (JsonVariant
*[]) { JSON_VARIANT_STRING_CONST("key"), v
}, 2);
392 log_info("max depth at %u", i
);
395 #if HAS_FEATURE_MEMORY_SANITIZER
396 /* msan doesn't like the stack nesting to be too deep. Let's quit early. */
398 log_info("quitting early at depth %u", i
);
405 json_variant_unref(v
);
409 json_variant_dump(v
, 0, stdout
, NULL
);
413 int main(int argc
, char *argv
[]) {
414 test_setup_logging(LOG_DEBUG
);
416 test_tokenizer("x", -EINVAL
);
417 test_tokenizer("", JSON_TOKEN_END
);
418 test_tokenizer(" ", JSON_TOKEN_END
);
419 test_tokenizer("0", JSON_TOKEN_UNSIGNED
, (uintmax_t) 0, JSON_TOKEN_END
);
420 test_tokenizer("-0", JSON_TOKEN_INTEGER
, (intmax_t) 0, JSON_TOKEN_END
);
421 test_tokenizer("1234", JSON_TOKEN_UNSIGNED
, (uintmax_t) 1234, JSON_TOKEN_END
);
422 test_tokenizer("-1234", JSON_TOKEN_INTEGER
, (intmax_t) -1234, JSON_TOKEN_END
);
423 test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED
, (uintmax_t) UINT64_MAX
, JSON_TOKEN_END
);
424 test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER
, (intmax_t) INT64_MIN
, JSON_TOKEN_END
);
425 test_tokenizer("18446744073709551616", JSON_TOKEN_REAL
, (long double) 18446744073709551616.0L, JSON_TOKEN_END
);
426 test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL
, (long double) -9223372036854775809.0L, JSON_TOKEN_END
);
427 test_tokenizer("-1234", JSON_TOKEN_INTEGER
, (intmax_t) -1234, JSON_TOKEN_END
);
428 test_tokenizer("3.141", JSON_TOKEN_REAL
, (long double) 3.141, JSON_TOKEN_END
);
429 test_tokenizer("0.0", JSON_TOKEN_REAL
, (long double) 0.0, JSON_TOKEN_END
);
430 test_tokenizer("7e3", JSON_TOKEN_REAL
, (long double) 7e3
, JSON_TOKEN_END
);
431 test_tokenizer("-7e-3", JSON_TOKEN_REAL
, (long double) -7e-3, JSON_TOKEN_END
);
432 test_tokenizer("true", JSON_TOKEN_BOOLEAN
, true, JSON_TOKEN_END
);
433 test_tokenizer("false", JSON_TOKEN_BOOLEAN
, false, JSON_TOKEN_END
);
434 test_tokenizer("null", JSON_TOKEN_NULL
, JSON_TOKEN_END
);
435 test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN
, JSON_TOKEN_OBJECT_CLOSE
, JSON_TOKEN_END
);
436 test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN
, JSON_TOKEN_OBJECT_CLOSE
, JSON_TOKEN_END
);
437 test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN
, JSON_TOKEN_ARRAY_CLOSE
, JSON_TOKEN_END
);
438 test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN
, JSON_TOKEN_ARRAY_CLOSE
, JSON_TOKEN_END
);
439 test_tokenizer("\"\"", JSON_TOKEN_STRING
, "", JSON_TOKEN_END
);
440 test_tokenizer("\"foo\"", JSON_TOKEN_STRING
, "foo", JSON_TOKEN_END
);
441 test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING
, "foo\nfoo", JSON_TOKEN_END
);
442 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
);
443 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
);
444 test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING
, "\xef\xbf\xbd", JSON_TOKEN_END
);
445 test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING
, "\xef\xbf\xbd", JSON_TOKEN_END
);
446 test_tokenizer("\"\\uf\"", -EINVAL
);
447 test_tokenizer("\"\\ud800a\"", -EINVAL
);
448 test_tokenizer("\"\\udc00\\udc00\"", -EINVAL
);
449 test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING
, "\xf0\x90\x90\xb7", JSON_TOKEN_END
);
451 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
);
453 test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1
);
454 test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2
);
455 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
);
457 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
);