]>
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"
8 #include "json-internal.h"
10 #include "string-util.h"
15 static void test_tokenizer(const char *data
, ...) {
16 unsigned line
= 0, column
= 0;
23 unsigned token_line
, token_column
;
24 _cleanup_free_
char *str
= NULL
;
25 JsonValue v
= JSON_VALUE_NULL
;
28 t
= json_tokenize(&data
, &str
, &v
, &token_line
, &token_column
, &state
, &line
, &column
);
33 if (t
== JSON_TOKEN_END
|| t
< 0)
36 else if (t
== JSON_TOKEN_STRING
) {
39 nn
= va_arg(ap
, const char *);
40 assert_se(streq_ptr(nn
, str
));
42 } else if (t
== JSON_TOKEN_REAL
) {
45 d
= va_arg(ap
, long double);
47 /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit:
48 * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits.
49 * Some architectures might not support long double either.
52 assert_se(fabsl(d
- v
.real
) < 1e-10 ||
53 fabsl((d
- v
.real
) / v
.real
) < 1e-10);
55 } else if (t
== JSON_TOKEN_INTEGER
) {
58 i
= va_arg(ap
, intmax_t);
59 assert_se(i
== v
.integer
);
61 } else if (t
== JSON_TOKEN_UNSIGNED
) {
64 u
= va_arg(ap
, uintmax_t);
65 assert_se(u
== v
.unsig
);
67 } else if (t
== JSON_TOKEN_BOOLEAN
) {
71 assert_se(b
== v
.boolean
);
78 typedef void (*Test
)(JsonVariant
*);
80 static void test_variant(const char *data
, Test test
) {
81 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
82 _cleanup_free_
char *s
= NULL
;
85 r
= json_parse(data
, &v
, NULL
, NULL
);
89 r
= json_variant_format(v
, 0, &s
);
93 log_info("formatted normally: %s\n", s
);
95 r
= json_parse(data
, &w
, NULL
, NULL
);
98 assert_se(json_variant_has_type(v
, json_variant_type(w
)));
99 assert_se(json_variant_has_type(w
, json_variant_type(v
)));
100 assert_se(json_variant_equal(v
, w
));
103 w
= json_variant_unref(w
);
105 r
= json_variant_format(v
, JSON_FORMAT_PRETTY
, &s
);
109 log_info("formatted prettily:\n%s", s
);
111 r
= json_parse(data
, &w
, NULL
, NULL
);
115 assert_se(json_variant_has_type(v
, json_variant_type(w
)));
116 assert_se(json_variant_has_type(w
, json_variant_type(v
)));
117 assert_se(json_variant_equal(v
, w
));
120 r
= json_variant_format(v
, JSON_FORMAT_COLOR
, &s
);
123 printf("Normal with color: %s\n", s
);
126 r
= json_variant_format(v
, JSON_FORMAT_COLOR
|JSON_FORMAT_PRETTY
, &s
);
129 printf("Pretty with color:\n%s\n", s
);
135 static void test_1(JsonVariant
*v
) {
139 /* 3 keys + 3 values */
140 assert_se(json_variant_elements(v
) == 6);
143 p
= json_variant_by_key(v
, "k");
144 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_STRING
);
147 assert_se(streq(json_variant_string(p
), "v"));
150 p
= json_variant_by_key(v
, "foo");
151 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 3);
153 /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
154 for (i
= 0; i
< 3; ++i
) {
155 q
= json_variant_by_index(p
, i
);
156 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == (i
+1));
157 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == (i
+1));
161 p
= json_variant_by_key(v
, "bar");
162 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_OBJECT
&& json_variant_elements(p
) == 2);
165 q
= json_variant_by_key(p
, "zap");
166 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_NULL
);
169 static void test_2(JsonVariant
*v
) {
172 /* 2 keys + 2 values */
173 assert_se(json_variant_elements(v
) == 4);
176 p
= json_variant_by_key(v
, "mutant");
177 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 4);
180 q
= json_variant_by_index(p
, 0);
181 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == 1);
182 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == 1);
184 /* mutant[1] == null */
185 q
= json_variant_by_index(p
, 1);
186 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_NULL
);
188 /* mutant[2] == "1" */
189 q
= json_variant_by_index(p
, 2);
190 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_STRING
&& streq(json_variant_string(q
), "1"));
192 /* mutant[3] == JSON_VARIANT_OBJECT */
193 q
= json_variant_by_index(p
, 3);
194 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_OBJECT
&& json_variant_elements(q
) == 2);
197 p
= json_variant_by_key(q
, "1");
198 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_ARRAY
&& json_variant_elements(p
) == 2);
201 q
= json_variant_by_index(p
, 0);
202 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_UNSIGNED
&& json_variant_unsigned(q
) == 1);
203 assert_se(q
&& json_variant_has_type(q
, JSON_VARIANT_INTEGER
) && json_variant_integer(q
) == 1);
206 q
= json_variant_by_index(p
, 1);
207 assert_se(q
&& json_variant_type(q
) == JSON_VARIANT_STRING
&& streq(json_variant_string(q
), "1"));
209 /* has thisisaverylongproperty */
210 p
= json_variant_by_key(v
, "thisisaverylongproperty");
211 assert_se(p
&& json_variant_type(p
) == JSON_VARIANT_REAL
&& fabsl(json_variant_real(p
) - 1.27) < 0.001);
214 static void test_zeroes(JsonVariant
*v
) {
217 /* Make sure zero is how we expect it. */
219 assert_se(json_variant_elements(v
) == 13);
221 for (i
= 0; i
< json_variant_elements(v
); i
++) {
225 assert_se(w
= json_variant_by_index(v
, i
));
227 assert_se(json_variant_integer(w
) == 0);
228 assert_se(json_variant_unsigned(w
) == 0U);
230 #pragma GCC diagnostic push
231 #pragma GCC diagnostic ignored "-Wfloat-equal"
232 assert_se(json_variant_real(w
) == 0.0L);
233 #pragma GCC diagnostic pop
235 assert_se(json_variant_is_integer(w
));
236 assert_se(json_variant_is_unsigned(w
));
237 assert_se(json_variant_is_real(w
));
238 assert_se(json_variant_is_number(w
));
240 assert_se(!json_variant_is_negative(w
));
242 assert_se(IN_SET(json_variant_type(w
), JSON_VARIANT_INTEGER
, JSON_VARIANT_UNSIGNED
, JSON_VARIANT_REAL
));
244 for (j
= 0; j
< json_variant_elements(v
); j
++) {
247 assert_se(q
= json_variant_by_index(v
, j
));
249 assert_se(json_variant_equal(w
, q
));
254 static void test_build(void) {
255 _cleanup_(json_variant_unrefp
) JsonVariant
*a
= NULL
, *b
= NULL
;
256 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
258 assert_se(json_build(&a
, JSON_BUILD_STRING("hallo")) >= 0);
259 assert_se(json_build(&b
, JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0);
260 assert_se(json_variant_equal(a
, b
));
262 b
= json_variant_unref(b
);
264 assert_se(json_build(&b
, JSON_BUILD_VARIANT(a
)) >= 0);
265 assert_se(json_variant_equal(a
, b
));
267 b
= json_variant_unref(b
);
268 assert_se(json_build(&b
, JSON_BUILD_STRING("pief")) >= 0);
269 assert_se(!json_variant_equal(a
, b
));
271 a
= json_variant_unref(a
);
272 b
= json_variant_unref(b
);
274 assert_se(json_build(&a
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("one", JSON_BUILD_INTEGER(7)),
275 JSON_BUILD_PAIR("two", JSON_BUILD_REAL(2.0)),
276 JSON_BUILD_PAIR("three", JSON_BUILD_INTEGER(0)))) >= 0);
278 assert_se(json_build(&b
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("two", JSON_BUILD_INTEGER(2)),
279 JSON_BUILD_PAIR("three", JSON_BUILD_REAL(0)),
280 JSON_BUILD_PAIR("one", JSON_BUILD_REAL(7)))) >= 0);
282 assert_se(json_variant_equal(a
, b
));
284 a
= json_variant_unref(a
);
285 b
= json_variant_unref(b
);
287 const char* arr_1234
[] = {"one", "two", "three", "four", NULL
};
288 assert_se(json_build(&a
, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)),
289 JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL
)))),
290 JSON_BUILD_VARIANT(NULL
),
291 JSON_BUILD_LITERAL(NULL
),
292 JSON_BUILD_STRING(NULL
),
294 JSON_BUILD_INTEGER(77),
295 JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")),
296 JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))),
297 JSON_BUILD_STRV((char**) arr_1234
))) >= 0);
299 assert_se(json_variant_format(a
, 0, &s
) >= 0);
300 log_info("GOT: %s\n", s
);
301 assert_se(json_parse(s
, &b
, NULL
, NULL
) >= 0);
302 assert_se(json_variant_equal(a
, b
));
304 a
= json_variant_unref(a
);
305 b
= json_variant_unref(b
);
307 assert_se(json_build(&a
, JSON_BUILD_REAL(M_PIl
)) >= 0);
310 assert_se(json_variant_format(a
, 0, &s
) >= 0);
311 log_info("GOT: %s\n", s
);
312 assert_se(json_parse(s
, &b
, NULL
, NULL
) >= 0);
313 assert_se(json_variant_format(b
, 0, &t
) >= 0);
314 log_info("GOT: %s\n", t
);
316 assert_se(streq(s
, t
));
318 a
= json_variant_unref(a
);
319 b
= json_variant_unref(b
);
321 assert_se(json_build(&a
, JSON_BUILD_OBJECT(
322 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
323 JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")),
324 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
327 assert_se(json_build(&b
, JSON_BUILD_OBJECT(
328 JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
329 JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")),
330 JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")),
331 JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))),
332 JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
335 assert_se(json_variant_equal(a
, b
));
338 static void test_source(void) {
339 static const char data
[] =
343 "\"foo\" : \"bar\", \n"
344 "\"qüüx\" : [ 1, 2, 3,\n"
347 "\"miep\" : { \"hallo\" : 1 },\n"
355 _cleanup_fclose_
FILE *f
= NULL
;
356 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
358 printf("--- original begin ---\n"
360 "--- original end ---\n", data
);
362 assert_se(f
= fmemopen_unlocked((void*) data
, strlen(data
), "r"));
364 assert_se(json_parse_file(f
, "waldo", &v
, NULL
, NULL
) >= 0);
366 printf("--- non-pretty begin ---\n");
367 json_variant_dump(v
, 0, stdout
, NULL
);
368 printf("\n--- non-pretty end ---\n");
370 printf("--- pretty begin ---\n");
371 json_variant_dump(v
, JSON_FORMAT_PRETTY
|JSON_FORMAT_COLOR
|JSON_FORMAT_SOURCE
, stdout
, NULL
);
372 printf("--- pretty end ---\n");
375 static void test_depth(void) {
376 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
380 v
= JSON_VARIANT_STRING_CONST("start");
382 /* Let's verify that the maximum depth checks work */
385 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
387 assert_se(i
<= UINT16_MAX
);
389 r
= json_variant_new_array(&w
, &v
, 1);
391 r
= json_variant_new_object(&w
, (JsonVariant
*[]) { JSON_VARIANT_STRING_CONST("key"), v
}, 2);
393 log_info("max depth at %u", i
);
396 #if HAS_FEATURE_MEMORY_SANITIZER
397 /* msan doesn't like the stack nesting to be too deep. Let's quit early. */
399 log_info("quitting early at depth %u", i
);
406 json_variant_unref(v
);
410 json_variant_dump(v
, 0, stdout
, NULL
);
414 int main(int argc
, char *argv
[]) {
415 test_setup_logging(LOG_DEBUG
);
417 test_tokenizer("x", -EINVAL
);
418 test_tokenizer("", JSON_TOKEN_END
);
419 test_tokenizer(" ", JSON_TOKEN_END
);
420 test_tokenizer("0", JSON_TOKEN_UNSIGNED
, (uintmax_t) 0, JSON_TOKEN_END
);
421 test_tokenizer("-0", JSON_TOKEN_INTEGER
, (intmax_t) 0, JSON_TOKEN_END
);
422 test_tokenizer("1234", JSON_TOKEN_UNSIGNED
, (uintmax_t) 1234, JSON_TOKEN_END
);
423 test_tokenizer("-1234", JSON_TOKEN_INTEGER
, (intmax_t) -1234, JSON_TOKEN_END
);
424 test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED
, (uintmax_t) UINT64_MAX
, JSON_TOKEN_END
);
425 test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER
, (intmax_t) INT64_MIN
, JSON_TOKEN_END
);
426 test_tokenizer("18446744073709551616", JSON_TOKEN_REAL
, (long double) 18446744073709551616.0L, JSON_TOKEN_END
);
427 test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL
, (long double) -9223372036854775809.0L, JSON_TOKEN_END
);
428 test_tokenizer("-1234", JSON_TOKEN_INTEGER
, (intmax_t) -1234, JSON_TOKEN_END
);
429 test_tokenizer("3.141", JSON_TOKEN_REAL
, (long double) 3.141, JSON_TOKEN_END
);
430 test_tokenizer("0.0", JSON_TOKEN_REAL
, (long double) 0.0, JSON_TOKEN_END
);
431 test_tokenizer("7e3", JSON_TOKEN_REAL
, (long double) 7e3
, JSON_TOKEN_END
);
432 test_tokenizer("-7e-3", JSON_TOKEN_REAL
, (long double) -7e-3, JSON_TOKEN_END
);
433 test_tokenizer("true", JSON_TOKEN_BOOLEAN
, true, JSON_TOKEN_END
);
434 test_tokenizer("false", JSON_TOKEN_BOOLEAN
, false, JSON_TOKEN_END
);
435 test_tokenizer("null", JSON_TOKEN_NULL
, JSON_TOKEN_END
);
436 test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN
, JSON_TOKEN_OBJECT_CLOSE
, JSON_TOKEN_END
);
437 test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN
, JSON_TOKEN_OBJECT_CLOSE
, JSON_TOKEN_END
);
438 test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN
, JSON_TOKEN_ARRAY_CLOSE
, JSON_TOKEN_END
);
439 test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN
, JSON_TOKEN_ARRAY_CLOSE
, JSON_TOKEN_END
);
440 test_tokenizer("\"\"", JSON_TOKEN_STRING
, "", JSON_TOKEN_END
);
441 test_tokenizer("\"foo\"", JSON_TOKEN_STRING
, "foo", JSON_TOKEN_END
);
442 test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING
, "foo\nfoo", JSON_TOKEN_END
);
443 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
);
444 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
);
445 test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING
, "\xef\xbf\xbd", JSON_TOKEN_END
);
446 test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING
, "\xef\xbf\xbd", JSON_TOKEN_END
);
447 test_tokenizer("\"\\uf\"", -EINVAL
);
448 test_tokenizer("\"\\ud800a\"", -EINVAL
);
449 test_tokenizer("\"\\udc00\\udc00\"", -EINVAL
);
450 test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING
, "\xf0\x90\x90\xb7", JSON_TOKEN_END
);
452 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
);
454 test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1
);
455 test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2
);
456 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
);
458 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
);