master
c 2,097 lines 84.2 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4
5 // ============================================================================
6 // Wrapper functions
7 //
8 // All JSONC_PARSE_* macros contain "return false;" on error, so they must
9 // live inside functions returning bool. Each wrapper isolates one macro
10 // call and returns true (success) or false (macro fired an error).
11 // ============================================================================
12
13 // --- BOOL ---
14 static bool wrap_parse_bool(json_object *jobj, const char *member,
15 bool *dst, BUFFER *error, int flags) {
16 const char *path = "";
17 JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, member, *dst, error, flags);
18 return true;
19 }
20
21 // --- INT64 ---
22 static bool wrap_parse_int64(json_object *jobj, const char *member,
23 int64_t *dst, BUFFER *error, int flags) {
24 const char *path = "";
25 JSONC_PARSE_INT64_OR_ERROR_AND_RETURN(jobj, path, member, *dst, error, flags);
26 return true;
27 }
28
29 // --- UINT64 ---
30 static bool wrap_parse_uint64(json_object *jobj, const char *member,
31 uint64_t *dst, BUFFER *error, int flags) {
32 const char *path = "";
33 JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, member, *dst, error, flags);
34 return true;
35 }
36
37 // --- DOUBLE ---
38 static bool wrap_parse_double(json_object *jobj, const char *member,
39 double *dst, BUFFER *error, int flags) {
40 const char *path = "";
41 JSONC_PARSE_DOUBLE_OR_ERROR_AND_RETURN(jobj, path, member, *dst, error, flags);
42 return true;
43 }
44
45 // --- TXT2STRING ---
46 static bool wrap_parse_txt2string(json_object *jobj, const char *member,
47 STRING **dst_ptr, BUFFER *error, int flags) {
48 const char *path = "";
49 STRING *dst = *dst_ptr;
50 JSONC_PARSE_TXT2STRING_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
51 *dst_ptr = dst;
52 return true;
53 }
54
55 // --- TXT2STRDUPZ ---
56 static bool wrap_parse_txt2strdupz(json_object *jobj, const char *member,
57 char **dst_ptr, BUFFER *error, int flags) {
58 const char *path = "";
59 const char *dst = *dst_ptr;
60 JSONC_PARSE_TXT2STRDUPZ_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
61 *dst_ptr = (char *)dst;
62 return true;
63 }
64
65 // --- SCALAR2STRDUPZ ---
66 static bool wrap_parse_scalar2strdupz(json_object *jobj, const char *member,
67 char **dst_ptr, BUFFER *error, int flags) {
68 const char *path = "";
69 const char *dst = *dst_ptr;
70 JSONC_PARSE_SCALAR2STRDUPZ_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
71 *dst_ptr = (char *)dst;
72 return true;
73 }
74
75 // --- TXT2CHAR ---
76 // dst must be a char array (sizeof used inside macro)
77 static bool wrap_parse_txt2char(json_object *jobj, const char *member,
78 char *out, BUFFER *error, int flags) {
79 const char *path = "";
80 char dst[256];
81 dst[0] = '\0';
82 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
83 strncpyz(out, dst, 255);
84 return true;
85 }
86
87 // --- TXT2BUFFER ---
88 static bool wrap_parse_txt2buffer(json_object *jobj, const char *member,
89 BUFFER **dst_ptr, BUFFER *error, int flags) {
90 const char *path = "";
91 BUFFER *dst = *dst_ptr;
92 JSONC_PARSE_TXT2BUFFER_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
93 *dst_ptr = dst;
94 return true;
95 }
96
97 // --- TXT2UUID ---
98 static bool wrap_parse_txt2uuid(json_object *jobj, const char *member,
99 nd_uuid_t dst, BUFFER *error, int flags) {
100 const char *path = "";
101 JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
102 return true;
103 }
104
105 // --- TXT2RFC3339 ---
106 static bool wrap_parse_txt2rfc3339(json_object *jobj, const char *member,
107 usec_t *dst, BUFFER *error, int flags) {
108 const char *path = "";
109 JSONC_PARSE_TXT2RFC3339_USEC_OR_ERROR_AND_RETURN(jobj, path, member, *dst, error, flags);
110 return true;
111 }
112
113 // --- TXT2PATTERN ---
114 static bool wrap_parse_txt2pattern(json_object *jobj, const char *member,
115 STRING **dst_ptr, BUFFER *error, int flags) {
116 const char *path = "";
117 STRING *dst = *dst_ptr;
118 JSONC_PARSE_TXT2PATTERN_OR_ERROR_AND_RETURN(jobj, path, member, dst, error, flags);
119 *dst_ptr = dst;
120 return true;
121 }
122
123 // --- TXT2ENUM ---
124 static int dummy_enum_converter(const char *s) {
125 if(strcmp(s, "alpha") == 0) return 1;
126 if(strcmp(s, "beta") == 0) return 2;
127 return 0;
128 }
129
130 static bool wrap_parse_txt2enum(json_object *jobj, const char *member,
131 int *dst, BUFFER *error, int flags) {
132 const char *path = "";
133 JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, member, dummy_enum_converter, *dst, error, flags);
134 return true;
135 }
136
137 // --- ARRAY_OF_TXT2BITMAP ---
138 static uint32_t dummy_bitmap_converter(const char *s) {
139 if(strcmp(s, "read") == 0) return 1;
140 if(strcmp(s, "write") == 0) return 2;
141 if(strcmp(s, "exec") == 0) return 4;
142 return 0;
143 }
144
145 static bool wrap_parse_array_of_txt2bitmap(json_object *jobj, const char *member,
146 uint32_t *dst, BUFFER *error, int flags) {
147 const char *path = "";
148 JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, member, dummy_bitmap_converter, *dst, error, flags);
149 return true;
150 }
151
152 // --- SUBOBJECT ---
153 static bool wrap_parse_subobject(json_object *jobj, const char *member,
154 bool *entered, BUFFER *error, int flags) {
155 char path[256] = "";
156 *entered = false;
157 JSONC_PARSE_SUBOBJECT(jobj, path, member, error, flags, {
158 *entered = true;
159 });
160 return true;
161 }
162
163 // --- ARRAY ---
164 static bool wrap_parse_array(json_object *jobj, const char *member,
165 size_t *count, BUFFER *error, int flags) {
166 char path[256] = "";
167 *count = 0;
168 JSONC_PARSE_ARRAY(jobj, path, member, error, flags, {
169 *count = json_object_array_length(jobj);
170 });
171 return true;
172 }
173
174 // --- ARRAY_ITEM_OBJECT ---
175 static bool wrap_parse_array_item_object(json_object *jobj_in, size_t *count,
176 BUFFER *error, int flags) {
177 char path[256] = "";
178 json_object *jobj = jobj_in;
179 size_t index;
180 *count = 0;
181 JSONC_PARSE_ARRAY_ITEM_OBJECT(jobj, path, index, flags, {
182 (*count)++;
183 });
184 return true;
185 }
186
187
188 // ============================================================================
189 // Test helpers
190 // ============================================================================
191
192 static bool json_function_payload_fail_with_error(json_object *jobj __maybe_unused, void *data, BUFFER *error) {
193 buffer_strcat(error, (const char *)data);
194 return false;
195 }
196
197 #define T(cond, msg) do { \
198 if (!(cond)) { fprintf(stderr, " FAILED: %s\n", msg); failed++; } \
199 } while(0)
200
201 #define R() buffer_flush(error)
202
203 // ============================================================================
204 // Test functions — each returns the number of failures (0 = all passed)
205 // ============================================================================
206
207 // ----------------------------------------------------------------------------
208 // BOOL — branches:
209 // key found: boolean, string(true/yes/on), string(false/no/off),
210 // string(invalid)→ALWAYS error, int, double, null→false,
211 // other+OPT→skip, other+REQ→error, other+STRICT→error
212 // key missing: OPT→skip, REQ→error, STRICT→skip
213 // ----------------------------------------------------------------------------
214 static int test_parse_bool(void) {
215 int failed = 0;
216 BUFFER *error = buffer_create(0, NULL);
217 json_object *root;
218 bool dst, ok;
219 char msg[256];
220
221 // --- type: boolean ---
222 root = json_object_new_object();
223 json_object_object_add(root, "k", json_object_new_boolean(1));
224 dst = false; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
225 T(ok && dst == true, "bool: boolean true");
226 json_object_put(root);
227
228 root = json_object_new_object();
229 json_object_object_add(root, "k", json_object_new_boolean(0));
230 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
231 T(ok && dst == false, "bool: boolean false");
232 json_object_put(root);
233
234 // --- type: string truthy (case-insensitive) ---
235 {
236 const char *vals[] = {"true", "yes", "on", "TRUE", "Yes", "ON", NULL};
237 for (int i = 0; vals[i]; i++) {
238 root = json_object_new_object();
239 json_object_object_add(root, "k", json_object_new_string(vals[i]));
240 dst = false; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
241 snprintfz(msg, sizeof(msg), "bool: str '%s'→true", vals[i]);
242 T(ok && dst == true, msg);
243 json_object_put(root);
244 }
245 }
246
247 // --- type: string falsy (case-insensitive) ---
248 {
249 const char *vals[] = {"false", "no", "off", "FALSE", "No", "OFF", NULL};
250 for (int i = 0; vals[i]; i++) {
251 root = json_object_new_object();
252 json_object_object_add(root, "k", json_object_new_string(vals[i]));
253 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
254 snprintfz(msg, sizeof(msg), "bool: str '%s'→false", vals[i]);
255 T(ok && dst == false, msg);
256 json_object_put(root);
257 }
258 }
259
260 // --- type: string invalid → ALWAYS error regardless of flags ---
261 {
262 const char *vals[] = {"garbage", "1", "0", "maybe", "", NULL};
263 for (int i = 0; vals[i]; i++) {
264 root = json_object_new_object();
265 json_object_object_add(root, "k", json_object_new_string(vals[i]));
266 dst = false; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_OPTIONAL);
267 snprintfz(msg, sizeof(msg), "bool: invalid str '%s'+OPT→error", vals[i]);
268 T(!ok, msg);
269 json_object_put(root);
270 }
271 }
272
273 // --- type: int ---
274 root = json_object_new_object();
275 json_object_object_add(root, "k", json_object_new_int64(42));
276 dst = false; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
277 T(ok && dst == true, "bool: int 42→true");
278 json_object_put(root);
279
280 root = json_object_new_object();
281 json_object_object_add(root, "k", json_object_new_int64(0));
282 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
283 T(ok && dst == false, "bool: int 0→false");
284 json_object_put(root);
285
286 // --- type: double ---
287 root = json_object_new_object();
288 json_object_object_add(root, "k", json_object_new_double(3.14));
289 dst = false; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
290 T(ok && dst == true, "bool: double 3.14→true");
291 json_object_put(root);
292
293 root = json_object_new_object();
294 json_object_object_add(root, "k", json_object_new_double(0.0));
295 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
296 T(ok && dst == false, "bool: double 0.0→false");
297 json_object_put(root);
298
299 // --- type: null → false ---
300 root = json_object_new_object();
301 json_object_object_add(root, "k", NULL);
302 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, 0);
303 T(ok && dst == false, "bool: null→false");
304 json_object_put(root);
305
306 // --- wrong type (array, object) × 3 flags ---
307 for (int wt = 0; wt < 2; wt++) {
308 root = json_object_new_object();
309 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
310 const char *wtn = wt == 0 ? "array" : "object";
311
312 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_OPTIONAL);
313 snprintfz(msg, sizeof(msg), "bool: %s+OPT→unchanged", wtn);
314 T(ok && dst == true, msg);
315
316 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_REQUIRED);
317 snprintfz(msg, sizeof(msg), "bool: %s+REQ→error", wtn);
318 T(!ok, msg);
319
320 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_STRICT);
321 snprintfz(msg, sizeof(msg), "bool: %s+STRICT→error", wtn);
322 T(!ok, msg);
323
324 json_object_put(root);
325 }
326
327 // --- missing key × 3 flags ---
328 root = json_object_new_object();
329 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_OPTIONAL);
330 T(ok && dst == true, "bool: missing+OPT→unchanged");
331 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_REQUIRED);
332 T(!ok, "bool: missing+REQ→error");
333 dst = true; R(); ok = wrap_parse_bool(root, "k", &dst, error, JSONC_STRICT);
334 T(ok && dst == true, "bool: missing+STRICT→unchanged");
335 json_object_put(root);
336
337 buffer_free(error);
338 return failed;
339 }
340
341 // ----------------------------------------------------------------------------
342 // INT64 — branches:
343 // key found: _j==NULL→0, int, double(truncate), boolean(0/1),
344 // string(valid strtoll), string(invalid)→ALWAYS error,
345 // other+OPT→skip, other+REQ→error, other+STRICT→error
346 // key missing: OPT→skip, REQ→error, STRICT→skip
347 // NOTE: json_type_null is NOT explicitly handled — falls to "other type"
348 // ----------------------------------------------------------------------------
349 static int test_parse_int64(void) {
350 int failed = 0;
351 BUFFER *error = buffer_create(0, NULL);
352 json_object *root;
353 int64_t dst;
354 bool ok;
355 char msg[256];
356
357 // --- type: int ---
358 root = json_object_new_object();
359 json_object_object_add(root, "k", json_object_new_int64(42));
360 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
361 T(ok && dst == 42, "int64: int 42");
362 json_object_put(root);
363
364 root = json_object_new_object();
365 json_object_object_add(root, "k", json_object_new_int64(-1));
366 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
367 T(ok && dst == -1, "int64: int -1");
368 json_object_put(root);
369
370 root = json_object_new_object();
371 json_object_object_add(root, "k", json_object_new_int64(0));
372 dst = 99; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
373 T(ok && dst == 0, "int64: int 0");
374 json_object_put(root);
375
376 // --- type: double (truncated) ---
377 root = json_object_new_object();
378 json_object_object_add(root, "k", json_object_new_double(3.7));
379 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
380 T(ok && dst == 3, "int64: double 3.7→3");
381 json_object_put(root);
382
383 // --- type: boolean ---
384 root = json_object_new_object();
385 json_object_object_add(root, "k", json_object_new_boolean(1));
386 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
387 T(ok && dst == 1, "int64: bool true→1");
388 json_object_put(root);
389
390 root = json_object_new_object();
391 json_object_object_add(root, "k", json_object_new_boolean(0));
392 dst = 99; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
393 T(ok && dst == 0, "int64: bool false→0");
394 json_object_put(root);
395
396 // --- type: string (valid) ---
397 root = json_object_new_object();
398 json_object_object_add(root, "k", json_object_new_string("123"));
399 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
400 T(ok && dst == 123, "int64: str '123'→123");
401 json_object_put(root);
402
403 root = json_object_new_object();
404 json_object_object_add(root, "k", json_object_new_string("-456"));
405 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, 0);
406 T(ok && dst == -456, "int64: str '-456'→-456");
407 json_object_put(root);
408
409 // --- type: string (invalid) → ALWAYS error ---
410 {
411 const char *vals[] = {"abc", "12.5", "", "0x1F", NULL};
412 for (int i = 0; vals[i]; i++) {
413 root = json_object_new_object();
414 json_object_object_add(root, "k", json_object_new_string(vals[i]));
415 dst = 0; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_OPTIONAL);
416 snprintfz(msg, sizeof(msg), "int64: invalid str '%s'+OPT→error", vals[i]);
417 T(!ok, msg);
418 json_object_put(root);
419 }
420 }
421
422 // --- null (_j==NULL): unconditionally sets dst=0, before flag checks ---
423 root = json_object_new_object();
424 json_object_object_add(root, "k", NULL);
425 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_OPTIONAL);
426 T(ok && dst == 0, "int64: null+OPT→0");
427 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_REQUIRED);
428 T(ok && dst == 0, "int64: null+REQ→0");
429 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_STRICT);
430 T(ok && dst == 0, "int64: null+STRICT→0");
431 json_object_put(root);
432
433 // --- wrong type (array, object) × 3 flags ---
434 for (int wt = 0; wt < 2; wt++) {
435 root = json_object_new_object();
436 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
437 const char *wtn = wt == 0 ? "array" : "object";
438
439 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_OPTIONAL);
440 snprintfz(msg, sizeof(msg), "int64: %s+OPT→unchanged", wtn);
441 T(ok && dst == -999, msg);
442
443 R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_REQUIRED);
444 snprintfz(msg, sizeof(msg), "int64: %s+REQ→error", wtn);
445 T(!ok, msg);
446
447 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_STRICT);
448 snprintfz(msg, sizeof(msg), "int64: %s+STRICT→error", wtn);
449 T(!ok, msg);
450
451 json_object_put(root);
452 }
453
454 // --- missing key × 3 flags ---
455 root = json_object_new_object();
456 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_OPTIONAL);
457 T(ok && dst == -999, "int64: missing+OPT→unchanged");
458 R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_REQUIRED);
459 T(!ok, "int64: missing+REQ→error");
460 dst = -999; R(); ok = wrap_parse_int64(root, "k", &dst, error, JSONC_STRICT);
461 T(ok && dst == -999, "int64: missing+STRICT→unchanged");
462 json_object_put(root);
463
464 buffer_free(error);
465 return failed;
466 }
467
468 // ----------------------------------------------------------------------------
469 // UINT64 — same as INT64 plus:
470 // string negative → ALWAYS error (before strtoull)
471 // uses get_uint64 instead of get_int64
472 // ----------------------------------------------------------------------------
473 static int test_parse_uint64(void) {
474 int failed = 0;
475 BUFFER *error = buffer_create(0, NULL);
476 json_object *root;
477 uint64_t dst;
478 bool ok;
479 char msg[256];
480
481 // --- type: int ---
482 root = json_object_new_object();
483 json_object_object_add(root, "k", json_object_new_int64(42));
484 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
485 T(ok && dst == 42, "uint64: int 42");
486 json_object_put(root);
487
488 root = json_object_new_object();
489 json_object_object_add(root, "k", json_object_new_int64(0));
490 dst = 99; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
491 T(ok && dst == 0, "uint64: int 0");
492 json_object_put(root);
493
494 // --- type: double ---
495 root = json_object_new_object();
496 json_object_object_add(root, "k", json_object_new_double(3.7));
497 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
498 T(ok && dst == 3, "uint64: double 3.7→3");
499 json_object_put(root);
500
501 // --- type: boolean ---
502 root = json_object_new_object();
503 json_object_object_add(root, "k", json_object_new_boolean(1));
504 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
505 T(ok && dst == 1, "uint64: bool true→1");
506 json_object_put(root);
507
508 root = json_object_new_object();
509 json_object_object_add(root, "k", json_object_new_boolean(0));
510 dst = 99; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
511 T(ok && dst == 0, "uint64: bool false→0");
512 json_object_put(root);
513
514 // --- type: string valid ---
515 root = json_object_new_object();
516 json_object_object_add(root, "k", json_object_new_string("123"));
517 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, 0);
518 T(ok && dst == 123, "uint64: str '123'→123");
519 json_object_put(root);
520
521 // --- type: string negative → ALWAYS error ---
522 root = json_object_new_object();
523 json_object_object_add(root, "k", json_object_new_string("-5"));
524 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_OPTIONAL);
525 T(!ok, "uint64: str '-5'+OPT→error (negative)");
526 json_object_put(root);
527
528 // --- type: string invalid → ALWAYS error ---
529 {
530 const char *vals[] = {"abc", "", "12.5", NULL};
531 for (int i = 0; vals[i]; i++) {
532 root = json_object_new_object();
533 json_object_object_add(root, "k", json_object_new_string(vals[i]));
534 dst = 0; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_OPTIONAL);
535 snprintfz(msg, sizeof(msg), "uint64: invalid str '%s'+OPT→error", vals[i]);
536 T(!ok, msg);
537 json_object_put(root);
538 }
539 }
540
541 // --- null (_j==NULL): unconditionally sets dst=0, before flag checks ---
542 root = json_object_new_object();
543 json_object_object_add(root, "k", NULL);
544 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_OPTIONAL);
545 T(ok && dst == 0, "uint64: null+OPT→0");
546 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_REQUIRED);
547 T(ok && dst == 0, "uint64: null+REQ→0");
548 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_STRICT);
549 T(ok && dst == 0, "uint64: null+STRICT→0");
550 json_object_put(root);
551
552 // --- wrong type (array, object) × 3 flags ---
553 for (int wt = 0; wt < 2; wt++) {
554 root = json_object_new_object();
555 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
556 const char *wtn = wt == 0 ? "array" : "object";
557
558 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_OPTIONAL);
559 snprintfz(msg, sizeof(msg), "uint64: %s+OPT→unchanged", wtn);
560 T(ok && dst == 999, msg);
561
562 R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_REQUIRED);
563 snprintfz(msg, sizeof(msg), "uint64: %s+REQ→error", wtn);
564 T(!ok, msg);
565
566 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_STRICT);
567 snprintfz(msg, sizeof(msg), "uint64: %s+STRICT→error", wtn);
568 T(!ok, msg);
569
570 json_object_put(root);
571 }
572
573 // --- missing key × 3 flags ---
574 root = json_object_new_object();
575 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_OPTIONAL);
576 T(ok && dst == 999, "uint64: missing+OPT→unchanged");
577 R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_REQUIRED);
578 T(!ok, "uint64: missing+REQ→error");
579 dst = 999; R(); ok = wrap_parse_uint64(root, "k", &dst, error, JSONC_STRICT);
580 T(ok && dst == 999, "uint64: missing+STRICT→unchanged");
581 json_object_put(root);
582
583 buffer_free(error);
584 return failed;
585 }
586
587 // ----------------------------------------------------------------------------
588 // DOUBLE — branches:
589 // key found: _j==NULL→NAN, double, int(cast), boolean(0.0/1.0),
590 // string(valid strtod), string(invalid)→ALWAYS error,
591 // other+OPT→skip, other+REQ→error, other+STRICT→error
592 // key missing: OPT→skip, REQ→error, STRICT→skip
593 // NOTE: json_type_null falls to "other type" (no explicit handling)
594 // ----------------------------------------------------------------------------
595 static int test_parse_double(void) {
596 int failed = 0;
597 BUFFER *error = buffer_create(0, NULL);
598 json_object *root;
599 double dst;
600 bool ok;
601 char msg[256];
602
603 // --- type: double ---
604 root = json_object_new_object();
605 json_object_object_add(root, "k", json_object_new_double(3.14));
606 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
607 T(ok && (dst > 3.13 && dst < 3.15), "double: double 3.14");
608 json_object_put(root);
609
610 root = json_object_new_object();
611 json_object_object_add(root, "k", json_object_new_double(0.0));
612 dst = 99; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
613 T(ok && dst == 0.0, "double: double 0.0");
614 json_object_put(root);
615
616 // --- type: int ---
617 root = json_object_new_object();
618 json_object_object_add(root, "k", json_object_new_int64(42));
619 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
620 T(ok && dst == 42.0, "double: int 42→42.0");
621 json_object_put(root);
622
623 // --- type: boolean ---
624 root = json_object_new_object();
625 json_object_object_add(root, "k", json_object_new_boolean(1));
626 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
627 T(ok && dst == 1.0, "double: bool true→1.0");
628 json_object_put(root);
629
630 root = json_object_new_object();
631 json_object_object_add(root, "k", json_object_new_boolean(0));
632 dst = 99; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
633 T(ok && dst == 0.0, "double: bool false→0.0");
634 json_object_put(root);
635
636 // --- type: string valid ---
637 root = json_object_new_object();
638 json_object_object_add(root, "k", json_object_new_string("3.14"));
639 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
640 T(ok && (dst > 3.13 && dst < 3.15), "double: str '3.14'→3.14");
641 json_object_put(root);
642
643 root = json_object_new_object();
644 json_object_object_add(root, "k", json_object_new_string("-1.5"));
645 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, 0);
646 T(ok && dst == -1.5, "double: str '-1.5'→-1.5");
647 json_object_put(root);
648
649 // --- type: string invalid → ALWAYS error ---
650 {
651 const char *vals[] = {"abc", "", "1.2.3", NULL};
652 for (int i = 0; vals[i]; i++) {
653 root = json_object_new_object();
654 json_object_object_add(root, "k", json_object_new_string(vals[i]));
655 dst = 0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_OPTIONAL);
656 snprintfz(msg, sizeof(msg), "double: invalid str '%s'+OPT→error", vals[i]);
657 T(!ok, msg);
658 json_object_put(root);
659 }
660 }
661
662 // --- null (_j==NULL): unconditionally sets dst=NAN, before flag checks ---
663 root = json_object_new_object();
664 json_object_object_add(root, "k", NULL);
665 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_OPTIONAL);
666 T(ok && isnan(dst), "double: null+OPT→NAN");
667 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_REQUIRED);
668 T(ok && isnan(dst), "double: null+REQ→NAN");
669 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_STRICT);
670 T(ok && isnan(dst), "double: null+STRICT→NAN");
671 json_object_put(root);
672
673 // --- wrong type (array, object) × 3 flags ---
674 for (int wt = 0; wt < 2; wt++) {
675 root = json_object_new_object();
676 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
677 const char *wtn = wt == 0 ? "array" : "object";
678
679 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_OPTIONAL);
680 snprintfz(msg, sizeof(msg), "double: %s+OPT→unchanged", wtn);
681 T(ok && dst == -999.0, msg);
682
683 R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_REQUIRED);
684 snprintfz(msg, sizeof(msg), "double: %s+REQ→error", wtn);
685 T(!ok, msg);
686
687 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_STRICT);
688 snprintfz(msg, sizeof(msg), "double: %s+STRICT→error", wtn);
689 T(!ok, msg);
690
691 json_object_put(root);
692 }
693
694 // --- missing key × 3 flags ---
695 root = json_object_new_object();
696 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_OPTIONAL);
697 T(ok && dst == -999.0, "double: missing+OPT→unchanged");
698 R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_REQUIRED);
699 T(!ok, "double: missing+REQ→error");
700 dst = -999.0; R(); ok = wrap_parse_double(root, "k", &dst, error, JSONC_STRICT);
701 T(ok && dst == -999.0, "double: missing+STRICT→unchanged");
702 json_object_put(root);
703
704 buffer_free(error);
705 return failed;
706 }
707
708 // ----------------------------------------------------------------------------
709 // TXT2STRING — branches:
710 // key found: string, int(print_int64), double(print_netdata_double),
711 // boolean("true"/"false"), null→NULL,
712 // other+OPT→skip, other+REQ→error, other+STRICT→error
713 // key missing: OPT→skip, REQ→error, STRICT→skip
714 // ----------------------------------------------------------------------------
715 static int test_parse_txt2string(void) {
716 int failed = 0;
717 BUFFER *error = buffer_create(0, NULL);
718 json_object *root;
719 STRING *dst;
720 bool ok;
721 char msg[256];
722
723 // --- type: string ---
724 root = json_object_new_object();
725 json_object_object_add(root, "k", json_object_new_string("hello"));
726 dst = NULL; R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
727 T(ok && dst && strcmp(string2str(dst), "hello") == 0, "txt2string: str 'hello'");
728 string_freez(dst); dst = NULL;
729 json_object_put(root);
730
731 // --- type: int ---
732 root = json_object_new_object();
733 json_object_object_add(root, "k", json_object_new_int64(42));
734 dst = NULL; R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
735 T(ok && dst && strcmp(string2str(dst), "42") == 0, "txt2string: int 42→'42'");
736 string_freez(dst); dst = NULL;
737 json_object_put(root);
738
739 // --- type: double ---
740 root = json_object_new_object();
741 json_object_object_add(root, "k", json_object_new_double(3.14));
742 dst = NULL; R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
743 T(ok && dst != NULL, "txt2string: double 3.14→string");
744 string_freez(dst); dst = NULL;
745 json_object_put(root);
746
747 // --- type: boolean ---
748 root = json_object_new_object();
749 json_object_object_add(root, "k", json_object_new_boolean(1));
750 dst = NULL; R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
751 T(ok && dst && strcmp(string2str(dst), "true") == 0, "txt2string: bool true→'true'");
752 string_freez(dst); dst = NULL;
753 json_object_put(root);
754
755 root = json_object_new_object();
756 json_object_object_add(root, "k", json_object_new_boolean(0));
757 dst = NULL; R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
758 T(ok && dst && strcmp(string2str(dst), "false") == 0, "txt2string: bool false→'false'");
759 string_freez(dst); dst = NULL;
760 json_object_put(root);
761
762 // --- type: null → NULL ---
763 root = json_object_new_object();
764 json_object_object_add(root, "k", NULL);
765 dst = string_strdupz("sentinel");
766 R(); ok = wrap_parse_txt2string(root, "k", &dst, error, 0);
767 T(ok && dst == NULL, "txt2string: null→NULL");
768 string_freez(dst); dst = NULL;
769 json_object_put(root);
770
771 // --- wrong type (array, object) × 3 flags ---
772 for (int wt = 0; wt < 2; wt++) {
773 root = json_object_new_object();
774 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
775 const char *wtn = wt == 0 ? "array" : "object";
776
777 dst = string_strdupz("sentinel"); R();
778 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_OPTIONAL);
779 snprintfz(msg, sizeof(msg), "txt2string: %s+OPT→unchanged", wtn);
780 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, msg);
781 string_freez(dst); dst = NULL;
782
783 dst = string_strdupz("sentinel"); R();
784 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_REQUIRED);
785 snprintfz(msg, sizeof(msg), "txt2string: %s+REQ→error", wtn);
786 T(!ok, msg);
787 string_freez(dst); dst = NULL;
788
789 dst = string_strdupz("sentinel"); R();
790 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_STRICT);
791 snprintfz(msg, sizeof(msg), "txt2string: %s+STRICT→error", wtn);
792 T(!ok, msg);
793 string_freez(dst); dst = NULL;
794
795 json_object_put(root);
796 }
797
798 // --- missing key × 3 flags ---
799 root = json_object_new_object();
800 dst = string_strdupz("sentinel"); R();
801 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_OPTIONAL);
802 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, "txt2string: missing+OPT→unchanged");
803 string_freez(dst);
804
805 dst = string_strdupz("sentinel"); R();
806 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_REQUIRED);
807 T(!ok, "txt2string: missing+REQ→error");
808 string_freez(dst);
809
810 dst = string_strdupz("sentinel"); R();
811 ok = wrap_parse_txt2string(root, "k", &dst, error, JSONC_STRICT);
812 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, "txt2string: missing+STRICT→unchanged");
813 string_freez(dst);
814 json_object_put(root);
815
816 buffer_free(error);
817 return failed;
818 }
819
820 // ----------------------------------------------------------------------------
821 // TXT2STRDUPZ — same structure as TXT2STRING but uses strdupz/freez
822 // ----------------------------------------------------------------------------
823 static int test_parse_txt2strdupz(void) {
824 int failed = 0;
825 BUFFER *error = buffer_create(0, NULL);
826 json_object *root;
827 char *dst;
828 bool ok;
829 char msg[256];
830
831 // --- type: string ---
832 root = json_object_new_object();
833 json_object_object_add(root, "k", json_object_new_string("hello"));
834 dst = NULL; R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
835 T(ok && dst && strcmp(dst, "hello") == 0, "txt2strdupz: str 'hello'");
836 freez(dst); dst = NULL;
837 json_object_put(root);
838
839 // --- type: int ---
840 root = json_object_new_object();
841 json_object_object_add(root, "k", json_object_new_int64(42));
842 dst = NULL; R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
843 T(ok && dst && strcmp(dst, "42") == 0, "txt2strdupz: int 42→'42'");
844 freez(dst); dst = NULL;
845 json_object_put(root);
846
847 // --- type: double ---
848 root = json_object_new_object();
849 json_object_object_add(root, "k", json_object_new_double(3.14));
850 dst = NULL; R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
851 T(ok && dst != NULL, "txt2strdupz: double→string");
852 freez(dst); dst = NULL;
853 json_object_put(root);
854
855 // --- type: boolean ---
856 root = json_object_new_object();
857 json_object_object_add(root, "k", json_object_new_boolean(1));
858 dst = NULL; R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
859 T(ok && dst && strcmp(dst, "true") == 0, "txt2strdupz: bool true→'true'");
860 freez(dst); dst = NULL;
861 json_object_put(root);
862
863 root = json_object_new_object();
864 json_object_object_add(root, "k", json_object_new_boolean(0));
865 dst = NULL; R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
866 T(ok && dst && strcmp(dst, "false") == 0, "txt2strdupz: bool false→'false'");
867 freez(dst); dst = NULL;
868 json_object_put(root);
869
870 // --- type: null → NULL ---
871 root = json_object_new_object();
872 json_object_object_add(root, "k", NULL);
873 dst = strdupz("sentinel");
874 R(); ok = wrap_parse_txt2strdupz(root, "k", &dst, error, 0);
875 T(ok && dst == NULL, "txt2strdupz: null→NULL");
876 freez(dst); dst = NULL;
877 json_object_put(root);
878
879 // --- wrong type (array, object) × 3 flags ---
880 for (int wt = 0; wt < 2; wt++) {
881 root = json_object_new_object();
882 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
883 const char *wtn = wt == 0 ? "array" : "object";
884
885 dst = strdupz("sentinel"); R();
886 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_OPTIONAL);
887 snprintfz(msg, sizeof(msg), "txt2strdupz: %s+OPT→unchanged", wtn);
888 T(ok && dst && strcmp(dst, "sentinel") == 0, msg);
889 freez(dst);
890
891 dst = strdupz("sentinel"); R();
892 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_REQUIRED);
893 snprintfz(msg, sizeof(msg), "txt2strdupz: %s+REQ→error", wtn);
894 T(!ok, msg);
895 freez(dst);
896
897 dst = strdupz("sentinel"); R();
898 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_STRICT);
899 snprintfz(msg, sizeof(msg), "txt2strdupz: %s+STRICT→error", wtn);
900 T(!ok, msg);
901 freez(dst);
902
903 json_object_put(root);
904 }
905
906 // --- missing key × 3 flags ---
907 root = json_object_new_object();
908 dst = strdupz("sentinel"); R();
909 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_OPTIONAL);
910 T(ok && dst && strcmp(dst, "sentinel") == 0, "txt2strdupz: missing+OPT→unchanged");
911 freez(dst);
912
913 dst = strdupz("sentinel"); R();
914 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_REQUIRED);
915 T(!ok, "txt2strdupz: missing+REQ→error");
916 freez(dst);
917
918 dst = strdupz("sentinel"); R();
919 ok = wrap_parse_txt2strdupz(root, "k", &dst, error, JSONC_STRICT);
920 T(ok && dst && strcmp(dst, "sentinel") == 0, "txt2strdupz: missing+STRICT→unchanged");
921 freez(dst);
922 json_object_put(root);
923
924 buffer_free(error);
925 return failed;
926 }
927
928 // ----------------------------------------------------------------------------
929 // SCALAR2STRDUPZ — same as TXT2STRDUPZ but different error message
930 // for array/object: "non-scalar type" instead of "cannot convert to string"
931 // ----------------------------------------------------------------------------
932 static int test_parse_scalar2strdupz(void) {
933 int failed = 0;
934 BUFFER *error = buffer_create(0, NULL);
935 json_object *root;
936 char *dst;
937 bool ok;
938 char msg[256];
939
940 // --- type: string ---
941 root = json_object_new_object();
942 json_object_object_add(root, "k", json_object_new_string("hello"));
943 dst = NULL; R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
944 T(ok && dst && strcmp(dst, "hello") == 0, "scalar2strdupz: str 'hello'");
945 freez(dst); dst = NULL;
946 json_object_put(root);
947
948 // --- type: int ---
949 root = json_object_new_object();
950 json_object_object_add(root, "k", json_object_new_int64(42));
951 dst = NULL; R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
952 T(ok && dst && strcmp(dst, "42") == 0, "scalar2strdupz: int 42→'42'");
953 freez(dst); dst = NULL;
954 json_object_put(root);
955
956 // --- type: double ---
957 root = json_object_new_object();
958 json_object_object_add(root, "k", json_object_new_double(3.14));
959 dst = NULL; R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
960 T(ok && dst != NULL, "scalar2strdupz: double→string");
961 freez(dst); dst = NULL;
962 json_object_put(root);
963
964 // --- type: boolean ---
965 root = json_object_new_object();
966 json_object_object_add(root, "k", json_object_new_boolean(1));
967 dst = NULL; R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
968 T(ok && dst && strcmp(dst, "true") == 0, "scalar2strdupz: bool true→'true'");
969 freez(dst); dst = NULL;
970 json_object_put(root);
971
972 root = json_object_new_object();
973 json_object_object_add(root, "k", json_object_new_boolean(0));
974 dst = NULL; R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
975 T(ok && dst && strcmp(dst, "false") == 0, "scalar2strdupz: bool false→'false'");
976 freez(dst); dst = NULL;
977 json_object_put(root);
978
979 // --- type: null → NULL ---
980 root = json_object_new_object();
981 json_object_object_add(root, "k", NULL);
982 dst = strdupz("sentinel");
983 R(); ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, 0);
984 T(ok && dst == NULL, "scalar2strdupz: null→NULL");
985 freez(dst); dst = NULL;
986 json_object_put(root);
987
988 // --- wrong type (array, object) × 3 flags ---
989 for (int wt = 0; wt < 2; wt++) {
990 root = json_object_new_object();
991 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
992 const char *wtn = wt == 0 ? "array" : "object";
993
994 dst = strdupz("sentinel"); R();
995 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_OPTIONAL);
996 snprintfz(msg, sizeof(msg), "scalar2strdupz: %s+OPT→unchanged", wtn);
997 T(ok && dst && strcmp(dst, "sentinel") == 0, msg);
998 freez(dst);
999
1000 dst = strdupz("sentinel"); R();
1001 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_REQUIRED);
1002 snprintfz(msg, sizeof(msg), "scalar2strdupz: %s+REQ→error", wtn);
1003 T(!ok, msg);
1004 freez(dst);
1005
1006 dst = strdupz("sentinel"); R();
1007 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_STRICT);
1008 snprintfz(msg, sizeof(msg), "scalar2strdupz: %s+STRICT→error", wtn);
1009 T(!ok, msg);
1010 freez(dst);
1011
1012 json_object_put(root);
1013 }
1014
1015 // --- missing key × 3 flags ---
1016 root = json_object_new_object();
1017 dst = strdupz("sentinel"); R();
1018 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_OPTIONAL);
1019 T(ok && dst && strcmp(dst, "sentinel") == 0, "scalar2strdupz: missing+OPT→unchanged");
1020 freez(dst);
1021
1022 dst = strdupz("sentinel"); R();
1023 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_REQUIRED);
1024 T(!ok, "scalar2strdupz: missing+REQ→error");
1025 freez(dst);
1026
1027 dst = strdupz("sentinel"); R();
1028 ok = wrap_parse_scalar2strdupz(root, "k", &dst, error, JSONC_STRICT);
1029 T(ok && dst && strcmp(dst, "sentinel") == 0, "scalar2strdupz: missing+STRICT→unchanged");
1030 freez(dst);
1031 json_object_put(root);
1032
1033 buffer_free(error);
1034 return failed;
1035 }
1036
1037 // ----------------------------------------------------------------------------
1038 // TXT2CHAR — branches:
1039 // key found: string, int(print_int64), double(print_netdata_double),
1040 // boolean("true"/"false"), null→"",
1041 // other+OPT→skip, other+REQ→error, other+STRICT→error
1042 // key missing: ALWAYS clears dst[0]='\0', then REQ→error
1043 // ----------------------------------------------------------------------------
1044 static int test_parse_txt2char(void) {
1045 int failed = 0;
1046 BUFFER *error = buffer_create(0, NULL);
1047 json_object *root;
1048 char dst[256];
1049 bool ok;
1050 char msg[256];
1051
1052 // --- type: string ---
1053 root = json_object_new_object();
1054 json_object_object_add(root, "k", json_object_new_string("hello"));
1055 dst[0] = 0; R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1056 T(ok && strcmp(dst, "hello") == 0, "txt2char: str 'hello'");
1057 json_object_put(root);
1058
1059 // --- type: int ---
1060 root = json_object_new_object();
1061 json_object_object_add(root, "k", json_object_new_int64(42));
1062 dst[0] = 0; R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1063 T(ok && strcmp(dst, "42") == 0, "txt2char: int 42→'42'");
1064 json_object_put(root);
1065
1066 // --- type: double ---
1067 root = json_object_new_object();
1068 json_object_object_add(root, "k", json_object_new_double(3.14));
1069 dst[0] = 0; R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1070 T(ok && dst[0] != '\0', "txt2char: double→string");
1071 json_object_put(root);
1072
1073 // --- type: boolean ---
1074 root = json_object_new_object();
1075 json_object_object_add(root, "k", json_object_new_boolean(1));
1076 dst[0] = 0; R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1077 T(ok && strcmp(dst, "true") == 0, "txt2char: bool true→'true'");
1078 json_object_put(root);
1079
1080 root = json_object_new_object();
1081 json_object_object_add(root, "k", json_object_new_boolean(0));
1082 dst[0] = 0; R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1083 T(ok && strcmp(dst, "false") == 0, "txt2char: bool false→'false'");
1084 json_object_put(root);
1085
1086 // --- type: null → "" ---
1087 root = json_object_new_object();
1088 json_object_object_add(root, "k", NULL);
1089 strncpyz(dst, "sentinel", sizeof(dst) - 1);
1090 R(); ok = wrap_parse_txt2char(root, "k", dst, error, 0);
1091 T(ok && dst[0] == '\0', "txt2char: null→empty");
1092 json_object_put(root);
1093
1094 // --- wrong type (array, object) × 3 flags ---
1095 // NOTE: wrapper always initializes its local dst to '\0'. On OPTIONAL
1096 // (macro skips), the wrapper copies empty string to out. On error
1097 // (macro returns false), the wrapper returns before copying, so out
1098 // is NOT updated.
1099 for (int wt = 0; wt < 2; wt++) {
1100 root = json_object_new_object();
1101 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
1102 const char *wtn = wt == 0 ? "array" : "object";
1103
1104 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1105 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_OPTIONAL);
1106 snprintfz(msg, sizeof(msg), "txt2char: %s+OPT→no error", wtn);
1107 T(ok, msg);
1108
1109 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1110 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_REQUIRED);
1111 snprintfz(msg, sizeof(msg), "txt2char: %s+REQ→error", wtn);
1112 T(!ok, msg);
1113
1114 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1115 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_STRICT);
1116 snprintfz(msg, sizeof(msg), "txt2char: %s+STRICT→error", wtn);
1117 T(!ok, msg);
1118
1119 json_object_put(root);
1120 }
1121
1122 // --- missing key: macro ALWAYS clears dst, then REQ→error ---
1123 // On error, wrapper returns before copying → out unchanged
1124 root = json_object_new_object();
1125
1126 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1127 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_OPTIONAL);
1128 T(ok && dst[0] == '\0', "txt2char: missing+OPT→cleared");
1129
1130 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1131 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_REQUIRED);
1132 T(!ok, "txt2char: missing+REQ→error");
1133
1134 strncpyz(dst, "sentinel", sizeof(dst) - 1); R();
1135 ok = wrap_parse_txt2char(root, "k", dst, error, JSONC_STRICT);
1136 T(ok && dst[0] == '\0', "txt2char: missing+STRICT→cleared");
1137
1138 json_object_put(root);
1139
1140 buffer_free(error);
1141 return failed;
1142 }
1143
1144 // ----------------------------------------------------------------------------
1145 // TXT2BUFFER — branches:
1146 // key found: string(non-empty→buffer, empty→NULL), int, double,
1147 // boolean, null→NULL,
1148 // other+OPT→skip(_type_ok=false), other+REQ→error, other+STRICT→error
1149 // key missing: OPT→skip, REQ→error, STRICT→skip
1150 // ----------------------------------------------------------------------------
1151 static int test_parse_txt2buffer(void) {
1152 int failed = 0;
1153 BUFFER *error = buffer_create(0, NULL);
1154 json_object *root;
1155 BUFFER *dst;
1156 bool ok;
1157 char msg[256];
1158
1159 // --- type: string non-empty ---
1160 root = json_object_new_object();
1161 json_object_object_add(root, "k", json_object_new_string("hello"));
1162 dst = NULL; R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1163 T(ok && dst && strcmp(buffer_tostring(dst), "hello") == 0, "txt2buffer: str 'hello'");
1164 buffer_free(dst); dst = NULL;
1165 json_object_put(root);
1166
1167 // --- type: string empty → NULL ---
1168 root = json_object_new_object();
1169 json_object_object_add(root, "k", json_object_new_string(""));
1170 dst = buffer_create(0, NULL);
1171 buffer_strcat(dst, "sentinel");
1172 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1173 T(ok && dst == NULL, "txt2buffer: str ''→NULL");
1174 buffer_free(dst); dst = NULL;
1175 json_object_put(root);
1176
1177 // --- type: int ---
1178 root = json_object_new_object();
1179 json_object_object_add(root, "k", json_object_new_int64(42));
1180 dst = NULL; R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1181 T(ok && dst && strcmp(buffer_tostring(dst), "42") == 0, "txt2buffer: int 42→'42'");
1182 buffer_free(dst); dst = NULL;
1183 json_object_put(root);
1184
1185 // --- type: double ---
1186 root = json_object_new_object();
1187 json_object_object_add(root, "k", json_object_new_double(3.14));
1188 dst = NULL; R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1189 T(ok && dst != NULL, "txt2buffer: double→buffer");
1190 buffer_free(dst); dst = NULL;
1191 json_object_put(root);
1192
1193 // --- type: boolean ---
1194 root = json_object_new_object();
1195 json_object_object_add(root, "k", json_object_new_boolean(1));
1196 dst = NULL; R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1197 T(ok && dst && strcmp(buffer_tostring(dst), "true") == 0, "txt2buffer: bool true→'true'");
1198 buffer_free(dst); dst = NULL;
1199 json_object_put(root);
1200
1201 root = json_object_new_object();
1202 json_object_object_add(root, "k", json_object_new_boolean(0));
1203 dst = NULL; R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1204 T(ok && dst && strcmp(buffer_tostring(dst), "false") == 0, "txt2buffer: bool false→'false'");
1205 buffer_free(dst); dst = NULL;
1206 json_object_put(root);
1207
1208 // --- type: null → NULL ---
1209 root = json_object_new_object();
1210 json_object_object_add(root, "k", NULL);
1211 dst = buffer_create(0, NULL);
1212 buffer_strcat(dst, "sentinel");
1213 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1214 T(ok && dst == NULL, "txt2buffer: null→NULL");
1215 buffer_free(dst); dst = NULL;
1216 json_object_put(root);
1217
1218 // --- type: string into existing buffer (flush+reuse) ---
1219 root = json_object_new_object();
1220 json_object_object_add(root, "k", json_object_new_string("new"));
1221 dst = buffer_create(0, NULL);
1222 buffer_strcat(dst, "old");
1223 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, 0);
1224 T(ok && dst && strcmp(buffer_tostring(dst), "new") == 0, "txt2buffer: str overwrites existing");
1225 buffer_free(dst); dst = NULL;
1226 json_object_put(root);
1227
1228 // --- wrong type (array, object) × 3 flags ---
1229 for (int wt = 0; wt < 2; wt++) {
1230 root = json_object_new_object();
1231 json_object_object_add(root, "k", wt == 0 ? json_object_new_array() : json_object_new_object());
1232 const char *wtn = wt == 0 ? "array" : "object";
1233
1234 dst = buffer_create(0, NULL);
1235 buffer_strcat(dst, "sentinel");
1236 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_OPTIONAL);
1237 snprintfz(msg, sizeof(msg), "txt2buffer: %s+OPT→unchanged", wtn);
1238 T(ok && dst && strcmp(buffer_tostring(dst), "sentinel") == 0, msg);
1239 buffer_free(dst);
1240
1241 dst = buffer_create(0, NULL); R();
1242 ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_REQUIRED);
1243 snprintfz(msg, sizeof(msg), "txt2buffer: %s+REQ→error", wtn);
1244 T(!ok, msg);
1245 buffer_free(dst);
1246
1247 dst = buffer_create(0, NULL); R();
1248 ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_STRICT);
1249 snprintfz(msg, sizeof(msg), "txt2buffer: %s+STRICT→error", wtn);
1250 T(!ok, msg);
1251 buffer_free(dst);
1252
1253 json_object_put(root);
1254 }
1255
1256 // --- missing key × 3 flags ---
1257 root = json_object_new_object();
1258
1259 dst = buffer_create(0, NULL);
1260 buffer_strcat(dst, "sentinel");
1261 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_OPTIONAL);
1262 T(ok && dst && strcmp(buffer_tostring(dst), "sentinel") == 0, "txt2buffer: missing+OPT→unchanged");
1263 buffer_free(dst);
1264
1265 dst = buffer_create(0, NULL); R();
1266 ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_REQUIRED);
1267 T(!ok, "txt2buffer: missing+REQ→error");
1268 buffer_free(dst);
1269
1270 dst = buffer_create(0, NULL);
1271 buffer_strcat(dst, "sentinel");
1272 R(); ok = wrap_parse_txt2buffer(root, "k", &dst, error, JSONC_STRICT);
1273 T(ok && dst && strcmp(buffer_tostring(dst), "sentinel") == 0, "txt2buffer: missing+STRICT→unchanged");
1274 buffer_free(dst);
1275
1276 json_object_put(root);
1277
1278 buffer_free(error);
1279 return failed;
1280 }
1281
1282 // ----------------------------------------------------------------------------
1283 // TXT2UUID — branches:
1284 // key found: string+valid UUID→parsed, string+invalid UUID+OPT→uuid_clear,
1285 // string+invalid UUID+REQ→error, string+invalid UUID+STRICT→error,
1286 // null→uuid_clear,
1287 // other+OPT→skip, other+REQ→error, other+STRICT→error
1288 // key missing: OPT→skip, REQ→error, STRICT→skip
1289 // ----------------------------------------------------------------------------
1290 static int test_parse_txt2uuid(void) {
1291 int failed = 0;
1292 BUFFER *error = buffer_create(0, NULL);
1293 json_object *root;
1294 nd_uuid_t dst;
1295 bool ok;
1296 char msg[256];
1297 static const nd_uuid_t zero_uuid = { 0 };
1298
1299 // --- type: string valid UUID ---
1300 root = json_object_new_object();
1301 json_object_object_add(root, "k", json_object_new_string("550e8400-e29b-41d4-a716-446655440000"));
1302 memset(dst, 0, sizeof(nd_uuid_t));
1303 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, 0);
1304 T(ok && memcmp(dst, zero_uuid, sizeof(nd_uuid_t)) != 0, "txt2uuid: valid UUID parsed");
1305 json_object_put(root);
1306
1307 // --- type: string invalid UUID + OPTIONAL → uuid_clear ---
1308 root = json_object_new_object();
1309 json_object_object_add(root, "k", json_object_new_string("not-a-uuid"));
1310 memset(dst, 0xFF, sizeof(nd_uuid_t));
1311 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_OPTIONAL);
1312 T(ok && memcmp(dst, zero_uuid, sizeof(nd_uuid_t)) == 0, "txt2uuid: invalid UUID+OPT→uuid_clear");
1313 json_object_put(root);
1314
1315 // --- type: string invalid UUID + REQUIRED → error ---
1316 root = json_object_new_object();
1317 json_object_object_add(root, "k", json_object_new_string("not-a-uuid"));
1318 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_REQUIRED);
1319 T(!ok, "txt2uuid: invalid UUID+REQ→error");
1320 json_object_put(root);
1321
1322 // --- type: string invalid UUID + STRICT → error ---
1323 root = json_object_new_object();
1324 json_object_object_add(root, "k", json_object_new_string("not-a-uuid"));
1325 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_STRICT);
1326 T(!ok, "txt2uuid: invalid UUID+STRICT→error");
1327 json_object_put(root);
1328
1329 // --- type: null → uuid_clear ---
1330 root = json_object_new_object();
1331 json_object_object_add(root, "k", NULL);
1332 memset(dst, 0xFF, sizeof(nd_uuid_t));
1333 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, 0);
1334 T(ok && memcmp(dst, zero_uuid, sizeof(nd_uuid_t)) == 0, "txt2uuid: null→uuid_clear");
1335 json_object_put(root);
1336
1337 // --- wrong type (int, array, object) × 3 flags ---
1338 {
1339 for (int wt = 0; wt < 3; wt++) {
1340 root = json_object_new_object();
1341 if (wt == 0) json_object_object_add(root, "k", json_object_new_int64(42));
1342 else if (wt == 1) json_object_object_add(root, "k", json_object_new_array());
1343 else json_object_object_add(root, "k", json_object_new_object());
1344 const char *wtn = (wt == 0) ? "int" : (wt == 1) ? "array" : "object";
1345
1346 memset(dst, 0xFF, sizeof(nd_uuid_t)); R();
1347 ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_OPTIONAL);
1348 snprintfz(msg, sizeof(msg), "txt2uuid: %s+OPT→unchanged", wtn);
1349 T(ok, msg);
1350
1351 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_REQUIRED);
1352 snprintfz(msg, sizeof(msg), "txt2uuid: %s+REQ→error", wtn);
1353 T(!ok, msg);
1354
1355 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_STRICT);
1356 snprintfz(msg, sizeof(msg), "txt2uuid: %s+STRICT→error", wtn);
1357 T(!ok, msg);
1358
1359 json_object_put(root);
1360 }
1361 }
1362
1363 // --- missing key × 3 flags ---
1364 root = json_object_new_object();
1365 memset(dst, 0xFF, sizeof(nd_uuid_t)); R();
1366 ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_OPTIONAL);
1367 T(ok, "txt2uuid: missing+OPT→no error");
1368
1369 R(); ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_REQUIRED);
1370 T(!ok, "txt2uuid: missing+REQ→error");
1371
1372 memset(dst, 0xFF, sizeof(nd_uuid_t)); R();
1373 ok = wrap_parse_txt2uuid(root, "k", dst, error, JSONC_STRICT);
1374 T(ok, "txt2uuid: missing+STRICT→no error");
1375
1376 json_object_put(root);
1377
1378 buffer_free(error);
1379 return failed;
1380 }
1381
1382 // ----------------------------------------------------------------------------
1383 // TXT2RFC3339 — branches:
1384 // key found: string → rfc3339_parse_ut,
1385 // other type → dst=0, then OPT→ok, REQ→error, STRICT→error
1386 // key missing: dst=0, then OPT→ok, REQ→error, STRICT→ok
1387 // NOTE: ALL non-string types (including null) → dst=0, flag check
1388 // ----------------------------------------------------------------------------
1389 static int test_parse_txt2rfc3339(void) {
1390 int failed = 0;
1391 BUFFER *error = buffer_create(0, NULL);
1392 json_object *root;
1393 usec_t dst;
1394 bool ok;
1395 char msg[256];
1396
1397 // --- type: string valid RFC3339 ---
1398 root = json_object_new_object();
1399 json_object_object_add(root, "k", json_object_new_string("2024-01-15T10:30:00Z"));
1400 dst = 0; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, 0);
1401 T(ok && dst != 0, "txt2rfc3339: valid RFC3339");
1402 json_object_put(root);
1403
1404 // --- non-string types → dst=0, flag check ---
1405 {
1406 struct { const char *name; int type_id; } types[] = {
1407 {"int", 0}, {"double", 1}, {"boolean", 2}, {"null", 3},
1408 {"array", 4}, {"object", 5},
1409 };
1410 for (int i = 0; i < 6; i++) {
1411 root = json_object_new_object();
1412 switch(i) {
1413 case 0: json_object_object_add(root, "k", json_object_new_int64(42)); break;
1414 case 1: json_object_object_add(root, "k", json_object_new_double(3.14)); break;
1415 case 2: json_object_object_add(root, "k", json_object_new_boolean(1)); break;
1416 case 3: json_object_object_add(root, "k", NULL); break;
1417 case 4: json_object_object_add(root, "k", json_object_new_array()); break;
1418 case 5: json_object_object_add(root, "k", json_object_new_object()); break;
1419 }
1420
1421 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_OPTIONAL);
1422 snprintfz(msg, sizeof(msg), "txt2rfc3339: %s+OPT→dst=0,ok", types[i].name);
1423 T(ok && dst == 0, msg);
1424
1425 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_REQUIRED);
1426 snprintfz(msg, sizeof(msg), "txt2rfc3339: %s+REQ→error", types[i].name);
1427 T(!ok && dst == 0, msg);
1428
1429 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_STRICT);
1430 snprintfz(msg, sizeof(msg), "txt2rfc3339: %s+STRICT→error", types[i].name);
1431 T(!ok && dst == 0, msg);
1432
1433 json_object_put(root);
1434 }
1435 }
1436
1437 // --- missing key: dst=0, flag check ---
1438 root = json_object_new_object();
1439
1440 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_OPTIONAL);
1441 T(ok && dst == 0, "txt2rfc3339: missing+OPT→dst=0,ok");
1442
1443 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_REQUIRED);
1444 T(!ok && dst == 0, "txt2rfc3339: missing+REQ→dst=0,error");
1445
1446 dst = 999; R(); ok = wrap_parse_txt2rfc3339(root, "k", &dst, error, JSONC_STRICT);
1447 T(ok && dst == 0, "txt2rfc3339: missing+STRICT→dst=0,ok");
1448
1449 json_object_put(root);
1450
1451 buffer_free(error);
1452 return failed;
1453 }
1454
1455 // ----------------------------------------------------------------------------
1456 // RFC3339 formatter regression coverage
1457 // ----------------------------------------------------------------------------
1458 static int test_format_rfc3339(void) {
1459 int failed = 0;
1460 char buffer[RFC3339_MAX_LENGTH];
1461 usec_t parsed;
1462 size_t len;
1463
1464 len = rfc3339_datetime_ut(buffer, sizeof(buffer), 123456, 3, true);
1465 T(len == strlen("1970-01-01T00:00:00.123Z") && strcmp(buffer, "1970-01-01T00:00:00.123Z") == 0,
1466 "format_rfc3339: 3 digits truncate microseconds");
1467
1468 len = rfc3339_datetime_ut(buffer, sizeof(buffer), 123456, 7, true);
1469 T(len == strlen("1970-01-01T00:00:00.1234560Z") && strcmp(buffer, "1970-01-01T00:00:00.1234560Z") == 0,
1470 "format_rfc3339: 7 digits keep microseconds and pad trailing zero");
1471 parsed = rfc3339_parse_ut(buffer, NULL);
1472 T(parsed == 123456, "format_rfc3339: 7-digit output parses back to the same microseconds");
1473
1474 len = rfc3339_datetime_ut(buffer, sizeof(buffer), 1, 9, true);
1475 T(len == strlen("1970-01-01T00:00:00.000001000Z") && strcmp(buffer, "1970-01-01T00:00:00.000001000Z") == 0,
1476 "format_rfc3339: 9 digits preserve leading zeros and pad nanoseconds");
1477 parsed = rfc3339_parse_ut(buffer, NULL);
1478 T(parsed == 1, "format_rfc3339: 9-digit output parses back to the same microseconds");
1479
1480 return failed;
1481 }
1482
1483 // ----------------------------------------------------------------------------
1484 // TXT2PATTERN — branches:
1485 // key found: string "*"→NULL, string other→string_strdupz,
1486 // other+OPT→skip, other+REQ→error, other+STRICT→error
1487 // key missing: OPT→skip, REQ→error, STRICT→skip
1488 // ----------------------------------------------------------------------------
1489 static int test_parse_txt2pattern(void) {
1490 int failed = 0;
1491 BUFFER *error = buffer_create(0, NULL);
1492 json_object *root;
1493 STRING *dst;
1494 bool ok;
1495 char msg[256];
1496
1497 // --- type: string normal ---
1498 root = json_object_new_object();
1499 json_object_object_add(root, "k", json_object_new_string("hello"));
1500 dst = NULL; R(); ok = wrap_parse_txt2pattern(root, "k", &dst, error, 0);
1501 T(ok && dst && strcmp(string2str(dst), "hello") == 0, "txt2pattern: str 'hello'");
1502 string_freez(dst); dst = NULL;
1503 json_object_put(root);
1504
1505 // --- type: string "*" → NULL (wildcard) ---
1506 root = json_object_new_object();
1507 json_object_object_add(root, "k", json_object_new_string("*"));
1508 dst = string_strdupz("sentinel");
1509 R(); ok = wrap_parse_txt2pattern(root, "k", &dst, error, 0);
1510 T(ok && dst == NULL, "txt2pattern: str '*'→NULL (wildcard)");
1511 string_freez(dst); dst = NULL;
1512 json_object_put(root);
1513
1514 // --- non-string types × 3 flags ---
1515 for (int wt = 0; wt < 3; wt++) {
1516 root = json_object_new_object();
1517 if (wt == 0) json_object_object_add(root, "k", json_object_new_int64(42));
1518 else if (wt == 1) json_object_object_add(root, "k", json_object_new_array());
1519 else json_object_object_add(root, "k", json_object_new_object());
1520 const char *wtn = (wt == 0) ? "int" : (wt == 1) ? "array" : "object";
1521
1522 dst = string_strdupz("sentinel"); R();
1523 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_OPTIONAL);
1524 snprintfz(msg, sizeof(msg), "txt2pattern: %s+OPT→unchanged", wtn);
1525 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, msg);
1526 string_freez(dst);
1527
1528 dst = string_strdupz("sentinel"); R();
1529 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_REQUIRED);
1530 snprintfz(msg, sizeof(msg), "txt2pattern: %s+REQ→error", wtn);
1531 T(!ok, msg);
1532 string_freez(dst);
1533
1534 dst = string_strdupz("sentinel"); R();
1535 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_STRICT);
1536 snprintfz(msg, sizeof(msg), "txt2pattern: %s+STRICT→error", wtn);
1537 T(!ok, msg);
1538 string_freez(dst);
1539
1540 json_object_put(root);
1541 }
1542
1543 // --- missing key × 3 flags ---
1544 root = json_object_new_object();
1545 dst = string_strdupz("sentinel"); R();
1546 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_OPTIONAL);
1547 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, "txt2pattern: missing+OPT→unchanged");
1548 string_freez(dst);
1549
1550 dst = string_strdupz("sentinel"); R();
1551 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_REQUIRED);
1552 T(!ok, "txt2pattern: missing+REQ→error");
1553 string_freez(dst);
1554
1555 dst = string_strdupz("sentinel"); R();
1556 ok = wrap_parse_txt2pattern(root, "k", &dst, error, JSONC_STRICT);
1557 T(ok && dst && strcmp(string2str(dst), "sentinel") == 0, "txt2pattern: missing+STRICT→unchanged");
1558 string_freez(dst);
1559
1560 json_object_put(root);
1561
1562 buffer_free(error);
1563 return failed;
1564 }
1565
1566 // ----------------------------------------------------------------------------
1567 // TXT2ENUM — branches:
1568 // key found: string → converter(str),
1569 // other+OPT→skip, other+REQ→error, other+STRICT→error
1570 // key missing: OPT→skip, REQ→error, STRICT→skip
1571 // ----------------------------------------------------------------------------
1572 static int test_parse_txt2enum(void) {
1573 int failed = 0;
1574 BUFFER *error = buffer_create(0, NULL);
1575 json_object *root;
1576 int dst;
1577 bool ok;
1578 char msg[256];
1579
1580 // --- type: string known value ---
1581 root = json_object_new_object();
1582 json_object_object_add(root, "k", json_object_new_string("alpha"));
1583 dst = 0; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, 0);
1584 T(ok && dst == 1, "txt2enum: str 'alpha'→1");
1585 json_object_put(root);
1586
1587 root = json_object_new_object();
1588 json_object_object_add(root, "k", json_object_new_string("beta"));
1589 dst = 0; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, 0);
1590 T(ok && dst == 2, "txt2enum: str 'beta'→2");
1591 json_object_put(root);
1592
1593 // --- type: string unknown → converter returns 0 ---
1594 root = json_object_new_object();
1595 json_object_object_add(root, "k", json_object_new_string("unknown"));
1596 dst = 99; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, 0);
1597 T(ok && dst == 0, "txt2enum: str 'unknown'→0");
1598 json_object_put(root);
1599
1600 // --- non-string types × 3 flags ---
1601 for (int wt = 0; wt < 4; wt++) {
1602 root = json_object_new_object();
1603 if (wt == 0) json_object_object_add(root, "k", json_object_new_int64(1));
1604 else if (wt == 1) json_object_object_add(root, "k", json_object_new_boolean(1));
1605 else if (wt == 2) json_object_object_add(root, "k", json_object_new_array());
1606 else json_object_object_add(root, "k", json_object_new_object());
1607 const char *wtn = (wt == 0) ? "int" : (wt == 1) ? "bool" : (wt == 2) ? "array" : "object";
1608
1609 dst = -999; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_OPTIONAL);
1610 snprintfz(msg, sizeof(msg), "txt2enum: %s+OPT→unchanged", wtn);
1611 T(ok && dst == -999, msg);
1612
1613 R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_REQUIRED);
1614 snprintfz(msg, sizeof(msg), "txt2enum: %s+REQ→error", wtn);
1615 T(!ok, msg);
1616
1617 dst = -999; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_STRICT);
1618 snprintfz(msg, sizeof(msg), "txt2enum: %s+STRICT→error", wtn);
1619 T(!ok, msg);
1620
1621 json_object_put(root);
1622 }
1623
1624 // --- missing key × 3 flags ---
1625 root = json_object_new_object();
1626 dst = -999; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_OPTIONAL);
1627 T(ok && dst == -999, "txt2enum: missing+OPT→unchanged");
1628 R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_REQUIRED);
1629 T(!ok, "txt2enum: missing+REQ→error");
1630 dst = -999; R(); ok = wrap_parse_txt2enum(root, "k", &dst, error, JSONC_STRICT);
1631 T(ok && dst == -999, "txt2enum: missing+STRICT→unchanged");
1632 json_object_put(root);
1633
1634 buffer_free(error);
1635 return failed;
1636 }
1637
1638 // ----------------------------------------------------------------------------
1639 // ARRAY_OF_TXT2BITMAP — branches:
1640 // key found + array: all string → OR bits, non-string item → ALWAYS error,
1641 // unknown string (converter→0) → error msg but continues
1642 // key found + non-array: OPT→skip, REQ→error, STRICT→error
1643 // key missing: OPT→skip, REQ→error, STRICT→skip
1644 // ----------------------------------------------------------------------------
1645 static int test_parse_array_of_txt2bitmap(void) {
1646 int failed = 0;
1647 BUFFER *error = buffer_create(0, NULL);
1648 json_object *root;
1649 uint32_t dst;
1650 bool ok;
1651 char msg[256];
1652
1653 // --- happy path: ["read","write"] → 3 ---
1654 {
1655 root = json_object_new_object();
1656 json_object *arr = json_object_new_array();
1657 json_object_array_add(arr, json_object_new_string("read"));
1658 json_object_array_add(arr, json_object_new_string("write"));
1659 json_object_object_add(root, "k", arr);
1660 dst = 0; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, 0);
1661 T(ok && dst == 3, "bitmap: ['read','write']→3");
1662 json_object_put(root);
1663 }
1664
1665 // --- happy path: ["exec"] → 4 ---
1666 {
1667 root = json_object_new_object();
1668 json_object *arr = json_object_new_array();
1669 json_object_array_add(arr, json_object_new_string("exec"));
1670 json_object_object_add(root, "k", arr);
1671 dst = 0; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, 0);
1672 T(ok && dst == 4, "bitmap: ['exec']→4");
1673 json_object_put(root);
1674 }
1675
1676 // --- empty array → dst=0 ---
1677 {
1678 root = json_object_new_object();
1679 json_object_object_add(root, "k", json_object_new_array());
1680 dst = 99; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, 0);
1681 T(ok && dst == 0, "bitmap: []→0");
1682 json_object_put(root);
1683 }
1684
1685 // --- non-string item in array → ALWAYS error ---
1686 {
1687 root = json_object_new_object();
1688 json_object *arr = json_object_new_array();
1689 json_object_array_add(arr, json_object_new_int64(42));
1690 json_object_object_add(root, "k", arr);
1691 dst = 0; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_OPTIONAL);
1692 T(!ok, "bitmap: non-string item+OPT→error");
1693 json_object_put(root);
1694 }
1695
1696 // --- unknown string (converter returns 0) → error msg but no return false ---
1697 {
1698 root = json_object_new_object();
1699 json_object *arr = json_object_new_array();
1700 json_object_array_add(arr, json_object_new_string("read"));
1701 json_object_array_add(arr, json_object_new_string("unknown"));
1702 json_object_object_add(root, "k", arr);
1703 dst = 0; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, 0);
1704 // error message written but return false is commented out, so ok=true
1705 T(ok && dst == 1, "bitmap: unknown string→error msg, continues, dst=1");
1706 json_object_put(root);
1707 }
1708
1709 // --- non-array type × 3 flags ---
1710 for (int wt = 0; wt < 3; wt++) {
1711 root = json_object_new_object();
1712 if (wt == 0) json_object_object_add(root, "k", json_object_new_string("read"));
1713 else if (wt == 1) json_object_object_add(root, "k", json_object_new_int64(1));
1714 else json_object_object_add(root, "k", json_object_new_object());
1715 const char *wtn = (wt == 0) ? "string" : (wt == 1) ? "int" : "object";
1716
1717 dst = 999; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_OPTIONAL);
1718 snprintfz(msg, sizeof(msg), "bitmap: %s+OPT→unchanged", wtn);
1719 T(ok && dst == 999, msg);
1720
1721 R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_REQUIRED);
1722 snprintfz(msg, sizeof(msg), "bitmap: %s+REQ→error", wtn);
1723 T(!ok, msg);
1724
1725 dst = 999; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_STRICT);
1726 snprintfz(msg, sizeof(msg), "bitmap: %s+STRICT→error", wtn);
1727 T(!ok, msg);
1728
1729 json_object_put(root);
1730 }
1731
1732 // --- missing key × 3 flags ---
1733 root = json_object_new_object();
1734 dst = 999; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_OPTIONAL);
1735 T(ok && dst == 999, "bitmap: missing+OPT→unchanged");
1736 R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_REQUIRED);
1737 T(!ok, "bitmap: missing+REQ→error");
1738 dst = 999; R(); ok = wrap_parse_array_of_txt2bitmap(root, "k", &dst, error, JSONC_STRICT);
1739 T(ok && dst == 999, "bitmap: missing+STRICT→unchanged");
1740 json_object_put(root);
1741
1742 buffer_free(error);
1743 return failed;
1744 }
1745
1746 // ----------------------------------------------------------------------------
1747 // SUBOBJECT — branches:
1748 // key found + object → enter block
1749 // key found + non-object: OPT→skip, REQ→error, STRICT→error
1750 // key missing: OPT→skip, REQ→error, STRICT→skip
1751 // ----------------------------------------------------------------------------
1752 static int test_parse_subobject(void) {
1753 int failed = 0;
1754 BUFFER *error = buffer_create(0, NULL);
1755 json_object *root;
1756 bool entered, ok;
1757 char msg[256];
1758
1759 // --- happy path: object present → block entered ---
1760 root = json_object_new_object();
1761 json_object_object_add(root, "k", json_object_new_object());
1762 R(); ok = wrap_parse_subobject(root, "k", &entered, error, 0);
1763 T(ok && entered, "subobject: object→entered");
1764 json_object_put(root);
1765
1766 // --- non-object type × 3 flags ---
1767 for (int wt = 0; wt < 3; wt++) {
1768 root = json_object_new_object();
1769 if (wt == 0) json_object_object_add(root, "k", json_object_new_string("str"));
1770 else if (wt == 1) json_object_object_add(root, "k", json_object_new_int64(42));
1771 else json_object_object_add(root, "k", json_object_new_array());
1772 const char *wtn = (wt == 0) ? "string" : (wt == 1) ? "int" : "array";
1773
1774 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_OPTIONAL);
1775 snprintfz(msg, sizeof(msg), "subobject: %s+OPT→not entered,ok", wtn);
1776 T(ok && !entered, msg);
1777
1778 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_REQUIRED);
1779 snprintfz(msg, sizeof(msg), "subobject: %s+REQ→error", wtn);
1780 T(!ok, msg);
1781
1782 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_STRICT);
1783 snprintfz(msg, sizeof(msg), "subobject: %s+STRICT→error", wtn);
1784 T(!ok, msg);
1785
1786 json_object_put(root);
1787 }
1788
1789 // --- missing key × 3 flags ---
1790 root = json_object_new_object();
1791
1792 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_OPTIONAL);
1793 T(ok && !entered, "subobject: missing+OPT→not entered,ok");
1794
1795 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_REQUIRED);
1796 T(!ok, "subobject: missing+REQ→error");
1797
1798 R(); ok = wrap_parse_subobject(root, "k", &entered, error, JSONC_STRICT);
1799 T(ok && !entered, "subobject: missing+STRICT→not entered,ok");
1800
1801 json_object_put(root);
1802
1803 buffer_free(error);
1804 return failed;
1805 }
1806
1807 // ----------------------------------------------------------------------------
1808 // ARRAY — branches:
1809 // key found + array → enter block
1810 // key found + non-array: OPT→skip, REQ→error, STRICT→error
1811 // key missing: OPT→skip, REQ→error, STRICT→skip
1812 // ----------------------------------------------------------------------------
1813 static int test_parse_array(void) {
1814 int failed = 0;
1815 BUFFER *error = buffer_create(0, NULL);
1816 json_object *root;
1817 size_t count;
1818 bool ok;
1819 char msg[256];
1820
1821 // --- happy path: array present → block entered, correct length ---
1822 {
1823 root = json_object_new_object();
1824 json_object *arr = json_object_new_array();
1825 json_object_array_add(arr, json_object_new_int64(1));
1826 json_object_array_add(arr, json_object_new_int64(2));
1827 json_object_array_add(arr, json_object_new_int64(3));
1828 json_object_object_add(root, "k", arr);
1829 R(); ok = wrap_parse_array(root, "k", &count, error, 0);
1830 T(ok && count == 3, "array: present→entered, len=3");
1831 json_object_put(root);
1832 }
1833
1834 // --- empty array ---
1835 {
1836 root = json_object_new_object();
1837 json_object_object_add(root, "k", json_object_new_array());
1838 R(); ok = wrap_parse_array(root, "k", &count, error, 0);
1839 T(ok && count == 0, "array: empty→entered, len=0");
1840 json_object_put(root);
1841 }
1842
1843 // --- non-array type × 3 flags ---
1844 for (int wt = 0; wt < 3; wt++) {
1845 root = json_object_new_object();
1846 if (wt == 0) json_object_object_add(root, "k", json_object_new_string("str"));
1847 else if (wt == 1) json_object_object_add(root, "k", json_object_new_int64(42));
1848 else json_object_object_add(root, "k", json_object_new_object());
1849 const char *wtn = (wt == 0) ? "string" : (wt == 1) ? "int" : "object";
1850
1851 count = 999; R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_OPTIONAL);
1852 snprintfz(msg, sizeof(msg), "array: %s+OPT→not entered,ok", wtn);
1853 T(ok && count == 0, msg);
1854
1855 R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_REQUIRED);
1856 snprintfz(msg, sizeof(msg), "array: %s+REQ→error", wtn);
1857 T(!ok, msg);
1858
1859 R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_STRICT);
1860 snprintfz(msg, sizeof(msg), "array: %s+STRICT→error", wtn);
1861 T(!ok, msg);
1862
1863 json_object_put(root);
1864 }
1865
1866 // --- missing key × 3 flags ---
1867 root = json_object_new_object();
1868
1869 count = 999; R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_OPTIONAL);
1870 T(ok && count == 0, "array: missing+OPT→not entered,ok");
1871
1872 R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_REQUIRED);
1873 T(!ok, "array: missing+REQ→error");
1874
1875 count = 999; R(); ok = wrap_parse_array(root, "k", &count, error, JSONC_STRICT);
1876 T(ok && count == 0, "array: missing+STRICT→not entered,ok");
1877
1878 json_object_put(root);
1879
1880 buffer_free(error);
1881 return failed;
1882 }
1883
1884 // ----------------------------------------------------------------------------
1885 // ARRAY_ITEM_OBJECT — branches:
1886 // item is object → enter block
1887 // item is non-object: OPT→skip, REQ→error, STRICT→error
1888 // empty array → no iterations
1889 // ----------------------------------------------------------------------------
1890 static int test_parse_array_item_object(void) {
1891 int failed = 0;
1892 BUFFER *error = buffer_create(0, NULL);
1893 json_object *arr;
1894 size_t count;
1895 bool ok;
1896
1897 // --- all items are objects ---
1898 {
1899 arr = json_object_new_array();
1900 json_object_array_add(arr, json_object_new_object());
1901 json_object_array_add(arr, json_object_new_object());
1902 json_object_array_add(arr, json_object_new_object());
1903 R(); ok = wrap_parse_array_item_object(arr, &count, error, 0);
1904 T(ok && count == 3, "array_item_object: 3 objects→count=3");
1905 json_object_put(arr);
1906 }
1907
1908 // --- empty array ---
1909 {
1910 arr = json_object_new_array();
1911 R(); ok = wrap_parse_array_item_object(arr, &count, error, 0);
1912 T(ok && count == 0, "array_item_object: empty→count=0");
1913 json_object_put(arr);
1914 }
1915
1916 // --- non-object item + OPTIONAL → skipped ---
1917 {
1918 arr = json_object_new_array();
1919 json_object_array_add(arr, json_object_new_object());
1920 json_object_array_add(arr, json_object_new_string("not_obj"));
1921 json_object_array_add(arr, json_object_new_object());
1922 R(); ok = wrap_parse_array_item_object(arr, &count, error, JSONC_OPTIONAL);
1923 T(ok && count == 2, "array_item_object: non-obj+OPT→skipped, count=2");
1924 json_object_put(arr);
1925 }
1926
1927 // --- non-object item + REQUIRED → error ---
1928 {
1929 arr = json_object_new_array();
1930 json_object_array_add(arr, json_object_new_string("not_obj"));
1931 R(); ok = wrap_parse_array_item_object(arr, &count, error, JSONC_REQUIRED);
1932 T(!ok, "array_item_object: non-obj+REQ→error");
1933 json_object_put(arr);
1934 }
1935
1936 // --- non-object item + STRICT → error ---
1937 {
1938 arr = json_object_new_array();
1939 json_object_array_add(arr, json_object_new_int64(42));
1940 R(); ok = wrap_parse_array_item_object(arr, &count, error, JSONC_STRICT);
1941 T(!ok, "array_item_object: non-obj+STRICT→error");
1942 json_object_put(arr);
1943 }
1944
1945 buffer_free(error);
1946 return failed;
1947 }
1948
1949 // ----------------------------------------------------------------------------
1950 // json_parse_function_payload_or_error() error path:
1951 // callback error should be capped and explicitly truncated
1952 // ----------------------------------------------------------------------------
1953 static int test_parse_function_payload_error_cap(void) {
1954 int failed = 0;
1955 BUFFER *payload = buffer_create(0, NULL);
1956 BUFFER *output = buffer_create(0, NULL);
1957 char long_error[1024];
1958 int code = 0;
1959
1960 memset(long_error, 'A', sizeof(long_error) - 1);
1961 long_error[sizeof(long_error) - 1] = '\0';
1962
1963 buffer_strcat(payload, "{}");
1964
1965 struct json_object *result = json_parse_function_payload_or_error(output, payload, &code,
1966 json_function_payload_fail_with_error,
1967 long_error);
1968
1969 T(result == NULL, "function_payload_error_cap: callback failure should return NULL");
1970 T(code == HTTP_RESP_BAD_REQUEST, "function_payload_error_cap: callback failure should return bad request");
1971
1972 json_object *response = json_tokener_parse(buffer_tostring(output));
1973 T(response != NULL, "function_payload_error_cap: output should be valid JSON");
1974
1975 const char *error_msg = NULL;
1976 if(response) {
1977 json_object *error_obj = NULL;
1978 T(json_object_object_get_ex(response, "errorMessage", &error_obj),
1979 "function_payload_error_cap: response should include errorMessage");
1980
1981 if(error_obj)
1982 error_msg = json_object_get_string(error_obj);
1983 }
1984
1985 T(error_msg != NULL, "function_payload_error_cap: errorMessage should be readable");
1986 T(error_msg && strncmp(error_msg, "JSON parser failed: ", strlen("JSON parser failed: ")) == 0,
1987 "function_payload_error_cap: errorMessage should include parser prefix");
1988 T(error_msg && strstr(error_msg, "...") != NULL,
1989 "function_payload_error_cap: errorMessage should explicitly indicate truncation");
1990 T(error_msg && strlen(error_msg) < sizeof(long_error) - 1,
1991 "function_payload_error_cap: errorMessage should be shorter than the original callback error");
1992 T(buffer_strlen(output) < sizeof(long_error),
1993 "function_payload_error_cap: output JSON should stay smaller than the original callback error");
1994
1995 if(response)
1996 json_object_put(response);
1997 buffer_free(output);
1998 buffer_free(payload);
1999
2000 return failed;
2001 }
2002
2003 // ----------------------------------------------------------------------------
2004 // json_parse_function_payload_or_error() error path:
2005 // empty callback error should fall back to "unknown error"
2006 // ----------------------------------------------------------------------------
2007 static int test_parse_function_payload_empty_error_fallback(void) {
2008 int failed = 0;
2009 BUFFER *payload = buffer_create(0, NULL);
2010 BUFFER *output = buffer_create(0, NULL);
2011 int code = 0;
2012
2013 buffer_strcat(payload, "{}");
2014
2015 struct json_object *result = json_parse_function_payload_or_error(output, payload, &code,
2016 json_function_payload_fail_with_error,
2017 "");
2018
2019 T(result == NULL, "function_payload_empty_error_fallback: callback failure should return NULL");
2020 T(code == HTTP_RESP_BAD_REQUEST, "function_payload_empty_error_fallback: callback failure should return bad request");
2021
2022 json_object *response = json_tokener_parse(buffer_tostring(output));
2023 T(response != NULL, "function_payload_empty_error_fallback: output should be valid JSON");
2024
2025 const char *error_msg = NULL;
2026 if(response) {
2027 json_object *error_obj = NULL;
2028 T(json_object_object_get_ex(response, "errorMessage", &error_obj),
2029 "function_payload_empty_error_fallback: response should include errorMessage");
2030
2031 if(error_obj)
2032 error_msg = json_object_get_string(error_obj);
2033 }
2034
2035 T(error_msg != NULL, "function_payload_empty_error_fallback: errorMessage should be readable");
2036 T(error_msg && strcmp(error_msg, "JSON parser failed: unknown error") == 0,
2037 "function_payload_empty_error_fallback: empty callback error should use the unknown error fallback");
2038
2039 if(response)
2040 json_object_put(response);
2041 buffer_free(output);
2042 buffer_free(payload);
2043
2044 return failed;
2045 }
2046
2047 // ============================================================================
2048 // Entry point
2049 // ============================================================================
2050
2051 #undef T
2052 #undef R
2053
2054 int json_c_parser_unittest(void) {
2055 struct {
2056 const char *name;
2057 int (*func)(void);
2058 } tests[] = {
2059 { "BOOL", test_parse_bool },
2060 { "INT64", test_parse_int64 },
2061 { "UINT64", test_parse_uint64 },
2062 { "DOUBLE", test_parse_double },
2063 { "TXT2STRING", test_parse_txt2string },
2064 { "TXT2STRDUPZ", test_parse_txt2strdupz },
2065 { "SCALAR2STRDUPZ", test_parse_scalar2strdupz },
2066 { "TXT2CHAR", test_parse_txt2char },
2067 { "TXT2BUFFER", test_parse_txt2buffer },
2068 { "TXT2UUID", test_parse_txt2uuid },
2069 { "TXT2RFC3339", test_parse_txt2rfc3339 },
2070 { "FORMAT_RFC3339", test_format_rfc3339 },
2071 { "TXT2PATTERN", test_parse_txt2pattern },
2072 { "TXT2ENUM", test_parse_txt2enum },
2073 { "ARRAY_OF_TXT2BITMAP", test_parse_array_of_txt2bitmap },
2074 { "SUBOBJECT", test_parse_subobject },
2075 { "ARRAY", test_parse_array },
2076 { "ARRAY_ITEM_OBJECT", test_parse_array_item_object },
2077 { "FUNCTION_PAYLOAD_ERROR_CAP", test_parse_function_payload_error_cap },
2078 { "FUNCTION_PAYLOAD_EMPTY_ERROR_FALLBACK", test_parse_function_payload_empty_error_fallback },
2079 { NULL, NULL }
2080 };
2081
2082 int total_failed = 0;
2083 fprintf(stderr, "\n%s\n", "JSON-C Parser Unit Tests");
2084 fprintf(stderr, "%s\n", "========================");
2085
2086 for (int i = 0; tests[i].name; i++) {
2087 int f = tests[i].func();
2088 if (f)
2089 fprintf(stderr, " %-25s FAILED (%d failures)\n", tests[i].name, f);
2090 else
2091 fprintf(stderr, " %-25s PASSED\n", tests[i].name);
2092 total_failed += f;
2093 }
2094
2095 fprintf(stderr, "\nTotal: %d failures\n\n", total_failed);
2096 return total_failed;
2097 }