From: Stephan Bosch Date: Sat, 22 Feb 2020 13:49:31 +0000 (+0100) Subject: lib-json: json-generator - Add support for formatted JSON output X-Git-Tag: 2.4.0~2376 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=308caf2994a5e98c332bce75bebfaf44ff88d261;p=thirdparty%2Fdovecot%2Fcore.git lib-json: json-generator - Add support for formatted JSON output --- diff --git a/src/lib-json/json-generator.c b/src/lib-json/json-generator.c index 225574ddd6..93c8c8480f 100644 --- a/src/lib-json/json-generator.c +++ b/src/lib-json/json-generator.c @@ -28,6 +28,15 @@ enum json_generator_state { JSON_GENERATOR_STATE_END, }; +enum json_format_state { + JSON_FORMAT_STATE_NONE = 0, + JSON_FORMAT_STATE_INDENT, + JSON_FORMAT_STATE_SPACE, + JSON_FORMAT_STATE_CR, + JSON_FORMAT_STATE_LF, + JSON_FORMAT_STATE_DONE, +}; + struct json_generator_level { bool object:1; }; @@ -55,6 +64,12 @@ struct json_generator { /* Write state: stack position of written syntax levels */ unsigned int level_stack_written; + /* Formatting state */ + struct json_format format; + char *format_indent; + enum json_format_state format_state; + unsigned int indent_pos, indent_count; + /* Currently opened string output stream */ struct json_string_ostream *str_stream; /* Currently pending string input stream */ @@ -72,6 +87,8 @@ struct json_generator { bool text_stream:1; /* API state */ /* A json_string_ostream is running the generator */ bool streaming:1; + /* Finish writing formatting whitespace element */ + bool format_finish:1; }; static int json_generator_flush_string_input(struct json_generator *generator); @@ -129,9 +146,26 @@ void json_generator_deinit(struct json_generator **_generator) str_free(&generator->buf); } array_free(&generator->level_stack); + i_free(generator->format_indent); i_free(generator); } +void json_generator_set_format(struct json_generator *generator, + const struct json_format *format) +{ + i_assert(generator->state == JSON_GENERATOR_STATE_VALUE); + i_assert(generator->write_state == JSON_GENERATOR_STATE_VALUE); + generator->format = *format; + + i_free(generator->format_indent); + if (format->indent_chars > 0) { + generator->format_indent = i_malloc(format->indent_chars); + memset(generator->format_indent, + (format->indent_tab ? '\t' : ' '), + format->indent_chars); + } +} + static inline size_t json_generator_bytes_available(struct json_generator *generator) { @@ -252,6 +286,94 @@ static int json_generator_flush_buffer(struct json_generator *generator) return 1; } +static int json_generator_flush_format(struct json_generator *generator) +{ + int ret; + + for (;;) switch (generator->format_state) { + case JSON_FORMAT_STATE_NONE: + return 1; + case JSON_FORMAT_STATE_CR: + ret = json_generator_write_all(generator, "\r", 1); + if (ret <= 0) + return ret; + generator->format_state = JSON_FORMAT_STATE_LF; + /* fall through */ + case JSON_FORMAT_STATE_LF: + ret = json_generator_write_all(generator, "\n", 1); + if (ret <= 0) + return ret; + if (generator->format.indent_chars == 0) { + generator->format_state = JSON_FORMAT_STATE_DONE; + break; + } + generator->format_state = JSON_FORMAT_STATE_INDENT; + /* fall through */ + case JSON_FORMAT_STATE_INDENT: + i_assert(generator->format.indent_chars != 0); + while (generator->indent_pos < generator->indent_count) { + ret = json_generator_write_buffered( + generator, generator->format_indent, + generator->format.indent_chars, FALSE); + if (ret <= 0) + return -1; + generator->indent_pos++; + } + generator->format_state = JSON_FORMAT_STATE_DONE; + break; + case JSON_FORMAT_STATE_SPACE: + ret = json_generator_write_all(generator, " ", 1); + if (ret <= 0) + return ret; + generator->format_state = JSON_FORMAT_STATE_DONE; + break; + case JSON_FORMAT_STATE_DONE: + if (!generator->format_finish) + return 1; + generator->format_state = JSON_FORMAT_STATE_NONE; + break; + } + i_unreached(); +} + +static int +json_generator_write_newline(struct json_generator *generator, + unsigned int indent_count, bool finish) +{ + if (generator->format_state == JSON_FORMAT_STATE_DONE) + return 1; + i_assert(generator->format_state == JSON_FORMAT_STATE_NONE); + if (!generator->format.new_line) + return 1; + if (generator->format.crlf) + generator->format_state = JSON_FORMAT_STATE_CR; + else + generator->format_state = JSON_FORMAT_STATE_LF; + generator->indent_pos = 0; + generator->indent_count = indent_count; + generator->format_finish = finish; + return json_generator_flush_format(generator); +} + +static int +json_generator_write_space(struct json_generator *generator, + bool finish) +{ + if (generator->format_state == JSON_FORMAT_STATE_DONE) + return 1; + i_assert(generator->format_state == JSON_FORMAT_STATE_NONE); + if (!generator->format.whitespace) + return 1; + generator->format_state = JSON_FORMAT_STATE_SPACE; + generator->format_finish = finish; + return json_generator_flush_format(generator); +} + +static void json_generator_finish_format(struct json_generator *generator) +{ + generator->format_state = JSON_FORMAT_STATE_NONE; +} + int json_generator_flush(struct json_generator *generator) { bool hide_root = HAS_ALL_BITS(generator->flags, @@ -260,6 +382,10 @@ int json_generator_flush(struct json_generator *generator) /* Flush buffer */ ret = json_generator_flush_buffer(generator); + if (ret <= 0) + return ret; + /* Flush formatting whitespace */ + ret = json_generator_flush_format(generator); if (ret <= 0) return ret; /* Flush closing string */ @@ -276,6 +402,9 @@ int json_generator_flush(struct json_generator *generator) if (ret <= 0) return ret; generator->write_state = JSON_GENERATOR_STATE_VALUE; + ret = json_generator_write_space(generator, TRUE); + if (ret <= 0) + return ret; } /* Flush opening objects/arrays */ for (;;) { @@ -296,6 +425,11 @@ int json_generator_flush(struct json_generator *generator) if (ret <= 0) return ret; generator->write_state = JSON_GENERATOR_STATE_VALUE; + ret = json_generator_write_newline( + generator, generator->level_stack_written, + TRUE); + if (ret <= 0) + return ret; } // FIXME: add indent @@ -321,6 +455,10 @@ int json_generator_flush(struct json_generator *generator) generator->object_level_written = FALSE; generator->write_state = JSON_GENERATOR_STATE_VALUE; } + ret = json_generator_write_newline( + generator, generator->level_stack_written, TRUE); + if (ret <= 0) + return ret; } /* Flush separator */ switch (generator->write_state) { @@ -328,6 +466,11 @@ int json_generator_flush(struct json_generator *generator) case JSON_GENERATOR_STATE_VALUE_END: if (generator->level_stack_pos == 0) { generator->write_state = JSON_GENERATOR_STATE_END; + ret = json_generator_write_newline( + generator, generator->level_stack_written, + TRUE); + if (ret <= 0) + return ret; break; } if (generator->state != JSON_GENERATOR_STATE_STRING && @@ -345,6 +488,10 @@ int json_generator_flush(struct json_generator *generator) } else { generator->write_state = JSON_GENERATOR_STATE_VALUE; } + ret = json_generator_write_newline( + generator, generator->level_stack_written, TRUE); + if (ret <= 0) + return ret; break; /* Flush colon */ case JSON_GENERATOR_STATE_OBJECT_VALUE: @@ -352,6 +499,9 @@ int json_generator_flush(struct json_generator *generator) if (ret <= 0) return ret; generator->write_state = JSON_GENERATOR_STATE_VALUE; + ret = json_generator_write_space(generator, TRUE); + if (ret <= 0) + return ret; break; default: break; @@ -858,6 +1008,10 @@ int json_generate_array_close(struct json_generator *generator) generator->write_state == JSON_GENERATOR_STATE_VALUE_END); i_assert(generator->level_stack_written > 0); + ret = json_generator_write_newline( + generator, generator->level_stack_written - 1, FALSE); + if (ret <= 0) + return ret; if (!hide_root || generator->level_stack_written > 1) { ret = json_generator_write_all(generator, "]", 1); if (ret <= 0) @@ -865,6 +1019,7 @@ int json_generate_array_close(struct json_generator *generator) } json_generator_level_close(generator, FALSE); json_generator_value_end(generator); + json_generator_finish_format(generator); return 1; } @@ -920,6 +1075,10 @@ int json_generate_object_close(struct json_generator *generator) i_assert(generator->write_state == JSON_GENERATOR_STATE_OBJECT_MEMBER || generator->write_state == JSON_GENERATOR_STATE_VALUE_END); i_assert(generator->level_stack_written > 0); + ret = json_generator_write_newline( + generator, generator->level_stack_written - 1, FALSE); + if (ret <= 0) + return ret; if (!hide_root || generator->level_stack_written > 1) { ret = json_generator_write_all(generator, "}", 1); if (ret <= 0) @@ -927,6 +1086,7 @@ int json_generate_object_close(struct json_generator *generator) } json_generator_level_close(generator, TRUE); json_generator_value_end(generator); + json_generator_finish_format(generator); return 1; } diff --git a/src/lib-json/json-generator.h b/src/lib-json/json-generator.h index d8a70864a2..7a833d99d6 100644 --- a/src/lib-json/json-generator.h +++ b/src/lib-json/json-generator.h @@ -25,6 +25,9 @@ json_generator_init_str(string_t *buf, enum json_generator_flags flags); void json_generator_deinit(struct json_generator **_generator); +void json_generator_set_format(struct json_generator *generator, + const struct json_format *format); + int json_generator_flush(struct json_generator *generator); /* number */ diff --git a/src/lib-json/json-ostream.c b/src/lib-json/json-ostream.c index 777073c39b..5658e05b9d 100644 --- a/src/lib-json/json-ostream.c +++ b/src/lib-json/json-ostream.c @@ -166,6 +166,12 @@ bool json_ostream_is_closed(struct json_ostream *stream) return stream->closed; } +void json_ostream_set_format(struct json_ostream *stream, + const struct json_format *format) +{ + json_generator_set_format(stream->generator, format); +} + void json_ostream_cork(struct json_ostream *stream) { if (stream->output != NULL) diff --git a/src/lib-json/json-ostream.h b/src/lib-json/json-ostream.h index bc0d5baf4b..da9d48df18 100644 --- a/src/lib-json/json-ostream.h +++ b/src/lib-json/json-ostream.h @@ -27,6 +27,9 @@ void json_ostream_destroy(struct json_ostream **_stream); void json_ostream_close(struct json_ostream *stream); bool json_ostream_is_closed(struct json_ostream *stream) ATTR_PURE; +void json_ostream_set_format(struct json_ostream *stream, + const struct json_format *format); + /* * Position */ diff --git a/src/lib-json/json-tree-io.c b/src/lib-json/json-tree-io.c index 00a3f356e6..3c80f7fd7c 100644 --- a/src/lib-json/json-tree-io.c +++ b/src/lib-json/json-tree-io.c @@ -59,22 +59,27 @@ int json_tree_read_cstr(const char *str, enum json_parser_flags parser_flags, */ void json_tree_write_buffer(const struct json_tree *jtree, buffer_t *buf, - enum json_generator_flags gen_flags) + enum json_generator_flags gen_flags, + const struct json_format *format) + { struct json_ostream *joutput; joutput = json_ostream_create_str(buf, gen_flags); + if (format != NULL) + json_ostream_set_format(joutput, format); json_ostream_nwrite_tree(joutput, NULL, jtree); json_ostream_nfinish_destroy(&joutput); } const char * json_tree_to_text(const struct json_tree *jtree, - enum json_generator_flags gen_flags) + enum json_generator_flags gen_flags, + const struct json_format *format) { string_t *str = t_str_new(1024); - json_tree_write_buffer(jtree, str, gen_flags); + json_tree_write_buffer(jtree, str, gen_flags, format); return str_c(str); } @@ -82,6 +87,6 @@ const char *json_tree_to_text_line(const struct json_tree *jtree) { string_t *str = t_str_new(1024); - json_tree_write_buffer(jtree, str, 0); + json_tree_write_buffer(jtree, str, 0, NULL); return str_c(str); } diff --git a/src/lib-json/json-tree-io.h b/src/lib-json/json-tree-io.h index a51577adde..dad89915f5 100644 --- a/src/lib-json/json-tree-io.h +++ b/src/lib-json/json-tree-io.h @@ -24,10 +24,13 @@ int json_tree_read_cstr(const char *str, enum json_parser_flags parser_flags, */ void json_tree_write_buffer(const struct json_tree *jtree, buffer_t *buf, - enum json_generator_flags gen_flags); + enum json_generator_flags gen_flags, + const struct json_format *format); + const char * json_tree_to_text(const struct json_tree *jtree, - enum json_generator_flags gen_flags); + enum json_generator_flags gen_flags, + const struct json_format *format); const char *json_tree_to_text_line(const struct json_tree *jtree); #endif diff --git a/src/lib-json/json-types.h b/src/lib-json/json-types.h index 454eb871c9..e4c4fd2ce3 100644 --- a/src/lib-json/json-types.h +++ b/src/lib-json/json-types.h @@ -571,4 +571,22 @@ struct json_limits { unsigned int max_list_items; }; +/* + * Format + */ + +struct json_format { + /* Number of indent characters (either TAB or SPACE) */ + unsigned int indent_chars; + + /* Indent character is TAB instead of SPACE */ + bool indent_tab:1; + /* Insert whitespace at appropriate places around separators */ + bool whitespace:1; + /* Insert newlines */ + bool new_line:1; + /* Newlines are CRLF rather than the default LF */ + bool crlf:1; +}; + #endif diff --git a/src/lib-json/test-json-generator.c b/src/lib-json/test-json-generator.c index fa2418df54..83f901140f 100644 --- a/src/lib-json/test-json-generator.c +++ b/src/lib-json/test-json-generator.c @@ -2157,6 +2157,389 @@ static void test_json_generate_stream(void) str_free(&buffer); } +static void test_json_generate_formatted(void) +{ + string_t *buffer; + struct ostream *output; + struct json_format format; + struct json_generator *generator; + unsigned int state, pos; + int ret; + + i_zero(&format); + format.indent_chars = 2; + format.indent_tab = FALSE; + format.whitespace = TRUE; + format.new_line = TRUE; + + buffer = str_new(default_pool, 256); + output = o_stream_create_buffer(buffer); + o_stream_set_no_error_handling(output, TRUE); + + /* value */ + test_begin("json format value"); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + ret = json_generate_number(generator, 23423); + test_assert(ret > 0); + json_generator_flush(generator); + test_assert(ret > 0); + json_generator_deinit(&generator); + test_assert(strcmp("23423\n", str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + /* [ value ] */ + test_begin("json format array - [ string ]"); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + json_generate_array_open(generator); + ret = json_generate_string(generator, "frop"); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + json_generator_flush(generator); + test_assert(ret > 0); + json_generator_deinit(&generator); + test_assert(strcmp("[\n" + " \"frop\"\n" + "]\n", str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + /* [ true, true, true ] */ + test_begin("json format array - [ true, true, true ]"); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + json_generate_array_open(generator); + ret = json_generate_true(generator); + test_assert(ret > 0); + ret = json_generate_true(generator); + test_assert(ret > 0); + ret = json_generate_true(generator); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + json_generator_flush(generator); + test_assert(ret > 0); + json_generator_deinit(&generator); + test_assert(strcmp("[\n" + " true,\n" + " true,\n" + " true\n" + "]\n", + str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + /* [ "frop", "friep", "frml" ] */ + test_begin("json format array - [ \"frop\", \"friep\", \"frml\" ]"); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + json_generate_array_open(generator); + ret = json_generate_string(generator, "frop"); + test_assert(ret > 0); + ret = json_generate_string(generator, "friep"); + test_assert(ret > 0); + ret = json_generate_string(generator, "frml"); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + json_generator_flush(generator); + test_assert(ret > 0); + json_generator_deinit(&generator); + test_assert(strcmp("[\n" + " \"frop\",\n" + " \"friep\",\n" + " \"frml\"\n" + "]\n", + str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + /* { "a": [{"d": 1}], "b": [{"e": 2}], "c": [{"f": 3}] } */ + test_begin("json format object - " + "{ \"a\": [{\"d\": 1}], \"b\": [{\"e\": 2}], " + "\"c\": [{\"f\": 3}] }"); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + json_generate_object_open(generator); + ret = json_generate_object_member(generator, "a"); + test_assert(ret > 0); + json_generate_array_open(generator); + json_generate_object_open(generator); + ret = json_generate_object_member(generator, "d"); + test_assert(ret > 0); + ret = json_generate_number(generator, 1); + ret = json_generate_object_close(generator); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + ret = json_generate_object_member(generator, "b"); + test_assert(ret > 0); + json_generate_array_open(generator); + json_generate_object_open(generator); + ret = json_generate_object_member(generator, "e"); + test_assert(ret > 0); + ret = json_generate_number(generator, 2); + ret = json_generate_object_close(generator); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + ret = json_generate_object_member(generator, "c"); + test_assert(ret > 0); + json_generate_array_open(generator); + json_generate_object_open(generator); + ret = json_generate_object_member(generator, "f"); + test_assert(ret > 0); + ret = json_generate_number(generator, 3); + ret = json_generate_object_close(generator); + test_assert(ret > 0); + ret = json_generate_array_close(generator); + test_assert(ret > 0); + ret = json_generate_object_close(generator); + test_assert(ret > 0); + json_generator_flush(generator); + test_assert(ret > 0); + json_generator_deinit(&generator); + test_assert(strcmp("{\n" + " \"a\": [\n" + " {\n" + " \"d\": 1\n" + " }\n" + " ],\n" + " \"b\": [\n" + " {\n" + " \"e\": 2\n" + " }\n" + " ],\n" + " \"c\": [\n" + " {\n" + " \"f\": 3\n" + " }\n" + " ]\n" + "}\n", str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + /* trickle */ + test_begin("json format object - trickle"); + o_stream_set_max_buffer_size(output, 0); + generator = json_generator_init(output, 0); + json_generator_set_format(generator, &format); + json_generate_object_open(generator); + state = 0; + for (pos = 0; pos < 65535 && state <= 25; pos++) { + o_stream_set_max_buffer_size(output, pos); + switch (state) { + case 0: + ret = json_generate_object_member(generator, "aaaaaa"); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_array_open(generator); + json_generate_object_open(generator); + state++; + continue; + case 1: + ret = json_generate_object_member(generator, "dddddd"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 2: + ret = json_generate_number(generator, 1); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 3: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_object_open(generator); + state++; + continue; + case 4: + ret = json_generate_object_member(generator, "gggggg"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 5: + ret = json_generate_number(generator, 4); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 6: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 7: + ret = json_generate_array_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 8: + ret = json_generate_object_member(generator, "bbbbbb"); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_array_open(generator); + json_generate_object_open(generator); + state++; + continue; + case 9: + ret = json_generate_object_member(generator, "eeeeee"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 10: + ret = json_generate_number(generator, 2); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 11: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_object_open(generator); + state++; + continue; + case 12: + ret = json_generate_object_member(generator, "hhhhhh"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 13: + ret = json_generate_number(generator, 5); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 14: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 15: + ret = json_generate_array_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 16: + ret = json_generate_object_member(generator, "cccccc"); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_array_open(generator); + json_generate_object_open(generator); + state++; + continue; + case 17: + ret = json_generate_object_member(generator, "ffffff"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 18: + ret = json_generate_number(generator, 3); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 19: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + json_generate_object_open(generator); + state++; + continue; + case 20: + ret = json_generate_object_member(generator, "iiiiii"); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 21: + ret = json_generate_number(generator, 6); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 22: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 23: + ret = json_generate_array_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 24: + ret = json_generate_object_close(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + case 25: + ret = json_generator_flush(generator); + test_assert(ret >= 0); + if (ret == 0) break; + state++; + continue; + } + } + json_generator_deinit(&generator); + test_assert(state == 26); + test_assert(strcmp("{\n" + " \"aaaaaa\": [\n" + " {\n" + " \"dddddd\": 1\n" + " },\n" + " {\n" + " \"gggggg\": 4\n" + " }\n" + " ],\n" + " \"bbbbbb\": [\n" + " {\n" + " \"eeeeee\": 2\n" + " },\n" + " {\n" + " \"hhhhhh\": 5\n" + " }\n" + " ],\n" + " \"cccccc\": [\n" + " {\n" + " \"ffffff\": 3\n" + " },\n" + " {\n" + " \"iiiiii\": 6\n" + " }\n" + " ]\n" + "}\n", str_c(buffer)) == 0); + test_end(); + str_truncate(buffer, 0); + output->offset = 0; + + o_stream_destroy(&output); + str_free(&buffer); +} + static void test_json_append_escaped(void) { string_t *str = t_str_new(32); @@ -2194,6 +2577,7 @@ int main(int argc, char *argv[]) static void (*test_functions[])(void) = { test_json_generate_buffer, test_json_generate_stream, + test_json_generate_formatted, test_json_append_escaped, test_json_append_escaped_data, NULL diff --git a/src/lib-json/test-json-io.c b/src/lib-json/test-json-io.c index 0813e4caea..ccbefc94e9 100644 --- a/src/lib-json/test-json-io.c +++ b/src/lib-json/test-json-io.c @@ -1145,12 +1145,12 @@ test_json_async_io_run(const struct json_io_test *test, unsigned int scenario) output = o_stream_create_buffer(outbuf); switch (scenario) { - case 0: case 2: + case 0: case 2: case 4: case 6: pipe1_input = i_stream_create_fd_autoclose(&fd_pipe1[0], 16); pipe2_input = i_stream_create_fd_autoclose(&fd_pipe2[0], 32); pipe3_input = i_stream_create_fd_autoclose(&fd_pipe3[0], 64); break; - case 1: case 3: + case 1: case 3: case 5: case 7: pipe1_input = i_stream_create_fd_autoclose(&fd_pipe1[0], 128); pipe2_input = i_stream_create_fd_autoclose(&fd_pipe2[0], 64); pipe3_input = i_stream_create_fd_autoclose(&fd_pipe3[0], 32); @@ -1160,12 +1160,12 @@ test_json_async_io_run(const struct json_io_test *test, unsigned int scenario) } switch (scenario) { - case 0: case 1: + case 0: case 1: case 4: case 5: pipe1_output = o_stream_create_fd_autoclose(&fd_pipe1[1], 32); pipe2_output = o_stream_create_fd_autoclose(&fd_pipe2[1], 64); pipe3_output = o_stream_create_fd_autoclose(&fd_pipe3[1], 128); break; - case 2: case 3: + case 2: case 3: case 6: case 7: pipe1_output = o_stream_create_fd_autoclose(&fd_pipe1[1], 64); pipe2_output = o_stream_create_fd_autoclose(&fd_pipe2[1], 32); pipe3_output = o_stream_create_fd_autoclose(&fd_pipe3[1], 16); @@ -1204,6 +1204,22 @@ test_json_async_io_run(const struct json_io_test *test, unsigned int scenario) tproc2.io = io_add_istream(tproc2.input, test_json_async_io_input_callback, &tproc2); + struct json_format json_format; + + switch (scenario) { + case 0: case 1: case 2: case 3: + break; + case 4: case 5: case 6: case 7: + i_zero(&json_format); + json_format.indent_chars = 2; + json_format.new_line = TRUE; + json_format.whitespace = TRUE; + json_generator_set_format(tproc1.generator, &json_format); + break; + default: + i_unreached(); + } + struct timeout *to = timeout_add(5000, io_loop_stop, ioloop); iostream_pump_start(tctx.pump_in); @@ -1244,7 +1260,7 @@ static void test_json_io_async(void) for (i = 0; i < tests_count; i++) T_BEGIN { test_begin(t_strdup_printf("json io async [%d]", i)); - for (sc = 0; sc < 4; sc++) + for (sc = 0; sc < 8; sc++) test_json_async_io_run(&tests[i], sc); test_end(); @@ -1567,12 +1583,12 @@ test_json_stream_io_async_run(const struct json_io_test *test, output = o_stream_create_buffer(outbuf); switch (scenario) { - case 0: case 2: + case 0: case 2: case 4: case 6: pipe1_input = i_stream_create_fd_autoclose(&fd_pipe1[0], 16); pipe2_input = i_stream_create_fd_autoclose(&fd_pipe2[0], 32); pipe3_input = i_stream_create_fd_autoclose(&fd_pipe3[0], 64); break; - case 1: case 3: + case 1: case 3: case 5: case 7: pipe1_input = i_stream_create_fd_autoclose(&fd_pipe1[0], 128); pipe2_input = i_stream_create_fd_autoclose(&fd_pipe2[0], 64); pipe3_input = i_stream_create_fd_autoclose(&fd_pipe3[0], 32); @@ -1582,12 +1598,12 @@ test_json_stream_io_async_run(const struct json_io_test *test, } switch (scenario) { - case 0: case 1: + case 0: case 1: case 4: case 5: pipe1_output = o_stream_create_fd_autoclose(&fd_pipe1[1], 32); pipe2_output = o_stream_create_fd_autoclose(&fd_pipe2[1], 64); pipe3_output = o_stream_create_fd_autoclose(&fd_pipe3[1], 128); break; - case 2: case 3: + case 2: case 3: case 6: case 7: pipe1_output = o_stream_create_fd_autoclose(&fd_pipe1[1], 64); pipe2_output = o_stream_create_fd_autoclose(&fd_pipe2[1], 32); pipe3_output = o_stream_create_fd_autoclose(&fd_pipe3[1], 16); @@ -1614,6 +1630,22 @@ test_json_stream_io_async_run(const struct json_io_test *test, tproc2.tctx = &tctx; tproc2.name = "proc_b"; + struct json_format json_format; + + switch (scenario) { + case 0: case 1: case 2: case 3: + break; + case 4: case 5: case 6: case 7: + i_zero(&json_format); + json_format.indent_chars = 2; + json_format.new_line = TRUE; + json_format.whitespace = TRUE; + json_ostream_set_format(tproc1.joutput, &json_format); + break; + default: + i_unreached(); + } + struct timeout *to = timeout_add(5000, io_loop_stop, ioloop); iostream_pump_start(tctx.pump_in); @@ -1654,7 +1686,7 @@ static void test_json_stream_io_async(void) for (i = 0; i < tests_count; i++) T_BEGIN { test_begin(t_strdup_printf("json stream io async [%d]", i)); - for (sc = 0; sc < 4; sc++) + for (sc = 0; sc < 8; sc++) test_json_stream_io_async_run(&tests[i], sc); test_end(); } T_END; diff --git a/src/lib-json/test-json-tree-io.c b/src/lib-json/test-json-tree-io.c index 0b988a8d55..28fa1c1669 100644 --- a/src/lib-json/test-json-tree-io.c +++ b/src/lib-json/test-json-tree-io.c @@ -276,7 +276,7 @@ static void test_json_tree_io(void) test_out_reason_quiet("input ok", ret >= 0, error); if (jtree != NULL) - json_tree_write_buffer(jtree, outbuf, 0); + json_tree_write_buffer(jtree, outbuf, 0, NULL); test_out_quiet("io match", strcmp(text_out, str_c(outbuf)) == 0);