]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-json.c
91e14a4726d48ce195ec65022179eaf5f586a053
[thirdparty/systemd.git] / src / test / test-json.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <float.h>
4 #include <sys/socket.h>
5 #include <sys/sysmacros.h>
6 #include <unistd.h>
7
8 #include "sd-json.h"
9
10 #include "alloc-util.h"
11 #include "escape.h"
12 #include "fd-util.h"
13 #include "format-util.h"
14 #include "fileio.h"
15 #include "iovec-util.h"
16 #include "json-internal.h"
17 #include "json-util.h"
18 #include "math-util.h"
19 #include "ordered-set.h"
20 #include "pidref.h"
21 #include "set.h"
22 #include "string-table.h"
23 #include "tests.h"
24 #include "tmpfile-util.h"
25
26 static void test_tokenizer_one(const char *data, ...) {
27 unsigned line = 0, column = 0;
28 void *state = NULL;
29 va_list ap;
30
31 _cleanup_free_ char *cdata = NULL;
32 assert_se(cdata = cescape(data));
33 log_info("/* %s data=\"%s\" */", __func__, cdata);
34
35 va_start(ap, data);
36
37 for (;;) {
38 unsigned token_line, token_column;
39 _cleanup_free_ char *str = NULL;
40 JsonValue v = JSON_VALUE_NULL;
41 int t, tt;
42
43 t = json_tokenize(&data, &str, &v, &token_line, &token_column, &state, &line, &column);
44 tt = va_arg(ap, int);
45
46 assert_se(t == tt);
47
48 if (t == JSON_TOKEN_END || t < 0)
49 break;
50
51 else if (t == JSON_TOKEN_STRING) {
52 const char *nn;
53
54 nn = va_arg(ap, const char *);
55 ASSERT_STREQ(nn, str);
56
57 } else if (t == JSON_TOKEN_REAL) {
58 double d;
59
60 d = va_arg(ap, double);
61
62 assert_se(fabs(d - v.real) < 1e-10 ||
63 fabs((d - v.real) / v.real) < 1e-10);
64
65 } else if (t == JSON_TOKEN_INTEGER) {
66 int64_t i;
67
68 i = va_arg(ap, int64_t);
69 assert_se(i == v.integer);
70
71 } else if (t == JSON_TOKEN_UNSIGNED) {
72 uint64_t u;
73
74 u = va_arg(ap, uint64_t);
75 assert_se(u == v.unsig);
76
77 } else if (t == JSON_TOKEN_BOOLEAN) {
78 bool b;
79
80 b = va_arg(ap, int);
81 assert_se(b == v.boolean);
82 }
83 }
84
85 va_end(ap);
86 }
87
88 typedef void (*Test)(sd_json_variant *);
89
90 static void test_variant_one(const char *data, Test test) {
91 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
92 _cleanup_free_ char *s = NULL;
93 int r;
94
95 _cleanup_free_ char *cdata;
96 assert_se(cdata = cescape(data));
97 log_info("/* %s data=\"%s\" */", __func__, cdata);
98
99 r = sd_json_parse(data, 0, &v, NULL, NULL);
100 assert_se(r == 0);
101 assert_se(v);
102
103 r = sd_json_variant_format(v, 0, &s);
104 assert_se(r >= 0);
105 assert_se(s);
106 assert_se((size_t) r == strlen(s));
107
108 log_info("formatted normally: %s", s);
109
110 r = sd_json_parse(data, SD_JSON_PARSE_SENSITIVE, &w, NULL, NULL);
111 assert_se(r == 0);
112 assert_se(w);
113 assert_se(sd_json_variant_has_type(v, sd_json_variant_type(w)));
114 assert_se(sd_json_variant_has_type(w, sd_json_variant_type(v)));
115 assert_se(sd_json_variant_equal(v, w));
116
117 s = mfree(s);
118 r = sd_json_variant_format(w, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
119 assert_se(s);
120 ASSERT_STREQ(s, "\"<sensitive data>\"");
121
122 s = mfree(s);
123 r = sd_json_variant_format(w, SD_JSON_FORMAT_PRETTY, &s);
124 assert_se(r >= 0);
125 assert_se(s);
126 assert_se((size_t) r == strlen(s));
127
128 s = mfree(s);
129 w = sd_json_variant_unref(w);
130
131 r = sd_json_variant_format(v, SD_JSON_FORMAT_PRETTY, &s);
132 assert_se(r >= 0);
133 assert_se(s);
134 assert_se((size_t) r == strlen(s));
135
136 log_info("formatted prettily:\n%s", s);
137
138 r = sd_json_parse(data, 0, &w, NULL, NULL);
139 assert_se(r == 0);
140 assert_se(w);
141
142 assert_se(sd_json_variant_has_type(v, sd_json_variant_type(w)));
143 assert_se(sd_json_variant_has_type(w, sd_json_variant_type(v)));
144 assert_se(sd_json_variant_equal(v, w));
145
146 s = mfree(s);
147 r = sd_json_variant_format(v, SD_JSON_FORMAT_COLOR, &s);
148 assert_se(r >= 0);
149 assert_se(s);
150 assert_se((size_t) r == strlen(s));
151 printf("Normal with color: %s\n", s);
152
153 s = mfree(s);
154 r = sd_json_variant_format(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, &s);
155 assert_se(r >= 0);
156 assert_se(s);
157 assert_se((size_t) r == strlen(s));
158 printf("Pretty with color:\n%s\n", s);
159
160 if (test)
161 test(v);
162 }
163
164 static void test_1(sd_json_variant *v) {
165 sd_json_variant *p, *q;
166 unsigned i;
167
168 log_info("/* %s */", __func__);
169
170 /* 3 keys + 3 values */
171 assert_se(sd_json_variant_elements(v) == 6);
172
173 /* has k */
174 p = sd_json_variant_by_key(v, "k");
175 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_STRING);
176
177 /* k equals v */
178 ASSERT_STREQ(sd_json_variant_string(p), "v");
179
180 /* has foo */
181 p = sd_json_variant_by_key(v, "foo");
182 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_ARRAY && sd_json_variant_elements(p) == 3);
183
184 /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
185 for (i = 0; i < 3; ++i) {
186 q = sd_json_variant_by_index(p, i);
187 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_UNSIGNED && sd_json_variant_unsigned(q) == (i+1));
188 assert_se(q && sd_json_variant_has_type(q, SD_JSON_VARIANT_INTEGER) && sd_json_variant_integer(q) == (i+1));
189 }
190
191 /* has bar */
192 p = sd_json_variant_by_key(v, "bar");
193 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_OBJECT && sd_json_variant_elements(p) == 2);
194
195 /* zap is null */
196 q = sd_json_variant_by_key(p, "zap");
197 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_NULL);
198 }
199
200 static void test_2(sd_json_variant *v) {
201 sd_json_variant *p, *q;
202
203 log_info("/* %s */", __func__);
204
205 /* 2 keys + 2 values */
206 assert_se(sd_json_variant_elements(v) == 4);
207
208 /* has mutant */
209 p = sd_json_variant_by_key(v, "mutant");
210 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_ARRAY && sd_json_variant_elements(p) == 4);
211
212 /* mutant[0] == 1 */
213 q = sd_json_variant_by_index(p, 0);
214 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_UNSIGNED && sd_json_variant_unsigned(q) == 1);
215 assert_se(q && sd_json_variant_has_type(q, SD_JSON_VARIANT_INTEGER) && sd_json_variant_integer(q) == 1);
216
217 /* mutant[1] == null */
218 q = sd_json_variant_by_index(p, 1);
219 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_NULL);
220
221 /* mutant[2] == "1" */
222 q = sd_json_variant_by_index(p, 2);
223 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_STRING && streq(sd_json_variant_string(q), "1"));
224
225 /* mutant[3] == SD_JSON_VARIANT_OBJECT */
226 q = sd_json_variant_by_index(p, 3);
227 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_OBJECT && sd_json_variant_elements(q) == 2);
228
229 /* has 1 */
230 p = sd_json_variant_by_key(q, "1");
231 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_ARRAY && sd_json_variant_elements(p) == 2);
232
233 /* "1"[0] == 1 */
234 q = sd_json_variant_by_index(p, 0);
235 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_UNSIGNED && sd_json_variant_unsigned(q) == 1);
236 assert_se(q && sd_json_variant_has_type(q, SD_JSON_VARIANT_INTEGER) && sd_json_variant_integer(q) == 1);
237
238 /* "1"[1] == "1" */
239 q = sd_json_variant_by_index(p, 1);
240 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_STRING && streq(sd_json_variant_string(q), "1"));
241
242 /* has thisisaverylongproperty */
243 p = sd_json_variant_by_key(v, "thisisaverylongproperty");
244 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_REAL && fabs(sd_json_variant_real(p) - 1.27) < 0.001);
245 }
246
247 static void test_zeroes(sd_json_variant *v) {
248 /* Make sure zero is how we expect it. */
249 log_info("/* %s */", __func__);
250
251 assert_se(sd_json_variant_elements(v) == 13);
252
253 for (size_t i = 0; i < sd_json_variant_elements(v); i++) {
254 sd_json_variant *w;
255 size_t j;
256
257 assert_se(w = sd_json_variant_by_index(v, i));
258
259 assert_se(sd_json_variant_integer(w) == 0);
260 assert_se(sd_json_variant_unsigned(w) == 0U);
261
262 assert_se(iszero_safe(sd_json_variant_real(w)));
263
264 assert_se(sd_json_variant_is_integer(w));
265 assert_se(sd_json_variant_is_unsigned(w));
266 assert_se(sd_json_variant_is_real(w));
267 assert_se(sd_json_variant_is_number(w));
268
269 assert_se(!sd_json_variant_is_negative(w));
270
271 assert_se(IN_SET(sd_json_variant_type(w), SD_JSON_VARIANT_INTEGER, SD_JSON_VARIANT_UNSIGNED, SD_JSON_VARIANT_REAL));
272
273 for (j = 0; j < sd_json_variant_elements(v); j++) {
274 sd_json_variant *q;
275
276 assert_se(q = sd_json_variant_by_index(v, j));
277
278 assert_se(sd_json_variant_equal(w, q));
279 }
280 }
281 }
282
283 static int test_callback(sd_json_variant **ret, const char *name, void *userdata) {
284
285 if (streq_ptr(name, "mypid1"))
286 assert_se(PTR_TO_INT(userdata) == 4711);
287 else if (streq_ptr(name, "mypid2"))
288 assert_se(PTR_TO_INT(userdata) == 4712);
289 else if (streq_ptr(name, "mypid3"))
290 return 0;
291 else
292 assert_not_reached();
293
294 return sd_json_build(ret, SD_JSON_BUILD_INTEGER(getpid()));
295 }
296
297 TEST(build) {
298 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a = NULL, *b = NULL;
299 _cleanup_free_ char *s = NULL, *t = NULL;
300
301 assert_se(sd_json_build(&a, SD_JSON_BUILD_STRING("hallo")) >= 0);
302 assert_se(sd_json_build(&b, SD_JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0);
303 assert_se(sd_json_variant_equal(a, b));
304
305 b = sd_json_variant_unref(b);
306
307 assert_se(sd_json_build(&b, SD_JSON_BUILD_VARIANT(a)) >= 0);
308 assert_se(sd_json_variant_equal(a, b));
309
310 b = sd_json_variant_unref(b);
311 assert_se(sd_json_build(&b, SD_JSON_BUILD_STRING("pief")) >= 0);
312 assert_se(!sd_json_variant_equal(a, b));
313
314 a = sd_json_variant_unref(a);
315 b = sd_json_variant_unref(b);
316
317 assert_se(sd_json_buildo(&a,
318 SD_JSON_BUILD_PAIR("one", SD_JSON_BUILD_INTEGER(7)),
319 SD_JSON_BUILD_PAIR("two", SD_JSON_BUILD_REAL(2.0)),
320 SD_JSON_BUILD_PAIR("four", JSON_BUILD_STRING_UNDERSCORIFY("foo-bar-baz")),
321 SD_JSON_BUILD_PAIR("three", SD_JSON_BUILD_INTEGER(0))) >= 0);
322
323 assert_se(sd_json_buildo(&b,
324 SD_JSON_BUILD_PAIR("two", SD_JSON_BUILD_INTEGER(2)),
325 SD_JSON_BUILD_PAIR("four", SD_JSON_BUILD_STRING("foo_bar_baz")),
326 SD_JSON_BUILD_PAIR("three", SD_JSON_BUILD_REAL(0)),
327 SD_JSON_BUILD_PAIR("one", SD_JSON_BUILD_REAL(7))) >= 0);
328
329 assert_se(sd_json_variant_equal(a, b));
330
331 a = sd_json_variant_unref(a);
332 b = sd_json_variant_unref(b);
333
334 const char* arr_1234[] = {"one", "two", "three", "four", NULL};
335 assert_se(sd_json_build(&a, SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("x", SD_JSON_BUILD_BOOLEAN(true)),
336 SD_JSON_BUILD_PAIR("y", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("this", SD_JSON_BUILD_NULL)))),
337 SD_JSON_BUILD_VARIANT(NULL),
338 SD_JSON_BUILD_LITERAL(NULL),
339 SD_JSON_BUILD_STRING(NULL),
340 SD_JSON_BUILD_NULL,
341 SD_JSON_BUILD_INTEGER(77),
342 SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")),
343 SD_JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))),
344 SD_JSON_BUILD_STRV((char**) arr_1234))) >= 0);
345
346 assert_se(sd_json_variant_format(a, 0, &s) >= 0);
347 log_info("GOT: %s", s);
348 assert_se(sd_json_parse(s, 0, &b, NULL, NULL) >= 0);
349 assert_se(sd_json_variant_equal(a, b));
350
351 a = sd_json_variant_unref(a);
352 b = sd_json_variant_unref(b);
353
354 assert_se(sd_json_build(&a, SD_JSON_BUILD_REAL(M_PI)) >= 0);
355
356 s = mfree(s);
357 assert_se(sd_json_variant_format(a, 0, &s) >= 0);
358 log_info("GOT: %s", s);
359 assert_se(sd_json_parse(s, 0, &b, NULL, NULL) >= 0);
360 assert_se(sd_json_variant_format(b, 0, &t) >= 0);
361 log_info("GOT: %s", t);
362
363 ASSERT_STREQ(s, t);
364
365 a = sd_json_variant_unref(a);
366 b = sd_json_variant_unref(b);
367
368 assert_se(sd_json_build(&a, SD_JSON_BUILD_OBJECT(
369 SD_JSON_BUILD_PAIR("x", SD_JSON_BUILD_STRING("y")),
370 SD_JSON_BUILD_PAIR("z", JSON_BUILD_CONST_STRING("a")),
371 SD_JSON_BUILD_PAIR("b", JSON_BUILD_CONST_STRING("c"))
372 )) >= 0);
373
374 assert_se(sd_json_build(&b, SD_JSON_BUILD_OBJECT(
375 SD_JSON_BUILD_PAIR("x", SD_JSON_BUILD_STRING("y")),
376 SD_JSON_BUILD_PAIR_CONDITION(false, "p", SD_JSON_BUILD_STRING("q")),
377 SD_JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_CONST_STRING("a")),
378 SD_JSON_BUILD_PAIR_CONDITION(false, "j", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_STRING("k"), JSON_BUILD_CONST_STRING("u"), JSON_BUILD_CONST_STRING("i"))),
379 SD_JSON_BUILD_PAIR("b", JSON_BUILD_CONST_STRING("c"))
380 )) >= 0);
381
382 assert_se(sd_json_variant_equal(a, b));
383
384 _cleanup_(sd_json_variant_unrefp) sd_json_variant *x = NULL;
385 assert_se(sd_json_build(&x, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("foo", SD_JSON_BUILD_INTEGER(77)),
386 SD_JSON_BUILD_PAIR("bar", SD_JSON_BUILD_INTEGER(88)))) >= 0);
387
388 sd_json_variant *array[] = { a, a, b, b, x, x };
389 _cleanup_(sd_json_variant_unrefp) sd_json_variant *va = NULL;
390
391 assert_se(sd_json_build(&va, SD_JSON_BUILD_VARIANT_ARRAY(array, ELEMENTSOF(array))) >= 0);
392
393 assert_se(sd_json_variant_is_array(va));
394 assert_se(sd_json_variant_elements(va) == 6);
395 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 0), a));
396 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 1), b));
397 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 2), a));
398 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 3), b));
399 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 4), x));
400 assert_se(sd_json_variant_equal(sd_json_variant_by_index(va, 5), x));
401
402 _cleanup_(sd_json_variant_unrefp) sd_json_variant *y = NULL;
403 assert_se(sd_json_build(&y, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("mypid1", SD_JSON_BUILD_CALLBACK(test_callback, INT_TO_PTR(4711))),
404 SD_JSON_BUILD_PAIR("mypid2", SD_JSON_BUILD_CALLBACK(test_callback, INT_TO_PTR(4712))))) >= 0);
405
406 _cleanup_free_ char *f1 = NULL, *f2 = NULL;
407 assert_se(asprintf(&f1, "{\"mypid1\":" PID_FMT ",\"mypid2\":" PID_FMT "}", getpid(), getpid()) >= 0);
408
409 assert_se(sd_json_variant_format(y, /* flags= */ 0, &f2));
410 ASSERT_STREQ(f1, f2);
411
412 _cleanup_(sd_json_variant_unrefp) sd_json_variant *z = NULL;
413 ASSERT_OK(sd_json_build(&z, SD_JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid3", test_callback, INT_TO_PTR(4713)))));
414 ASSERT_TRUE(sd_json_variant_is_blank_object(z));
415 z = sd_json_variant_unref(z);
416 f2 = mfree(f2);
417 ASSERT_OK(sd_json_build(&z, SD_JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid1", test_callback, INT_TO_PTR(4711)),
418 JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid2", test_callback, INT_TO_PTR(4712)))));
419 ASSERT_OK(sd_json_variant_format(z, /* flags= */ 0, &f2));
420 ASSERT_STREQ(f1, f2);
421
422 _cleanup_set_free_ Set *ss = NULL;
423 assert_se(set_ensure_put(&ss, &string_hash_ops_free, ASSERT_PTR(strdup("pief"))) >= 0);
424 assert_se(set_ensure_put(&ss, &string_hash_ops_free, ASSERT_PTR(strdup("xxxx"))) >= 0);
425 assert_se(set_ensure_put(&ss, &string_hash_ops_free, ASSERT_PTR(strdup("kawumm"))) >= 0);
426
427 _cleanup_(sd_json_variant_unrefp) sd_json_variant *ssv = NULL;
428 assert_se(sd_json_build(&ssv, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("zzz", JSON_BUILD_STRING_SET(ss)))) >= 0);
429 assert_se(sd_json_variant_sort(&ssv) >= 0);
430
431 _cleanup_(sd_json_variant_unrefp) sd_json_variant *ssv2 = NULL;
432 assert_se(sd_json_build(&ssv2, SD_JSON_BUILD_LITERAL("{\"zzz\":[\"kawumm\",\"pief\",\"xxxx\"]}")) >= 0);
433
434 assert_se(sd_json_variant_equal(ssv, ssv2));
435
436 _cleanup_ordered_set_free_ OrderedSet *oss = NULL;
437 assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("pief"))) >= 0);
438 assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("xxxx"))) >= 0);
439 assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("kawumm"))) >= 0);
440
441 _cleanup_(sd_json_variant_unrefp) sd_json_variant *ossv = NULL;
442 assert_se(sd_json_build(&ossv, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("zzz", JSON_BUILD_STRING_ORDERED_SET(oss)))) >= 0);
443
444 _cleanup_(sd_json_variant_unrefp) sd_json_variant *ossv2 = NULL;
445 assert_se(sd_json_build(&ossv2, SD_JSON_BUILD_LITERAL("{\"zzz\":[\"pief\",\"xxxx\",\"kawumm\"]}")) >= 0);
446
447 assert_se(sd_json_variant_equal(ossv, ossv2));
448 }
449
450 TEST(json_buildo) {
451 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a = NULL, *b = NULL;
452
453 assert_se(sd_json_buildo(&a,
454 SD_JSON_BUILD_PAIR("foo", SD_JSON_BUILD_INTEGER(4711)),
455 SD_JSON_BUILD_PAIR("bar", SD_JSON_BUILD_STRING("xxxx"))) >= 0);
456
457 assert_se(sd_json_build(&b,
458 SD_JSON_BUILD_OBJECT(
459 SD_JSON_BUILD_PAIR("bar", SD_JSON_BUILD_STRING("xxxx")),
460 SD_JSON_BUILD_PAIR("foo", SD_JSON_BUILD_INTEGER(4711)))) >= 0);
461
462 assert_se(sd_json_variant_equal(a, b));
463 }
464
465 TEST(json_parse_file_empty) {
466 _cleanup_fclose_ FILE *f = NULL;
467 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
468
469 assert_se(fopen_unlocked("/dev/null", "re", &f) >= 0);
470 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -ENODATA);
471 ASSERT_NULL(v);
472 }
473
474 TEST(json_parse_file_invalid) {
475 _cleanup_fclose_ FILE *f = NULL;
476 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
477
478 assert_se(f = fmemopen_unlocked((void*) "kookoo", 6, "r"));
479 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -EINVAL);
480 ASSERT_NULL(v);
481 }
482
483 TEST(source) {
484 static const char data[] =
485 "\n"
486 "\n"
487 "{\n"
488 "\"foo\" : \"bar\", \n"
489 "\"qüüx\" : [ 1, 2, 3,\n"
490 "4,\n"
491 "5 ],\n"
492 "\"miep\" : { \"hallo\" : 1 },\n"
493 "\n"
494 "\"zzzzzz\" \n"
495 ":\n"
496 "[ true, \n"
497 "false, 7.5, {} ]\n"
498 "}\n";
499
500 _cleanup_fclose_ FILE *f = NULL;
501 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
502
503 printf("--- original begin ---\n"
504 "%s"
505 "--- original end ---\n", data);
506
507 assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r"));
508
509 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) >= 0);
510
511 printf("--- non-pretty begin ---\n");
512 sd_json_variant_dump(v, 0, stdout, NULL);
513 printf("\n--- non-pretty end ---\n");
514
515 printf("--- pretty begin ---\n");
516 sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_SOURCE, stdout, NULL);
517 printf("--- pretty end ---\n");
518 }
519
520 TEST(depth) {
521 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
522 int r;
523
524 v = JSON_VARIANT_STRING_CONST("start");
525
526 /* Let's verify that the maximum depth checks work */
527
528 for (unsigned i = 0;; i++) {
529 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
530
531 assert_se(i <= UINT16_MAX);
532 if (i & 1)
533 r = sd_json_variant_new_array(&w, &v, 1);
534 else
535 r = sd_json_variant_new_object(&w, (sd_json_variant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2);
536 if (r == -ELNRNG) {
537 log_info("max depth at %u", i);
538 break;
539 }
540 #if HAS_FEATURE_MEMORY_SANITIZER
541 /* msan doesn't like the stack nesting to be too deep. Let's quit early. */
542 if (i >= 128) {
543 log_info("quitting early at depth %u", i);
544 break;
545 }
546 #endif
547
548 assert_se(r >= 0);
549
550 sd_json_variant_unref(v);
551 v = TAKE_PTR(w);
552 }
553
554 sd_json_variant_dump(v, 0, stdout, NULL);
555 fputs("\n", stdout);
556 }
557
558 TEST(normalize) {
559 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
560 _cleanup_free_ char *t = NULL;
561
562 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
563 SD_JSON_BUILD_PAIR("b", SD_JSON_BUILD_STRING("x")),
564 SD_JSON_BUILD_PAIR("c", JSON_BUILD_CONST_STRING("y")),
565 SD_JSON_BUILD_PAIR("a", JSON_BUILD_CONST_STRING("z")))) >= 0);
566
567 assert_se(!sd_json_variant_is_sorted(v));
568 assert_se(!sd_json_variant_is_normalized(v));
569
570 assert_se(sd_json_variant_format(v, 0, &t) >= 0);
571 ASSERT_STREQ(t, "{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}");
572 t = mfree(t);
573
574 assert_se(sd_json_build(&w, SD_JSON_BUILD_OBJECT(
575 SD_JSON_BUILD_PAIR("bar", SD_JSON_BUILD_STRING("zzz")),
576 SD_JSON_BUILD_PAIR("foo", SD_JSON_BUILD_VARIANT(v)))) >= 0);
577
578 assert_se(sd_json_variant_is_sorted(w));
579 assert_se(!sd_json_variant_is_normalized(w));
580
581 assert_se(sd_json_variant_format(w, 0, &t) >= 0);
582 ASSERT_STREQ(t, "{\"bar\":\"zzz\",\"foo\":{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}}");
583 t = mfree(t);
584
585 assert_se(sd_json_variant_sort(&v) >= 0);
586 assert_se(sd_json_variant_is_sorted(v));
587 assert_se(sd_json_variant_is_normalized(v));
588
589 assert_se(sd_json_variant_format(v, 0, &t) >= 0);
590 ASSERT_STREQ(t, "{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}");
591 t = mfree(t);
592
593 assert_se(sd_json_variant_normalize(&w) >= 0);
594 assert_se(sd_json_variant_is_sorted(w));
595 assert_se(sd_json_variant_is_normalized(w));
596
597 assert_se(sd_json_variant_format(w, 0, &t) >= 0);
598 ASSERT_STREQ(t, "{\"bar\":\"zzz\",\"foo\":{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}}");
599 t = mfree(t);
600 }
601
602 TEST(bisect) {
603 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
604
605 /* Tests the bisection logic in sd_json_variant_by_key() */
606
607 for (char c = 'z'; c >= 'a'; c--) {
608
609 if ((c % 3) == 0)
610 continue;
611
612 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
613 assert_se(sd_json_variant_new_stringn(&w, (char[4]) { '<', c, c, '>' }, 4) >= 0);
614 assert_se(sd_json_variant_set_field(&v, (char[2]) { c, 0 }, w) >= 0);
615 }
616
617 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
618
619 assert_se(!sd_json_variant_is_sorted(v));
620 assert_se(!sd_json_variant_is_normalized(v));
621 assert_se(sd_json_variant_normalize(&v) >= 0);
622 assert_se(sd_json_variant_is_sorted(v));
623 assert_se(sd_json_variant_is_normalized(v));
624
625 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
626
627 for (char c = 'a'; c <= 'z'; c++) {
628 sd_json_variant *k;
629 const char *z;
630
631 k = sd_json_variant_by_key(v, (char[2]) { c, 0 });
632 assert_se(!k == ((c % 3) == 0));
633
634 if (!k)
635 continue;
636
637 assert_se(sd_json_variant_is_string(k));
638
639 z = (char[5]){ '<', c, c, '>', 0};
640 ASSERT_STREQ(sd_json_variant_string(k), z);
641 }
642 }
643
644 static void test_float_match(sd_json_variant *v) {
645 const double delta = 0.0001;
646
647 assert_se(sd_json_variant_is_array(v));
648 assert_se(sd_json_variant_elements(v) == 11);
649 assert_se(fabs(1.0 - (DBL_MIN / sd_json_variant_real(sd_json_variant_by_index(v, 0)))) <= delta);
650 assert_se(fabs(1.0 - (DBL_MAX / sd_json_variant_real(sd_json_variant_by_index(v, 1)))) <= delta);
651 assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 2))); /* nan is not supported by json → null */
652 assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 3))); /* +inf is not supported by json → null */
653 assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 4))); /* -inf is not supported by json → null */
654 assert_se(sd_json_variant_is_null(sd_json_variant_by_index(v, 5)) ||
655 fabs(1.0 - (HUGE_VAL / sd_json_variant_real(sd_json_variant_by_index(v, 5)))) <= delta); /* HUGE_VAL might be +inf, but might also be something else */
656 assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 6)) &&
657 sd_json_variant_is_integer(sd_json_variant_by_index(v, 6)) &&
658 sd_json_variant_integer(sd_json_variant_by_index(v, 6)) == 0);
659 assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 7)) &&
660 sd_json_variant_is_integer(sd_json_variant_by_index(v, 7)) &&
661 sd_json_variant_integer(sd_json_variant_by_index(v, 7)) == 10);
662 assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 8)) &&
663 sd_json_variant_is_integer(sd_json_variant_by_index(v, 8)) &&
664 sd_json_variant_integer(sd_json_variant_by_index(v, 8)) == -10);
665 assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 9)) &&
666 !sd_json_variant_is_integer(sd_json_variant_by_index(v, 9)));
667 assert_se(fabs(1.0 - (DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 9)))) <= delta);
668 assert_se(sd_json_variant_is_real(sd_json_variant_by_index(v, 10)) &&
669 !sd_json_variant_is_integer(sd_json_variant_by_index(v, 10)));
670 assert_se(fabs(1.0 - (-DBL_MIN / 2 / sd_json_variant_real(sd_json_variant_by_index(v, 10)))) <= delta);
671 }
672
673 TEST(float) {
674 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
675 _cleanup_free_ char *text = NULL;
676
677 assert_se(sd_json_build(&v, SD_JSON_BUILD_ARRAY(
678 SD_JSON_BUILD_REAL(DBL_MIN),
679 SD_JSON_BUILD_REAL(DBL_MAX),
680 SD_JSON_BUILD_REAL(NAN),
681 SD_JSON_BUILD_REAL(INFINITY),
682 SD_JSON_BUILD_REAL(-INFINITY),
683 SD_JSON_BUILD_REAL(HUGE_VAL),
684 SD_JSON_BUILD_REAL(0),
685 SD_JSON_BUILD_REAL(10),
686 SD_JSON_BUILD_REAL(-10),
687 SD_JSON_BUILD_REAL(DBL_MIN / 2),
688 SD_JSON_BUILD_REAL(-DBL_MIN / 2))) >= 0);
689
690 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
691
692 test_float_match(v);
693
694 assert_se(sd_json_variant_format(v, 0, &text) >= 0);
695 assert_se(sd_json_parse(text, 0, &w, NULL, NULL) >= 0);
696
697 sd_json_variant_dump(w, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
698
699 test_float_match(w);
700 }
701
702 static void test_equal_text(sd_json_variant *v, const char *text) {
703 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
704
705 assert_se(sd_json_parse(text, 0, &w, NULL, NULL) >= 0);
706 assert_se(sd_json_variant_equal(v, w) || (!v && sd_json_variant_is_null(w)));
707 }
708
709 TEST(set_field) {
710 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
711
712 test_equal_text(v, "null");
713 assert_se(sd_json_variant_set_field(&v, "foo", NULL) >= 0);
714 test_equal_text(v, "{\"foo\" : null}");
715 assert_se(sd_json_variant_set_field(&v, "bar", JSON_VARIANT_STRING_CONST("quux")) >= 0);
716 test_equal_text(v, "{\"foo\" : null, \"bar\" : \"quux\"}");
717 assert_se(sd_json_variant_set_field(&v, "foo", JSON_VARIANT_STRING_CONST("quux2")) >= 0);
718 test_equal_text(v, "{\"foo\" : \"quux2\", \"bar\" : \"quux\"}");
719 assert_se(sd_json_variant_set_field(&v, "bar", NULL) >= 0);
720 test_equal_text(v, "{\"foo\" : \"quux2\", \"bar\" : null}");
721 }
722
723 TEST(tokenizer) {
724 test_tokenizer_one("x", -EINVAL);
725 test_tokenizer_one("", JSON_TOKEN_END);
726 test_tokenizer_one(" ", JSON_TOKEN_END);
727 test_tokenizer_one("0", JSON_TOKEN_UNSIGNED, (uint64_t) 0, JSON_TOKEN_END);
728 test_tokenizer_one("-0", JSON_TOKEN_INTEGER, (int64_t) 0, JSON_TOKEN_END);
729 test_tokenizer_one("1234", JSON_TOKEN_UNSIGNED, (uint64_t) 1234, JSON_TOKEN_END);
730 test_tokenizer_one("-1234", JSON_TOKEN_INTEGER, (int64_t) -1234, JSON_TOKEN_END);
731 test_tokenizer_one("18446744073709551615", JSON_TOKEN_UNSIGNED, (uint64_t) UINT64_MAX, JSON_TOKEN_END);
732 test_tokenizer_one("-9223372036854775808", JSON_TOKEN_INTEGER, (int64_t) INT64_MIN, JSON_TOKEN_END);
733 test_tokenizer_one("18446744073709551616", JSON_TOKEN_REAL, (double) 18446744073709551616.0L, JSON_TOKEN_END);
734 test_tokenizer_one("-9223372036854775809", JSON_TOKEN_REAL, (double) -9223372036854775809.0L, JSON_TOKEN_END);
735 test_tokenizer_one("-1234", JSON_TOKEN_INTEGER, (int64_t) -1234, JSON_TOKEN_END);
736 test_tokenizer_one("3.141", JSON_TOKEN_REAL, (double) 3.141, JSON_TOKEN_END);
737 test_tokenizer_one("0.0", JSON_TOKEN_REAL, (double) 0.0, JSON_TOKEN_END);
738 test_tokenizer_one("7e3", JSON_TOKEN_REAL, (double) 7e3, JSON_TOKEN_END);
739 test_tokenizer_one("-7e-3", JSON_TOKEN_REAL, (double) -7e-3, JSON_TOKEN_END);
740 test_tokenizer_one("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END);
741 test_tokenizer_one("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END);
742 test_tokenizer_one("null", JSON_TOKEN_NULL, JSON_TOKEN_END);
743 test_tokenizer_one("{}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
744 test_tokenizer_one("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
745 test_tokenizer_one("[]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
746 test_tokenizer_one("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
747 test_tokenizer_one("\"\"", JSON_TOKEN_STRING, "", JSON_TOKEN_END);
748 test_tokenizer_one("\"foo\"", JSON_TOKEN_STRING, "foo", JSON_TOKEN_END);
749 test_tokenizer_one("\"foo\\nfoo\"", JSON_TOKEN_STRING, "foo\nfoo", JSON_TOKEN_END);
750 test_tokenizer_one("{\"foo\" : \"bar\"}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_STRING, "foo", JSON_TOKEN_COLON, JSON_TOKEN_STRING, "bar", JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END);
751 test_tokenizer_one("{\"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);
752 test_tokenizer_one("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
753 test_tokenizer_one("\"\\ufffd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END);
754 test_tokenizer_one("\"\\uf\"", -EINVAL);
755 test_tokenizer_one("\"\\ud800a\"", -EINVAL);
756 test_tokenizer_one("\"\\udc00\\udc00\"", -EINVAL);
757 test_tokenizer_one("\"\\ud801\\udc37\"", JSON_TOKEN_STRING, "\xf0\x90\x90\xb7", JSON_TOKEN_END);
758
759 test_tokenizer_one("[1, 2, -3]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_UNSIGNED, (uint64_t) 1, JSON_TOKEN_COMMA, JSON_TOKEN_UNSIGNED, (uint64_t) 2, JSON_TOKEN_COMMA, JSON_TOKEN_INTEGER, (int64_t) -3, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END);
760 }
761
762 TEST(variant) {
763 test_variant_one("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
764 test_variant_one("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2);
765 test_variant_one("{\"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);
766
767 test_variant_one("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes);
768 }
769
770 TEST(json_variant_merge_objectb) {
771 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
772
773 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
774 SD_JSON_BUILD_PAIR("b", SD_JSON_BUILD_STRING("x")),
775 SD_JSON_BUILD_PAIR("c", JSON_BUILD_CONST_STRING("y")),
776 SD_JSON_BUILD_PAIR("a", JSON_BUILD_CONST_STRING("z")))) >= 0);
777
778 assert_se(sd_json_variant_merge_objectb(&w, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("b", SD_JSON_BUILD_STRING("x")))) >= 0);
779 assert_se(sd_json_variant_merge_objectb(&w, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_STRING("y")))) >= 0);
780 assert_se(sd_json_variant_merge_objectb(&w, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("a", SD_JSON_BUILD_STRING("z")))) >= 0);
781
782 assert_se(sd_json_variant_equal(v, w));
783 }
784
785 static void json_array_append_with_source_one(bool source) {
786 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a, *b;
787
788 /* Parse two sources, each with a different name and line/column numbers */
789
790 assert_se(sd_json_parse_with_source(" [41]", source ? "string 1" : NULL, 0,
791 &a, NULL, NULL) >= 0);
792 assert_se(sd_json_parse_with_source("\n\n [42]", source ? "string 2" : NULL, 0,
793 &b, NULL, NULL) >= 0);
794
795 assert_se(sd_json_variant_is_array(a));
796 assert_se(sd_json_variant_elements(a) == 1);
797 assert_se(sd_json_variant_is_array(b));
798 assert_se(sd_json_variant_elements(b) == 1);
799
800 /* Verify source information */
801
802 const char *s1, *s2;
803 unsigned line1, col1, line2, col2;
804 assert_se(sd_json_variant_get_source(a, &s1, &line1, &col1) >= 0);
805 assert_se(sd_json_variant_get_source(b, &s2, &line2, &col2) >= 0);
806
807 ASSERT_STREQ(s1, source ? "string 1" : NULL);
808 ASSERT_STREQ(s2, source ? "string 2" : NULL);
809 assert_se(line1 == 1);
810 assert_se(col1 == 2);
811 assert_se(line2 == 3);
812 assert_se(col2 == 4);
813
814 /* Append one elem from the second array (and source) to the first. */
815
816 sd_json_variant *elem;
817 assert_se(elem = sd_json_variant_by_index(b, 0));
818 assert_se(sd_json_variant_is_integer(elem));
819 assert_se(sd_json_variant_elements(elem) == 0);
820
821 assert_se(sd_json_variant_append_array(&a, elem) >= 0);
822
823 assert_se(sd_json_variant_is_array(a));
824 assert_se(sd_json_variant_elements(a) == 2);
825
826 /* Verify that source information was propagated correctly */
827
828 assert_se(sd_json_variant_get_source(elem, &s1, &line1, &col1) >= 0);
829 assert_se(elem = sd_json_variant_by_index(a, 1));
830 assert_se(sd_json_variant_get_source(elem, &s2, &line2, &col2) >= 0);
831
832 ASSERT_STREQ(s1, source ? "string 2" : NULL);
833 ASSERT_STREQ(s2, source ? "string 2" : NULL);
834 assert_se(line1 == 3);
835 assert_se(col1 == 5);
836 assert_se(line2 == 3);
837 assert_se(col2 == 5);
838 }
839
840 TEST(json_array_append_with_source) {
841 json_array_append_with_source_one(true);
842 }
843
844 TEST(json_array_append_without_source) {
845 json_array_append_with_source_one(false);
846 }
847
848 TEST(json_array_append_nodup) {
849 _cleanup_(sd_json_variant_unrefp) sd_json_variant *l = NULL, *s = NULL, *wd = NULL, *nd = NULL;
850
851 assert_se(sd_json_build(&l, SD_JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "bar", "baz", "foo", "qux", "baz"))) >= 0);
852 assert_se(sd_json_build(&s, SD_JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "qux"))) >= 0);
853
854 assert_se(!sd_json_variant_equal(l, s));
855 assert_se(sd_json_variant_elements(l) == 8);
856 assert_se(sd_json_variant_elements(s) == 4);
857
858 sd_json_variant *i;
859 JSON_VARIANT_ARRAY_FOREACH(i, l) {
860 assert_se(sd_json_variant_append_array(&wd, i) >= 0);
861 assert_se(sd_json_variant_append_array_nodup(&nd, i) >= 0);
862 }
863
864 assert_se(sd_json_variant_elements(wd) == 8);
865 assert_se(sd_json_variant_equal(l, wd));
866 assert_se(!sd_json_variant_equal(s, wd));
867
868 assert_se(sd_json_variant_elements(nd) == 4);
869 assert_se(!sd_json_variant_equal(l, nd));
870 assert_se(sd_json_variant_equal(s, nd));
871 }
872
873 TEST(json_dispatch) {
874 struct foobar {
875 uint64_t a, b;
876 int64_t c, d;
877 uint32_t e, f;
878 int32_t g, h;
879 uint16_t i, j;
880 int16_t k, l;
881 uint8_t m, n;
882 int8_t o, p;
883 } foobar = {};
884
885 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
886
887 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
888 SD_JSON_BUILD_PAIR("a", SD_JSON_BUILD_UNSIGNED(UINT64_MAX)),
889 SD_JSON_BUILD_PAIR("b", SD_JSON_BUILD_STRING("18446744073709551615")),
890 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
891 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
892 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_UNSIGNED(UINT32_MAX)),
893 SD_JSON_BUILD_PAIR("f", SD_JSON_BUILD_STRING("4294967295")),
894 SD_JSON_BUILD_PAIR("g", SD_JSON_BUILD_INTEGER(INT32_MIN)),
895 SD_JSON_BUILD_PAIR("h", SD_JSON_BUILD_STRING("-2147483648")),
896 SD_JSON_BUILD_PAIR("i", SD_JSON_BUILD_UNSIGNED(UINT16_MAX)),
897 SD_JSON_BUILD_PAIR("j", SD_JSON_BUILD_STRING("65535")),
898 SD_JSON_BUILD_PAIR("k", SD_JSON_BUILD_INTEGER(INT16_MIN)),
899 SD_JSON_BUILD_PAIR("l", SD_JSON_BUILD_STRING("-32768")),
900 SD_JSON_BUILD_PAIR("m", SD_JSON_BUILD_INTEGER(UINT8_MAX)),
901 SD_JSON_BUILD_PAIR("n", SD_JSON_BUILD_STRING("255")),
902 SD_JSON_BUILD_PAIR("o", SD_JSON_BUILD_INTEGER(INT8_MIN)),
903 SD_JSON_BUILD_PAIR("p", SD_JSON_BUILD_STRING("-128")))) >= 0);
904
905 assert_se(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO, stdout, /* prefix= */ NULL) >= 0);
906
907 sd_json_dispatch_field table[] = {
908 { "a", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct foobar, a) },
909 { "b", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct foobar, b) },
910 { "c", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int64, offsetof(struct foobar, c) },
911 { "d", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int64, offsetof(struct foobar, d) },
912 { "e", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(struct foobar, e) },
913 { "f", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(struct foobar, f) },
914 { "g", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int32, offsetof(struct foobar, g) },
915 { "h", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int32, offsetof(struct foobar, h) },
916 { "i", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct foobar, i) },
917 { "j", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct foobar, j) },
918 { "k", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int16, offsetof(struct foobar, k) },
919 { "l", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int16, offsetof(struct foobar, l) },
920 { "m", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(struct foobar, m) },
921 { "n", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(struct foobar, n) },
922 { "o", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int8, offsetof(struct foobar, o) },
923 { "p", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int8, offsetof(struct foobar, p) },
924 {}
925 };
926
927 assert_se(sd_json_dispatch(v, table, SD_JSON_LOG, &foobar) >= 0);
928
929 assert_se(foobar.a == UINT64_MAX);
930 assert_se(foobar.b == UINT64_MAX);
931 assert_se(foobar.c == INT64_MIN);
932 assert_se(foobar.d == INT64_MIN);
933
934 assert_se(foobar.e == UINT32_MAX);
935 assert_se(foobar.f == UINT32_MAX);
936 assert_se(foobar.g == INT32_MIN);
937 assert_se(foobar.h == INT32_MIN);
938
939 assert_se(foobar.i == UINT16_MAX);
940 assert_se(foobar.j == UINT16_MAX);
941 assert_se(foobar.k == INT16_MIN);
942 assert_se(foobar.l == INT16_MIN);
943
944 assert_se(foobar.m == UINT8_MAX);
945 assert_se(foobar.n == UINT8_MAX);
946 assert_se(foobar.o == INT8_MIN);
947 assert_se(foobar.p == INT8_MIN);
948 }
949
950 typedef enum mytestenum {
951 myfoo, mybar, mybaz, with_some_dashes, _mymax, _myinvalid = -EINVAL,
952 } mytestenum;
953
954 static const char *mytestenum_table[_mymax] = {
955 [myfoo] = "myfoo",
956 [mybar] = "mybar",
957 [mybaz] = "mybaz",
958 [with_some_dashes] = "with-some-dashes",
959 };
960
961 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(mytestenum, mytestenum);
962
963 static JSON_DISPATCH_ENUM_DEFINE(dispatch_mytestenum, mytestenum, mytestenum_from_string);
964
965 TEST(json_dispatch_enum_define) {
966
967 struct data {
968 mytestenum a, b, c, d, e;
969 } data = {
970 .a = _myinvalid,
971 .b = _myinvalid,
972 .c = _myinvalid,
973 .d = mybar,
974 .e = _myinvalid,
975 };
976
977 _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
978
979 assert_se(sd_json_buildo(&j,
980 SD_JSON_BUILD_PAIR("a", SD_JSON_BUILD_STRING("mybaz")),
981 SD_JSON_BUILD_PAIR("b", SD_JSON_BUILD_STRING("mybar")),
982 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_STRING("myfoo")),
983 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_NULL),
984 SD_JSON_BUILD_PAIR("e", JSON_BUILD_STRING_UNDERSCORIFY(mytestenum_to_string(with_some_dashes)))) >= 0);
985
986 assert_se(sd_json_dispatch(j,
987 (const sd_json_dispatch_field[]) {
988 { "a", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, a), 0 },
989 { "b", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, b), 0 },
990 { "c", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, c), 0 },
991 { "d", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, d), 0 },
992 { "e", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, e), 0 },
993 {},
994 },
995 /* flags= */ 0,
996 &data) >= 0);
997
998 assert(data.a == mybaz);
999 assert(data.b == mybar);
1000 assert(data.c == myfoo);
1001 assert(data.d < 0);
1002 assert(data.e == with_some_dashes);
1003 }
1004
1005 TEST(json_dispatch_double) {
1006
1007 _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
1008
1009 assert_se(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
1010 SD_JSON_BUILD_PAIR("x1", SD_JSON_BUILD_REAL(0.5)),
1011 SD_JSON_BUILD_PAIR("x2", SD_JSON_BUILD_REAL(-0.5)),
1012 SD_JSON_BUILD_PAIR("x3", JSON_BUILD_CONST_STRING("infinity")),
1013 SD_JSON_BUILD_PAIR("x4", JSON_BUILD_CONST_STRING("-infinity")),
1014 SD_JSON_BUILD_PAIR("x5", JSON_BUILD_CONST_STRING("nan")),
1015 SD_JSON_BUILD_PAIR("x6", JSON_BUILD_CONST_STRING("inf")),
1016 SD_JSON_BUILD_PAIR("x7", JSON_BUILD_CONST_STRING("-inf")))) >= 0);
1017
1018 struct data {
1019 double x1, x2, x3, x4, x5, x6, x7;
1020 } data = {};
1021
1022 assert_se(sd_json_dispatch(j,
1023 (const sd_json_dispatch_field[]) {
1024 { "x1", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x1), 0 },
1025 { "x2", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x2), 0 },
1026 { "x3", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x3), 0 },
1027 { "x4", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x4), 0 },
1028 { "x5", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x5), 0 },
1029 { "x6", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x6), 0 },
1030 { "x7", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_double, offsetof(struct data, x7), 0 },
1031 {},
1032 },
1033 /* flags= */ 0,
1034 &data) >= 0);
1035
1036 assert_se(fabs(data.x1 - 0.5) < 0.01);
1037 assert_se(fabs(data.x2 + 0.5) < 0.01);
1038 assert_se(isinf(data.x3));
1039 assert_se(data.x3 > 0);
1040 assert_se(isinf(data.x4));
1041 assert_se(data.x4 < 0);
1042 assert_se(isnan(data.x5));
1043 assert_se(isinf(data.x6));
1044 assert_se(data.x6 > 0);
1045 assert_se(isinf(data.x7));
1046 assert_se(data.x7 < 0);
1047 }
1048
1049 TEST(json_sensitive) {
1050 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a = NULL, *b = NULL, *v = NULL;
1051 _cleanup_free_ char *s = NULL;
1052 int r;
1053
1054 assert_se(sd_json_build(&a, SD_JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "bar", "baz", "foo", "qux", "baz"))) >= 0);
1055 assert_se(sd_json_build(&b, SD_JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "qux"))) >= 0);
1056
1057 sd_json_variant_sensitive(a);
1058
1059 assert_se(sd_json_variant_format(a, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
1060 ASSERT_STREQ(s, "\"<sensitive data>\"");
1061 s = mfree(s);
1062
1063 r = sd_json_variant_format(b, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
1064 assert_se(r >= 0);
1065 assert_se(s);
1066 assert_se((size_t) r == strlen(s));
1067 s = mfree(s);
1068
1069 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1070 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1071 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1072 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT))) >= 0);
1073 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1074
1075 r = sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
1076 assert_se(r >= 0);
1077 assert_se(s);
1078 assert_se((size_t) r == strlen(s));
1079 s = mfree(s);
1080 v = sd_json_variant_unref(v);
1081
1082 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1083 SD_JSON_BUILD_PAIR_VARIANT("b", b),
1084 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1085 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1086 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT))) >= 0);
1087 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1088
1089 r = sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
1090 assert_se(r >= 0);
1091 assert_se(s);
1092 assert_se((size_t) r == strlen(s));
1093 s = mfree(s);
1094 v = sd_json_variant_unref(v);
1095
1096 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1097 SD_JSON_BUILD_PAIR_VARIANT("b", b),
1098 SD_JSON_BUILD_PAIR_VARIANT("a", a),
1099 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1100 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1101 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT))) >= 0);
1102 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1103
1104 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
1105 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"a\":\"<sensitive data>\",\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"e\":{}}");
1106 s = mfree(s);
1107 v = sd_json_variant_unref(v);
1108
1109 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1110 SD_JSON_BUILD_PAIR_VARIANT("b", b),
1111 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1112 SD_JSON_BUILD_PAIR_VARIANT("a", a),
1113 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1114 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT))) >= 0);
1115 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1116
1117 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
1118 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"a\":\"<sensitive data>\",\"d\":\"-9223372036854775808\",\"e\":{}}");
1119 s = mfree(s);
1120 v = sd_json_variant_unref(v);
1121
1122 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1123 SD_JSON_BUILD_PAIR_VARIANT("b", b),
1124 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1125 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1126 SD_JSON_BUILD_PAIR_VARIANT("a", a),
1127 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT))) >= 0);
1128 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1129
1130 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
1131 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"a\":\"<sensitive data>\",\"e\":{}}");
1132 s = mfree(s);
1133 v = sd_json_variant_unref(v);
1134
1135 assert_se(sd_json_build(&v, SD_JSON_BUILD_OBJECT(
1136 SD_JSON_BUILD_PAIR_VARIANT("b", b),
1137 SD_JSON_BUILD_PAIR("c", SD_JSON_BUILD_INTEGER(INT64_MIN)),
1138 SD_JSON_BUILD_PAIR("d", SD_JSON_BUILD_STRING("-9223372036854775808")),
1139 SD_JSON_BUILD_PAIR("e", SD_JSON_BUILD_EMPTY_OBJECT),
1140 SD_JSON_BUILD_PAIR_VARIANT("a", a))) >= 0);
1141 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1142
1143 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
1144 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"e\":{},\"a\":\"<sensitive data>\"}");
1145 }
1146
1147 TEST(json_iovec) {
1148 struct iovec iov1 = CONST_IOVEC_MAKE_STRING("üxknürz"), iov2 = CONST_IOVEC_MAKE_STRING("wuffwuffmiau");
1149
1150 _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
1151 assert_se(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
1152 SD_JSON_BUILD_PAIR("nr1", JSON_BUILD_IOVEC_BASE64(&iov1)),
1153 SD_JSON_BUILD_PAIR("nr2", JSON_BUILD_IOVEC_HEX(&iov2)))) >= 0);
1154
1155 sd_json_variant_dump(j, SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO, /* f= */ NULL, /* prefix= */ NULL);
1156
1157 _cleanup_(iovec_done) struct iovec a = {}, b = {};
1158 assert_se(json_variant_unbase64_iovec(sd_json_variant_by_key(j, "nr1"), &a) >= 0);
1159 assert_se(json_variant_unhex_iovec(sd_json_variant_by_key(j, "nr2"), &b) >= 0);
1160
1161 assert_se(iovec_memcmp(&iov1, &a) == 0);
1162 assert_se(iovec_memcmp(&iov2, &b) == 0);
1163 assert_se(iovec_memcmp(&iov2, &a) < 0);
1164 assert_se(iovec_memcmp(&iov1, &b) > 0);
1165 }
1166
1167 TEST(json_dispatch_nullable) {
1168
1169 _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
1170
1171 assert_se(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
1172 SD_JSON_BUILD_PAIR("x1", JSON_BUILD_CONST_STRING("foo")),
1173 SD_JSON_BUILD_PAIR("x2", JSON_BUILD_CONST_STRING("bar")),
1174 SD_JSON_BUILD_PAIR("x3", JSON_BUILD_CONST_STRING("waldo")),
1175 SD_JSON_BUILD_PAIR("x4", JSON_BUILD_CONST_STRING("foo2")),
1176 SD_JSON_BUILD_PAIR("x5", JSON_BUILD_CONST_STRING("bar2")),
1177 SD_JSON_BUILD_PAIR("x6", JSON_BUILD_CONST_STRING("waldo2")),
1178 SD_JSON_BUILD_PAIR("x7", SD_JSON_BUILD_NULL),
1179 SD_JSON_BUILD_PAIR("x8", SD_JSON_BUILD_NULL),
1180 SD_JSON_BUILD_PAIR("x9", SD_JSON_BUILD_NULL))) >= 0);
1181
1182 struct data {
1183 const char *x1, *x2, *x3, *x4, *x5, *x6, *x7, *x8, *x9;
1184 } data = {
1185 .x1 = POINTER_MAX,
1186 .x2 = POINTER_MAX,
1187 .x3 = POINTER_MAX,
1188 .x4 = POINTER_MAX,
1189 .x5 = POINTER_MAX,
1190 .x6 = POINTER_MAX,
1191 .x7 = POINTER_MAX,
1192 .x8 = POINTER_MAX,
1193 .x9 = POINTER_MAX,
1194 };
1195
1196 assert_se(sd_json_dispatch(j,
1197 (const sd_json_dispatch_field[]) {
1198 { "x1", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x1), SD_JSON_NULLABLE },
1199 { "x2", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x2), SD_JSON_REFUSE_NULL },
1200 { "x3", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x3), 0 },
1201 { "x4", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x4), SD_JSON_NULLABLE },
1202 { "x5", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x5), SD_JSON_REFUSE_NULL },
1203 { "x6", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x6), 0 },
1204 { "x7", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x7), SD_JSON_NULLABLE },
1205 { "x8", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x8), 0 },
1206 { "x9", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x9), SD_JSON_NULLABLE },
1207 {},
1208 },
1209 /* flags= */ 0,
1210 &data) >= 0);
1211
1212 assert_se(streq_ptr(data.x1, "foo"));
1213 assert_se(streq_ptr(data.x2, "bar"));
1214 assert_se(streq_ptr(data.x3, "waldo"));
1215 assert_se(streq_ptr(data.x4, "foo2"));
1216 assert_se(streq_ptr(data.x5, "bar2"));
1217 assert_se(streq_ptr(data.x6, "waldo2"));
1218 assert_se(!data.x7);
1219 assert_se(!data.x8);
1220 assert_se(!data.x9);
1221
1222 assert_se(sd_json_dispatch(j,
1223 (const sd_json_dispatch_field[]) {
1224 { "x7", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_const_string, offsetof(struct data, x7), SD_JSON_REFUSE_NULL },
1225 {},
1226 },
1227 /* flags= */ SD_JSON_ALLOW_EXTENSIONS,
1228 &data) == -EINVAL);
1229
1230 assert_se(sd_json_dispatch(j,
1231 (const sd_json_dispatch_field[]) {
1232 { "x7", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x7), SD_JSON_REFUSE_NULL },
1233 {},
1234 },
1235 /* flags= */ SD_JSON_ALLOW_EXTENSIONS,
1236 &data) == -EINVAL);
1237
1238 assert_se(sd_json_dispatch(j,
1239 (const sd_json_dispatch_field[]) {
1240 { "x7", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct data, x7), 0 },
1241 {},
1242 },
1243 /* flags= */ SD_JSON_ALLOW_EXTENSIONS,
1244 &data) == -EINVAL);
1245 }
1246
1247 TEST(parse_continue) {
1248 unsigned line = 23, column = 43;
1249
1250 /* First try to parse with continue logic off, this should fail */
1251 _cleanup_(sd_json_variant_unrefp) sd_json_variant *x = NULL;
1252 assert_se(sd_json_parse_with_source("4711 512", "piff", /* flags= */ 0, &x, &line, &column) == -EINVAL);
1253 assert_se(line == 1);
1254 assert_se(column == 6);
1255
1256 /* Then try to parse with continue logic on, which should yield two numbers */
1257 const char *p = "4711 512";
1258 assert_se(sd_json_parse_with_source_continue(&p, "piff", /* flags= */ 0, &x, &line, &column) >= 0);
1259 assert_se(sd_json_variant_is_unsigned(x));
1260 assert_se(sd_json_variant_unsigned(x) == 4711);
1261 x = sd_json_variant_unref(x);
1262
1263 assert_se(streq_ptr(p, " 512"));
1264 assert_se(sd_json_parse_with_source_continue(&p, "piff", /* flags= */ 0, &x, &line, &column) >= 0);
1265 assert_se(sd_json_variant_is_unsigned(x));
1266 assert_se(sd_json_variant_unsigned(x) == 512);
1267
1268 assert_se(isempty(p));
1269 assert_se(sd_json_parse_with_source_continue(&p, "piff", /* flags= */ 0, &x, &line, &column) == -EINVAL);
1270 }
1271
1272 TEST(pidref) {
1273 _cleanup_(pidref_done) PidRef myself = PIDREF_NULL, pid1 = PIDREF_NULL;
1274
1275 assert_se(pidref_set_pid(&myself, 0) >= 0);
1276 assert_se(pidref_set_pid(&pid1, 1) >= 0);
1277
1278 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
1279 sd_id128_t randomized_boot_id;
1280 assert_se(sd_id128_randomize(&randomized_boot_id) >= 0);
1281 assert_se(sd_json_buildo(&v,
1282 JSON_BUILD_PAIR_PIDREF("myself", &myself),
1283 JSON_BUILD_PAIR_PIDREF("pid1", &pid1),
1284 SD_JSON_BUILD_PAIR("remote", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_UNSIGNED("pid", 1),
1285 SD_JSON_BUILD_PAIR_UNSIGNED("pidfdId", 4711),
1286 SD_JSON_BUILD_PAIR_ID128("bootId", randomized_boot_id))),
1287 SD_JSON_BUILD_PAIR("automatic", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_UNSIGNED("pid", 0)))) >= 0);
1288
1289 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1290
1291 struct {
1292 PidRef myself, pid1, remote, automatic;
1293 } data = {
1294 .myself = PIDREF_NULL,
1295 .pid1 = PIDREF_NULL,
1296 .remote = PIDREF_NULL,
1297 .automatic = PIDREF_NULL,
1298 };
1299
1300 assert_se(sd_json_dispatch(
1301 v,
1302 (const sd_json_dispatch_field[]) {
1303 { "myself", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, myself), SD_JSON_STRICT },
1304 { "pid1", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, pid1), SD_JSON_STRICT },
1305 { "remote", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, remote), 0 },
1306 { "automatic", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, voffsetof(data, automatic), SD_JSON_RELAX },
1307 {},
1308 },
1309 /* flags= */ 0,
1310 &data) >= 0);
1311
1312 assert_se(pidref_equal(&myself, &data.myself));
1313 assert_se(pidref_equal(&pid1, &data.pid1));
1314
1315 assert_se(!pidref_equal(&myself, &data.pid1));
1316 assert_se(!pidref_equal(&pid1, &data.myself));
1317 assert_se(!pidref_equal(&myself, &data.remote));
1318 assert_se(!pidref_equal(&pid1, &data.remote));
1319
1320 assert_se((myself.fd_id > 0) == (data.myself.fd_id > 0));
1321 assert_se((pid1.fd_id > 0) == (data.pid1.fd_id > 0));
1322
1323 assert_se(!pidref_is_set(&data.automatic));
1324 assert_se(pidref_is_automatic(&data.automatic));
1325 assert_se(pidref_is_set(&data.remote));
1326 assert_se(pidref_is_remote(&data.remote));
1327
1328 pidref_done(&data.myself);
1329 pidref_done(&data.pid1);
1330 pidref_done(&data.remote);
1331 }
1332
1333 TEST(devnum) {
1334 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
1335 dev_t dev = makedev(123, 456), parsed;
1336
1337 ASSERT_OK(json_variant_new_devnum(&v, dev));
1338 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1339 ASSERT_OK(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
1340 ASSERT_EQ(major(parsed), major(dev));
1341 ASSERT_EQ(minor(parsed), minor(dev));
1342 v = sd_json_variant_unref(v);
1343
1344 dev = makedev(1 << 12, 456);
1345 ASSERT_OK(json_variant_new_devnum(&v, dev));
1346 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1347 ASSERT_FAIL(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
1348 v = sd_json_variant_unref(v);
1349
1350 dev = makedev(123, 1 << 20);
1351 ASSERT_OK(json_variant_new_devnum(&v, dev));
1352 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1353 ASSERT_FAIL(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
1354 }
1355
1356 TEST(fd_info) {
1357 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
1358 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1359 _cleanup_close_ int fd = -EBADF;
1360
1361 /* directories */
1362 ASSERT_OK(json_variant_new_fd_info(&v, AT_FDCWD));
1363 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1364 v = sd_json_variant_unref(v);
1365
1366 ASSERT_OK_ERRNO(fd = openat(AT_FDCWD, ".", O_CLOEXEC | O_DIRECTORY | O_PATH));
1367 ASSERT_OK(json_variant_new_fd_info(&v, fd));
1368 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1369 v = sd_json_variant_unref(v);
1370 fd = safe_close(fd);
1371
1372 /* regular file */
1373 ASSERT_OK(fd = open_tmpfile_unlinkable(NULL, O_RDWR));
1374 ASSERT_OK(json_variant_new_fd_info(&v, fd));
1375 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1376 v = sd_json_variant_unref(v);
1377 fd = safe_close(fd);
1378
1379 fd = open("/sys/class/net/lo/uevent", O_CLOEXEC | O_PATH);
1380 if (fd >= 0) {
1381 ASSERT_OK(json_variant_new_fd_info(&v, fd));
1382 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1383 v = sd_json_variant_unref(v);
1384 fd = safe_close(fd);
1385 }
1386
1387 /* block device */
1388 fd = open("/dev/sda", O_CLOEXEC | O_PATH);
1389 if (fd >= 0) {
1390 ASSERT_OK(json_variant_new_fd_info(&v, fd));
1391 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1392 v = sd_json_variant_unref(v);
1393 fd = safe_close(fd);
1394 }
1395
1396 /* stream */
1397 ASSERT_OK(json_variant_new_fd_info(&v, fileno(stdout)));
1398 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1399 v = sd_json_variant_unref(v);
1400
1401 /* socket */
1402 ASSERT_OK_ERRNO(fd = socket(AF_INET, SOCK_DGRAM, 0));
1403 ASSERT_OK(json_variant_new_fd_info(&v, fd));
1404 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1405 v = sd_json_variant_unref(v);
1406 fd = safe_close(fd);
1407
1408 /* pidfd */
1409 ASSERT_OK(pidref_set_pid(&pidref, 0));
1410 if (pidref.fd >= 0) {
1411 ASSERT_OK(json_variant_new_fd_info(&v, pidref.fd));
1412 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1413 v = sd_json_variant_unref(v);
1414 }
1415 pidref_done(&pidref);
1416
1417 ASSERT_OK(pidref_set_pid(&pidref, 1));
1418 if (pidref.fd >= 0) {
1419 ASSERT_OK(json_variant_new_fd_info(&v, pidref.fd));
1420 ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
1421 v = sd_json_variant_unref(v);
1422 }
1423 pidref_done(&pidref);
1424 }
1425
1426 TEST(unit_name) {
1427 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
1428 ASSERT_OK(sd_json_buildo(&v,
1429 SD_JSON_BUILD_PAIR_STRING("plain", "myservice.service"),
1430 SD_JSON_BUILD_PAIR_STRING("instance", "myservice@instance1.service"),
1431 SD_JSON_BUILD_PAIR_STRING("template", "myservice@.service")));
1432
1433 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1434
1435 struct {
1436 const char *plain, *instance, *template;
1437 } data = {};
1438
1439 ASSERT_OK(sd_json_dispatch(
1440 v,
1441 (const sd_json_dispatch_field[]) {
1442 { "plain", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, plain), SD_JSON_STRICT },
1443 { "instance", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, instance), 0 },
1444 { "template", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, template), SD_JSON_RELAX },
1445 {},
1446 },
1447 /* flags= */ 0,
1448 &data));
1449
1450 ASSERT_STREQ(data.plain, "myservice.service");
1451 ASSERT_STREQ(data.instance, "myservice@instance1.service");
1452 ASSERT_STREQ(data.template, "myservice@.service");
1453
1454 ASSERT_ERROR(sd_json_dispatch(
1455 v,
1456 (const sd_json_dispatch_field[]) {
1457 { "plain", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, plain), SD_JSON_RELAX },
1458 /* instance value is not allowed with SD_JSON_STRICT */
1459 { "instance", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, instance), SD_JSON_STRICT },
1460 { "template", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, template), SD_JSON_RELAX },
1461 {},
1462 },
1463 /* flags= */ 0,
1464 &data), EINVAL);
1465
1466 ASSERT_ERROR(sd_json_dispatch(
1467 v,
1468 (const sd_json_dispatch_field[]) {
1469 { "plain", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, plain), SD_JSON_RELAX },
1470 { "instance", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, instance), SD_JSON_RELAX },
1471 /* template value is not allowed by default */
1472 { "template", SD_JSON_VARIANT_STRING, json_dispatch_const_unit_name, voffsetof(data, template), 0 },
1473 {},
1474 },
1475 /* flags= */ 0,
1476 &data), EINVAL);
1477 }
1478
1479 DEFINE_TEST_MAIN(LOG_DEBUG);