From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59182) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a7B26-0005wh-CW for qemu-devel@nongnu.org; Thu, 10 Dec 2015 18:54:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1a7B24-0001tD-2F for qemu-devel@nongnu.org; Thu, 10 Dec 2015 18:53:58 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59091) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a7B23-0001t6-P9 for qemu-devel@nongnu.org; Thu, 10 Dec 2015 18:53:55 -0500 From: Eric Blake Date: Thu, 10 Dec 2015 16:53:40 -0700 Message-Id: <1449791621-16185-11-git-send-email-eblake@redhat.com> In-Reply-To: <1449791621-16185-1-git-send-email-eblake@redhat.com> References: <1449791621-16185-1-git-send-email-eblake@redhat.com> Subject: [Qemu-devel] [PATCH 10/11] qapi: Support pretty printing in JSON output visitor List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Markus Armbruster , Michael Roth Similar to pretty printing in the QObject visitor. Trickiest parts are the fact that during type_any(), we have to coordinate with QObject to also print pretty; and the fact that the testsuite now has to honor parameterization on whether pretty printing is enabled. Signed-off-by: Eric Blake --- include/qapi/json-output-visitor.h | 2 +- qapi/json-output-visitor.c | 25 +++++- qjson.c | 2 +- tests/test-json-output-visitor.c | 160 ++++++++++++++++++++++++++----------- 4 files changed, 136 insertions(+), 53 deletions(-) diff --git a/include/qapi/json-output-visitor.h b/include/qapi/json-output-visitor.h index 5be5a13..e5e16e6 100644 --- a/include/qapi/json-output-visitor.h +++ b/include/qapi/json-output-visitor.h @@ -15,7 +15,7 @@ typedef struct JsonOutputVisitor JsonOutputVisitor; -JsonOutputVisitor *json_output_visitor_new(void); +JsonOutputVisitor *json_output_visitor_new(bool pretty); void json_output_visitor_cleanup(JsonOutputVisitor *v); void json_output_visitor_reset(JsonOutputVisitor *v); diff --git a/qapi/json-output-visitor.c b/qapi/json-output-visitor.c index 0d759c4..a939af1 100644 --- a/qapi/json-output-visitor.c +++ b/qapi/json-output-visitor.c @@ -18,6 +18,7 @@ struct JsonOutputVisitor { Visitor visitor; QString *str; + bool pretty; bool comma; int depth; }; @@ -33,10 +34,13 @@ static void json_output_name(JsonOutputVisitor *jov, const char *name) jov->str = qstring_new(); } if (jov->comma) { - qstring_append(jov->str, ", "); + qstring_append(jov->str, jov->pretty ? "," : ", "); } else { jov->comma = true; } + if (jov->pretty && jov->depth) { + qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, ""); + } if (name && jov->depth) { qstring_append_json_string(jov->str, name); qstring_append(jov->str, ": "); @@ -59,6 +63,9 @@ static void json_output_end_struct(Visitor *v) JsonOutputVisitor *jov = to_jov(v); assert(jov->depth); jov->depth--; + if (jov->pretty) { + qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, ""); + } qstring_append(jov->str, "}"); jov->comma = true; } @@ -85,6 +92,9 @@ static void json_output_end_list(Visitor *v) JsonOutputVisitor *jov = to_jov(v); assert(jov->depth); jov->depth--; + if (jov->pretty) { + qstring_append_format(jov->str, "\n%*s", 4 * jov->depth, ""); + } qstring_append(jov->str, "]"); jov->comma = true; } @@ -134,7 +144,15 @@ static void json_output_type_any(Visitor *v, QObject **obj, const char *name, Error **errp) { JsonOutputVisitor *jov = to_jov(v); - QString *str = qobject_to_json(*obj); + QString *str; + + if (jov->pretty) { + char *prefix = g_strdup_printf("%*s", 4 * jov->depth, ""); + str = qobject_to_json_pretty_prefix(*obj, prefix); + g_free(prefix); + } else { + str = qobject_to_json(*obj); + } assert(str); json_output_name(jov, name); qstring_append(jov->str, qstring_get_str(str)); @@ -178,11 +196,12 @@ void json_output_visitor_cleanup(JsonOutputVisitor *v) g_free(v); } -JsonOutputVisitor *json_output_visitor_new(void) +JsonOutputVisitor *json_output_visitor_new(bool pretty) { JsonOutputVisitor *v; v = g_malloc0(sizeof(*v)); + v->pretty = pretty; v->visitor.start_struct = json_output_start_struct; v->visitor.end_struct = json_output_end_struct; diff --git a/qjson.c b/qjson.c index 6aac46d..9debf1d 100644 --- a/qjson.c +++ b/qjson.c @@ -84,7 +84,7 @@ void qjson_finish(QJSON *json) static void qjson_initfn(Object *obj) { QJSON *json = QJSON(obj); - json->jov = json_output_visitor_new(); + json->jov = json_output_visitor_new(false); } static void qjson_finalizefn(Object *obj) diff --git a/tests/test-json-output-visitor.c b/tests/test-json-output-visitor.c index e47571a..bfa21f7 100644 --- a/tests/test-json-output-visitor.c +++ b/tests/test-json-output-visitor.c @@ -21,9 +21,10 @@ typedef struct TestOutputVisitorData { } TestOutputVisitorData; static void visitor_output_setup(TestOutputVisitorData *data, - const void *unused) + const void *arg) { - data->jov = json_output_visitor_new(); + const bool *pretty = arg; + data->jov = json_output_visitor_new(*pretty); g_assert(data->jov); data->ov = json_output_get_visitor(data->jov); @@ -149,8 +150,9 @@ static void test_visitor_out_struct(TestOutputVisitorData *data, } static void test_visitor_out_struct_nested(TestOutputVisitorData *data, - const void *unused) + const void *arg) { + const bool *pretty = arg; int64_t value = 42; UserDefTwo *ud2; const char *string = "user def string"; @@ -180,27 +182,51 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, visit_type_UserDefTwo(data->ov, &ud2, "unused", &error_abort); out = json_output_get_string(data->jov); - g_assert_cmpstr(out, ==, - "{" - "\"string0\": \"forty two\", " - "\"dict1\": {" - "\"string1\": \"forty three\", " - "\"dict2\": {" - "\"userdef\": {" - "\"integer\": 42, " - "\"string\": \"user def string\"" - "}, " - "\"string\": \"forty four\"" - "}, " - "\"dict3\": {" - "\"userdef\": {" - "\"integer\": 42, " - "\"string\": \"user def string\"" - "}, " - "\"string\": \"forty five\"" - "}" - "}" - "}"); + if (*pretty) { + g_assert_cmpstr(out, ==, + "{\n" + " \"string0\": \"forty two\",\n" + " \"dict1\": {\n" + " \"string1\": \"forty three\",\n" + " \"dict2\": {\n" + " \"userdef\": {\n" + " \"integer\": 42,\n" + " \"string\": \"user def string\"\n" + " },\n" + " \"string\": \"forty four\"\n" + " },\n" + " \"dict3\": {\n" + " \"userdef\": {\n" + " \"integer\": 42,\n" + " \"string\": \"user def string\"\n" + " },\n" + " \"string\": \"forty five\"\n" + " }\n" + " }\n" + "}"); + } else { + g_assert_cmpstr(out, ==, + "{" + "\"string0\": \"forty two\", " + "\"dict1\": {" + "\"string1\": \"forty three\", " + "\"dict2\": {" + "\"userdef\": {" + "\"integer\": 42, " + "\"string\": \"user def string\"" + "}, " + "\"string\": \"forty four\"" + "}, " + "\"dict3\": {" + "\"userdef\": {" + "\"integer\": 42, " + "\"string\": \"user def string\"" + "}, " + "\"string\": \"forty five\"" + "}" + "}" + "}"); + } qapi_free_UserDefTwo(ud2); g_free(out); } @@ -279,16 +305,23 @@ static void test_visitor_out_list(TestOutputVisitorData *data, } static void test_visitor_out_any(TestOutputVisitorData *data, - const void *unused) + const void *arg) { + const bool *pretty = arg; QObject *qobj; QDict *qdict; char *out; qobj = QOBJECT(qint_from_int(-42)); + visit_start_list(data->ov, NULL, NULL, 0, &error_abort); visit_type_any(data->ov, &qobj, NULL, &error_abort); + visit_end_list(data->ov); out = json_output_get_string(data->jov); - g_assert_cmpstr(out, ==, "-42"); + if (*pretty) { + g_assert_cmpstr(out, ==, "[\n -42\n]"); + } else { + g_assert_cmpstr(out, ==, "[-42]"); + } qobject_decref(qobj); g_free(out); @@ -297,15 +330,30 @@ static void test_visitor_out_any(TestOutputVisitorData *data, qdict_put(qdict, "boolean", qbool_from_bool(true)); qdict_put(qdict, "string", qstring_from_str("foo")); qobj = QOBJECT(qdict); + visit_start_list(data->ov, NULL, NULL, 0, &error_abort); visit_type_any(data->ov, &qobj, NULL, &error_abort); + visit_end_list(data->ov); qobject_decref(qobj); out = json_output_get_string(data->jov); - g_assert_cmpstr(out, ==, - "{" - "\"integer\": -42, " - "\"boolean\": true, " - "\"string\": \"foo\"" - "}"); + if (*pretty) { + g_assert_cmpstr(out, ==, + "[\n" + " {\n" + " \"integer\": -42,\n" + " \"boolean\": true,\n" + " \"string\": \"foo\"\n" + " }\n" + "]"); + } else { + g_assert_cmpstr(out, ==, + "[" + "{" + "\"integer\": -42, " + "\"boolean\": true, " + "\"string\": \"foo\"" + "}" + "]"); + } g_free(out); } @@ -372,37 +420,53 @@ static void test_visitor_out_empty(TestOutputVisitorData *data, g_free(out); } -static void output_visitor_test_add(const char *testpath, +static void output_visitor_test_add(const char *testpath, bool *data, void (*test_func)(TestOutputVisitorData *, const void *)) { - g_test_add(testpath, TestOutputVisitorData, NULL, visitor_output_setup, + g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, test_func, visitor_output_teardown); } int main(int argc, char **argv) { + bool plain = false; + bool pretty = true; + g_test_init(&argc, &argv, NULL); - output_visitor_test_add("/visitor/json/int", test_visitor_out_int); - output_visitor_test_add("/visitor/json/bool", test_visitor_out_bool); - output_visitor_test_add("/visitor/json/number", test_visitor_out_number); - output_visitor_test_add("/visitor/json/string", test_visitor_out_string); - output_visitor_test_add("/visitor/json/enum", test_visitor_out_enum); - output_visitor_test_add("/visitor/json/enum-errors", + output_visitor_test_add("/visitor/json/int", &plain, + test_visitor_out_int); + output_visitor_test_add("/visitor/json/bool", &plain, + test_visitor_out_bool); + output_visitor_test_add("/visitor/json/number", &plain, + test_visitor_out_number); + output_visitor_test_add("/visitor/json/string", &plain, + test_visitor_out_string); + output_visitor_test_add("/visitor/json/enum", &plain, + test_visitor_out_enum); + output_visitor_test_add("/visitor/json/enum-errors", &plain, test_visitor_out_enum_errors); - output_visitor_test_add("/visitor/json/struct", test_visitor_out_struct); - output_visitor_test_add("/visitor/json/struct-nested", + output_visitor_test_add("/visitor/json/struct", &plain, + test_visitor_out_struct); + output_visitor_test_add("/visitor/json/struct-nested", &plain, test_visitor_out_struct_nested); - output_visitor_test_add("/visitor/json/struct-errors", + output_visitor_test_add("/visitor/json-pretty/struct-nested", &pretty, + test_visitor_out_struct_nested); + output_visitor_test_add("/visitor/json/struct-errors", &plain, test_visitor_out_struct_errors); - output_visitor_test_add("/visitor/json/list", test_visitor_out_list); - output_visitor_test_add("/visitor/json/any", test_visitor_out_any); - output_visitor_test_add("/visitor/json/union-flat", + output_visitor_test_add("/visitor/json/list", &plain, + test_visitor_out_list); + output_visitor_test_add("/visitor/json/any", &plain, + test_visitor_out_any); + output_visitor_test_add("/visitor/json-pretty/any", &pretty, + test_visitor_out_any); + output_visitor_test_add("/visitor/json/union-flat", &plain, test_visitor_out_union_flat); - output_visitor_test_add("/visitor/json/alternate", + output_visitor_test_add("/visitor/json/alternate", &plain, test_visitor_out_alternate); - output_visitor_test_add("/visitor/json/empty", test_visitor_out_empty); + output_visitor_test_add("/visitor/json/empty", &plain, + test_visitor_out_empty); g_test_run(); -- 2.4.3