3 #include "json-writer.h"
5 static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
6 static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
7 static const char *expect_obj3 = "{\"a\":0,\"b\":4294967295,\"c\":9223372036854775807}";
8 static const char *expect_obj4 = "{\"t\":true,\"f\":false,\"n\":null}";
9 static const char *expect_obj5 = "{\"abc\\tdef\":\"abc\\\\def\"}";
10 static const char *expect_obj6 = "{\"a\":3.14}";
12 static const char *pretty_obj1 = ("{\n"
17 static const char *pretty_obj2 = ("{\n"
19 " \"b\": 2147483647,\n"
22 static const char *pretty_obj3 = ("{\n"
24 " \"b\": 4294967295,\n"
25 " \"c\": 9223372036854775807\n"
27 static const char *pretty_obj4 = ("{\n"
33 static struct json_writer obj1 = JSON_WRITER_INIT;
34 static struct json_writer obj2 = JSON_WRITER_INIT;
35 static struct json_writer obj3 = JSON_WRITER_INIT;
36 static struct json_writer obj4 = JSON_WRITER_INIT;
37 static struct json_writer obj5 = JSON_WRITER_INIT;
38 static struct json_writer obj6 = JSON_WRITER_INIT;
40 static void make_obj1(int pretty)
42 jw_object_begin(&obj1, pretty);
44 jw_object_string(&obj1, "a", "abc");
45 jw_object_intmax(&obj1, "b", 42);
46 jw_object_true(&obj1, "c");
51 static void make_obj2(int pretty)
53 jw_object_begin(&obj2, pretty);
55 jw_object_intmax(&obj2, "a", -1);
56 jw_object_intmax(&obj2, "b", 0x7fffffff);
57 jw_object_intmax(&obj2, "c", 0);
62 static void make_obj3(int pretty)
64 jw_object_begin(&obj3, pretty);
66 jw_object_intmax(&obj3, "a", 0);
67 jw_object_intmax(&obj3, "b", 0xffffffff);
68 jw_object_intmax(&obj3, "c", 0x7fffffffffffffffULL);
73 static void make_obj4(int pretty)
75 jw_object_begin(&obj4, pretty);
77 jw_object_true(&obj4, "t");
78 jw_object_false(&obj4, "f");
79 jw_object_null(&obj4, "n");
84 static void make_obj5(int pretty)
86 jw_object_begin(&obj5, pretty);
88 jw_object_string(&obj5, "abc" "\x09" "def", "abc" "\\" "def");
93 static void make_obj6(int pretty)
95 jw_object_begin(&obj6, pretty);
97 jw_object_double(&obj6, "a", 2, 3.14159);
102 static const char *expect_arr1 = "[\"abc\",42,true]";
103 static const char *expect_arr2 = "[-1,2147483647,0]";
104 static const char *expect_arr3 = "[0,4294967295,9223372036854775807]";
105 static const char *expect_arr4 = "[true,false,null]";
107 static const char *pretty_arr1 = ("[\n"
112 static const char *pretty_arr2 = ("[\n"
117 static const char *pretty_arr3 = ("[\n"
120 " 9223372036854775807\n"
122 static const char *pretty_arr4 = ("[\n"
128 static struct json_writer arr1 = JSON_WRITER_INIT;
129 static struct json_writer arr2 = JSON_WRITER_INIT;
130 static struct json_writer arr3 = JSON_WRITER_INIT;
131 static struct json_writer arr4 = JSON_WRITER_INIT;
133 static void make_arr1(int pretty)
135 jw_array_begin(&arr1, pretty);
137 jw_array_string(&arr1, "abc");
138 jw_array_intmax(&arr1, 42);
139 jw_array_true(&arr1);
144 static void make_arr2(int pretty)
146 jw_array_begin(&arr2, pretty);
148 jw_array_intmax(&arr2, -1);
149 jw_array_intmax(&arr2, 0x7fffffff);
150 jw_array_intmax(&arr2, 0);
155 static void make_arr3(int pretty)
157 jw_array_begin(&arr3, pretty);
159 jw_array_intmax(&arr3, 0);
160 jw_array_intmax(&arr3, 0xffffffff);
161 jw_array_intmax(&arr3, 0x7fffffffffffffffULL);
166 static void make_arr4(int pretty)
168 jw_array_begin(&arr4, pretty);
170 jw_array_true(&arr4);
171 jw_array_false(&arr4);
172 jw_array_null(&arr4);
177 static char *expect_nest1 =
178 "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}";
180 static struct json_writer nest1 = JSON_WRITER_INIT;
182 static void make_nest1(int pretty)
184 jw_object_begin(&nest1, pretty);
186 jw_object_sub_jw(&nest1, "obj1", &obj1);
187 jw_object_sub_jw(&nest1, "arr1", &arr1);
192 static char *expect_inline1 =
193 "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}";
195 static char *pretty_inline1 =
209 static struct json_writer inline1 = JSON_WRITER_INIT;
211 static void make_inline1(int pretty)
213 jw_object_begin(&inline1, pretty);
215 jw_object_inline_begin_object(&inline1, "obj1");
217 jw_object_string(&inline1, "a", "abc");
218 jw_object_intmax(&inline1, "b", 42);
219 jw_object_true(&inline1, "c");
222 jw_object_inline_begin_array(&inline1, "arr1");
224 jw_array_string(&inline1, "abc");
225 jw_array_intmax(&inline1, 42);
226 jw_array_true(&inline1);
233 static char *expect_inline2 =
234 "[[1,2],[3,4],{\"a\":\"abc\"}]";
236 static char *pretty_inline2 =
251 static struct json_writer inline2 = JSON_WRITER_INIT;
253 static void make_inline2(int pretty)
255 jw_array_begin(&inline2, pretty);
257 jw_array_inline_begin_array(&inline2);
259 jw_array_intmax(&inline2, 1);
260 jw_array_intmax(&inline2, 2);
263 jw_array_inline_begin_array(&inline2);
265 jw_array_intmax(&inline2, 3);
266 jw_array_intmax(&inline2, 4);
269 jw_array_inline_begin_object(&inline2);
271 jw_object_string(&inline2, "a", "abc");
279 * When super is compact, we expect subs to be compacted (even if originally
282 static const char *expect_mixed1 =
283 ("{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},"
284 "\"arr1\":[\"abc\",42,true]}");
287 * When super is pretty, a compact sub (obj1) is kept compact and a pretty
288 * sub (arr1) is re-indented.
290 static const char *pretty_mixed1 =
292 " \"obj1\": {\"a\":\"abc\",\"b\":42,\"c\":true},\n"
300 static struct json_writer mixed1 = JSON_WRITER_INIT;
302 static void make_mixed1(int pretty)
307 make_obj1(0); /* obj1 is compact */
308 make_arr1(1); /* arr1 is pretty */
310 jw_object_begin(&mixed1, pretty);
312 jw_object_sub_jw(&mixed1, "obj1", &obj1);
313 jw_object_sub_jw(&mixed1, "arr1", &arr1);
318 static void cmp(const char *test, const struct json_writer *jw, const char *exp)
320 if (!strcmp(jw->json.buf, exp))
323 printf("error[%s]: observed '%s' expected '%s'\n",
324 test, jw->json.buf, exp);
328 #define t(v) do { make_##v(0); cmp(#v, &v, expect_##v); } while (0)
329 #define p(v) do { make_##v(1); cmp(#v, &v, pretty_##v); } while (0)
332 * Run some basic regression tests with some known patterns.
333 * These tests also demonstrate how to use the jw_ API.
335 static int unit_tests(void)
337 /* comptact (canonical) forms */
390 static void get_s(int line_nr, char **s_in)
392 *s_in = strtok(NULL, " ");
394 die("line[%d]: expected: <s>", line_nr);
397 static void get_i(int line_nr, intmax_t *s_in)
404 *s_in = strtol(s, &endptr, 10);
405 if (*endptr || errno == ERANGE)
406 die("line[%d]: invalid integer value", line_nr);
409 static void get_d(int line_nr, double *s_in)
416 *s_in = strtod(s, &endptr);
417 if (*endptr || errno == ERANGE)
418 die("line[%d]: invalid float value", line_nr);
423 #define MAX_LINE_LENGTH (64 * 1024)
425 static char *get_trimmed_line(char *buf, int buf_size)
429 if (!fgets(buf, buf_size, stdin))
434 char c = buf[len - 1];
435 if (c == '\n' || c == '\r' || c == ' ' || c == '\t')
441 while (*buf == ' ' || *buf == '\t')
447 static int scripted(void)
449 struct json_writer jw = JSON_WRITER_INIT;
450 char buf[MAX_LINE_LENGTH];
454 line = get_trimmed_line(buf, MAX_LINE_LENGTH);
458 if (!strcmp(line, "object"))
459 jw_object_begin(&jw, pretty);
460 else if (!strcmp(line, "array"))
461 jw_array_begin(&jw, pretty);
463 die("expected first line to be 'object' or 'array'");
465 while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
474 verb = strtok(line, " ");
476 if (!strcmp(verb, "end")) {
479 else if (!strcmp(verb, "object-string")) {
480 get_s(line_nr, &key);
481 get_s(line_nr, &s_value);
482 jw_object_string(&jw, key, s_value);
484 else if (!strcmp(verb, "object-int")) {
485 get_s(line_nr, &key);
486 get_i(line_nr, &i_value);
487 jw_object_intmax(&jw, key, i_value);
489 else if (!strcmp(verb, "object-double")) {
490 get_s(line_nr, &key);
491 get_i(line_nr, &i_value);
492 get_d(line_nr, &d_value);
493 jw_object_double(&jw, key, i_value, d_value);
495 else if (!strcmp(verb, "object-true")) {
496 get_s(line_nr, &key);
497 jw_object_true(&jw, key);
499 else if (!strcmp(verb, "object-false")) {
500 get_s(line_nr, &key);
501 jw_object_false(&jw, key);
503 else if (!strcmp(verb, "object-null")) {
504 get_s(line_nr, &key);
505 jw_object_null(&jw, key);
507 else if (!strcmp(verb, "object-object")) {
508 get_s(line_nr, &key);
509 jw_object_inline_begin_object(&jw, key);
511 else if (!strcmp(verb, "object-array")) {
512 get_s(line_nr, &key);
513 jw_object_inline_begin_array(&jw, key);
515 else if (!strcmp(verb, "array-string")) {
516 get_s(line_nr, &s_value);
517 jw_array_string(&jw, s_value);
519 else if (!strcmp(verb, "array-int")) {
520 get_i(line_nr, &i_value);
521 jw_array_intmax(&jw, i_value);
523 else if (!strcmp(verb, "array-double")) {
524 get_i(line_nr, &i_value);
525 get_d(line_nr, &d_value);
526 jw_array_double(&jw, i_value, d_value);
528 else if (!strcmp(verb, "array-true"))
530 else if (!strcmp(verb, "array-false"))
532 else if (!strcmp(verb, "array-null"))
534 else if (!strcmp(verb, "array-object"))
535 jw_array_inline_begin_object(&jw);
536 else if (!strcmp(verb, "array-array"))
537 jw_array_inline_begin_array(&jw);
539 die("unrecognized token: '%s'", verb);
542 if (!jw_is_terminated(&jw))
543 die("json not terminated: '%s'", jw.json.buf);
545 printf("%s\n", jw.json.buf);
547 strbuf_release(&jw.json);
551 int cmd__json_writer(int argc, const char **argv)
553 argc--; /* skip over "json-writer" arg */
556 if (argc > 0 && argv[0][0] == '-') {
557 if (!strcmp(argv[0], "-u") || !strcmp(argv[0], "--unit"))
560 if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--pretty"))