]>
Commit | Line | Data |
---|---|---|
75459410 JH |
1 | #include "test-tool.h" |
2 | #include "cache.h" | |
3 | #include "json-writer.h" | |
4 | ||
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}"; | |
11 | ||
12 | static const char *pretty_obj1 = ("{\n" | |
13 | " \"a\": \"abc\",\n" | |
14 | " \"b\": 42,\n" | |
15 | " \"c\": true\n" | |
16 | "}"); | |
17 | static const char *pretty_obj2 = ("{\n" | |
18 | " \"a\": -1,\n" | |
19 | " \"b\": 2147483647,\n" | |
20 | " \"c\": 0\n" | |
21 | "}"); | |
22 | static const char *pretty_obj3 = ("{\n" | |
23 | " \"a\": 0,\n" | |
24 | " \"b\": 4294967295,\n" | |
25 | " \"c\": 9223372036854775807\n" | |
26 | "}"); | |
27 | static const char *pretty_obj4 = ("{\n" | |
28 | " \"t\": true,\n" | |
29 | " \"f\": false,\n" | |
30 | " \"n\": null\n" | |
31 | "}"); | |
32 | ||
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; | |
39 | ||
40 | static void make_obj1(int pretty) | |
41 | { | |
42 | jw_object_begin(&obj1, pretty); | |
43 | { | |
44 | jw_object_string(&obj1, "a", "abc"); | |
45 | jw_object_intmax(&obj1, "b", 42); | |
46 | jw_object_true(&obj1, "c"); | |
47 | } | |
48 | jw_end(&obj1); | |
49 | } | |
50 | ||
51 | static void make_obj2(int pretty) | |
52 | { | |
53 | jw_object_begin(&obj2, pretty); | |
54 | { | |
55 | jw_object_intmax(&obj2, "a", -1); | |
56 | jw_object_intmax(&obj2, "b", 0x7fffffff); | |
57 | jw_object_intmax(&obj2, "c", 0); | |
58 | } | |
59 | jw_end(&obj2); | |
60 | } | |
61 | ||
62 | static void make_obj3(int pretty) | |
63 | { | |
64 | jw_object_begin(&obj3, pretty); | |
65 | { | |
66 | jw_object_intmax(&obj3, "a", 0); | |
67 | jw_object_intmax(&obj3, "b", 0xffffffff); | |
68 | jw_object_intmax(&obj3, "c", 0x7fffffffffffffffULL); | |
69 | } | |
70 | jw_end(&obj3); | |
71 | } | |
72 | ||
73 | static void make_obj4(int pretty) | |
74 | { | |
75 | jw_object_begin(&obj4, pretty); | |
76 | { | |
77 | jw_object_true(&obj4, "t"); | |
78 | jw_object_false(&obj4, "f"); | |
79 | jw_object_null(&obj4, "n"); | |
80 | } | |
81 | jw_end(&obj4); | |
82 | } | |
83 | ||
84 | static void make_obj5(int pretty) | |
85 | { | |
86 | jw_object_begin(&obj5, pretty); | |
87 | { | |
88 | jw_object_string(&obj5, "abc" "\x09" "def", "abc" "\\" "def"); | |
89 | } | |
90 | jw_end(&obj5); | |
91 | } | |
92 | ||
93 | static void make_obj6(int pretty) | |
94 | { | |
95 | jw_object_begin(&obj6, pretty); | |
96 | { | |
97 | jw_object_double(&obj6, "a", 2, 3.14159); | |
98 | } | |
99 | jw_end(&obj6); | |
100 | } | |
101 | ||
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]"; | |
106 | ||
107 | static const char *pretty_arr1 = ("[\n" | |
108 | " \"abc\",\n" | |
109 | " 42,\n" | |
110 | " true\n" | |
111 | "]"); | |
112 | static const char *pretty_arr2 = ("[\n" | |
113 | " -1,\n" | |
114 | " 2147483647,\n" | |
115 | " 0\n" | |
116 | "]"); | |
117 | static const char *pretty_arr3 = ("[\n" | |
118 | " 0,\n" | |
119 | " 4294967295,\n" | |
120 | " 9223372036854775807\n" | |
121 | "]"); | |
122 | static const char *pretty_arr4 = ("[\n" | |
123 | " true,\n" | |
124 | " false,\n" | |
125 | " null\n" | |
126 | "]"); | |
127 | ||
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; | |
132 | ||
133 | static void make_arr1(int pretty) | |
134 | { | |
135 | jw_array_begin(&arr1, pretty); | |
136 | { | |
137 | jw_array_string(&arr1, "abc"); | |
138 | jw_array_intmax(&arr1, 42); | |
139 | jw_array_true(&arr1); | |
140 | } | |
141 | jw_end(&arr1); | |
142 | } | |
143 | ||
144 | static void make_arr2(int pretty) | |
145 | { | |
146 | jw_array_begin(&arr2, pretty); | |
147 | { | |
148 | jw_array_intmax(&arr2, -1); | |
149 | jw_array_intmax(&arr2, 0x7fffffff); | |
150 | jw_array_intmax(&arr2, 0); | |
151 | } | |
152 | jw_end(&arr2); | |
153 | } | |
154 | ||
155 | static void make_arr3(int pretty) | |
156 | { | |
157 | jw_array_begin(&arr3, pretty); | |
158 | { | |
159 | jw_array_intmax(&arr3, 0); | |
160 | jw_array_intmax(&arr3, 0xffffffff); | |
161 | jw_array_intmax(&arr3, 0x7fffffffffffffffULL); | |
162 | } | |
163 | jw_end(&arr3); | |
164 | } | |
165 | ||
166 | static void make_arr4(int pretty) | |
167 | { | |
168 | jw_array_begin(&arr4, pretty); | |
169 | { | |
170 | jw_array_true(&arr4); | |
171 | jw_array_false(&arr4); | |
172 | jw_array_null(&arr4); | |
173 | } | |
174 | jw_end(&arr4); | |
175 | } | |
176 | ||
177 | static char *expect_nest1 = | |
178 | "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; | |
179 | ||
180 | static struct json_writer nest1 = JSON_WRITER_INIT; | |
181 | ||
182 | static void make_nest1(int pretty) | |
183 | { | |
184 | jw_object_begin(&nest1, pretty); | |
185 | { | |
186 | jw_object_sub_jw(&nest1, "obj1", &obj1); | |
187 | jw_object_sub_jw(&nest1, "arr1", &arr1); | |
188 | } | |
189 | jw_end(&nest1); | |
190 | } | |
191 | ||
192 | static char *expect_inline1 = | |
193 | "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; | |
194 | ||
195 | static char *pretty_inline1 = | |
196 | ("{\n" | |
197 | " \"obj1\": {\n" | |
198 | " \"a\": \"abc\",\n" | |
199 | " \"b\": 42,\n" | |
200 | " \"c\": true\n" | |
201 | " },\n" | |
202 | " \"arr1\": [\n" | |
203 | " \"abc\",\n" | |
204 | " 42,\n" | |
205 | " true\n" | |
206 | " ]\n" | |
207 | "}"); | |
208 | ||
209 | static struct json_writer inline1 = JSON_WRITER_INIT; | |
210 | ||
211 | static void make_inline1(int pretty) | |
212 | { | |
213 | jw_object_begin(&inline1, pretty); | |
214 | { | |
215 | jw_object_inline_begin_object(&inline1, "obj1"); | |
216 | { | |
217 | jw_object_string(&inline1, "a", "abc"); | |
218 | jw_object_intmax(&inline1, "b", 42); | |
219 | jw_object_true(&inline1, "c"); | |
220 | } | |
221 | jw_end(&inline1); | |
222 | jw_object_inline_begin_array(&inline1, "arr1"); | |
223 | { | |
224 | jw_array_string(&inline1, "abc"); | |
225 | jw_array_intmax(&inline1, 42); | |
226 | jw_array_true(&inline1); | |
227 | } | |
228 | jw_end(&inline1); | |
229 | } | |
230 | jw_end(&inline1); | |
231 | } | |
232 | ||
233 | static char *expect_inline2 = | |
234 | "[[1,2],[3,4],{\"a\":\"abc\"}]"; | |
235 | ||
236 | static char *pretty_inline2 = | |
237 | ("[\n" | |
238 | " [\n" | |
239 | " 1,\n" | |
240 | " 2\n" | |
241 | " ],\n" | |
242 | " [\n" | |
243 | " 3,\n" | |
244 | " 4\n" | |
245 | " ],\n" | |
246 | " {\n" | |
247 | " \"a\": \"abc\"\n" | |
248 | " }\n" | |
249 | "]"); | |
250 | ||
251 | static struct json_writer inline2 = JSON_WRITER_INIT; | |
252 | ||
253 | static void make_inline2(int pretty) | |
254 | { | |
255 | jw_array_begin(&inline2, pretty); | |
256 | { | |
257 | jw_array_inline_begin_array(&inline2); | |
258 | { | |
259 | jw_array_intmax(&inline2, 1); | |
260 | jw_array_intmax(&inline2, 2); | |
261 | } | |
262 | jw_end(&inline2); | |
263 | jw_array_inline_begin_array(&inline2); | |
264 | { | |
265 | jw_array_intmax(&inline2, 3); | |
266 | jw_array_intmax(&inline2, 4); | |
267 | } | |
268 | jw_end(&inline2); | |
269 | jw_array_inline_begin_object(&inline2); | |
270 | { | |
271 | jw_object_string(&inline2, "a", "abc"); | |
272 | } | |
273 | jw_end(&inline2); | |
274 | } | |
275 | jw_end(&inline2); | |
276 | } | |
277 | ||
278 | /* | |
279 | * When super is compact, we expect subs to be compacted (even if originally | |
280 | * pretty). | |
281 | */ | |
282 | static const char *expect_mixed1 = | |
283 | ("{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true}," | |
284 | "\"arr1\":[\"abc\",42,true]}"); | |
285 | ||
286 | /* | |
287 | * When super is pretty, a compact sub (obj1) is kept compact and a pretty | |
288 | * sub (arr1) is re-indented. | |
289 | */ | |
290 | static const char *pretty_mixed1 = | |
291 | ("{\n" | |
292 | " \"obj1\": {\"a\":\"abc\",\"b\":42,\"c\":true},\n" | |
293 | " \"arr1\": [\n" | |
294 | " \"abc\",\n" | |
295 | " 42,\n" | |
296 | " true\n" | |
297 | " ]\n" | |
298 | "}"); | |
299 | ||
300 | static struct json_writer mixed1 = JSON_WRITER_INIT; | |
301 | ||
302 | static void make_mixed1(int pretty) | |
303 | { | |
304 | jw_init(&obj1); | |
305 | jw_init(&arr1); | |
306 | ||
307 | make_obj1(0); /* obj1 is compact */ | |
308 | make_arr1(1); /* arr1 is pretty */ | |
309 | ||
310 | jw_object_begin(&mixed1, pretty); | |
311 | { | |
312 | jw_object_sub_jw(&mixed1, "obj1", &obj1); | |
313 | jw_object_sub_jw(&mixed1, "arr1", &arr1); | |
314 | } | |
315 | jw_end(&mixed1); | |
316 | } | |
317 | ||
318 | static void cmp(const char *test, const struct json_writer *jw, const char *exp) | |
319 | { | |
320 | if (!strcmp(jw->json.buf, exp)) | |
321 | return; | |
322 | ||
323 | printf("error[%s]: observed '%s' expected '%s'\n", | |
324 | test, jw->json.buf, exp); | |
325 | exit(1); | |
326 | } | |
327 | ||
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) | |
330 | ||
331 | /* | |
332 | * Run some basic regression tests with some known patterns. | |
333 | * These tests also demonstrate how to use the jw_ API. | |
334 | */ | |
335 | static int unit_tests(void) | |
336 | { | |
337 | /* comptact (canonical) forms */ | |
338 | t(obj1); | |
339 | t(obj2); | |
340 | t(obj3); | |
341 | t(obj4); | |
342 | t(obj5); | |
343 | t(obj6); | |
344 | ||
345 | t(arr1); | |
346 | t(arr2); | |
347 | t(arr3); | |
348 | t(arr4); | |
349 | ||
350 | t(nest1); | |
351 | ||
352 | t(inline1); | |
353 | t(inline2); | |
354 | ||
355 | jw_init(&obj1); | |
356 | jw_init(&obj2); | |
357 | jw_init(&obj3); | |
358 | jw_init(&obj4); | |
359 | ||
360 | jw_init(&arr1); | |
361 | jw_init(&arr2); | |
362 | jw_init(&arr3); | |
363 | jw_init(&arr4); | |
364 | ||
365 | jw_init(&inline1); | |
366 | jw_init(&inline2); | |
367 | ||
368 | /* pretty forms */ | |
369 | p(obj1); | |
370 | p(obj2); | |
371 | p(obj3); | |
372 | p(obj4); | |
373 | ||
374 | p(arr1); | |
375 | p(arr2); | |
376 | p(arr3); | |
377 | p(arr4); | |
378 | ||
379 | p(inline1); | |
380 | p(inline2); | |
381 | ||
382 | /* mixed forms */ | |
383 | t(mixed1); | |
384 | jw_init(&mixed1); | |
385 | p(mixed1); | |
386 | ||
387 | return 0; | |
388 | } | |
389 | ||
390 | static void get_s(int line_nr, char **s_in) | |
391 | { | |
392 | *s_in = strtok(NULL, " "); | |
393 | if (!*s_in) | |
394 | die("line[%d]: expected: <s>", line_nr); | |
395 | } | |
396 | ||
397 | static void get_i(int line_nr, intmax_t *s_in) | |
398 | { | |
399 | char *s; | |
400 | char *endptr; | |
401 | ||
402 | get_s(line_nr, &s); | |
403 | ||
404 | *s_in = strtol(s, &endptr, 10); | |
405 | if (*endptr || errno == ERANGE) | |
406 | die("line[%d]: invalid integer value", line_nr); | |
407 | } | |
408 | ||
409 | static void get_d(int line_nr, double *s_in) | |
410 | { | |
411 | char *s; | |
412 | char *endptr; | |
413 | ||
414 | get_s(line_nr, &s); | |
415 | ||
416 | *s_in = strtod(s, &endptr); | |
417 | if (*endptr || errno == ERANGE) | |
418 | die("line[%d]: invalid float value", line_nr); | |
419 | } | |
420 | ||
421 | static int pretty; | |
422 | ||
423 | #define MAX_LINE_LENGTH (64 * 1024) | |
424 | ||
425 | static char *get_trimmed_line(char *buf, int buf_size) | |
426 | { | |
427 | int len; | |
428 | ||
429 | if (!fgets(buf, buf_size, stdin)) | |
430 | return NULL; | |
431 | ||
432 | len = strlen(buf); | |
433 | while (len > 0) { | |
434 | char c = buf[len - 1]; | |
435 | if (c == '\n' || c == '\r' || c == ' ' || c == '\t') | |
436 | buf[--len] = 0; | |
437 | else | |
438 | break; | |
439 | } | |
440 | ||
441 | while (*buf == ' ' || *buf == '\t') | |
442 | buf++; | |
443 | ||
444 | return buf; | |
445 | } | |
446 | ||
447 | static int scripted(void) | |
448 | { | |
449 | struct json_writer jw = JSON_WRITER_INIT; | |
450 | char buf[MAX_LINE_LENGTH]; | |
451 | char *line; | |
452 | int line_nr = 0; | |
453 | ||
454 | line = get_trimmed_line(buf, MAX_LINE_LENGTH); | |
455 | if (!line) | |
456 | return 0; | |
457 | ||
458 | if (!strcmp(line, "object")) | |
459 | jw_object_begin(&jw, pretty); | |
460 | else if (!strcmp(line, "array")) | |
461 | jw_array_begin(&jw, pretty); | |
462 | else | |
463 | die("expected first line to be 'object' or 'array'"); | |
464 | ||
465 | while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) { | |
466 | char *verb; | |
467 | char *key; | |
468 | char *s_value; | |
469 | intmax_t i_value; | |
470 | double d_value; | |
471 | ||
472 | line_nr++; | |
473 | ||
474 | verb = strtok(line, " "); | |
475 | ||
476 | if (!strcmp(verb, "end")) { | |
477 | jw_end(&jw); | |
478 | } | |
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); | |
483 | } | |
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); | |
488 | } | |
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); | |
494 | } | |
495 | else if (!strcmp(verb, "object-true")) { | |
496 | get_s(line_nr, &key); | |
497 | jw_object_true(&jw, key); | |
498 | } | |
499 | else if (!strcmp(verb, "object-false")) { | |
500 | get_s(line_nr, &key); | |
501 | jw_object_false(&jw, key); | |
502 | } | |
503 | else if (!strcmp(verb, "object-null")) { | |
504 | get_s(line_nr, &key); | |
505 | jw_object_null(&jw, key); | |
506 | } | |
507 | else if (!strcmp(verb, "object-object")) { | |
508 | get_s(line_nr, &key); | |
509 | jw_object_inline_begin_object(&jw, key); | |
510 | } | |
511 | else if (!strcmp(verb, "object-array")) { | |
512 | get_s(line_nr, &key); | |
513 | jw_object_inline_begin_array(&jw, key); | |
514 | } | |
515 | else if (!strcmp(verb, "array-string")) { | |
516 | get_s(line_nr, &s_value); | |
517 | jw_array_string(&jw, s_value); | |
518 | } | |
519 | else if (!strcmp(verb, "array-int")) { | |
520 | get_i(line_nr, &i_value); | |
521 | jw_array_intmax(&jw, i_value); | |
522 | } | |
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); | |
527 | } | |
528 | else if (!strcmp(verb, "array-true")) | |
529 | jw_array_true(&jw); | |
530 | else if (!strcmp(verb, "array-false")) | |
531 | jw_array_false(&jw); | |
532 | else if (!strcmp(verb, "array-null")) | |
533 | jw_array_null(&jw); | |
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); | |
538 | else | |
539 | die("unrecognized token: '%s'", verb); | |
540 | } | |
541 | ||
542 | if (!jw_is_terminated(&jw)) | |
543 | die("json not terminated: '%s'", jw.json.buf); | |
544 | ||
545 | printf("%s\n", jw.json.buf); | |
546 | ||
547 | strbuf_release(&jw.json); | |
548 | return 0; | |
549 | } | |
550 | ||
551 | int cmd__json_writer(int argc, const char **argv) | |
552 | { | |
553 | argc--; /* skip over "json-writer" arg */ | |
554 | argv++; | |
555 | ||
556 | if (argc > 0 && argv[0][0] == '-') { | |
557 | if (!strcmp(argv[0], "-u") || !strcmp(argv[0], "--unit")) | |
558 | return unit_tests(); | |
559 | ||
560 | if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--pretty")) | |
561 | pretty = 1; | |
562 | } | |
563 | ||
564 | return scripted(); | |
565 | } |