diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-03-07 17:06:48 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-03-07 17:06:48 +0000 |
commit | 87467097f8811258cd91d42c141a7bd8492ed08a (patch) | |
tree | 4c9f130fca163f66038c12af9b3416860bad6338 /tests | |
parent | 43c227f9dd7945bb4a895f841ecdb957bd8a12da (diff) | |
parent | 0b2c1beea4358e40d1049b8ee019408ce96b37ce (diff) | |
download | qemu-87467097f8811258cd91d42c141a7bd8492ed08a.zip qemu-87467097f8811258cd91d42c141a7bd8492ed08a.tar.gz qemu-87467097f8811258cd91d42c141a7bd8492ed08a.tar.bz2 |
Merge remote-tracking branch 'remotes/armbru/tags/pull-block-2017-02-28-v4' into staging
block: Command line option -blockdev
# gpg: Signature made Tue 07 Mar 2017 15:07:59 GMT
# gpg: using RSA key 0x3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-block-2017-02-28-v4: (24 commits)
keyval: Support lists
docs/qapi-code-gen.txt: Clarify naming rules
qapi: Improve how keyval input visitor reports unexpected dicts
block: Initial implementation of -blockdev
qapi: New qobject_input_visitor_new_str() for convenience
keyval: Restrict key components to valid QAPI names
qapi: New parse_qapi_name()
test-qapi-util: New, covering qapi/qapi-util.c
monitor: Assert qmp_schema_json[] is sane
test-visitor-serialization: Pass &error_abort to qobject_from_json()
check-qjson: Test errors from qobject_from_json()
block: More detailed syntax error reporting for JSON filenames
qobject: Propagate parse errors through qobject_from_json()
test-qobject-input-visitor: Abort earlier on bad test input
qjson: Abort earlier on qobject_from_jsonf() misuse
libqtest: Fix qmp() & friends to abort on JSON parse errors
qobject: Propagate parse errors through qobject_from_jsonv()
qapi: Factor out common qobject_input_get_keyval()
qapi: Factor out common part of qobject input visitor creation
test-keyval: Cover use with qobject input visitor
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/.gitignore | 2 | ||||
-rw-r--r-- | tests/Makefile.include | 10 | ||||
-rw-r--r-- | tests/check-qjson.c | 88 | ||||
-rw-r--r-- | tests/libqtest.c | 3 | ||||
-rw-r--r-- | tests/test-keyval.c | 624 | ||||
-rw-r--r-- | tests/test-qapi-util.c | 85 | ||||
-rw-r--r-- | tests/test-qemu-opts.c | 5 | ||||
-rw-r--r-- | tests/test-qobject-input-visitor.c | 190 | ||||
-rw-r--r-- | tests/test-visitor-serialization.c | 2 |
9 files changed, 968 insertions, 41 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index dc37519..a966740 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -47,11 +47,13 @@ test-io-channel-file.txt test-io-channel-socket test-io-channel-tls test-io-task +test-keyval test-logging test-mul64 test-opts-visitor test-qapi-event.[ch] test-qapi-types.[ch] +test-qapi-util test-qapi-visit.[ch] test-qdev-global-props test-qemu-opts diff --git a/tests/Makefile.include b/tests/Makefile.include index ace4e80..346345e 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -93,7 +93,9 @@ gcov-files-check-qom-interface-y = qom/object.c check-unit-y += tests/check-qom-proplist$(EXESUF) gcov-files-check-qom-proplist-y = qom/object.c check-unit-y += tests/test-qemu-opts$(EXESUF) -gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c +gcov-files-test-qemu-opts-y = util/qemu-option.c +check-unit-y += tests/test-keyval$(EXESUF) +gcov-files-test-keyval-y = util/keyval.c check-unit-y += tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y = block/write-threshold.c check-unit-y += tests/test-crypto-hash$(EXESUF) @@ -118,14 +120,16 @@ check-unit-y += tests/test-crypto-ivgen$(EXESUF) check-unit-y += tests/test-crypto-afsplit$(EXESUF) check-unit-y += tests/test-crypto-xts$(EXESUF) check-unit-y += tests/test-crypto-block$(EXESUF) -gcov-files-test-logging-y = tests/test-logging.c check-unit-y += tests/test-logging$(EXESUF) +gcov-files-test-logging-y = util/log.c check-unit-$(CONFIG_REPLICATION) += tests/test-replication$(EXESUF) check-unit-y += tests/test-bufferiszero$(EXESUF) gcov-files-check-bufferiszero-y = util/bufferiszero.c check-unit-y += tests/test-uuid$(EXESUF) check-unit-y += tests/ptimer-test$(EXESUF) gcov-files-ptimer-test-y = hw/core/ptimer.c +check-unit-y += tests/test-qapi-util$(EXESUF) +gcov-files-test-qapi-util-y = qapi/qapi-util.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -720,6 +724,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \ $(chardev-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y) +tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y) tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y) tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y) tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) @@ -729,6 +734,7 @@ tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o contrib/libvhost-user/libvhost-user.o $(test-util-obj-y) tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o +tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@") diff --git a/tests/check-qjson.c b/tests/check-qjson.c index e6d6935..963dd46 100644 --- a/tests/check-qjson.c +++ b/tests/check-qjson.c @@ -10,8 +10,10 @@ * See the COPYING.LIB file in the top-level directory. * */ + #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qmp/types.h" #include "qapi/qmp/qjson.h" #include "qemu-common.h" @@ -53,7 +55,7 @@ static void escaped_string(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); str = qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded); @@ -85,7 +87,7 @@ static void simple_string(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); str = qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0); @@ -116,7 +118,7 @@ static void single_quote_string(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); str = qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0); @@ -809,7 +811,7 @@ static void utf8_string(void) utf8_in = test_cases[i].utf8_in ?: test_cases[i].utf8_out; json_out = test_cases[i].json_out ?: test_cases[i].json_in; - obj = qobject_from_json(json_in); + obj = qobject_from_json(json_in, utf8_out ? &error_abort : NULL); if (utf8_out) { str = qobject_to_qstring(obj); g_assert(str); @@ -836,7 +838,7 @@ static void utf8_string(void) * FIXME Enable once these bugs have been fixed. */ if (0 && json_out != json_in) { - obj = qobject_from_json(json_out); + obj = qobject_from_json(json_out, &error_abort); str = qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), ==, utf8_out); @@ -886,7 +888,8 @@ static void simple_number(void) for (i = 0; test_cases[i].encoded; i++) { QInt *qint; - qint = qobject_to_qint(qobject_from_json(test_cases[i].encoded)); + qint = qobject_to_qint(qobject_from_json(test_cases[i].encoded, + &error_abort)); g_assert(qint); g_assert(qint_get_int(qint) == test_cases[i].decoded); if (test_cases[i].skip == 0) { @@ -920,7 +923,7 @@ static void float_number(void) QObject *obj; QFloat *qfloat; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); qfloat = qobject_to_qfloat(obj); g_assert(qfloat); g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded); @@ -965,7 +968,7 @@ static void keyword_literal(void) QObject *null; QString *str; - obj = qobject_from_json("true"); + obj = qobject_from_json("true", &error_abort); qbool = qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) == true); @@ -976,7 +979,7 @@ static void keyword_literal(void) QDECREF(qbool); - obj = qobject_from_json("false"); + obj = qobject_from_json("false", &error_abort); qbool = qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) == false); @@ -998,7 +1001,7 @@ static void keyword_literal(void) g_assert(qbool_get_bool(qbool) == true); QDECREF(qbool); - obj = qobject_from_json("null"); + obj = qobject_from_json("null", &error_abort); g_assert(obj != NULL); g_assert(qobject_type(obj) == QTYPE_QNULL); @@ -1134,13 +1137,13 @@ static void simple_dict(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); str = qobject_to_json(obj); qobject_decref(obj); - obj = qobject_from_json(qstring_get_str(str)); + obj = qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); qobject_decref(obj); QDECREF(str); @@ -1192,7 +1195,7 @@ static void large_dict(void) QObject *obj; gen_test_json(gstr, 10, 100); - obj = qobject_from_json(gstr->str); + obj = qobject_from_json(gstr->str, &error_abort); g_assert(obj != NULL); qobject_decref(obj); @@ -1243,13 +1246,13 @@ static void simple_list(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); str = qobject_to_json(obj); qobject_decref(obj); - obj = qobject_from_json(qstring_get_str(str)); + obj = qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); qobject_decref(obj); QDECREF(str); @@ -1305,13 +1308,13 @@ static void simple_whitespace(void) QObject *obj; QString *str; - obj = qobject_from_json(test_cases[i].encoded); + obj = qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); str = qobject_to_json(obj); qobject_decref(obj); - obj = qobject_from_json(qstring_get_str(str)); + obj = qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1); qobject_decref(obj); @@ -1332,7 +1335,7 @@ static void simple_varargs(void) {}})), {}})); - embedded_obj = qobject_from_json("[32, 42]"); + embedded_obj = qobject_from_json("[32, 42]", &error_abort); g_assert(embedded_obj != NULL); obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj); @@ -1344,68 +1347,87 @@ static void simple_varargs(void) static void empty_input(void) { const char *empty = ""; - - QObject *obj = qobject_from_json(empty); + QObject *obj = qobject_from_json(empty, &error_abort); g_assert(obj == NULL); } static void unterminated_string(void) { - QObject *obj = qobject_from_json("\"abc"); + Error *err = NULL; + QObject *obj = qobject_from_json("\"abc", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void unterminated_sq_string(void) { - QObject *obj = qobject_from_json("'abc"); + Error *err = NULL; + QObject *obj = qobject_from_json("'abc", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void unterminated_escape(void) { - QObject *obj = qobject_from_json("\"abc\\\""); + Error *err = NULL; + QObject *obj = qobject_from_json("\"abc\\\"", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void unterminated_array(void) { - QObject *obj = qobject_from_json("[32"); + Error *err = NULL; + QObject *obj = qobject_from_json("[32", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void unterminated_array_comma(void) { - QObject *obj = qobject_from_json("[32,"); + Error *err = NULL; + QObject *obj = qobject_from_json("[32,", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void invalid_array_comma(void) { - QObject *obj = qobject_from_json("[32,}"); + Error *err = NULL; + QObject *obj = qobject_from_json("[32,}", &err); + error_free_or_abort(&err); g_assert(obj == NULL); } static void unterminated_dict(void) { - QObject *obj = qobject_from_json("{'abc':32"); + Error *err = NULL; + QObject *obj = qobject_from_json("{'abc':32", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void unterminated_dict_comma(void) { - QObject *obj = qobject_from_json("{'abc':32,"); + Error *err = NULL; + QObject *obj = qobject_from_json("{'abc':32,", &err); + g_assert(!err); /* BUG */ g_assert(obj == NULL); } static void invalid_dict_comma(void) { - QObject *obj = qobject_from_json("{'abc':32,}"); + Error *err = NULL; + QObject *obj = qobject_from_json("{'abc':32,}", &err); + error_free_or_abort(&err); g_assert(obj == NULL); } static void unterminated_literal(void) { - QObject *obj = qobject_from_json("nul"); + Error *err = NULL; + QObject *obj = qobject_from_json("nul", &err); + error_free_or_abort(&err); g_assert(obj == NULL); } @@ -1421,15 +1443,17 @@ static char *make_nest(char *buf, size_t cnt) static void limits_nesting(void) { + Error *err = NULL; enum { max_nesting = 1024 }; /* see qobject/json-streamer.c */ char buf[2 * (max_nesting + 1) + 1]; QObject *obj; - obj = qobject_from_json(make_nest(buf, max_nesting)); + obj = qobject_from_json(make_nest(buf, max_nesting), &error_abort); g_assert(obj != NULL); qobject_decref(obj); - obj = qobject_from_json(make_nest(buf, max_nesting + 1)); + obj = qobject_from_json(make_nest(buf, max_nesting + 1), &err); + error_free_or_abort(&err); g_assert(obj == NULL); } diff --git a/tests/libqtest.c b/tests/libqtest.c index ca6b641..a5c3d2b 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -21,6 +21,7 @@ #include <sys/wait.h> #include <sys/un.h> +#include "qapi/error.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/json-streamer.h" #include "qapi/qmp/qjson.h" @@ -442,7 +443,7 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap) * is an array type. */ va_copy(ap_copy, ap); - qobj = qobject_from_jsonv(fmt, &ap_copy); + qobj = qobject_from_jsonv(fmt, &ap_copy, &error_abort); va_end(ap_copy); /* No need to send anything for an empty QObject. */ diff --git a/tests/test-keyval.c b/tests/test-keyval.c new file mode 100644 index 0000000..71288b0 --- /dev/null +++ b/tests/test-keyval.c @@ -0,0 +1,624 @@ +/* + * Unit tests for parsing of KEY=VALUE,... strings + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster <armbru@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qobject-input-visitor.h" +#include "qemu/cutils.h" +#include "qemu/option.h" + +static void test_keyval_parse(void) +{ + Error *err = NULL; + QDict *qdict, *sub_qdict; + char long_key[129]; + char *params; + + /* Nothing */ + qdict = keyval_parse("", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 0); + QDECREF(qdict); + + /* Empty key (qemu_opts_parse() accepts this) */ + qdict = keyval_parse("=val", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Empty key fragment */ + qdict = keyval_parse(".", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict = keyval_parse("key.", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Invalid non-empty key (qemu_opts_parse() doesn't care) */ + qdict = keyval_parse("7up=val", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Overlong key */ + memset(long_key, 'a', 127); + long_key[127] = 'z'; + long_key[128] = 0; + params = g_strdup_printf("k.%s=v", long_key); + qdict = keyval_parse(params + 2, NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Overlong key fragment */ + qdict = keyval_parse(params, NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + g_free(params); + + /* Long key (qemu_opts_parse() accepts and truncates silently) */ + params = g_strdup_printf("k.%s=v", long_key + 1); + qdict = keyval_parse(params + 2, NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, long_key + 1), ==, "v"); + QDECREF(qdict); + + /* Long key fragment */ + qdict = keyval_parse(params, NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + sub_qdict = qdict_get_qdict(qdict, "k"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, long_key + 1), ==, "v"); + QDECREF(qdict); + g_free(params); + + /* Crap after valid key */ + qdict = keyval_parse("key[0]=val", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Multiple keys, last one wins */ + qdict = keyval_parse("a=1,b=2,,x,a=3", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 2); + g_assert_cmpstr(qdict_get_try_str(qdict, "a"), ==, "3"); + g_assert_cmpstr(qdict_get_try_str(qdict, "b"), ==, "2,x"); + QDECREF(qdict); + + /* Even when it doesn't in qemu_opts_parse() */ + qdict = keyval_parse("id=foo,id=bar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "bar"); + QDECREF(qdict); + + /* Dotted keys */ + qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 2); + sub_qdict = qdict_get_qdict(qdict, "a"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + sub_qdict = qdict_get_qdict(sub_qdict, "b"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "c"), ==, "2"); + g_assert_cmpstr(qdict_get_try_str(qdict, "d"), ==, "3"); + QDECREF(qdict); + + /* Inconsistent dotted keys */ + qdict = keyval_parse("a.b=1,a=2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict = keyval_parse("a.b=1,a.b.c=2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Trailing comma is ignored */ + qdict = keyval_parse("x=y,", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, "y"); + QDECREF(qdict); + + /* Except when it isn't */ + qdict = keyval_parse(",", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Value containing ,id= not misinterpreted as qemu_opts_parse() does */ + qdict = keyval_parse("x=,,id=bar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, ",id=bar"); + QDECREF(qdict); + + /* Anti-social ID is left to caller (qemu_opts_parse() rejects it) */ + qdict = keyval_parse("id=666", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "666"); + QDECREF(qdict); + + /* Implied value not supported (unlike qemu_opts_parse()) */ + qdict = keyval_parse("an,noaus,noaus=", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Implied value, key "no" (qemu_opts_parse(): negated empty key) */ + qdict = keyval_parse("no", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Implied key */ + qdict = keyval_parse("an,aus=off,noaus=", "implied", &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 3); + g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "an"); + g_assert_cmpstr(qdict_get_try_str(qdict, "aus"), ==, "off"); + g_assert_cmpstr(qdict_get_try_str(qdict, "noaus"), ==, ""); + QDECREF(qdict); + + /* Implied dotted key */ + qdict = keyval_parse("val", "eins.zwei", &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + sub_qdict = qdict_get_qdict(qdict, "eins"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "zwei"), ==, "val"); + QDECREF(qdict); + + /* Implied key with empty value (qemu_opts_parse() accepts this) */ + qdict = keyval_parse(",", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Likewise (qemu_opts_parse(): implied key with comma value) */ + qdict = keyval_parse(",,,a=1", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Empty key is not an implied key */ + qdict = keyval_parse("=val", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); +} + +static void check_list012(QList *qlist) +{ + static const char *expected[] = { "null", "eins", "zwei" }; + int i; + QString *qstr; + + g_assert(qlist); + for (i = 0; i < ARRAY_SIZE(expected); i++) { + qstr = qobject_to_qstring(qlist_pop(qlist)); + g_assert(qstr); + g_assert_cmpstr(qstring_get_str(qstr), ==, expected[i]); + QDECREF(qstr); + } + g_assert(qlist_empty(qlist)); +} + +static void test_keyval_parse_list(void) +{ + Error *err = NULL; + QDict *qdict, *sub_qdict; + + /* Root can't be a list */ + qdict = keyval_parse("0=1", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* List elements need not be in order */ + qdict = keyval_parse("list.0=null,list.2=zwei,list.1=eins", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), ==, 1); + check_list012(qdict_get_qlist(qdict, "list")); + QDECREF(qdict); + + /* Multiple indexes, last one wins */ + qdict = keyval_parse("list.1=goner,list.0=null,list.1=eins,list.2=zwei", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), ==, 1); + check_list012(qdict_get_qlist(qdict, "list")); + QDECREF(qdict); + + /* List at deeper nesting */ + qdict = keyval_parse("a.list.1=eins,a.list.0=null,a.list.2=zwei", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), ==, 1); + sub_qdict = qdict_get_qdict(qdict, "a"); + g_assert_cmpint(qdict_size(sub_qdict), ==, 1); + check_list012(qdict_get_qlist(sub_qdict, "list")); + QDECREF(qdict); + + /* Inconsistent dotted keys: both list and dictionary */ + qdict = keyval_parse("a.b.c=1,a.b.0=2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict = keyval_parse("a.0.c=1,a.b.c=2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Missing list indexes */ + qdict = keyval_parse("list.2=lonely", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict = keyval_parse("list.0=null,list.2=eins,list.02=zwei", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); +} + +static void test_keyval_visit_bool(void) +{ + Error *err = NULL; + Visitor *v; + QDict *qdict; + bool b; + + qdict = keyval_parse("bool1=on,bool2=off", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &error_abort); + g_assert(b); + visit_type_bool(v, "bool2", &b, &error_abort); + g_assert(!b); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict = keyval_parse("bool1=offer", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_number(void) +{ + Error *err = NULL; + Visitor *v; + QDict *qdict; + uint64_t u; + + /* Lower limit zero */ + qdict = keyval_parse("number1=0", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, ==, 0); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Upper limit 2^64-1 */ + qdict = keyval_parse("number1=18446744073709551615,number2=-1", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmphex(u, ==, UINT64_MAX); + visit_type_uint64(v, "number2", &u, &error_abort); + g_assert_cmphex(u, ==, UINT64_MAX); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Above upper limit */ + qdict = keyval_parse("number1=18446744073709551616", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Below lower limit */ + qdict = keyval_parse("number1=-18446744073709551616", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Hex and octal */ + qdict = keyval_parse("number1=0x2a,number2=052", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, ==, 42); + visit_type_uint64(v, "number2", &u, &error_abort); + g_assert_cmpuint(u, ==, 42); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Trailing crap */ + qdict = keyval_parse("number1=3.14,number2=08", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_type_uint64(v, "number2", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_size(void) +{ + Error *err = NULL; + Visitor *v; + QDict *qdict; + uint64_t sz; + + /* Lower limit zero */ + qdict = keyval_parse("sz1=0", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, ==, 0); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Note: precision is 53 bits since we're parsing with strtod() */ + + /* Around limit of precision: 2^53-1, 2^53, 2^53+1 */ + qdict = keyval_parse("sz1=9007199254740991," + "sz2=9007199254740992," + "sz3=9007199254740993", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x1fffffffffffff); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x20000000000000); + visit_type_size(v, "sz3", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x20000000000000); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ + qdict = keyval_parse("sz1=9223372036854774784," /* 7ffffffffffffc00 */ + "sz2=9223372036854775295", /* 7ffffffffffffdff */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x7ffffffffffffc00); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x7ffffffffffffc00); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ + qdict = keyval_parse("sz1=18446744073709549568," /* fffffffffffff800 */ + "sz2=18446744073709550591", /* fffffffffffffbff */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0xfffffffffffff800); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0xfffffffffffff800); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Beyond limits */ + qdict = keyval_parse("sz1=-1," + "sz2=18446744073709550592", /* fffffffffffffc00 */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_type_size(v, "sz2", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Suffixes */ + qdict = keyval_parse("sz1=8b,sz2=1.5k,sz3=2M,sz4=0.1G,sz5=16777215T", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, ==, 8); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmpuint(sz, ==, 1536); + visit_type_size(v, "sz3", &sz, &error_abort); + g_assert_cmphex(sz, ==, 2 * M_BYTE); + visit_type_size(v, "sz4", &sz, &error_abort); + g_assert_cmphex(sz, ==, G_BYTE / 10); + visit_type_size(v, "sz5", &sz, &error_abort); + g_assert_cmphex(sz, ==, 16777215 * T_BYTE); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Beyond limit with suffix */ + qdict = keyval_parse("sz1=16777216T", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Trailing crap */ + qdict = keyval_parse("sz1=16E,sz2=16Gi", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_type_size(v, "sz2", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_dict(void) +{ + Error *err = NULL; + Visitor *v; + QDict *qdict; + int64_t i; + + qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_start_struct(v, "b", NULL, 0, &error_abort); + visit_type_int(v, "c", &i, &error_abort); + g_assert_cmpint(i, ==, 2); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_type_int(v, "d", &i, &error_abort); + g_assert_cmpint(i, ==, 3); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict = keyval_parse("a.b=", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_type_int(v, "c", &i, &err); /* a.c missing */ + error_free_or_abort(&err); + visit_check_struct(v, &err); + error_free_or_abort(&err); /* a.b unexpected */ + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_list(void) +{ + Error *err = NULL; + Visitor *v; + QDict *qdict; + char *s; + + qdict = keyval_parse("a.0=,a.1=I,a.2.0=II", NULL, &error_abort); + /* TODO empty list */ + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, ==, ""); + g_free(s); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, ==, "I"); + g_free(s); + visit_start_list(v, NULL, NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, ==, "II"); + g_free(s); + visit_check_list(v, &error_abort); + visit_end_list(v, NULL); + visit_check_list(v, &error_abort); + visit_end_list(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict = keyval_parse("a.0=,b.0.0=head", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_check_list(v, &err); /* a[0] unexpected */ + error_free_or_abort(&err); + visit_end_list(v, NULL); + visit_start_list(v, "b", NULL, 0, &error_abort); + visit_start_list(v, NULL, NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, ==, "head"); + g_free(s); + visit_type_str(v, NULL, &s, &err); /* b[0][1] missing */ + error_free_or_abort(&err); + visit_end_list(v, NULL); + visit_end_list(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_optional(void) +{ + Visitor *v; + QDict *qdict; + bool present; + int64_t i; + + qdict = keyval_parse("a.b=1", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_optional(v, "b", &present); + g_assert(!present); /* b missing */ + visit_optional(v, "a", &present); + g_assert(present); /* a present */ + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_optional(v, "b", &present); + g_assert(present); /* a.b present */ + visit_type_int(v, "b", &i, &error_abort); + g_assert_cmpint(i, ==, 1); + visit_optional(v, "a", &present); + g_assert(!present); /* a.a missing */ + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/keyval/keyval_parse", test_keyval_parse); + g_test_add_func("/keyval/keyval_parse/list", test_keyval_parse_list); + g_test_add_func("/keyval/visit/bool", test_keyval_visit_bool); + g_test_add_func("/keyval/visit/number", test_keyval_visit_number); + g_test_add_func("/keyval/visit/size", test_keyval_visit_size); + g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict); + g_test_add_func("/keyval/visit/list", test_keyval_visit_list); + g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional); + g_test_run(); + return 0; +} diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c new file mode 100644 index 0000000..e869757 --- /dev/null +++ b/tests/test-qapi-util.c @@ -0,0 +1,85 @@ +/* + * Unit tests for QAPI utility functions + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster <armbru@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/util.h" +#include "test-qapi-types.h" + +static void test_qapi_enum_parse(void) +{ + Error *err = NULL; + int ret; + + ret = qapi_enum_parse(QType_lookup, NULL, QTYPE__MAX, QTYPE_NONE, + &error_abort); + g_assert_cmpint(ret, ==, QTYPE_NONE); + + ret = qapi_enum_parse(QType_lookup, "junk", QTYPE__MAX, -1, + NULL); + g_assert_cmpint(ret, ==, -1); + + ret = qapi_enum_parse(QType_lookup, "junk", QTYPE__MAX, -1, + &err); + error_free_or_abort(&err); + + ret = qapi_enum_parse(QType_lookup, "none", QTYPE__MAX, -1, + &error_abort); + g_assert_cmpint(ret, ==, QTYPE_NONE); + + ret = qapi_enum_parse(QType_lookup, QType_lookup[QTYPE__MAX - 1], + QTYPE__MAX, QTYPE__MAX - 1, + &error_abort); + g_assert_cmpint(ret, ==, QTYPE__MAX - 1); +} + +static void test_parse_qapi_name(void) +{ + int ret; + + /* Must start with a letter */ + ret = parse_qapi_name("a", true); + g_assert(ret == 1); + ret = parse_qapi_name("a$", false); + g_assert(ret == 1); + ret = parse_qapi_name("", false); + g_assert(ret == -1); + ret = parse_qapi_name("1", false); + g_assert(ret == -1); + + /* Only letters, digits, hyphen, underscore */ + ret = parse_qapi_name("A-Za-z0-9_", true); + g_assert(ret == 10); + ret = parse_qapi_name("A-Za-z0-9_$", false); + g_assert(ret == 10); + ret = parse_qapi_name("A-Za-z0-9_$", true); + g_assert(ret == -1); + + /* __RFQDN_ */ + ret = parse_qapi_name("__com.redhat_supports", true); + g_assert(ret == 21); + ret = parse_qapi_name("_com.example_", false); + g_assert(ret == -1); + ret = parse_qapi_name("__com.example", false); + g_assert(ret == -1); + ret = parse_qapi_name("__com.example_", false); + g_assert(ret == -1); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/qapi/util/qapi_enum_parse", test_qapi_enum_parse); + g_test_add_func("/qapi/util/parse_qapi_name", test_parse_qapi_name); + g_test_run(); + return 0; +} diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index c46ef31..f6310b3 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -532,6 +532,11 @@ static void test_opts_parse(void) g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); + /* Implied value, negated empty key */ + opts = qemu_opts_parse(&opts_list_03, "no", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "off"); + /* Implied key */ opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true, &error_abort); diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c index 94305f5..6eb48fe 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -45,19 +45,38 @@ static void visitor_input_teardown(TestInputVisitorData *data, function so that the JSON string used by the tests are kept in the test functions (and not in main()). */ static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data, + bool keyval, const char *json_string, va_list *ap) { visitor_input_teardown(data, NULL); - data->obj = qobject_from_jsonv(json_string, ap); + data->obj = qobject_from_jsonv(json_string, ap, &error_abort); g_assert(data->obj); - data->qiv = qobject_input_visitor_new(data->obj); + if (keyval) { + data->qiv = qobject_input_visitor_new_keyval(data->obj); + } else { + data->qiv = qobject_input_visitor_new(data->obj); + } g_assert(data->qiv); return data->qiv; } +static GCC_FMT_ATTR(3, 4) +Visitor *visitor_input_test_init_full(TestInputVisitorData *data, + bool keyval, + const char *json_string, ...) +{ + Visitor *v; + va_list ap; + + va_start(ap, json_string); + v = visitor_input_test_init_internal(data, keyval, json_string, &ap); + va_end(ap); + return v; +} + static GCC_FMT_ATTR(2, 3) Visitor *visitor_input_test_init(TestInputVisitorData *data, const char *json_string, ...) @@ -66,7 +85,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data, va_list ap; va_start(ap, json_string); - v = visitor_input_test_init_internal(data, json_string, &ap); + v = visitor_input_test_init_internal(data, false, json_string, &ap); va_end(ap); return v; } @@ -81,7 +100,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data, static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data, const char *json_string) { - return visitor_input_test_init_internal(data, json_string, NULL); + return visitor_input_test_init_internal(data, false, json_string, NULL); } static void test_visitor_in_int(TestInputVisitorData *data, @@ -114,6 +133,43 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, error_free_or_abort(&err); } +static void test_visitor_in_int_keyval(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0, value = -42; + Error *err = NULL; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "%" PRId64, value); + visit_type_int(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_int_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0, value = -42; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "\"-42\""); + + visit_type_int(v, NULL, &res, &error_abort); + g_assert_cmpint(res, ==, value); +} + +static void test_visitor_in_int_str_fail(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0; + Visitor *v; + Error *err = NULL; + + v = visitor_input_test_init(data, "\"-42\""); + + visit_type_int(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { @@ -126,6 +182,44 @@ static void test_visitor_in_bool(TestInputVisitorData *data, g_assert_cmpint(res, ==, true); } +static void test_visitor_in_bool_keyval(TestInputVisitorData *data, + const void *unused) +{ + bool res = false; + Error *err = NULL; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "true"); + + visit_type_bool(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_bool_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + bool res = false; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "\"on\""); + + visit_type_bool(v, NULL, &res, &error_abort); + g_assert_cmpint(res, ==, true); +} + +static void test_visitor_in_bool_str_fail(TestInputVisitorData *data, + const void *unused) +{ + bool res = false; + Visitor *v; + Error *err = NULL; + + v = visitor_input_test_init(data, "\"true\""); + + visit_type_bool(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { @@ -138,6 +232,69 @@ static void test_visitor_in_number(TestInputVisitorData *data, g_assert_cmpfloat(res, ==, value); } +static void test_visitor_in_number_keyval(TestInputVisitorData *data, + const void *unused) +{ + double res = 0, value = 3.14; + Error *err = NULL; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "%f", value); + + visit_type_number(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_number_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + double res = 0, value = 3.14; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "\"3.14\""); + + visit_type_number(v, NULL, &res, &error_abort); + g_assert_cmpfloat(res, ==, value); +} + +static void test_visitor_in_number_str_fail(TestInputVisitorData *data, + const void *unused) +{ + double res = 0; + Visitor *v; + Error *err = NULL; + + v = visitor_input_test_init(data, "\"3.14\""); + + visit_type_number(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_size_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + uint64_t res, value = 500 * 1024 * 1024; + Visitor *v; + + v = visitor_input_test_init_full(data, true, "\"500M\""); + + visit_type_size(v, NULL, &res, &error_abort); + g_assert_cmpfloat(res, ==, value); +} + +static void test_visitor_in_size_str_fail(TestInputVisitorData *data, + const void *unused) +{ + uint64_t res = 0; + Visitor *v; + Error *err = NULL; + + v = visitor_input_test_init(data, "\"500M\""); + + visit_type_size(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { @@ -294,7 +451,8 @@ static void test_visitor_in_null(TestInputVisitorData *data, * when input is not null. */ - v = visitor_input_test_init(data, "{ 'a': null, 'b': '', 'c': null }"); + v = visitor_input_test_init_full(data, false, + "{ 'a': null, 'b': '' }"); visit_start_struct(v, NULL, NULL, 0, &error_abort); visit_type_null(v, "a", &error_abort); visit_type_null(v, "b", &err); @@ -1069,10 +1227,32 @@ int main(int argc, char **argv) NULL, test_visitor_in_int); input_visitor_test_add("/visitor/input/int_overflow", NULL, test_visitor_in_int_overflow); + input_visitor_test_add("/visitor/input/int_keyval", + NULL, test_visitor_in_int_keyval); + input_visitor_test_add("/visitor/input/int_str_keyval", + NULL, test_visitor_in_int_str_keyval); + input_visitor_test_add("/visitor/input/int_str_fail", + NULL, test_visitor_in_int_str_fail); input_visitor_test_add("/visitor/input/bool", NULL, test_visitor_in_bool); + input_visitor_test_add("/visitor/input/bool_keyval", + NULL, test_visitor_in_bool_keyval); + input_visitor_test_add("/visitor/input/bool_str_keyval", + NULL, test_visitor_in_bool_str_keyval); + input_visitor_test_add("/visitor/input/bool_str_fail", + NULL, test_visitor_in_bool_str_fail); input_visitor_test_add("/visitor/input/number", NULL, test_visitor_in_number); + input_visitor_test_add("/visitor/input/number_keyval", + NULL, test_visitor_in_number_keyval); + input_visitor_test_add("/visitor/input/number_str_keyval", + NULL, test_visitor_in_number_str_keyval); + input_visitor_test_add("/visitor/input/number_str_fail", + NULL, test_visitor_in_number_str_fail); + input_visitor_test_add("/visitor/input/size_str_keyval", + NULL, test_visitor_in_size_str_keyval); + input_visitor_test_add("/visitor/input/size_str_fail", + NULL, test_visitor_in_size_str_fail); input_visitor_test_add("/visitor/input/string", NULL, test_visitor_in_string); input_visitor_test_add("/visitor/input/enum", diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index c7e64f0..4d47cee 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -1037,7 +1037,7 @@ static void qmp_deserialize(void **native_out, void *datap, visit_complete(d->qov, &d->obj); obj_orig = d->obj; output_json = qobject_to_json(obj_orig); - obj = qobject_from_json(qstring_get_str(output_json)); + obj = qobject_from_json(qstring_get_str(output_json), &error_abort); QDECREF(output_json); d->qiv = qobject_input_visitor_new(obj); |