[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 03/54] qobject: add literal qobject type
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH v2 03/54] qobject: add literal qobject type |
Date: |
Tue, 22 Aug 2017 15:22:04 +0200 |
Promote LiteralQObject from tests/check-qjson.c to qobject/qlit.c,
allowing to statically declare complex qobjects.
Signed-off-by: Marc-André Lureau <address@hidden>
---
include/qapi/qmp/qlit.h | 54 +++++++++++++++++
qobject/qlit.c | 106 ++++++++++++++++++++++++++++++++++
tests/check-qjson.c | 150 +++++++++---------------------------------------
tests/check-qlit.c | 68 ++++++++++++++++++++++
qobject/Makefile.objs | 2 +-
tests/Makefile.include | 5 +-
6 files changed, 261 insertions(+), 124 deletions(-)
create mode 100644 include/qapi/qmp/qlit.h
create mode 100644 qobject/qlit.c
create mode 100644 tests/check-qlit.c
diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
new file mode 100644
index 0000000000..2cdceb448d
--- /dev/null
+++ b/include/qapi/qmp/qlit.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright IBM, Corp. 2009
+ * Copyright (c) 2013, 2015, 2017 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ * Markus Armbruster <address@hidden>
+ * Marc-André Lureau <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QLIT_H_
+#define QLIT_H_
+
+#include "qapi-types.h"
+#include "qobject.h"
+
+typedef struct QLitDictEntry QLitDictEntry;
+typedef struct QLitObject QLitObject;
+
+struct QLitObject {
+ int type;
+ union {
+ bool qbool;
+ int64_t qnum;
+ const char *qstr;
+ QLitDictEntry *qdict;
+ QLitObject *qlist;
+ } value;
+};
+
+struct QLitDictEntry {
+ const char *key;
+ QLitObject value;
+};
+
+#define QLIT_QNULL \
+ { .type = QTYPE_QNULL }
+#define QLIT_QBOOL(val) \
+ { .type = QTYPE_QBOOL, .value.qbool = (val) }
+#define QLIT_QNUM(val) \
+ { .type = QTYPE_QNUM, .value.qnum = (val) }
+#define QLIT_QSTR(val) \
+ { .type = QTYPE_QSTRING, .value.qstr = (val) }
+#define QLIT_QDICT(val) \
+ { .type = QTYPE_QDICT, .value.qdict = (val) }
+#define QLIT_QLIST(val) \
+ { .type = QTYPE_QLIST, .value.qlist = (val) }
+
+bool qlit_equal_qobject(QLitObject *lhs, QObject *rhs);
+
+#endif /* QLIT_H_ */
diff --git a/qobject/qlit.c b/qobject/qlit.c
new file mode 100644
index 0000000000..f4ebeb6259
--- /dev/null
+++ b/qobject/qlit.c
@@ -0,0 +1,106 @@
+/*
+ * QLit literal qobject
+ *
+ * Copyright IBM, Corp. 2009
+ * Copyright (c) 2013, 2015, 2017 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ * Markus Armbruster <address@hidden>
+ * Marc-André Lureau <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/qmp/qlit.h"
+#include "qapi/qmp/types.h"
+
+typedef struct QListCompareHelper {
+ int index;
+ QLitObject *objs;
+ bool result;
+} QListCompareHelper;
+
+static void compare_helper(QObject *obj, void *opaque)
+{
+ QListCompareHelper *helper = opaque;
+
+ if (!helper->result) {
+ return;
+ }
+
+ if (helper->objs[helper->index].type == QTYPE_NONE) {
+ helper->result = false;
+ return;
+ }
+
+ helper->result =
+ qlit_equal_qobject(&helper->objs[helper->index++], obj);
+}
+
+bool qlit_equal_qobject(QLitObject *lhs, QObject *rhs)
+{
+ int64_t val;
+
+ if (!rhs || lhs->type != qobject_type(rhs)) {
+ return false;
+ }
+
+ switch (lhs->type) {
+ case QTYPE_QBOOL:
+ return lhs->value.qbool == qbool_get_bool(qobject_to_qbool(rhs));
+ case QTYPE_QNUM:
+ val = qnum_get_int(qobject_to_qnum(rhs));
+ return lhs->value.qnum == val;
+ case QTYPE_QSTRING:
+ return g_str_equal(lhs->value.qstr,
+ qstring_get_str(qobject_to_qstring(rhs)));
+ case QTYPE_QDICT: {
+ int i;
+
+ for (i = 0; lhs->value.qdict[i].key; i++) {
+ QObject *obj = qdict_get(qobject_to_qdict(rhs),
+ lhs->value.qdict[i].key);
+
+ if (!qlit_equal_qobject(&lhs->value.qdict[i].value, obj)) {
+ return false;
+ }
+ }
+
+ if (qdict_size(qobject_to_qdict(rhs)) != i) {
+ return false;
+ }
+
+ return true;
+ }
+ case QTYPE_QLIST: {
+ QListCompareHelper helper;
+ int i;
+
+ for (i = 0; lhs->value.qlist[i].type != QTYPE_NONE; i++) {
+ continue;
+ }
+
+ if (qlist_size(qobject_to_qlist(rhs)) != i) {
+ return false;
+ }
+
+ helper.index = 0;
+ helper.objs = lhs->value.qlist;
+ helper.result = true;
+
+ qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
+
+ return helper.result;
+ }
+ case QTYPE_QNULL:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index a3a97b0d99..59227934ce 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -16,6 +16,7 @@
#include "qapi/error.h"
#include "qapi/qmp/types.h"
#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qlit.h"
#include "qemu-common.h"
static void escaped_string(void)
@@ -1059,123 +1060,28 @@ static void keyword_literal(void)
QDECREF(null);
}
-typedef struct LiteralQDictEntry LiteralQDictEntry;
-typedef struct LiteralQObject LiteralQObject;
-
-struct LiteralQObject
-{
- int type;
- union {
- int64_t qnum;
- const char *qstr;
- LiteralQDictEntry *qdict;
- LiteralQObject *qlist;
- } value;
-};
-
-struct LiteralQDictEntry
-{
- const char *key;
- LiteralQObject value;
-};
-
-#define QLIT_QNUM(val) (LiteralQObject){.type = QTYPE_QNUM, .value.qnum =
(val)}
-#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr =
(val)}
-#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict =
(val)}
-#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist =
(val)}
-
-typedef struct QListCompareHelper
-{
- int index;
- LiteralQObject *objs;
- int result;
-} QListCompareHelper;
-
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
-
-static void compare_helper(QObject *obj, void *opaque)
-{
- QListCompareHelper *helper = opaque;
-
- if (helper->result == 0) {
- return;
- }
-
- if (helper->objs[helper->index].type == QTYPE_NONE) {
- helper->result = 0;
- return;
- }
-
- helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++],
obj);
-}
-
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
-{
- int64_t val;
-
- if (!rhs || lhs->type != qobject_type(rhs)) {
- return 0;
- }
-
- switch (lhs->type) {
- case QTYPE_QNUM:
- g_assert(qnum_get_try_int(qobject_to_qnum(rhs), &val));
- return lhs->value.qnum == val;
- case QTYPE_QSTRING:
- return (strcmp(lhs->value.qstr,
qstring_get_str(qobject_to_qstring(rhs))) == 0);
- case QTYPE_QDICT: {
- int i;
-
- for (i = 0; lhs->value.qdict[i].key; i++) {
- QObject *obj = qdict_get(qobject_to_qdict(rhs),
lhs->value.qdict[i].key);
-
- if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
- return 0;
- }
- }
-
- return 1;
- }
- case QTYPE_QLIST: {
- QListCompareHelper helper;
-
- helper.index = 0;
- helper.objs = lhs->value.qlist;
- helper.result = 1;
-
- qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
-
- return helper.result;
- }
- default:
- break;
- }
-
- return 0;
-}
-
static void simple_dict(void)
{
int i;
struct {
const char *encoded;
- LiteralQObject decoded;
+ QLitObject decoded;
} test_cases[] = {
{
.encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ .decoded = QLIT_QDICT(((QLitDictEntry[]){
{ "foo", QLIT_QNUM(42) },
{ "bar", QLIT_QSTR("hello world") },
{ }
})),
}, {
.encoded = "{}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ .decoded = QLIT_QDICT(((QLitDictEntry[]){
{ }
})),
}, {
.encoded = "{\"foo\": 43}",
- .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
+ .decoded = QLIT_QDICT(((QLitDictEntry[]){
{ "foo", QLIT_QNUM(43) },
{ }
})),
@@ -1188,13 +1094,13 @@ static void simple_dict(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded, &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str), &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
qobject_decref(obj);
QDECREF(str);
}
@@ -1257,11 +1163,11 @@ static void simple_list(void)
int i;
struct {
const char *encoded;
- LiteralQObject decoded;
+ QLitObject decoded;
} test_cases[] = {
{
.encoded = "[43,42]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(43),
QLIT_QNUM(42),
{ }
@@ -1269,21 +1175,21 @@ static void simple_list(void)
},
{
.encoded = "[43]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(43),
{ }
})),
},
{
.encoded = "[]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
{ }
})),
},
{
.encoded = "[{}]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
- QLIT_QDICT(((LiteralQDictEntry[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
+ QLIT_QDICT(((QLitDictEntry[]){
{},
})),
{},
@@ -1297,13 +1203,13 @@ static void simple_list(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded, &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str), &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
qobject_decref(obj);
QDECREF(str);
}
@@ -1314,11 +1220,11 @@ static void simple_whitespace(void)
int i;
struct {
const char *encoded;
- LiteralQObject decoded;
+ QLitObject decoded;
} test_cases[] = {
{
.encoded = " [ 43 , 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(43),
QLIT_QNUM(42),
{ }
@@ -1326,12 +1232,12 @@ static void simple_whitespace(void)
},
{
.encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(43),
- QLIT_QDICT(((LiteralQDictEntry[]){
+ QLIT_QDICT(((QLitDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ }})),
- QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QLIST(((QLitObject[]){
{ }})),
QLIT_QNUM(42),
{ }
@@ -1339,13 +1245,13 @@ static void simple_whitespace(void)
},
{
.encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
- .decoded = QLIT_QLIST(((LiteralQObject[]){
+ .decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(43),
- QLIT_QDICT(((LiteralQDictEntry[]){
+ QLIT_QDICT(((QLitDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ "a", QLIT_QNUM(32) },
{ }})),
- QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QLIST(((QLitObject[]){
{ }})),
QLIT_QNUM(42),
{ }
@@ -1359,13 +1265,13 @@ static void simple_whitespace(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded, &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str), &error_abort);
- g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj));
qobject_decref(obj);
QDECREF(str);
@@ -1376,10 +1282,10 @@ static void simple_varargs(void)
{
QObject *embedded_obj;
QObject *obj;
- LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
+ QLitObject decoded = QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(1),
QLIT_QNUM(2),
- QLIT_QLIST(((LiteralQObject[]){
+ QLIT_QLIST(((QLitObject[]){
QLIT_QNUM(32),
QLIT_QNUM(42),
{}})),
@@ -1389,7 +1295,7 @@ static void simple_varargs(void)
g_assert(embedded_obj != NULL);
obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
- g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
+ g_assert(qlit_equal_qobject(&decoded, obj));
qobject_decref(obj);
}
diff --git a/tests/check-qlit.c b/tests/check-qlit.c
new file mode 100644
index 0000000000..5736b61ebf
--- /dev/null
+++ b/tests/check-qlit.c
@@ -0,0 +1,68 @@
+/*
+ * QLit unit-tests.
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlit.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+
+static QLitObject qlit = QLIT_QDICT(((QLitDictEntry[]) {
+ { "foo", QLIT_QNUM(42) },
+ { "bar", QLIT_QSTR("hello world") },
+ { "baz", QLIT_QNULL },
+ { "bee", QLIT_QLIST(((QLitObject[]) {
+ QLIT_QNUM(43),
+ QLIT_QNUM(44),
+ QLIT_QBOOL(true),
+ { },
+ }))},
+ { },
+}));
+
+static QObject *make_qobject(void)
+{
+ QDict *qdict = qdict_new();
+ QList *list = qlist_new();
+
+ qdict_put_int(qdict, "foo", 42);
+ qdict_put_str(qdict, "bar", "hello world");
+ qdict_put_null(qdict, "baz");
+
+ qlist_append_int(list, 43);
+ qlist_append_int(list, 44);
+ qlist_append_bool(list, true);
+ qdict_put(qdict, "bee", list);
+
+ return QOBJECT(qdict);
+}
+
+static void qlit_equal_qobject_test(void)
+{
+ QObject *qobj = make_qobject();
+ QList *list = qlist_new();
+
+ g_assert(qlit_equal_qobject(&qlit, qobj));
+
+ qdict_put(qobject_to_qdict(qobj), "bee", list);
+ g_assert(!qlit_equal_qobject(&qlit, qobj));
+
+ qobject_decref(qobj);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/qlit/equal_qobject", qlit_equal_qobject_test);
+
+ return g_test_run();
+}
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
index fc8885c9a4..002d25873a 100644
--- a/qobject/Makefile.objs
+++ b/qobject/Makefile.objs
@@ -1,2 +1,2 @@
-util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o
+util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o qlit.o
util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 37c1bed683..3653c7b40a 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -43,6 +43,8 @@ check-unit-y += tests/check-qnull$(EXESUF)
gcov-files-check-qnull-y = qobject/qnull.c
check-unit-y += tests/check-qjson$(EXESUF)
gcov-files-check-qjson-y = qobject/qjson.c
+check-unit-y += tests/check-qlit$(EXESUF)
+gcov-files-check-qlit-y = qobject/qlit.c
check-unit-y += tests/test-qobject-output-visitor$(EXESUF)
gcov-files-test-qobject-output-visitor-y = qapi/qobject-output-visitor.c
check-unit-y += tests/test-clone-visitor$(EXESUF)
@@ -535,7 +537,7 @@ GENERATED_FILES += tests/test-qapi-types.h
tests/test-qapi-visit.h \
test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
tests/check-qlist.o tests/check-qnull.o \
- tests/check-qjson.o \
+ tests/check-qjson.o tests/check-qlit.o \
tests/test-coroutine.o tests/test-string-output-visitor.o \
tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \
tests/test-clone-visitor.o \
@@ -569,6 +571,7 @@ tests/check-qdict$(EXESUF): tests/check-qdict.o
$(test-util-obj-y)
tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
+tests/check-qlit$(EXESUF): tests/check-qlit.o $(test-util-obj-y)
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o
$(test-qom-obj-y)
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
--
2.14.1.146.gd35faa819
- Re: [Qemu-devel] [PATCH v2 28/54] qapi: do not define enumeration value explicitely, (continued)
- [Qemu-devel] [PATCH v2 34/54] qapi: add #if conditions to generated struct members, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 20/54] qapi-introspect: modify to_qlit() to take an optional suffix, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 18/54] qapi: add 'ifcond' to visitor methods, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 39/54] qapi: add #if conditions to generated alternate variants, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 10/54] block: use qemu_enum_parse() in blkdebug_debug_breakpoint, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 24/54] qapi-event: add #if conditions to events, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 14/54] qapi2texi: minor python code simplification, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 03/54] qobject: add literal qobject type,
Marc-André Lureau <=
- [Qemu-devel] [PATCH v2 02/54] qdict: add qdict_put_null() helper, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 37/54] qapi: 'if' to alternate variant, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 32/54] qapi: add 'if' to struct members, Marc-André Lureau, 2017/08/22
- [Qemu-devel] [PATCH v2 08/54] hmp: use qapi_enum_parse() in hmp_migrate_set_capability, Marc-André Lureau, 2017/08/22