From patchwork Thu Apr 28 21:45:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 616475 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qwrLT4K8Rz9t7n for ; Fri, 29 Apr 2016 07:58:25 +1000 (AEST) Received: from localhost ([::1]:51265 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avtx1-0002vr-QU for incoming@patchwork.ozlabs.org; Thu, 28 Apr 2016 17:58:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55084) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avtkl-0007ro-AM for qemu-devel@nongnu.org; Thu, 28 Apr 2016 17:45:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1avtkk-0000GT-1e for qemu-devel@nongnu.org; Thu, 28 Apr 2016 17:45:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48995) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avtkj-0000G6-RT for qemu-devel@nongnu.org; Thu, 28 Apr 2016 17:45:42 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 63C1478224; Thu, 28 Apr 2016 21:45:41 +0000 (UTC) Received: from red.redhat.com (ovpn-113-21.phx2.redhat.com [10.3.113.21]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u3SLjY8b019512; Thu, 28 Apr 2016 17:45:41 -0400 From: Eric Blake To: qemu-devel@nongnu.org Date: Thu, 28 Apr 2016 15:45:23 -0600 Message-Id: <1461879932-9020-16-git-send-email-eblake@redhat.com> In-Reply-To: <1461879932-9020-1-git-send-email-eblake@redhat.com> References: <1461879932-9020-1-git-send-email-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v16 15/24] qmp: Support explicit null during visits X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: armbru@redhat.com, Michael Roth Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Implement the new type_null() callback for the qmp input and output visitors. While we don't yet have a use for this in QAPI input (the generator will need some tweaks first), some potential usages have already been discussed on the list. Meanwhile, the output visitor could already output explicit null via type_any, but this gives us finer control. At any rate, it's easy to test that we can round-trip an explicit null through manual use of visit_type_null() wrapped by a virtual visit_start_struct() walk, even if we can't do the visit in a QAPI type. Repurpose the test_visitor_out_empty test, particularly since a future patch will tighten semantics to forbid use of qmp_output_get_qobject() without at least one intervening visit_type_*. Signed-off-by: Eric Blake --- v16: one more testsuite enhancement v15: hoist stubs to earlier patch, testsuite improvements v14: rebase to header inclusion cleanups v13: no change v12: retitle and merge in output visitor support, move refcount tests to separate file [no v10, v11] v9: new patch --- qapi/qmp-input-visitor.c | 8 +++++++- qapi/qmp-output-visitor.c | 3 ++- tests/check-qnull.c | 13 +++++++++++-- tests/test-qmp-input-visitor.c | 29 +++++++++++++++++++++++++++++ tests/test-qmp-output-visitor.c | 20 +++++++++++++++----- 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index fa460a3..30e7cb3 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -342,7 +342,13 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) { - abort(); + QmpInputVisitor *qiv = to_qiv(v); + QObject *qobj = qmp_input_get_object(qiv, name, true); + + if (qobject_type(qobj) != QTYPE_QNULL) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "null"); + } } static void qmp_input_optional(Visitor *v, const char *name, bool *present) diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index adf7731..5681ad3 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -198,7 +198,8 @@ static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) { - abort(); + QmpOutputVisitor *qov = to_qov(v); + qmp_output_add_obj(qov, name, qnull()); } /* Finish building, and return the root object. Will not be NULL. */ diff --git a/tests/check-qnull.c b/tests/check-qnull.c index 4a1c3d8..fd9c68f 100644 --- a/tests/check-qnull.c +++ b/tests/check-qnull.c @@ -11,7 +11,9 @@ #include "qapi/qmp/qobject.h" #include "qemu-common.h" +#include "qapi/qmp-input-visitor.h" #include "qapi/qmp-output-visitor.h" +#include "qapi/error.h" /* * Public Interface test-cases @@ -37,6 +39,7 @@ static void qnull_visit_test(void) { QObject *obj; QmpOutputVisitor *qov; + QmpInputVisitor *qiv; /* * Most tests of interactions between QObject and visitors are in @@ -45,13 +48,19 @@ static void qnull_visit_test(void) */ g_assert(qnull_.refcnt == 1); + obj = qnull(); + qiv = qmp_input_visitor_new(obj, true); + qobject_decref(obj); + visit_type_null(qmp_input_get_visitor(qiv), NULL, &error_abort); + qmp_input_visitor_cleanup(qiv); + qov = qmp_output_visitor_new(); - /* FIXME: Empty visits are ugly, we should have a visit_type_null(). */ + visit_type_null(qmp_output_get_visitor(qov), NULL, &error_abort); obj = qmp_output_get_qobject(qov); g_assert(obj == &qnull_); qobject_decref(obj); - qmp_output_visitor_cleanup(qov); + g_assert(qnull_.refcnt == 1); } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index c039806..10e00ec 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -279,6 +279,33 @@ static void test_visitor_in_any(TestInputVisitorData *data, qobject_decref(res); } +static void test_visitor_in_null(TestInputVisitorData *data, + const void *unused) +{ + Visitor *v; + Error *err = NULL; + char *tmp; + + /* + * FIXME: Since QAPI doesn't know the 'null' type yet, we can't + * test visit_type_null() by reading into a QAPI struct then + * checking that it was populated correctly. The best we can do + * for now is ensure that we consumed null from the input, proven + * by the fact that we can't re-read the key; and that we detect + * when input is not null. + */ + + v = visitor_input_test_init(data, "{ 'a': null, 'b': '' }"); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_null(v, "a", &error_abort); + visit_type_str(v, "a", &tmp, &err); + g_assert(!tmp); + error_free_or_abort(&err); + visit_type_null(v, "b", &err); + error_free_or_abort(&err); + visit_end_struct(v, &error_abort); +} + static void test_visitor_in_union_flat(TestInputVisitorData *data, const void *unused) { @@ -829,6 +856,8 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_list); input_visitor_test_add("/visitor/input/any", &in_visitor_data, test_visitor_in_any); + input_visitor_test_add("/visitor/input/null", + &in_visitor_data, test_visitor_in_null); input_visitor_test_add("/visitor/input/union-flat", &in_visitor_data, test_visitor_in_union_flat); input_visitor_test_add("/visitor/input/alternate", diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index fddb5a6..8acc229 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -477,13 +477,23 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, qobject_decref(arg); } -static void test_visitor_out_empty(TestOutputVisitorData *data, - const void *unused) +static void test_visitor_out_null(TestOutputVisitorData *data, + const void *unused) { QObject *arg; + QDict *qdict; + QObject *nil; + visit_start_struct(data->ov, NULL, NULL, 0, &error_abort); + visit_type_null(data->ov, "a", &error_abort); + visit_end_struct(data->ov, &error_abort); arg = qmp_output_get_qobject(data->qov); - g_assert(qobject_type(arg) == QTYPE_QNULL); + g_assert(qobject_type(arg) == QTYPE_QDICT); + qdict = qobject_to_qdict(arg); + g_assert_cmpint(qdict_size(qdict), ==, 1); + nil = qdict_get(qdict, "a"); + g_assert(nil); + g_assert(qobject_type(nil) == QTYPE_QNULL); qobject_decref(arg); } @@ -837,8 +847,8 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_union_flat); output_visitor_test_add("/visitor/output/alternate", &out_visitor_data, test_visitor_out_alternate); - output_visitor_test_add("/visitor/output/empty", - &out_visitor_data, test_visitor_out_empty); + output_visitor_test_add("/visitor/output/null", + &out_visitor_data, test_visitor_out_null); output_visitor_test_add("/visitor/output/native_list/int", &out_visitor_data, test_visitor_out_native_list_int);