]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-json.c
tree-wide: Add more socket units (#37991)
[thirdparty/systemd.git] / src / test / test-json.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
788c34be 2
c79aaff9 3#include <float.h>
fa34123c 4#include <sys/socket.h>
3b7d3320 5#include <sys/sysmacros.h>
4f18ff2e 6#include <unistd.h>
788c34be 7
309a747f
LP
8#include "sd-json.h"
9
788c34be 10#include "alloc-util.h"
4d7f5175 11#include "escape.h"
788c34be 12#include "fd-util.h"
fa34123c 13#include "format-util.h"
673a1e6f 14#include "fileio.h"
9d1c3e94 15#include "iovec-util.h"
788c34be 16#include "json-internal.h"
309a747f 17#include "json-util.h"
1561db8a 18#include "math-util.h"
ed207e52 19#include "ordered-set.h"
fa34123c
DDM
20#include "pidref.h"
21#include "set.h"
8618ff13 22#include "string-table.h"
adbdcfbe 23#include "tests.h"
60ae3b86 24#include "tmpfile-util.h"
788c34be 25
4f7452a8 26static void test_tokenizer_one(const char *data, ...) {
788c34be
LP
27 unsigned line = 0, column = 0;
28 void *state = NULL;
29 va_list ap;
30
3d41b6b8 31 _cleanup_free_ char *cdata = NULL;
4d7f5175
ZJS
32 assert_se(cdata = cescape(data));
33 log_info("/* %s data=\"%s\" */", __func__, cdata);
34
788c34be
LP
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 *);
c79e88b3 55 ASSERT_STREQ(nn, str);
788c34be
LP
56
57 } else if (t == JSON_TOKEN_REAL) {
337712e7 58 double d;
788c34be 59
337712e7 60 d = va_arg(ap, double);
aa70783f 61
39229a2a
YW
62 assert_se(fabs(d - v.real) < 1e-10 ||
63 fabs((d - v.real) / v.real) < 1e-10);
788c34be
LP
64
65 } else if (t == JSON_TOKEN_INTEGER) {
718ca772 66 int64_t i;
788c34be 67
718ca772 68 i = va_arg(ap, int64_t);
788c34be
LP
69 assert_se(i == v.integer);
70
71 } else if (t == JSON_TOKEN_UNSIGNED) {
718ca772 72 uint64_t u;
788c34be 73
718ca772 74 u = va_arg(ap, uint64_t);
788c34be
LP
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
309a747f 88typedef void (*Test)(sd_json_variant *);
788c34be 89
4f7452a8 90static void test_variant_one(const char *data, Test test) {
309a747f 91 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
788c34be
LP
92 _cleanup_free_ char *s = NULL;
93 int r;
94
4d7f5175
ZJS
95 _cleanup_free_ char *cdata;
96 assert_se(cdata = cescape(data));
97 log_info("/* %s data=\"%s\" */", __func__, cdata);
98
309a747f 99 r = sd_json_parse(data, 0, &v, NULL, NULL);
788c34be
LP
100 assert_se(r == 0);
101 assert_se(v);
102
309a747f 103 r = sd_json_variant_format(v, 0, &s);
788c34be
LP
104 assert_se(r >= 0);
105 assert_se(s);
2a04712c 106 assert_se((size_t) r == strlen(s));
788c34be 107
0c13daee 108 log_info("formatted normally: %s", s);
788c34be 109
309a747f 110 r = sd_json_parse(data, SD_JSON_PARSE_SENSITIVE, &w, NULL, NULL);
788c34be
LP
111 assert_se(r == 0);
112 assert_se(w);
309a747f
LP
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));
788c34be 116
fa9a6db4 117 s = mfree(s);
309a747f 118 r = sd_json_variant_format(w, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
99128971 119 assert_se(s);
c79e88b3 120 ASSERT_STREQ(s, "\"<sensitive data>\"");
fa9a6db4
LB
121
122 s = mfree(s);
309a747f 123 r = sd_json_variant_format(w, SD_JSON_FORMAT_PRETTY, &s);
fa9a6db4
LB
124 assert_se(r >= 0);
125 assert_se(s);
126 assert_se((size_t) r == strlen(s));
127
788c34be 128 s = mfree(s);
309a747f 129 w = sd_json_variant_unref(w);
788c34be 130
309a747f 131 r = sd_json_variant_format(v, SD_JSON_FORMAT_PRETTY, &s);
788c34be
LP
132 assert_se(r >= 0);
133 assert_se(s);
2a04712c 134 assert_se((size_t) r == strlen(s));
788c34be
LP
135
136 log_info("formatted prettily:\n%s", s);
137
309a747f 138 r = sd_json_parse(data, 0, &w, NULL, NULL);
788c34be
LP
139 assert_se(r == 0);
140 assert_se(w);
141
309a747f
LP
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));
788c34be
LP
145
146 s = mfree(s);
309a747f 147 r = sd_json_variant_format(v, SD_JSON_FORMAT_COLOR, &s);
788c34be
LP
148 assert_se(r >= 0);
149 assert_se(s);
2a04712c 150 assert_se((size_t) r == strlen(s));
788c34be
LP
151 printf("Normal with color: %s\n", s);
152
153 s = mfree(s);
309a747f 154 r = sd_json_variant_format(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, &s);
788c34be
LP
155 assert_se(r >= 0);
156 assert_se(s);
2a04712c 157 assert_se((size_t) r == strlen(s));
788c34be
LP
158 printf("Pretty with color:\n%s\n", s);
159
160 if (test)
161 test(v);
162}
163
309a747f
LP
164static void test_1(sd_json_variant *v) {
165 sd_json_variant *p, *q;
788c34be
LP
166 unsigned i;
167
4d7f5175
ZJS
168 log_info("/* %s */", __func__);
169
788c34be 170 /* 3 keys + 3 values */
309a747f 171 assert_se(sd_json_variant_elements(v) == 6);
788c34be
LP
172
173 /* has k */
309a747f
LP
174 p = sd_json_variant_by_key(v, "k");
175 assert_se(p && sd_json_variant_type(p) == SD_JSON_VARIANT_STRING);
788c34be
LP
176
177 /* k equals v */
309a747f 178 ASSERT_STREQ(sd_json_variant_string(p), "v");
788c34be
LP
179
180 /* has foo */
309a747f
LP
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);
788c34be
LP
183
184 /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
185 for (i = 0; i < 3; ++i) {
309a747f
LP
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));
788c34be
LP
189 }
190
191 /* has bar */
309a747f
LP
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);
788c34be
LP
194
195 /* zap is null */
309a747f
LP
196 q = sd_json_variant_by_key(p, "zap");
197 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_NULL);
788c34be
LP
198}
199
309a747f
LP
200static void test_2(sd_json_variant *v) {
201 sd_json_variant *p, *q;
788c34be 202
4d7f5175
ZJS
203 log_info("/* %s */", __func__);
204
788c34be 205 /* 2 keys + 2 values */
309a747f 206 assert_se(sd_json_variant_elements(v) == 4);
788c34be
LP
207
208 /* has mutant */
309a747f
LP
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);
788c34be
LP
211
212 /* mutant[0] == 1 */
309a747f
LP
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);
788c34be
LP
216
217 /* mutant[1] == null */
309a747f
LP
218 q = sd_json_variant_by_index(p, 1);
219 assert_se(q && sd_json_variant_type(q) == SD_JSON_VARIANT_NULL);
788c34be
LP
220
221 /* mutant[2] == "1" */
309a747f
LP
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"));
788c34be 224
309a747f
LP
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);
788c34be
LP
228
229 /* has 1 */
309a747f
LP
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);
788c34be
LP
232
233 /* "1"[0] == 1 */
309a747f
LP
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);
788c34be
LP
237
238 /* "1"[1] == "1" */
309a747f
LP
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"));
788c34be
LP
241
242 /* has thisisaverylongproperty */
309a747f
LP
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);
788c34be
LP
245}
246
309a747f 247static void test_zeroes(sd_json_variant *v) {
788c34be 248 /* Make sure zero is how we expect it. */
4d7f5175 249 log_info("/* %s */", __func__);
788c34be 250
309a747f 251 assert_se(sd_json_variant_elements(v) == 13);
788c34be 252
309a747f
LP
253 for (size_t i = 0; i < sd_json_variant_elements(v); i++) {
254 sd_json_variant *w;
788c34be
LP
255 size_t j;
256
309a747f 257 assert_se(w = sd_json_variant_by_index(v, i));
788c34be 258
309a747f
LP
259 assert_se(sd_json_variant_integer(w) == 0);
260 assert_se(sd_json_variant_unsigned(w) == 0U);
788c34be 261
309a747f 262 assert_se(iszero_safe(sd_json_variant_real(w)));
788c34be 263
309a747f
LP
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));
788c34be 268
309a747f 269 assert_se(!sd_json_variant_is_negative(w));
788c34be 270
309a747f 271 assert_se(IN_SET(sd_json_variant_type(w), SD_JSON_VARIANT_INTEGER, SD_JSON_VARIANT_UNSIGNED, SD_JSON_VARIANT_REAL));
788c34be 272
309a747f
LP
273 for (j = 0; j < sd_json_variant_elements(v); j++) {
274 sd_json_variant *q;
788c34be 275
309a747f 276 assert_se(q = sd_json_variant_by_index(v, j));
788c34be 277
309a747f 278 assert_se(sd_json_variant_equal(w, q));
788c34be
LP
279 }
280 }
281}
282
f000a97b
LP
283static 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);
9ba489c7
DDM
289 else if (streq_ptr(name, "mypid3"))
290 return 0;
f000a97b
LP
291 else
292 assert_not_reached();
293
294 return sd_json_build(ret, SD_JSON_BUILD_INTEGER(getpid()));
295}
296
4f7452a8 297TEST(build) {
309a747f 298 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a = NULL, *b = NULL;
788c34be
LP
299 _cleanup_free_ char *s = NULL, *t = NULL;
300
309a747f
LP
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));
788c34be 304
309a747f 305 b = sd_json_variant_unref(b);
788c34be 306
309a747f
LP
307 assert_se(sd_json_build(&b, SD_JSON_BUILD_VARIANT(a)) >= 0);
308 assert_se(sd_json_variant_equal(a, b));
788c34be 309
309a747f
LP
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));
788c34be 313
309a747f
LP
314 a = sd_json_variant_unref(a);
315 b = sd_json_variant_unref(b);
788c34be 316
a556a71e
LP
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);
788c34be 328
309a747f 329 assert_se(sd_json_variant_equal(a, b));
788c34be 330
309a747f
LP
331 a = sd_json_variant_unref(a);
332 b = sd_json_variant_unref(b);
788c34be 333
14648b76 334 const char* arr_1234[] = {"one", "two", "three", "four", NULL};
309a747f
LP
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);
0c13daee 347 log_info("GOT: %s", s);
309a747f
LP
348 assert_se(sd_json_parse(s, 0, &b, NULL, NULL) >= 0);
349 assert_se(sd_json_variant_equal(a, b));
788c34be 350
309a747f
LP
351 a = sd_json_variant_unref(a);
352 b = sd_json_variant_unref(b);
788c34be 353
309a747f 354 assert_se(sd_json_build(&a, SD_JSON_BUILD_REAL(M_PI)) >= 0);
788c34be
LP
355
356 s = mfree(s);
309a747f 357 assert_se(sd_json_variant_format(a, 0, &s) >= 0);
0c13daee 358 log_info("GOT: %s", s);
309a747f
LP
359 assert_se(sd_json_parse(s, 0, &b, NULL, NULL) >= 0);
360 assert_se(sd_json_variant_format(b, 0, &t) >= 0);
0c13daee 361 log_info("GOT: %s", t);
788c34be 362
c79e88b3 363 ASSERT_STREQ(s, t);
788c34be 364
309a747f
LP
365 a = sd_json_variant_unref(a);
366 b = sd_json_variant_unref(b);
319a4f27 367
309a747f
LP
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"))
319a4f27
LP
372 )) >= 0);
373
309a747f
LP
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"))
319a4f27
LP
380 )) >= 0);
381
309a747f 382 assert_se(sd_json_variant_equal(a, b));
f000a97b
LP
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
9ba489c7
DDM
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
f000a97b
LP
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));
ed207e52
DDM
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));
788c34be
LP
448}
449
004c69a2
LP
450TEST(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
87a16eb8
ZJS
465TEST(json_parse_file_empty) {
466 _cleanup_fclose_ FILE *f = NULL;
309a747f 467 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
87a16eb8
ZJS
468
469 assert_se(fopen_unlocked("/dev/null", "re", &f) >= 0);
309a747f 470 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -ENODATA);
5152b845 471 ASSERT_NULL(v);
87a16eb8
ZJS
472}
473
474TEST(json_parse_file_invalid) {
475 _cleanup_fclose_ FILE *f = NULL;
309a747f 476 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
87a16eb8
ZJS
477
478 assert_se(f = fmemopen_unlocked((void*) "kookoo", 6, "r"));
309a747f 479 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -EINVAL);
5152b845 480 ASSERT_NULL(v);
87a16eb8
ZJS
481}
482
4f7452a8 483TEST(source) {
788c34be
LP
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;
309a747f 501 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
788c34be
LP
502
503 printf("--- original begin ---\n"
504 "%s"
505 "--- original end ---\n", data);
506
673a1e6f 507 assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r"));
788c34be 508
309a747f 509 assert_se(sd_json_parse_file(f, "waldo", 0, &v, NULL, NULL) >= 0);
788c34be
LP
510
511 printf("--- non-pretty begin ---\n");
309a747f 512 sd_json_variant_dump(v, 0, stdout, NULL);
788c34be
LP
513 printf("\n--- non-pretty end ---\n");
514
515 printf("--- pretty begin ---\n");
309a747f 516 sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_SOURCE, stdout, NULL);
788c34be
LP
517 printf("--- pretty end ---\n");
518}
519
4f7452a8 520TEST(depth) {
309a747f 521 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
b2fa0d4f
LP
522 int r;
523
d520d519 524 v = JSON_VARIANT_STRING_CONST("start");
b2fa0d4f
LP
525
526 /* Let's verify that the maximum depth checks work */
527
4d7f5175 528 for (unsigned i = 0;; i++) {
309a747f 529 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
b2fa0d4f
LP
530
531 assert_se(i <= UINT16_MAX);
532 if (i & 1)
309a747f 533 r = sd_json_variant_new_array(&w, &v, 1);
b2fa0d4f 534 else
309a747f 535 r = sd_json_variant_new_object(&w, (sd_json_variant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2);
b2fa0d4f
LP
536 if (r == -ELNRNG) {
537 log_info("max depth at %u", i);
538 break;
539 }
b6cda3ec
ZJS
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
b2fa0d4f
LP
547
548 assert_se(r >= 0);
549
309a747f 550 sd_json_variant_unref(v);
b2fa0d4f
LP
551 v = TAKE_PTR(w);
552 }
553
309a747f 554 sd_json_variant_dump(v, 0, stdout, NULL);
d520d519 555 fputs("\n", stdout);
b2fa0d4f
LP
556}
557
4f7452a8 558TEST(normalize) {
309a747f 559 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
b7fc90a2
LP
560 _cleanup_free_ char *t = NULL;
561
309a747f
LP
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);
b7fc90a2 566
309a747f
LP
567 assert_se(!sd_json_variant_is_sorted(v));
568 assert_se(!sd_json_variant_is_normalized(v));
b7fc90a2 569
309a747f 570 assert_se(sd_json_variant_format(v, 0, &t) >= 0);
c79e88b3 571 ASSERT_STREQ(t, "{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}");
b7fc90a2
LP
572 t = mfree(t);
573
309a747f
LP
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);
b7fc90a2 577
309a747f
LP
578 assert_se(sd_json_variant_is_sorted(w));
579 assert_se(!sd_json_variant_is_normalized(w));
b7fc90a2 580
309a747f 581 assert_se(sd_json_variant_format(w, 0, &t) >= 0);
c79e88b3 582 ASSERT_STREQ(t, "{\"bar\":\"zzz\",\"foo\":{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}}");
b7fc90a2
LP
583 t = mfree(t);
584
309a747f
LP
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));
b7fc90a2 588
309a747f 589 assert_se(sd_json_variant_format(v, 0, &t) >= 0);
c79e88b3 590 ASSERT_STREQ(t, "{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}");
b7fc90a2
LP
591 t = mfree(t);
592
309a747f
LP
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));
b7fc90a2 596
309a747f 597 assert_se(sd_json_variant_format(w, 0, &t) >= 0);
c79e88b3 598 ASSERT_STREQ(t, "{\"bar\":\"zzz\",\"foo\":{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}}");
b7fc90a2
LP
599 t = mfree(t);
600}
601
4f7452a8 602TEST(bisect) {
309a747f 603 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
b7fc90a2 604
309a747f 605 /* Tests the bisection logic in sd_json_variant_by_key() */
b7fc90a2 606
4d7f5175 607 for (char c = 'z'; c >= 'a'; c--) {
b7fc90a2
LP
608
609 if ((c % 3) == 0)
610 continue;
611
309a747f
LP
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);
b7fc90a2
LP
615 }
616
309a747f 617 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
b7fc90a2 618
309a747f
LP
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));
b7fc90a2 624
309a747f 625 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
b7fc90a2 626
4d7f5175 627 for (char c = 'a'; c <= 'z'; c++) {
309a747f 628 sd_json_variant *k;
b7fc90a2
LP
629 const char *z;
630
309a747f 631 k = sd_json_variant_by_key(v, (char[2]) { c, 0 });
b7fc90a2
LP
632 assert_se(!k == ((c % 3) == 0));
633
634 if (!k)
635 continue;
636
309a747f 637 assert_se(sd_json_variant_is_string(k));
b7fc90a2
LP
638
639 z = (char[5]){ '<', c, c, '>', 0};
309a747f 640 ASSERT_STREQ(sd_json_variant_string(k), z);
b7fc90a2
LP
641 }
642}
643
309a747f 644static void test_float_match(sd_json_variant *v) {
337712e7 645 const double delta = 0.0001;
c79aaff9 646
309a747f
LP
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);
c79aaff9
LP
671}
672
4f7452a8 673TEST(float) {
309a747f 674 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
c79aaff9
LP
675 _cleanup_free_ char *text = NULL;
676
309a747f
LP
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);
c79aaff9
LP
691
692 test_float_match(v);
693
309a747f
LP
694 assert_se(sd_json_variant_format(v, 0, &text) >= 0);
695 assert_se(sd_json_parse(text, 0, &w, NULL, NULL) >= 0);
c79aaff9 696
309a747f 697 sd_json_variant_dump(w, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
c79aaff9
LP
698
699 test_float_match(w);
700}
701
309a747f
LP
702static void test_equal_text(sd_json_variant *v, const char *text) {
703 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
e2c7efd3 704
309a747f
LP
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)));
e2c7efd3
LP
707}
708
4f7452a8 709TEST(set_field) {
309a747f 710 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
e2c7efd3 711
e2c7efd3 712 test_equal_text(v, "null");
309a747f 713 assert_se(sd_json_variant_set_field(&v, "foo", NULL) >= 0);
e2c7efd3 714 test_equal_text(v, "{\"foo\" : null}");
309a747f 715 assert_se(sd_json_variant_set_field(&v, "bar", JSON_VARIANT_STRING_CONST("quux")) >= 0);
e2c7efd3 716 test_equal_text(v, "{\"foo\" : null, \"bar\" : \"quux\"}");
309a747f 717 assert_se(sd_json_variant_set_field(&v, "foo", JSON_VARIANT_STRING_CONST("quux2")) >= 0);
e2c7efd3 718 test_equal_text(v, "{\"foo\" : \"quux2\", \"bar\" : \"quux\"}");
309a747f 719 assert_se(sd_json_variant_set_field(&v, "bar", NULL) >= 0);
e2c7efd3
LP
720 test_equal_text(v, "{\"foo\" : \"quux2\", \"bar\" : null}");
721}
722
4f7452a8
JJ
723TEST(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);
788c34be 760}
4f7452a8
JJ
761
762TEST(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
e931768e 770TEST(json_variant_merge_objectb) {
309a747f 771 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
41dceb91 772
309a747f
LP
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);
41dceb91 777
309a747f
LP
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);
41dceb91 781
309a747f 782 assert_se(sd_json_variant_equal(v, w));
41dceb91
YW
783}
784
cf1ab844 785static void json_array_append_with_source_one(bool source) {
309a747f 786 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a, *b;
b0eeb945
ZJS
787
788 /* Parse two sources, each with a different name and line/column numbers */
789
309a747f 790 assert_se(sd_json_parse_with_source(" [41]", source ? "string 1" : NULL, 0,
b0eeb945 791 &a, NULL, NULL) >= 0);
309a747f 792 assert_se(sd_json_parse_with_source("\n\n [42]", source ? "string 2" : NULL, 0,
b0eeb945
ZJS
793 &b, NULL, NULL) >= 0);
794
309a747f
LP
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);
b0eeb945
ZJS
799
800 /* Verify source information */
801
802 const char *s1, *s2;
803 unsigned line1, col1, line2, col2;
309a747f
LP
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);
b0eeb945 806
c79e88b3
IK
807 ASSERT_STREQ(s1, source ? "string 1" : NULL);
808 ASSERT_STREQ(s2, source ? "string 2" : NULL);
b0eeb945
ZJS
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
309a747f
LP
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);
b0eeb945 820
309a747f 821 assert_se(sd_json_variant_append_array(&a, elem) >= 0);
b0eeb945 822
309a747f
LP
823 assert_se(sd_json_variant_is_array(a));
824 assert_se(sd_json_variant_elements(a) == 2);
b0eeb945
ZJS
825
826 /* Verify that source information was propagated correctly */
827
309a747f
LP
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);
b0eeb945 831
c79e88b3
IK
832 ASSERT_STREQ(s1, source ? "string 2" : NULL);
833 ASSERT_STREQ(s2, source ? "string 2" : NULL);
b0eeb945
ZJS
834 assert_se(line1 == 3);
835 assert_se(col1 == 5);
836 assert_se(line2 == 3);
837 assert_se(col2 == 5);
838}
839
840TEST(json_array_append_with_source) {
841 json_array_append_with_source_one(true);
842}
843
844TEST(json_array_append_without_source) {
845 json_array_append_with_source_one(false);
846}
847
3bb326c5 848TEST(json_array_append_nodup) {
309a747f 849 _cleanup_(sd_json_variant_unrefp) sd_json_variant *l = NULL, *s = NULL, *wd = NULL, *nd = NULL;
3bb326c5 850
309a747f
LP
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);
3bb326c5 853
309a747f
LP
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);
3bb326c5 857
309a747f 858 sd_json_variant *i;
3bb326c5 859 JSON_VARIANT_ARRAY_FOREACH(i, l) {
309a747f
LP
860 assert_se(sd_json_variant_append_array(&wd, i) >= 0);
861 assert_se(sd_json_variant_append_array_nodup(&nd, i) >= 0);
3bb326c5
LP
862 }
863
309a747f
LP
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));
3bb326c5 867
309a747f
LP
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));
3bb326c5
LP
871}
872
67a30285
LP
873TEST(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;
f000a97b
LP
881 uint8_t m, n;
882 int8_t o, p;
67a30285
LP
883 } foobar = {};
884
309a747f
LP
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)),
f000a97b
LP
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);
309a747f
LP
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) },
f000a97b
LP
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) },
67a30285
LP
924 {}
925 };
926
309a747f 927 assert_se(sd_json_dispatch(v, table, SD_JSON_LOG, &foobar) >= 0);
67a30285
LP
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);
f000a97b
LP
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);
67a30285
LP
948}
949
8618ff13 950typedef enum mytestenum {
45840c22 951 myfoo, mybar, mybaz, with_some_dashes, _mymax, _myinvalid = -EINVAL,
8618ff13
LP
952} mytestenum;
953
954static const char *mytestenum_table[_mymax] = {
955 [myfoo] = "myfoo",
956 [mybar] = "mybar",
957 [mybaz] = "mybaz",
45840c22 958 [with_some_dashes] = "with-some-dashes",
8618ff13
LP
959};
960
45840c22 961DEFINE_PRIVATE_STRING_TABLE_LOOKUP(mytestenum, mytestenum);
8618ff13
LP
962
963static JSON_DISPATCH_ENUM_DEFINE(dispatch_mytestenum, mytestenum, mytestenum_from_string);
964
965TEST(json_dispatch_enum_define) {
966
967 struct data {
45840c22 968 mytestenum a, b, c, d, e;
8618ff13
LP
969 } data = {
970 .a = _myinvalid,
971 .b = _myinvalid,
972 .c = _myinvalid,
973 .d = mybar,
45840c22 974 .e = _myinvalid,
8618ff13
LP
975 };
976
309a747f 977 _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
8618ff13 978
45840c22
LP
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);
8618ff13 985
309a747f
LP
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 },
45840c22 992 { "e", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, e), 0 },
8618ff13
LP
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);
45840c22 1002 assert(data.e == with_some_dashes);
8618ff13
LP
1003}
1004
4fae650a
LP
1005TEST(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
fa9a6db4 1049TEST(json_sensitive) {
309a747f 1050 _cleanup_(sd_json_variant_unrefp) sd_json_variant *a = NULL, *b = NULL, *v = NULL;
fa9a6db4
LB
1051 _cleanup_free_ char *s = NULL;
1052 int r;
1053
309a747f
LP
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);
fa9a6db4 1056
309a747f 1057 sd_json_variant_sensitive(a);
fa9a6db4 1058
309a747f 1059 assert_se(sd_json_variant_format(a, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
c79e88b3 1060 ASSERT_STREQ(s, "\"<sensitive data>\"");
99128971 1061 s = mfree(s);
fa9a6db4 1062
309a747f 1063 r = sd_json_variant_format(b, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
fa9a6db4
LB
1064 assert_se(r >= 0);
1065 assert_se(s);
1066 assert_se((size_t) r == strlen(s));
1067 s = mfree(s);
1068
309a747f
LP
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);
fa9a6db4 1074
309a747f 1075 r = sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
fa9a6db4
LB
1076 assert_se(r >= 0);
1077 assert_se(s);
1078 assert_se((size_t) r == strlen(s));
1079 s = mfree(s);
309a747f 1080 v = sd_json_variant_unref(v);
fa9a6db4 1081
309a747f
LP
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);
fa9a6db4 1088
309a747f 1089 r = sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s);
fa9a6db4
LB
1090 assert_se(r >= 0);
1091 assert_se(s);
1092 assert_se((size_t) r == strlen(s));
1093 s = mfree(s);
309a747f 1094 v = sd_json_variant_unref(v);
fa9a6db4 1095
309a747f
LP
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);
fa9a6db4 1103
309a747f 1104 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
c79e88b3 1105 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"a\":\"<sensitive data>\",\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"e\":{}}");
99128971 1106 s = mfree(s);
309a747f 1107 v = sd_json_variant_unref(v);
fa9a6db4 1108
309a747f
LP
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);
fa9a6db4 1116
309a747f 1117 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
c79e88b3 1118 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"a\":\"<sensitive data>\",\"d\":\"-9223372036854775808\",\"e\":{}}");
99128971 1119 s = mfree(s);
309a747f 1120 v = sd_json_variant_unref(v);
fa9a6db4 1121
309a747f
LP
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);
fa9a6db4 1129
309a747f 1130 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
c79e88b3 1131 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"a\":\"<sensitive data>\",\"e\":{}}");
99128971 1132 s = mfree(s);
309a747f 1133 v = sd_json_variant_unref(v);
fa9a6db4 1134
309a747f
LP
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);
fa9a6db4 1142
309a747f 1143 assert_se(sd_json_variant_format(v, SD_JSON_FORMAT_CENSOR_SENSITIVE, &s) >= 0);
c79e88b3 1144 ASSERT_STREQ(s, "{\"b\":[\"foo\",\"bar\",\"baz\",\"qux\"],\"c\":-9223372036854775808,\"d\":\"-9223372036854775808\",\"e\":{},\"a\":\"<sensitive data>\"}");
fa9a6db4
LB
1145}
1146
9d1c3e94
LP
1147TEST(json_iovec) {
1148 struct iovec iov1 = CONST_IOVEC_MAKE_STRING("üxknürz"), iov2 = CONST_IOVEC_MAKE_STRING("wuffwuffmiau");
1149
309a747f
LP
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);
9d1c3e94 1154
309a747f 1155 sd_json_variant_dump(j, SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO, /* f= */ NULL, /* prefix= */ NULL);
9d1c3e94
LP
1156
1157 _cleanup_(iovec_done) struct iovec a = {}, b = {};
309a747f
LP
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);
9d1c3e94
LP
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
3d6c2c91
LP
1167TEST(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
f000a97b
LP
1247TEST(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
1eb8a560
LP
1272TEST(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;
92881e7a
LP
1279 sd_id128_t randomized_boot_id;
1280 assert_se(sd_id128_randomize(&randomized_boot_id) >= 0);
1eb8a560
LP
1281 assert_se(sd_json_buildo(&v,
1282 JSON_BUILD_PAIR_PIDREF("myself", &myself),
92881e7a
LP
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);
1eb8a560
LP
1288
1289 sd_json_variant_dump(v, SD_JSON_FORMAT_COLOR|SD_JSON_FORMAT_PRETTY, NULL, NULL);
1290
1291 struct {
92881e7a 1292 PidRef myself, pid1, remote, automatic;
1eb8a560
LP
1293 } data = {
1294 .myself = PIDREF_NULL,
1295 .pid1 = PIDREF_NULL,
92881e7a
LP
1296 .remote = PIDREF_NULL,
1297 .automatic = PIDREF_NULL,
1eb8a560
LP
1298 };
1299
1300 assert_se(sd_json_dispatch(
1301 v,
1302 (const sd_json_dispatch_field[]) {
92881e7a
LP
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 },
1eb8a560
LP
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));
92881e7a
LP
1317 assert_se(!pidref_equal(&myself, &data.remote));
1318 assert_se(!pidref_equal(&pid1, &data.remote));
1eb8a560
LP
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
92881e7a
LP
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
1eb8a560
LP
1328 pidref_done(&data.myself);
1329 pidref_done(&data.pid1);
92881e7a 1330 pidref_done(&data.remote);
1eb8a560
LP
1331}
1332
32944d1c
YW
1333TEST(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
60ae3b86
YW
1356TEST(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 */
d9000d70 1373 ASSERT_OK(fd = open_tmpfile_unlinkable(NULL, O_RDWR));
60ae3b86
YW
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
7693e8d9
YW
1379 fd = open("/sys/class/net/lo/uevent", O_CLOEXEC | O_PATH);
1380 if (fd >= 0) {
60ae3b86
YW
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 */
7693e8d9
YW
1388 fd = open("/dev/sda", O_CLOEXEC | O_PATH);
1389 if (fd >= 0) {
60ae3b86
YW
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
2af33c3d
IK
1426TEST(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
4f7452a8 1479DEFINE_TEST_MAIN(LOG_DEBUG);