All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: armbru@redhat.com, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PATCH v6 12/15] qapi: Support pretty printing in JSON output visitor
Date: Mon, 10 Oct 2016 08:23:54 -0500	[thread overview]
Message-ID: <1476105837-9861-13-git-send-email-eblake@redhat.com> (raw)
In-Reply-To: <1476105837-9861-1-git-send-email-eblake@redhat.com>

Add pretty printing, where the format intentionally matches that of
qobject_to_json() (a later patch will then rework qobject-json.c to
work on top of the JSON visitor).  The trickiest part is probably
that the testsuite now has to honor parameterization on whether
pretty printing is enabled.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: tweak commit message, use of 'bool pretty' in testsuite
[no v5 due to series split]
v4: rebase to earlier changes, defer type_any() to later
v3: rebase to earlier changes
v2: rebase to earlier changes
---
 include/qapi/json-output-visitor.h |   5 +-
 qapi/json-output-visitor.c         |  15 ++++-
 tests/test-json-output-visitor.c   | 124 +++++++++++++++++++++++++------------
 3 files changed, 101 insertions(+), 43 deletions(-)

diff --git a/include/qapi/json-output-visitor.h b/include/qapi/json-output-visitor.h
index 41c79f4..94c9e0f 100644
--- a/include/qapi/json-output-visitor.h
+++ b/include/qapi/json-output-visitor.h
@@ -21,8 +21,11 @@ typedef struct JsonOutputVisitor JsonOutputVisitor;
  * If everything else succeeds, pass @result to visit_complete() to
  * collect the result of the visit.
  *
+ * If @pretty, make the output legible with newlines and indentation;
+ * otherwise the output uses a single line.
+ *
  * For now, this cannot be used to visit the 'any' type.
  */
-Visitor *json_output_visitor_new(char **result);
+Visitor *json_output_visitor_new(bool pretty, char **result);

 #endif
diff --git a/qapi/json-output-visitor.c b/qapi/json-output-visitor.c
index 805154a..7d12879 100644
--- a/qapi/json-output-visitor.c
+++ b/qapi/json-output-visitor.c
@@ -17,6 +17,7 @@
 struct JsonOutputVisitor {
     Visitor visitor;
     QString *str;
+    bool pretty;
     bool comma;
     unsigned int depth;
     char **result;
@@ -30,10 +31,13 @@ static JsonOutputVisitor *to_jov(Visitor *v)
 static void json_output_name(JsonOutputVisitor *jov, const char *name)
 {
     if (jov->comma) {
-        qstring_append(jov->str, ", ");
+        qstring_append(jov->str, jov->pretty ? "," : ", ");
     } else {
         jov->comma = true;
     }
+    if (jov->pretty && jov->depth) {
+        qstring_append_printf(jov->str, "\n%*s", 4 * jov->depth, "");
+    }
     if (name && jov->depth) {
         qstring_append_json_string(jov->str, name);
         qstring_append(jov->str, ": ");
@@ -57,6 +61,9 @@ static void json_output_end_struct(Visitor *v, void **obj)

     assert(jov->depth);
     jov->depth--;
+    if (jov->pretty) {
+        qstring_append_printf(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, void **obj)

     assert(jov->depth);
     jov->depth--;
+    if (jov->pretty) {
+        qstring_append_printf(jov->str, "\n%*s", 4 * jov->depth, "");
+    }
     qstring_append(jov->str, "]");
     jov->comma = true;
 }
@@ -165,11 +175,12 @@ static void json_output_free(Visitor *v)
     g_free(jov);
 }

-Visitor *json_output_visitor_new(char **result)
+Visitor *json_output_visitor_new(bool pretty, char **result)
 {
     JsonOutputVisitor *v;

     v = g_malloc0(sizeof(*v));
+    v->pretty = pretty;
     v->result = result;
     *result = NULL;
     v->str = qstring_new();
diff --git a/tests/test-json-output-visitor.c b/tests/test-json-output-visitor.c
index 3c77a61..849cf2b 100644
--- a/tests/test-json-output-visitor.c
+++ b/tests/test-json-output-visitor.c
@@ -24,13 +24,17 @@

 typedef struct TestOutputVisitorData {
     Visitor *ov;
+    bool pretty;
     char *str;
 } TestOutputVisitorData;

 static void visitor_output_setup(TestOutputVisitorData *data,
-                                 const void *unused)
+                                 const void *arg)
 {
-    data->ov = json_output_visitor_new(&data->str);
+    bool pretty = *(bool *)arg;
+
+    data->pretty = pretty;
+    data->ov = json_output_visitor_new(pretty, &data->str);
     g_assert(data->ov);
 }

@@ -52,8 +56,10 @@ static const char *visitor_get(TestOutputVisitorData *data)

 static void visitor_reset(TestOutputVisitorData *data)
 {
+    bool pretty = data->pretty;
+
     visitor_output_teardown(data, NULL);
-    visitor_output_setup(data, NULL);
+    visitor_output_setup(data, &pretty);
 }

 static void test_visitor_out_int(TestOutputVisitorData *data,
@@ -161,8 +167,9 @@ static void test_visitor_out_struct(TestOutputVisitorData *data,
 }

 static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
-                                           const void *unused)
+                                           const void *arg)
 {
+    bool pretty = *(bool *)arg;
     int64_t value = 42;
     UserDefTwo *ud2;
     const char *string = "user def string";
@@ -192,27 +199,51 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
     visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort);

     out = visitor_get(data);
-    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);
 }

@@ -346,36 +377,49 @@ static void test_visitor_out_null(TestOutputVisitorData *data,
     g_assert_cmpstr(out, ==, "null");
 }

-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/union-flat",
+    output_visitor_test_add("/visitor/json/list", &plain,
+                            test_visitor_out_list);
+    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/null", test_visitor_out_null);
+    output_visitor_test_add("/visitor/json/null", &plain,
+                            test_visitor_out_null);

     g_test_run();

-- 
2.7.4

  parent reply	other threads:[~2016-10-10 13:24 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-10 13:23 [Qemu-devel] [PATCH v6 00/15] Add qapi-to-JSON visitor Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 01/15] qapi: Visitor documentation tweak Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 02/15] qapi: Assert finite use of 'number' Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 03/15] qapi: Factor out JSON string escaping Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 04/15] qapi: Factor out JSON number formatting Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 05/15] qapi: Add qstring_append_printf() Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 06/15] qapi: Use qstring_append_chr() where appropriate Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 07/15] qstring: Add qstring_consume_str() Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 08/15] qstring: Add qstring_wrap_str() Eric Blake
2016-10-11 11:08   ` Marc-André Lureau
2016-10-11 15:04     ` Eric Blake
2016-10-11 15:05       ` Eric Blake
2016-10-11 15:25         ` Marc-André Lureau
2016-10-11 15:24   ` [Qemu-devel] [PATCH v6 08.5/15] fixup! " Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 09/15] qobject: Consolidate qobject_to_json() calls Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 10/15] tests: Test qobject_to_json() pretty formatting Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 11/15] qapi: Add JSON output visitor Eric Blake
2016-10-10 13:23 ` Eric Blake [this message]
2016-10-11 11:20   ` [Qemu-devel] [PATCH v6 12/15] qapi: Support pretty printing in " Marc-André Lureau
2016-10-11 15:09     ` Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 13/15] qobject: Implement qobject_to_json() atop JSON visitor Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 14/15] qapi: Add 'any' support to JSON output Eric Blake
2016-10-10 13:23 ` [Qemu-devel] [PATCH v6 15/15] qemu-img: Use new JSON output formatter Eric Blake
2016-10-11 12:14 ` [Qemu-devel] [PATCH v6 00/15] Add qapi-to-JSON visitor Marc-André Lureau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1476105837-9861-13-git-send-email-eblake@redhat.com \
    --to=eblake@redhat.com \
    --cc=armbru@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.