]>
Commit | Line | Data |
---|---|---|
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); |