]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
788c34be LP |
2 | |
3 | #include <math.h> | |
788c34be LP |
4 | |
5 | #include "alloc-util.h" | |
4d7f5175 | 6 | #include "escape.h" |
788c34be | 7 | #include "fd-util.h" |
673a1e6f | 8 | #include "fileio.h" |
788c34be LP |
9 | #include "json-internal.h" |
10 | #include "json.h" | |
11 | #include "string-util.h" | |
12 | #include "strv.h" | |
adbdcfbe | 13 | #include "tests.h" |
788c34be LP |
14 | #include "util.h" |
15 | ||
16 | static void test_tokenizer(const char *data, ...) { | |
17 | unsigned line = 0, column = 0; | |
18 | void *state = NULL; | |
19 | va_list ap; | |
20 | ||
4d7f5175 ZJS |
21 | _cleanup_free_ char *cdata; |
22 | assert_se(cdata = cescape(data)); | |
23 | log_info("/* %s data=\"%s\" */", __func__, cdata); | |
24 | ||
788c34be LP |
25 | va_start(ap, data); |
26 | ||
27 | for (;;) { | |
28 | unsigned token_line, token_column; | |
29 | _cleanup_free_ char *str = NULL; | |
30 | JsonValue v = JSON_VALUE_NULL; | |
31 | int t, tt; | |
32 | ||
33 | t = json_tokenize(&data, &str, &v, &token_line, &token_column, &state, &line, &column); | |
34 | tt = va_arg(ap, int); | |
35 | ||
36 | assert_se(t == tt); | |
37 | ||
38 | if (t == JSON_TOKEN_END || t < 0) | |
39 | break; | |
40 | ||
41 | else if (t == JSON_TOKEN_STRING) { | |
42 | const char *nn; | |
43 | ||
44 | nn = va_arg(ap, const char *); | |
45 | assert_se(streq_ptr(nn, str)); | |
46 | ||
47 | } else if (t == JSON_TOKEN_REAL) { | |
48 | long double d; | |
49 | ||
50 | d = va_arg(ap, long double); | |
51 | ||
aa70783f ZJS |
52 | /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit: |
53 | * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits. | |
54 | * Some architectures might not support long double either. | |
55 | */ | |
56 | ||
57 | assert_se(fabsl(d - v.real) < 1e-10 || | |
58 | fabsl((d - v.real) / v.real) < 1e-10); | |
788c34be LP |
59 | |
60 | } else if (t == JSON_TOKEN_INTEGER) { | |
61 | intmax_t i; | |
62 | ||
63 | i = va_arg(ap, intmax_t); | |
64 | assert_se(i == v.integer); | |
65 | ||
66 | } else if (t == JSON_TOKEN_UNSIGNED) { | |
67 | uintmax_t u; | |
68 | ||
69 | u = va_arg(ap, uintmax_t); | |
70 | assert_se(u == v.unsig); | |
71 | ||
72 | } else if (t == JSON_TOKEN_BOOLEAN) { | |
73 | bool b; | |
74 | ||
75 | b = va_arg(ap, int); | |
76 | assert_se(b == v.boolean); | |
77 | } | |
78 | } | |
79 | ||
80 | va_end(ap); | |
81 | } | |
82 | ||
83 | typedef void (*Test)(JsonVariant *); | |
84 | ||
85 | static void test_variant(const char *data, Test test) { | |
86 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; | |
87 | _cleanup_free_ char *s = NULL; | |
88 | int r; | |
89 | ||
4d7f5175 ZJS |
90 | _cleanup_free_ char *cdata; |
91 | assert_se(cdata = cescape(data)); | |
92 | log_info("/* %s data=\"%s\" */", __func__, cdata); | |
93 | ||
d642f640 | 94 | r = json_parse(data, 0, &v, NULL, NULL); |
788c34be LP |
95 | assert_se(r == 0); |
96 | assert_se(v); | |
97 | ||
98 | r = json_variant_format(v, 0, &s); | |
99 | assert_se(r >= 0); | |
100 | assert_se(s); | |
2a04712c | 101 | assert_se((size_t) r == strlen(s)); |
788c34be LP |
102 | |
103 | log_info("formatted normally: %s\n", s); | |
104 | ||
d642f640 | 105 | r = json_parse(data, JSON_PARSE_SENSITIVE, &w, NULL, NULL); |
788c34be LP |
106 | assert_se(r == 0); |
107 | assert_se(w); | |
108 | assert_se(json_variant_has_type(v, json_variant_type(w))); | |
109 | assert_se(json_variant_has_type(w, json_variant_type(v))); | |
110 | assert_se(json_variant_equal(v, w)); | |
111 | ||
112 | s = mfree(s); | |
113 | w = json_variant_unref(w); | |
114 | ||
115 | r = json_variant_format(v, JSON_FORMAT_PRETTY, &s); | |
116 | assert_se(r >= 0); | |
117 | assert_se(s); | |
2a04712c | 118 | assert_se((size_t) r == strlen(s)); |
788c34be LP |
119 | |
120 | log_info("formatted prettily:\n%s", s); | |
121 | ||
d642f640 | 122 | r = json_parse(data, 0, &w, NULL, NULL); |
788c34be LP |
123 | assert_se(r == 0); |
124 | assert_se(w); | |
125 | ||
126 | assert_se(json_variant_has_type(v, json_variant_type(w))); | |
127 | assert_se(json_variant_has_type(w, json_variant_type(v))); | |
128 | assert_se(json_variant_equal(v, w)); | |
129 | ||
130 | s = mfree(s); | |
131 | r = json_variant_format(v, JSON_FORMAT_COLOR, &s); | |
132 | assert_se(r >= 0); | |
133 | assert_se(s); | |
2a04712c | 134 | assert_se((size_t) r == strlen(s)); |
788c34be LP |
135 | printf("Normal with color: %s\n", s); |
136 | ||
137 | s = mfree(s); | |
138 | r = json_variant_format(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, &s); | |
139 | assert_se(r >= 0); | |
140 | assert_se(s); | |
2a04712c | 141 | assert_se((size_t) r == strlen(s)); |
788c34be LP |
142 | printf("Pretty with color:\n%s\n", s); |
143 | ||
144 | if (test) | |
145 | test(v); | |
146 | } | |
147 | ||
148 | static void test_1(JsonVariant *v) { | |
149 | JsonVariant *p, *q; | |
150 | unsigned i; | |
151 | ||
4d7f5175 ZJS |
152 | log_info("/* %s */", __func__); |
153 | ||
788c34be LP |
154 | /* 3 keys + 3 values */ |
155 | assert_se(json_variant_elements(v) == 6); | |
156 | ||
157 | /* has k */ | |
158 | p = json_variant_by_key(v, "k"); | |
159 | assert_se(p && json_variant_type(p) == JSON_VARIANT_STRING); | |
160 | ||
161 | /* k equals v */ | |
162 | assert_se(streq(json_variant_string(p), "v")); | |
163 | ||
164 | /* has foo */ | |
165 | p = json_variant_by_key(v, "foo"); | |
166 | assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 3); | |
167 | ||
168 | /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */ | |
169 | for (i = 0; i < 3; ++i) { | |
170 | q = json_variant_by_index(p, i); | |
171 | assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == (i+1)); | |
172 | assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == (i+1)); | |
173 | } | |
174 | ||
175 | /* has bar */ | |
176 | p = json_variant_by_key(v, "bar"); | |
177 | assert_se(p && json_variant_type(p) == JSON_VARIANT_OBJECT && json_variant_elements(p) == 2); | |
178 | ||
179 | /* zap is null */ | |
180 | q = json_variant_by_key(p, "zap"); | |
181 | assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL); | |
182 | } | |
183 | ||
184 | static void test_2(JsonVariant *v) { | |
185 | JsonVariant *p, *q; | |
186 | ||
4d7f5175 ZJS |
187 | log_info("/* %s */", __func__); |
188 | ||
788c34be LP |
189 | /* 2 keys + 2 values */ |
190 | assert_se(json_variant_elements(v) == 4); | |
191 | ||
192 | /* has mutant */ | |
193 | p = json_variant_by_key(v, "mutant"); | |
194 | assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 4); | |
195 | ||
196 | /* mutant[0] == 1 */ | |
197 | q = json_variant_by_index(p, 0); | |
198 | assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1); | |
199 | assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1); | |
200 | ||
201 | /* mutant[1] == null */ | |
202 | q = json_variant_by_index(p, 1); | |
203 | assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL); | |
204 | ||
205 | /* mutant[2] == "1" */ | |
206 | q = json_variant_by_index(p, 2); | |
207 | assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); | |
208 | ||
209 | /* mutant[3] == JSON_VARIANT_OBJECT */ | |
210 | q = json_variant_by_index(p, 3); | |
211 | assert_se(q && json_variant_type(q) == JSON_VARIANT_OBJECT && json_variant_elements(q) == 2); | |
212 | ||
213 | /* has 1 */ | |
214 | p = json_variant_by_key(q, "1"); | |
215 | assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 2); | |
216 | ||
217 | /* "1"[0] == 1 */ | |
218 | q = json_variant_by_index(p, 0); | |
219 | assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1); | |
220 | assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1); | |
221 | ||
222 | /* "1"[1] == "1" */ | |
223 | q = json_variant_by_index(p, 1); | |
224 | assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); | |
225 | ||
226 | /* has thisisaverylongproperty */ | |
227 | p = json_variant_by_key(v, "thisisaverylongproperty"); | |
40990eac | 228 | assert_se(p && json_variant_type(p) == JSON_VARIANT_REAL && fabsl(json_variant_real(p) - 1.27) < 0.001); |
788c34be LP |
229 | } |
230 | ||
788c34be | 231 | static void test_zeroes(JsonVariant *v) { |
788c34be | 232 | /* Make sure zero is how we expect it. */ |
4d7f5175 | 233 | log_info("/* %s */", __func__); |
788c34be LP |
234 | |
235 | assert_se(json_variant_elements(v) == 13); | |
236 | ||
4d7f5175 | 237 | for (size_t i = 0; i < json_variant_elements(v); i++) { |
788c34be LP |
238 | JsonVariant *w; |
239 | size_t j; | |
240 | ||
241 | assert_se(w = json_variant_by_index(v, i)); | |
242 | ||
243 | assert_se(json_variant_integer(w) == 0); | |
244 | assert_se(json_variant_unsigned(w) == 0U); | |
245 | ||
6a5b28de | 246 | DISABLE_WARNING_FLOAT_EQUAL; |
788c34be | 247 | assert_se(json_variant_real(w) == 0.0L); |
6a5b28de | 248 | REENABLE_WARNING; |
788c34be LP |
249 | |
250 | assert_se(json_variant_is_integer(w)); | |
251 | assert_se(json_variant_is_unsigned(w)); | |
252 | assert_se(json_variant_is_real(w)); | |
253 | assert_se(json_variant_is_number(w)); | |
254 | ||
255 | assert_se(!json_variant_is_negative(w)); | |
256 | ||
257 | assert_se(IN_SET(json_variant_type(w), JSON_VARIANT_INTEGER, JSON_VARIANT_UNSIGNED, JSON_VARIANT_REAL)); | |
258 | ||
259 | for (j = 0; j < json_variant_elements(v); j++) { | |
260 | JsonVariant *q; | |
261 | ||
262 | assert_se(q = json_variant_by_index(v, j)); | |
263 | ||
264 | assert_se(json_variant_equal(w, q)); | |
265 | } | |
266 | } | |
267 | } | |
268 | ||
269 | static void test_build(void) { | |
4d7f5175 ZJS |
270 | log_info("/* %s */", __func__); |
271 | ||
788c34be LP |
272 | _cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL; |
273 | _cleanup_free_ char *s = NULL, *t = NULL; | |
274 | ||
275 | assert_se(json_build(&a, JSON_BUILD_STRING("hallo")) >= 0); | |
276 | assert_se(json_build(&b, JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0); | |
277 | assert_se(json_variant_equal(a, b)); | |
278 | ||
279 | b = json_variant_unref(b); | |
280 | ||
281 | assert_se(json_build(&b, JSON_BUILD_VARIANT(a)) >= 0); | |
282 | assert_se(json_variant_equal(a, b)); | |
283 | ||
284 | b = json_variant_unref(b); | |
285 | assert_se(json_build(&b, JSON_BUILD_STRING("pief")) >= 0); | |
286 | assert_se(!json_variant_equal(a, b)); | |
287 | ||
288 | a = json_variant_unref(a); | |
289 | b = json_variant_unref(b); | |
290 | ||
291 | assert_se(json_build(&a, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("one", JSON_BUILD_INTEGER(7)), | |
292 | JSON_BUILD_PAIR("two", JSON_BUILD_REAL(2.0)), | |
293 | JSON_BUILD_PAIR("three", JSON_BUILD_INTEGER(0)))) >= 0); | |
294 | ||
295 | assert_se(json_build(&b, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("two", JSON_BUILD_INTEGER(2)), | |
296 | JSON_BUILD_PAIR("three", JSON_BUILD_REAL(0)), | |
297 | JSON_BUILD_PAIR("one", JSON_BUILD_REAL(7)))) >= 0); | |
298 | ||
299 | assert_se(json_variant_equal(a, b)); | |
300 | ||
301 | a = json_variant_unref(a); | |
302 | b = json_variant_unref(b); | |
303 | ||
14648b76 | 304 | const char* arr_1234[] = {"one", "two", "three", "four", NULL}; |
788c34be LP |
305 | assert_se(json_build(&a, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)), |
306 | JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL)))), | |
307 | JSON_BUILD_VARIANT(NULL), | |
308 | JSON_BUILD_LITERAL(NULL), | |
309 | JSON_BUILD_STRING(NULL), | |
310 | JSON_BUILD_NULL, | |
311 | JSON_BUILD_INTEGER(77), | |
14648b76 ZJS |
312 | JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")), |
313 | JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))), | |
314 | JSON_BUILD_STRV((char**) arr_1234))) >= 0); | |
788c34be LP |
315 | |
316 | assert_se(json_variant_format(a, 0, &s) >= 0); | |
317 | log_info("GOT: %s\n", s); | |
d642f640 | 318 | assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0); |
788c34be LP |
319 | assert_se(json_variant_equal(a, b)); |
320 | ||
321 | a = json_variant_unref(a); | |
322 | b = json_variant_unref(b); | |
323 | ||
324 | assert_se(json_build(&a, JSON_BUILD_REAL(M_PIl)) >= 0); | |
325 | ||
326 | s = mfree(s); | |
327 | assert_se(json_variant_format(a, 0, &s) >= 0); | |
328 | log_info("GOT: %s\n", s); | |
d642f640 | 329 | assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0); |
788c34be LP |
330 | assert_se(json_variant_format(b, 0, &t) >= 0); |
331 | log_info("GOT: %s\n", t); | |
332 | ||
333 | assert_se(streq(s, t)); | |
334 | ||
335 | a = json_variant_unref(a); | |
336 | b = json_variant_unref(b); | |
319a4f27 LP |
337 | |
338 | assert_se(json_build(&a, JSON_BUILD_OBJECT( | |
339 | JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")), | |
340 | JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")), | |
341 | JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c")) | |
342 | )) >= 0); | |
343 | ||
344 | assert_se(json_build(&b, JSON_BUILD_OBJECT( | |
345 | JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")), | |
346 | JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")), | |
347 | JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")), | |
348 | JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))), | |
349 | JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c")) | |
350 | )) >= 0); | |
351 | ||
352 | assert_se(json_variant_equal(a, b)); | |
788c34be LP |
353 | } |
354 | ||
355 | static void test_source(void) { | |
356 | static const char data[] = | |
357 | "\n" | |
358 | "\n" | |
359 | "{\n" | |
360 | "\"foo\" : \"bar\", \n" | |
361 | "\"qüüx\" : [ 1, 2, 3,\n" | |
362 | "4,\n" | |
363 | "5 ],\n" | |
364 | "\"miep\" : { \"hallo\" : 1 },\n" | |
365 | "\n" | |
366 | "\"zzzzzz\" \n" | |
367 | ":\n" | |
368 | "[ true, \n" | |
369 | "false, 7.5, {} ]\n" | |
370 | "}\n"; | |
371 | ||
4d7f5175 ZJS |
372 | log_info("/* %s */", __func__); |
373 | ||
788c34be LP |
374 | _cleanup_fclose_ FILE *f = NULL; |
375 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; | |
376 | ||
377 | printf("--- original begin ---\n" | |
378 | "%s" | |
379 | "--- original end ---\n", data); | |
380 | ||
673a1e6f | 381 | assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r")); |
788c34be | 382 | |
d642f640 | 383 | assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) >= 0); |
788c34be LP |
384 | |
385 | printf("--- non-pretty begin ---\n"); | |
386 | json_variant_dump(v, 0, stdout, NULL); | |
387 | printf("\n--- non-pretty end ---\n"); | |
388 | ||
389 | printf("--- pretty begin ---\n"); | |
390 | json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, stdout, NULL); | |
391 | printf("--- pretty end ---\n"); | |
392 | } | |
393 | ||
b2fa0d4f | 394 | static void test_depth(void) { |
4d7f5175 ZJS |
395 | log_info("/* %s */", __func__); |
396 | ||
d520d519 | 397 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; |
b2fa0d4f LP |
398 | int r; |
399 | ||
d520d519 | 400 | v = JSON_VARIANT_STRING_CONST("start"); |
b2fa0d4f LP |
401 | |
402 | /* Let's verify that the maximum depth checks work */ | |
403 | ||
4d7f5175 | 404 | for (unsigned i = 0;; i++) { |
b2fa0d4f LP |
405 | _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; |
406 | ||
407 | assert_se(i <= UINT16_MAX); | |
408 | if (i & 1) | |
409 | r = json_variant_new_array(&w, &v, 1); | |
410 | else | |
d520d519 | 411 | r = json_variant_new_object(&w, (JsonVariant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2); |
b2fa0d4f LP |
412 | if (r == -ELNRNG) { |
413 | log_info("max depth at %u", i); | |
414 | break; | |
415 | } | |
b6cda3ec ZJS |
416 | #if HAS_FEATURE_MEMORY_SANITIZER |
417 | /* msan doesn't like the stack nesting to be too deep. Let's quit early. */ | |
418 | if (i >= 128) { | |
419 | log_info("quitting early at depth %u", i); | |
420 | break; | |
421 | } | |
422 | #endif | |
b2fa0d4f LP |
423 | |
424 | assert_se(r >= 0); | |
425 | ||
426 | json_variant_unref(v); | |
427 | v = TAKE_PTR(w); | |
428 | } | |
429 | ||
430 | json_variant_dump(v, 0, stdout, NULL); | |
d520d519 | 431 | fputs("\n", stdout); |
b2fa0d4f LP |
432 | } |
433 | ||
b7fc90a2 | 434 | static void test_normalize(void) { |
4d7f5175 ZJS |
435 | log_info("/* %s */", __func__); |
436 | ||
b7fc90a2 LP |
437 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; |
438 | _cleanup_free_ char *t = NULL; | |
439 | ||
440 | assert_se(json_build(&v, JSON_BUILD_OBJECT( | |
441 | JSON_BUILD_PAIR("b", JSON_BUILD_STRING("x")), | |
442 | JSON_BUILD_PAIR("c", JSON_BUILD_STRING("y")), | |
443 | JSON_BUILD_PAIR("a", JSON_BUILD_STRING("z")))) >= 0); | |
444 | ||
445 | assert_se(!json_variant_is_sorted(v)); | |
446 | assert_se(!json_variant_is_normalized(v)); | |
447 | ||
448 | assert_se(json_variant_format(v, 0, &t) >= 0); | |
449 | assert_se(streq(t, "{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}")); | |
450 | t = mfree(t); | |
451 | ||
452 | assert_se(json_build(&w, JSON_BUILD_OBJECT( | |
453 | JSON_BUILD_PAIR("bar", JSON_BUILD_STRING("zzz")), | |
454 | JSON_BUILD_PAIR("foo", JSON_BUILD_VARIANT(v)))) >= 0); | |
455 | ||
456 | assert_se(json_variant_is_sorted(w)); | |
457 | assert_se(!json_variant_is_normalized(w)); | |
458 | ||
459 | assert_se(json_variant_format(w, 0, &t) >= 0); | |
460 | assert_se(streq(t, "{\"bar\":\"zzz\",\"foo\":{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}}")); | |
461 | t = mfree(t); | |
462 | ||
463 | assert_se(json_variant_sort(&v) >= 0); | |
464 | assert_se(json_variant_is_sorted(v)); | |
465 | assert_se(json_variant_is_normalized(v)); | |
466 | ||
467 | assert_se(json_variant_format(v, 0, &t) >= 0); | |
468 | assert_se(streq(t, "{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}")); | |
469 | t = mfree(t); | |
470 | ||
471 | assert_se(json_variant_normalize(&w) >= 0); | |
472 | assert_se(json_variant_is_sorted(w)); | |
473 | assert_se(json_variant_is_normalized(w)); | |
474 | ||
475 | assert_se(json_variant_format(w, 0, &t) >= 0); | |
476 | assert_se(streq(t, "{\"bar\":\"zzz\",\"foo\":{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}}")); | |
477 | t = mfree(t); | |
478 | } | |
479 | ||
480 | static void test_bisect(void) { | |
4d7f5175 ZJS |
481 | log_info("/* %s */", __func__); |
482 | ||
b7fc90a2 | 483 | _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; |
b7fc90a2 LP |
484 | |
485 | /* Tests the bisection logic in json_variant_by_key() */ | |
486 | ||
4d7f5175 | 487 | for (char c = 'z'; c >= 'a'; c--) { |
b7fc90a2 LP |
488 | |
489 | if ((c % 3) == 0) | |
490 | continue; | |
491 | ||
492 | _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; | |
493 | assert_se(json_variant_new_stringn(&w, (char[4]) { '<', c, c, '>' }, 4) >= 0); | |
494 | assert_se(json_variant_set_field(&v, (char[2]) { c, 0 }, w) >= 0); | |
495 | } | |
496 | ||
497 | json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL); | |
498 | ||
499 | assert_se(!json_variant_is_sorted(v)); | |
500 | assert_se(!json_variant_is_normalized(v)); | |
501 | assert_se(json_variant_normalize(&v) >= 0); | |
502 | assert_se(json_variant_is_sorted(v)); | |
503 | assert_se(json_variant_is_normalized(v)); | |
504 | ||
505 | json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL); | |
506 | ||
4d7f5175 | 507 | for (char c = 'a'; c <= 'z'; c++) { |
b7fc90a2 LP |
508 | JsonVariant *k; |
509 | const char *z; | |
510 | ||
511 | k = json_variant_by_key(v, (char[2]) { c, 0 }); | |
512 | assert_se(!k == ((c % 3) == 0)); | |
513 | ||
514 | if (!k) | |
515 | continue; | |
516 | ||
517 | assert_se(json_variant_is_string(k)); | |
518 | ||
519 | z = (char[5]){ '<', c, c, '>', 0}; | |
520 | assert_se(streq(json_variant_string(k), z)); | |
521 | } | |
522 | } | |
523 | ||
788c34be | 524 | int main(int argc, char *argv[]) { |
adbdcfbe | 525 | test_setup_logging(LOG_DEBUG); |
788c34be LP |
526 | |
527 | test_tokenizer("x", -EINVAL); | |
528 | test_tokenizer("", JSON_TOKEN_END); | |
529 | test_tokenizer(" ", JSON_TOKEN_END); | |
530 | test_tokenizer("0", JSON_TOKEN_UNSIGNED, (uintmax_t) 0, JSON_TOKEN_END); | |
531 | test_tokenizer("-0", JSON_TOKEN_INTEGER, (intmax_t) 0, JSON_TOKEN_END); | |
532 | test_tokenizer("1234", JSON_TOKEN_UNSIGNED, (uintmax_t) 1234, JSON_TOKEN_END); | |
533 | test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END); | |
534 | test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED, (uintmax_t) UINT64_MAX, JSON_TOKEN_END); | |
535 | test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER, (intmax_t) INT64_MIN, JSON_TOKEN_END); | |
536 | test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (long double) 18446744073709551616.0L, JSON_TOKEN_END); | |
537 | test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (long double) -9223372036854775809.0L, JSON_TOKEN_END); | |
538 | test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END); | |
539 | test_tokenizer("3.141", JSON_TOKEN_REAL, (long double) 3.141, JSON_TOKEN_END); | |
540 | test_tokenizer("0.0", JSON_TOKEN_REAL, (long double) 0.0, JSON_TOKEN_END); | |
541 | test_tokenizer("7e3", JSON_TOKEN_REAL, (long double) 7e3, JSON_TOKEN_END); | |
542 | test_tokenizer("-7e-3", JSON_TOKEN_REAL, (long double) -7e-3, JSON_TOKEN_END); | |
543 | test_tokenizer("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END); | |
544 | test_tokenizer("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END); | |
545 | test_tokenizer("null", JSON_TOKEN_NULL, JSON_TOKEN_END); | |
546 | test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); | |
547 | test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); | |
548 | test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END); | |
549 | test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END); | |
550 | test_tokenizer("\"\"", JSON_TOKEN_STRING, "", JSON_TOKEN_END); | |
551 | test_tokenizer("\"foo\"", JSON_TOKEN_STRING, "foo", JSON_TOKEN_END); | |
552 | test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING, "foo\nfoo", JSON_TOKEN_END); | |
553 | 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); | |
554 | 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); | |
555 | test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END); | |
556 | test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END); | |
557 | test_tokenizer("\"\\uf\"", -EINVAL); | |
558 | test_tokenizer("\"\\ud800a\"", -EINVAL); | |
559 | test_tokenizer("\"\\udc00\\udc00\"", -EINVAL); | |
560 | test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING, "\xf0\x90\x90\xb7", JSON_TOKEN_END); | |
561 | ||
562 | 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); | |
563 | ||
564 | test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1); | |
565 | test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2); | |
ea9afe00 | 566 | test_variant("{\"foo\" : \"\\u0935\\u093f\\u0935\\u0947\\u0915\\u0916\\u094d\\u092f\\u093e\\u0924\\u093f\\u0930\\u0935\\u093f\\u092a\\u094d\\u0932\\u0935\\u093e\\u0020\\u0939\\u093e\\u0928\\u094b\\u092a\\u093e\\u092f\\u0903\\u0964\"}", NULL); |
788c34be LP |
567 | |
568 | 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); | |
569 | ||
570 | test_build(); | |
788c34be | 571 | test_source(); |
b2fa0d4f LP |
572 | test_depth(); |
573 | ||
b7fc90a2 LP |
574 | test_normalize(); |
575 | test_bisect(); | |
576 | ||
788c34be LP |
577 | return 0; |
578 | } |