Promote LiteralQObject from tests/check-qjson.c to qobject/qlit.c,
allowing to statically declare complex qobjects.
Add a helper qobject_from_qlit() to instantiate a literal qobject to a
real QObject. Add some simple test.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/qapi/qmp/qlit.h | 53 ++++++++++++++++++++++++++++++++++++
qobject/qlit.c | 53 ++++++++++++++++++++++++++++++++++++
tests/check-qjson.c | 72 +++++++++++++++++--------------------------------
tests/check-qlit.c | 52 +++++++++++++++++++++++++++++++++++
qobject/Makefile.objs | 2 +-
tests/Makefile.include | 5 +++-
6 files changed, 187 insertions(+), 50 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..fd6bfc3e69
--- /dev/null
+++ b/include/qapi/qmp/qlit.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright IBM, Corp. 2009
+ * Copyright (c) 2013, 2015 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@redhat.com>
+ *
+ * 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) }
+
+QObject *qobject_from_qlit(const QLitObject *qlit);
+
+#endif /* QLIT_H_ */
diff --git a/qobject/qlit.c b/qobject/qlit.c
new file mode 100644
index 0000000000..d7407b4b34
--- /dev/null
+++ b/qobject/qlit.c
@@ -0,0 +1,53 @@
+/*
+ * QLit literal qobject
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ *
+ * Authors:
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * 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"
+
+QObject *qobject_from_qlit(const QLitObject *qlit)
+{
+ int i;
+
+ switch (qlit->type) {
+ case QTYPE_QNULL:
+ return QOBJECT(qnull());
+ case QTYPE_QNUM:
+ return QOBJECT(qnum_from_int(qlit->value.qnum));
+ case QTYPE_QSTRING:
+ return QOBJECT(qstring_from_str(qlit->value.qstr));
+ case QTYPE_QDICT: {
+ QDict *qdict = qdict_new();
+ for (i = 0; qlit->value.qdict[i].value.type != QTYPE_NONE; i++) {
+ QLitDictEntry *e = &qlit->value.qdict[i];
+
+ qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
+ }
+ return QOBJECT(qdict);
+ }
+ case QTYPE_QLIST: {
+ QList *qlist = qlist_new();
+
+ for (i = 0; qlit->value.qlist[i].type != QTYPE_NONE; i++) {
+ qlist_append_obj(qlist, qobject_from_qlit(&qlit->value.qlist[i]));
+ }
+ return QOBJECT(qlist);
+ }
+ case QTYPE_QBOOL:
+ return QOBJECT(qbool_from_bool(qlit->value.qbool));
+ case QTYPE_NONE:
+ assert(0);
+ }
+
+ return NULL;
+}
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 9c42a46b7d..1a95aff2ba 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,39 +1060,14 @@ 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;
+ QLitObject *objs;
int result;
} QListCompareHelper;
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
+static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs);
static void compare_helper(QObject *obj, void *opaque)
{
@@ -1109,7 +1085,7 @@ static void compare_helper(QObject *obj, void *opaque)
helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
}
-static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
+static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs)
{
int64_t val;
@@ -1159,23 +1135,23 @@ 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) },
{ }
})),
@@ -1257,11 +1233,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 +1245,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[]){
{},
})),
{},
@@ -1314,11 +1290,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 +1302,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 +1315,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),
{ }
@@ -1393,10 +1369,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),
{}})),
diff --git a/tests/check-qlit.c b/tests/check-qlit.c
new file mode 100644
index 0000000000..cda4620f92
--- /dev/null
+++ b/tests/check-qlit.c
@@ -0,0 +1,52 @@
+/*
+ * 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/qlit.h"
+
+static void qobject_from_qlit_test(void)
+{
+ char *str;
+ QObject *qobj = NULL;
+ 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),
+ { },
+ }))
+ },
+ { },
+ }));
+
+ qobj = qobject_from_qlit(&qlit);
+
+ str = qobject_to_string(qobj);
+ g_assert_cmpstr(str, ==,
+ "bee:\n [0]: 43\n [1]: 44\n [2]: true\n" \
+ "baz: null\nbar: hello world\nfoo: 42\n");
+
+ g_free(str);
+ qobject_decref(qobj);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/qlit/qobject_from_qlit", qobject_from_qlit_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 7af278db55..960ab8c6dd 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -12,6 +12,8 @@ check-unit-y += tests/test-char$(EXESUF)
gcov-files-check-qdict-y = chardev/char.c
check-unit-y += tests/check-qnum$(EXESUF)
gcov-files-check-qnum-y = qobject/qnum.c
+check-unit-y += tests/check-qlit$(EXESUF)
+gcov-files-check-qlit-y = qobject/qlit.c
check-unit-y += tests/check-qstring$(EXESUF)
gcov-files-check-qstring-y = qobject/qstring.c
check-unit-y += tests/check-qlist$(EXESUF)
@@ -523,7 +525,7 @@ test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
tests/rcutorture.o tests/test-rcu-list.o \
tests/test-qdist.o tests/test-shift128.o \
tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
- tests/atomic_add-bench.o
+ tests/atomic_add-bench.o tests/check-qlit.o
$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
@@ -541,6 +543,7 @@ test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
+tests/check-qlit$(EXESUF): tests/check-qlit.o $(test-util-obj-y)
tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
--
2.14.0.rc0.1.g40ca67566
In the subject: s/qboject: add/qobject: Add/
Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> Promote LiteralQObject from tests/check-qjson.c to qobject/qlit.c,
> allowing to statically declare complex qobjects.
>
> Add a helper qobject_from_qlit() to instantiate a literal qobject to a
> real QObject. Add some simple test.
Suggest
* to also move the existing function making use of LiteralQObject
compare_litqobj_to_qobj(), so other tests can use it to verify a
QObject matches expectations, and
* to split the patch into the move and the addition of
qobject_from_qlit().
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/qapi/qmp/qlit.h | 53 ++++++++++++++++++++++++++++++++++++
> qobject/qlit.c | 53 ++++++++++++++++++++++++++++++++++++
> tests/check-qjson.c | 72 +++++++++++++++++--------------------------------
> tests/check-qlit.c | 52 +++++++++++++++++++++++++++++++++++
> qobject/Makefile.objs | 2 +-
> tests/Makefile.include | 5 +++-
> 6 files changed, 187 insertions(+), 50 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..fd6bfc3e69
> --- /dev/null
> +++ b/include/qapi/qmp/qlit.h
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright IBM, Corp. 2009
> + * Copyright (c) 2013, 2015 Red Hat Inc.
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + * Markus Armbruster <armbru@redhat.com>
> + *
> + * 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;
Not this patch's fault: QLitObject restricts numbers to signed integers.
> + 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) }
> +
> +QObject *qobject_from_qlit(const QLitObject *qlit);
> +
> +#endif /* QLIT_H_ */
> diff --git a/qobject/qlit.c b/qobject/qlit.c
> new file mode 100644
> index 0000000000..d7407b4b34
> --- /dev/null
> +++ b/qobject/qlit.c
> @@ -0,0 +1,53 @@
> +/*
> + * QLit literal qobject
> + *
> + * Copyright (C) 2017 Red Hat Inc.
> + *
> + * Authors:
> + * Marc-André Lureau <marcandre.lureau@redhat.com>
> + *
> + * 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"
> +
> +QObject *qobject_from_qlit(const QLitObject *qlit)
> +{
> + int i;
> +
> + switch (qlit->type) {
> + case QTYPE_QNULL:
> + return QOBJECT(qnull());
> + case QTYPE_QNUM:
> + return QOBJECT(qnum_from_int(qlit->value.qnum));
> + case QTYPE_QSTRING:
> + return QOBJECT(qstring_from_str(qlit->value.qstr));
> + case QTYPE_QDICT: {
> + QDict *qdict = qdict_new();
> + for (i = 0; qlit->value.qdict[i].value.type != QTYPE_NONE; i++) {
> + QLitDictEntry *e = &qlit->value.qdict[i];
> +
> + qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
> + }
> + return QOBJECT(qdict);
> + }
> + case QTYPE_QLIST: {
> + QList *qlist = qlist_new();
> +
> + for (i = 0; qlit->value.qlist[i].type != QTYPE_NONE; i++) {
> + qlist_append_obj(qlist, qobject_from_qlit(&qlit->value.qlist[i]));
> + }
> + return QOBJECT(qlist);
> + }
> + case QTYPE_QBOOL:
> + return QOBJECT(qbool_from_bool(qlit->value.qbool));
> + case QTYPE_NONE:
> + assert(0);
> + }
> +
> + return NULL;
> +}
> diff --git a/tests/check-qjson.c b/tests/check-qjson.c
> index 9c42a46b7d..1a95aff2ba 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,39 +1060,14 @@ 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;
> + QLitObject *objs;
> int result;
> } QListCompareHelper;
>
> -static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
> +static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs);
>
> static void compare_helper(QObject *obj, void *opaque)
> {
> @@ -1109,7 +1085,7 @@ static void compare_helper(QObject *obj, void *opaque)
> helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
> }
>
> -static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
> +static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs)
> {
> int64_t val;
>
> @@ -1159,23 +1135,23 @@ 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) },
> { }
> })),
> @@ -1257,11 +1233,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 +1245,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[]){
> {},
> })),
> {},
> @@ -1314,11 +1290,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 +1302,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 +1315,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),
> { }
> @@ -1393,10 +1369,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),
> {}})),
> diff --git a/tests/check-qlit.c b/tests/check-qlit.c
> new file mode 100644
> index 0000000000..cda4620f92
> --- /dev/null
> +++ b/tests/check-qlit.c
> @@ -0,0 +1,52 @@
> +/*
> + * 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/qlit.h"
> +
> +static void qobject_from_qlit_test(void)
> +{
> + char *str;
> + QObject *qobj = NULL;
> + 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),
> + { },
> + }))
> + },
> + { },
> + }));
> +
> + qobj = qobject_from_qlit(&qlit);
> +
> + str = qobject_to_string(qobj);
> + g_assert_cmpstr(str, ==,
> + "bee:\n [0]: 43\n [1]: 44\n [2]: true\n" \
> + "baz: null\nbar: hello world\nfoo: 42\n");
I don't like this. The order of QDict members in @str depends on
qdict_first()/qdict_next() iteration order, which is unspecified.
Here's how we check elsewhere that a QObject matches expectations:
static void qobject_from_qlit_test(void)
{
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),
{ },
}))
},
{ },
}));
QObject *qobj = qobject_from_qlit(&qlit);
QDict *qdict;
QList *baz;
qdict = qobject_to_qdict(qobj);
g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
baz = qdict_get_qlist(qdict, "bee");
g_assert_cmpint(qnum_get_int(qobject_to_qnum(qlist_pop(baz))), ==, 43);
g_assert_cmpint(qnum_get_int(qobject_to_qnum(qlist_pop(baz))), ==, 44);
g_assert_cmpint(qbool_get_bool(qobject_to_qbool(qlist_pop(baz))), ==, 1);
qobject_decref(qobj);
}
Robust, just tedious.
check-qjson.c uses a differently tedious technique: compare expected
QLitObject to actual QObject with compare_litqobj_to_qobj(). I like
that better, because I find the QLIT... initializers easier to read, and
less error prone to write. You might prefer not to use QLit to test
QLit, though.
> +
> + g_free(str);
> + qobject_decref(qobj);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + g_test_init(&argc, &argv, NULL);
> +
> + g_test_add_func("/qlit/qobject_from_qlit", qobject_from_qlit_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 7af278db55..960ab8c6dd 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -12,6 +12,8 @@ check-unit-y += tests/test-char$(EXESUF)
> gcov-files-check-qdict-y = chardev/char.c
> check-unit-y += tests/check-qnum$(EXESUF)
> gcov-files-check-qnum-y = qobject/qnum.c
> +check-unit-y += tests/check-qlit$(EXESUF)
> +gcov-files-check-qlit-y = qobject/qlit.c
> check-unit-y += tests/check-qstring$(EXESUF)
> gcov-files-check-qstring-y = qobject/qstring.c
> check-unit-y += tests/check-qlist$(EXESUF)
> @@ -523,7 +525,7 @@ test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
> tests/rcutorture.o tests/test-rcu-list.o \
> tests/test-qdist.o tests/test-shift128.o \
> tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
> - tests/atomic_add-bench.o
> + tests/atomic_add-bench.o tests/check-qlit.o
Please add it right next to the other qobject-related tests:
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 \
>
> $(test-obj-y): QEMU_INCLUDES += -Itests
> QEMU_CFLAGS += -I$(SRC_PATH)/tests
> @@ -541,6 +543,7 @@ test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
> test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
>
> tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
> +tests/check-qlit$(EXESUF): tests/check-qlit.o $(test-util-obj-y)
> tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
> tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
> tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
Same order as in test-obj-y, please.
Hi
On Wed, Aug 16, 2017 at 10:59 AM, Markus Armbruster <armbru@redhat.com> wrote:
> In the subject: s/qboject: add/qobject: Add/
>
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Promote LiteralQObject from tests/check-qjson.c to qobject/qlit.c,
>> allowing to statically declare complex qobjects.
>>
>> Add a helper qobject_from_qlit() to instantiate a literal qobject to a
>> real QObject. Add some simple test.
>
> Suggest
>
> * to also move the existing function making use of LiteralQObject
> compare_litqobj_to_qobj(), so other tests can use it to verify a
> QObject matches expectations, and
>
> * to split the patch into the move and the addition of
> qobject_from_qlit().
>
ok
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>> include/qapi/qmp/qlit.h | 53 ++++++++++++++++++++++++++++++++++++
>> qobject/qlit.c | 53 ++++++++++++++++++++++++++++++++++++
>> tests/check-qjson.c | 72 +++++++++++++++++--------------------------------
>> tests/check-qlit.c | 52 +++++++++++++++++++++++++++++++++++
>> qobject/Makefile.objs | 2 +-
>> tests/Makefile.include | 5 +++-
>> 6 files changed, 187 insertions(+), 50 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..fd6bfc3e69
>> --- /dev/null
>> +++ b/include/qapi/qmp/qlit.h
>> @@ -0,0 +1,53 @@
>> +/*
>> + * Copyright IBM, Corp. 2009
>> + * Copyright (c) 2013, 2015 Red Hat Inc.
>> + *
>> + * Authors:
>> + * Anthony Liguori <aliguori@us.ibm.com>
>> + * Markus Armbruster <armbru@redhat.com>
>> + *
>> + * 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;
>
> Not this patch's fault: QLitObject restricts numbers to signed integers.
>
>> + 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) }
>> +
>> +QObject *qobject_from_qlit(const QLitObject *qlit);
>> +
>> +#endif /* QLIT_H_ */
>> diff --git a/qobject/qlit.c b/qobject/qlit.c
>> new file mode 100644
>> index 0000000000..d7407b4b34
>> --- /dev/null
>> +++ b/qobject/qlit.c
>> @@ -0,0 +1,53 @@
>> +/*
>> + * QLit literal qobject
>> + *
>> + * Copyright (C) 2017 Red Hat Inc.
>> + *
>> + * Authors:
>> + * Marc-André Lureau <marcandre.lureau@redhat.com>
>> + *
>> + * 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"
>> +
>> +QObject *qobject_from_qlit(const QLitObject *qlit)
>> +{
>> + int i;
>> +
>> + switch (qlit->type) {
>> + case QTYPE_QNULL:
>> + return QOBJECT(qnull());
>> + case QTYPE_QNUM:
>> + return QOBJECT(qnum_from_int(qlit->value.qnum));
>> + case QTYPE_QSTRING:
>> + return QOBJECT(qstring_from_str(qlit->value.qstr));
>> + case QTYPE_QDICT: {
>> + QDict *qdict = qdict_new();
>> + for (i = 0; qlit->value.qdict[i].value.type != QTYPE_NONE; i++) {
>> + QLitDictEntry *e = &qlit->value.qdict[i];
>> +
>> + qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
>> + }
>> + return QOBJECT(qdict);
>> + }
>> + case QTYPE_QLIST: {
>> + QList *qlist = qlist_new();
>> +
>> + for (i = 0; qlit->value.qlist[i].type != QTYPE_NONE; i++) {
>> + qlist_append_obj(qlist, qobject_from_qlit(&qlit->value.qlist[i]));
>> + }
>> + return QOBJECT(qlist);
>> + }
>> + case QTYPE_QBOOL:
>> + return QOBJECT(qbool_from_bool(qlit->value.qbool));
>> + case QTYPE_NONE:
>> + assert(0);
>> + }
>> +
>> + return NULL;
>> +}
>> diff --git a/tests/check-qjson.c b/tests/check-qjson.c
>> index 9c42a46b7d..1a95aff2ba 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,39 +1060,14 @@ 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;
>> + QLitObject *objs;
>> int result;
>> } QListCompareHelper;
>>
>> -static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
>> +static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs);
>>
>> static void compare_helper(QObject *obj, void *opaque)
>> {
>> @@ -1109,7 +1085,7 @@ static void compare_helper(QObject *obj, void *opaque)
>> helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
>> }
>>
>> -static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
>> +static int compare_litqobj_to_qobj(QLitObject *lhs, QObject *rhs)
>> {
>> int64_t val;
>>
>> @@ -1159,23 +1135,23 @@ 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) },
>> { }
>> })),
>> @@ -1257,11 +1233,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 +1245,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[]){
>> {},
>> })),
>> {},
>> @@ -1314,11 +1290,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 +1302,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 +1315,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),
>> { }
>> @@ -1393,10 +1369,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),
>> {}})),
>> diff --git a/tests/check-qlit.c b/tests/check-qlit.c
>> new file mode 100644
>> index 0000000000..cda4620f92
>> --- /dev/null
>> +++ b/tests/check-qlit.c
>> @@ -0,0 +1,52 @@
>> +/*
>> + * 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/qlit.h"
>> +
>> +static void qobject_from_qlit_test(void)
>> +{
>> + char *str;
>> + QObject *qobj = NULL;
>> + 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),
>> + { },
>> + }))
>> + },
>> + { },
>> + }));
>> +
>> + qobj = qobject_from_qlit(&qlit);
>> +
>> + str = qobject_to_string(qobj);
>> + g_assert_cmpstr(str, ==,
>> + "bee:\n [0]: 43\n [1]: 44\n [2]: true\n" \
>> + "baz: null\nbar: hello world\nfoo: 42\n");
>
> I don't like this. The order of QDict members in @str depends on
> qdict_first()/qdict_next() iteration order, which is unspecified.
>
> Here's how we check elsewhere that a QObject matches expectations:
>
> static void qobject_from_qlit_test(void)
> {
> 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),
> { },
> }))
> },
> { },
> }));
> QObject *qobj = qobject_from_qlit(&qlit);
> QDict *qdict;
> QList *baz;
>
> qdict = qobject_to_qdict(qobj);
> g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
> g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
> g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
> baz = qdict_get_qlist(qdict, "bee");
> g_assert_cmpint(qnum_get_int(qobject_to_qnum(qlist_pop(baz))), ==, 43);
> g_assert_cmpint(qnum_get_int(qobject_to_qnum(qlist_pop(baz))), ==, 44);
> g_assert_cmpint(qbool_get_bool(qobject_to_qbool(qlist_pop(baz))), ==, 1);
>
> qobject_decref(qobj);
> }
>
> Robust, just tedious.
done the tedious way
>
> check-qjson.c uses a differently tedious technique: compare expected
> QLitObject to actual QObject with compare_litqobj_to_qobj(). I like
> that better, because I find the QLIT... initializers easier to read, and
> less error prone to write. You might prefer not to use QLit to test
> QLit, though.
>
ok
>> +
>> + g_free(str);
>> + qobject_decref(qobj);
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> + g_test_init(&argc, &argv, NULL);
>> +
>> + g_test_add_func("/qlit/qobject_from_qlit", qobject_from_qlit_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 7af278db55..960ab8c6dd 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -12,6 +12,8 @@ check-unit-y += tests/test-char$(EXESUF)
>> gcov-files-check-qdict-y = chardev/char.c
>> check-unit-y += tests/check-qnum$(EXESUF)
>> gcov-files-check-qnum-y = qobject/qnum.c
>> +check-unit-y += tests/check-qlit$(EXESUF)
>> +gcov-files-check-qlit-y = qobject/qlit.c
>> check-unit-y += tests/check-qstring$(EXESUF)
>> gcov-files-check-qstring-y = qobject/qstring.c
>> check-unit-y += tests/check-qlist$(EXESUF)
>> @@ -523,7 +525,7 @@ test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
>> tests/rcutorture.o tests/test-rcu-list.o \
>> tests/test-qdist.o tests/test-shift128.o \
>> tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
>> - tests/atomic_add-bench.o
>> + tests/atomic_add-bench.o tests/check-qlit.o
>
> Please add it right next to the other qobject-related tests:
>
ok
> 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 \
>
>>
>> $(test-obj-y): QEMU_INCLUDES += -Itests
>> QEMU_CFLAGS += -I$(SRC_PATH)/tests
>> @@ -541,6 +543,7 @@ test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
>> test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
>>
>> tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
>> +tests/check-qlit$(EXESUF): tests/check-qlit.o $(test-util-obj-y)
>> tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
>> tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
>> tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
>
> Same order as in test-obj-y, please.
>
ok
--
Marc-André Lureau
© 2016 - 2026 Red Hat, Inc.