diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-05-23 14:16:34 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-05-23 14:16:35 -0500 |
commit | 64afc2b4d48fb21e085517c38a59a3f61a11283c (patch) | |
tree | bd5bb47861b2fa77d81d37dd684e1be46005ceec | |
parent | 95de21a430f7bc4166a153b1f69b1425c8a99c7b (diff) | |
parent | 70e098af88f79340d420992af526254866a42ddd (diff) |
Merge remote-tracking branch 'luiz/queue/qmp' into staging
# By Michael Roth (10) and others
# Via Luiz Capitulino
* luiz/queue/qmp:
monitor: allow to disable the default monitor
ui/input.c: replace magic numbers with macros
qapi: add native list coverage for QMP input visitor tests
qapi: add native list coverage for QMP output visitor tests
qapi: add native list coverage for visitor serialization tests
qapi: fix visitor serialization tests for numbers/doubles
qapi: add QMP input test for large integers
json-parser: fix handling of large whole number values
qapi: enable generation of native list code
qapi: qapi-visit.py, native list support
qapi: qapi-visit.py, fix list handling for union types
qapi: qapi-types.py, native list support
Message-id: 1369333232-24145-1-git-send-email-lcapitulino@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | qapi-schema-test.json | 15 | ||||
-rw-r--r-- | qemu-options.hx | 1 | ||||
-rw-r--r-- | qobject/json-parser.c | 26 | ||||
-rw-r--r-- | scripts/qapi-types.py | 45 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 36 | ||||
-rw-r--r-- | scripts/qapi.py | 23 | ||||
-rw-r--r-- | tests/test-qmp-input-visitor.c | 358 | ||||
-rw-r--r-- | tests/test-qmp-output-visitor.c | 332 | ||||
-rw-r--r-- | tests/test-visitor-serialization.c | 476 | ||||
-rw-r--r-- | ui/input.c | 13 | ||||
-rw-r--r-- | vl.c | 4 |
12 files changed, 1278 insertions, 57 deletions
@@ -178,7 +178,7 @@ Makefile: $(version-obj-y) $(version-lobj-y) # Build libraries libqemustub.a: $(stub-obj-y) -libqemuutil.a: $(util-obj-y) +libqemuutil.a: $(util-obj-y) qapi-types.o qapi-visit.o ###################################################################### @@ -215,10 +215,10 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) qapi-types.c qapi-types.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." -b < $<, " GEN $@") qapi-visit.c qapi-visit.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." -b < $<, " GEN $@") qmp-commands.h qmp-marshal.c :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") diff --git a/qapi-schema-test.json b/qapi-schema-test.json index 9eae3501d7..4434fa3961 100644 --- a/qapi-schema-test.json +++ b/qapi-schema-test.json @@ -32,6 +32,21 @@ { 'union': 'UserDefUnion', 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } +# for testing native lists +{ 'union': 'UserDefNativeListUnion', + 'data': { 'integer': ['int'], + 's8': ['int8'], + 's16': ['int16'], + 's32': ['int32'], + 's64': ['int64'], + 'u8': ['uint8'], + 'u16': ['uint16'], + 'u32': ['uint32'], + 'u64': ['uint64'], + 'number': ['number'], + 'boolean': ['bool'], + 'string': ['str'] } } + # testing commands { 'command': 'user_def_cmd', 'data': {} } { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} } diff --git a/qemu-options.hx b/qemu-options.hx index fb3961d8f7..bf94862b58 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2528,6 +2528,7 @@ Redirect the monitor to host device @var{dev} (same devices as the serial port). The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. +Use @code{-monitor none} to disable the default monitor. ETEXI DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \ "-qmp dev like -monitor but opens in 'control' mode\n", diff --git a/qobject/json-parser.c b/qobject/json-parser.c index 05279c11eb..e7947b340c 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -640,9 +640,29 @@ static QObject *parse_literal(JSONParserContext *ctxt) case JSON_STRING: obj = QOBJECT(qstring_from_escaped_str(ctxt, token)); break; - case JSON_INTEGER: - obj = QOBJECT(qint_from_int(strtoll(token_get_value(token), NULL, 10))); - break; + case JSON_INTEGER: { + /* A possibility exists that this is a whole-valued float where the + * fractional part was left out due to being 0 (.0). It's not a big + * deal to treat these as ints in the parser, so long as users of the + * resulting QObject know to expect a QInt in place of a QFloat in + * cases like these. + * + * However, in some cases these values will overflow/underflow a + * QInt/int64 container, thus we should assume these are to be handled + * as QFloats/doubles rather than silently changing their values. + * + * strtoll() indicates these instances by setting errno to ERANGE + */ + int64_t value; + + errno = 0; /* strtoll doesn't set errno on success */ + value = strtoll(token_get_value(token), NULL, 10); + if (errno != ERANGE) { + obj = QOBJECT(qint_from_int(value)); + break; + } + /* fall through to JSON_FLOAT */ + } case JSON_FLOAT: /* FIXME dependent on locale */ obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL))); diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 9e19920970..fd42d71da1 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -16,8 +16,21 @@ import os import getopt import errno -def generate_fwd_struct(name, members): +def generate_fwd_struct(name, members, builtin_type=False): + if builtin_type: + return mcgen(''' + +typedef struct %(name)sList +{ + %(type)s value; + struct %(name)sList *next; +} %(name)sList; +''', + type=c_type(name), + name=name) + return mcgen(''' + typedef struct %(name)s %(name)s; typedef struct %(name)sList @@ -164,6 +177,7 @@ void qapi_free_%(type)s(%(c_type)s obj); def generate_type_cleanup(name): ret = mcgen(''' + void qapi_free_%(type)s(%(c_type)s obj) { QapiDeallocVisitor *md; @@ -184,8 +198,9 @@ void qapi_free_%(type)s(%(c_type)s obj) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", - ["source", "header", "prefix=", "output-dir="]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", + ["source", "header", "builtins", + "prefix=", "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -197,6 +212,7 @@ h_file = 'qapi-types.h' do_c = False do_h = False +do_builtins = False for o, a in opts: if o in ("-p", "--prefix"): @@ -207,6 +223,8 @@ for o, a in opts: do_c = True elif o in ("-h", "--header"): do_h = True + elif o in ("-b", "--builtins"): + do_builtins = True if not do_c and not do_h: do_c = True @@ -282,6 +300,11 @@ fdecl.write(mcgen(''' exprs = parse_schema(sys.stdin) exprs = filter(lambda expr: not expr.has_key('gen'), exprs) +fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL")) +for typename in builtin_types: + fdecl.write(generate_fwd_struct(typename, None, builtin_type=True)) +fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL")) + for expr in exprs: ret = "\n" if expr.has_key('type'): @@ -298,6 +321,22 @@ for expr in exprs: continue fdecl.write(ret) +# to avoid header dependency hell, we always generate declarations +# for built-in types in our header files and simply guard them +fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL")) +for typename in builtin_types: + fdecl.write(generate_type_cleanup_decl(typename + "List")) +fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL")) + +# ...this doesn't work for cases where we link in multiple objects that +# have the functions defined, so we use -b option to provide control +# over these cases +if do_builtins: + fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF")) + for typename in builtin_types: + fdef.write(generate_type_cleanup(typename + "List")) + fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF")) + for expr in exprs: ret = "\n" if expr.has_key('type'): diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index a276540a18..6cac05acd5 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -174,7 +174,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** ''', abbrev = de_camel_case(name).upper(), enum = c_fun(de_camel_case(key),False).upper(), - c_type=members[key], + c_type=type_name(members[key]), c_name=c_fun(key)) ret += mcgen(''' @@ -202,12 +202,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** return ret -def generate_declaration(name, members, genlist=True): - ret = mcgen(''' +def generate_declaration(name, members, genlist=True, builtin_type=False): + ret = "" + if not builtin_type: + ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp); ''', - name=name) + name=name) if genlist: ret += mcgen(''' @@ -235,8 +237,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e name=name) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", - ["source", "header", "prefix=", "output-dir="]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:", + ["source", "header", "builtins", "prefix=", + "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -248,6 +251,7 @@ h_file = 'qapi-visit.h' do_c = False do_h = False +do_builtins = False for o, a in opts: if o in ("-p", "--prefix"): @@ -258,6 +262,8 @@ for o, a in opts: do_c = True elif o in ("-h", "--header"): do_h = True + elif o in ("-b", "--builtins"): + do_builtins = True if not do_c and not do_h: do_c = True @@ -324,11 +330,29 @@ fdecl.write(mcgen(''' #include "qapi/visitor.h" #include "%(prefix)sqapi-types.h" + ''', prefix=prefix, guard=guardname(h_file))) exprs = parse_schema(sys.stdin) +# to avoid header dependency hell, we always generate declarations +# for built-in types in our header files and simply guard them +fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) +for typename in builtin_types: + fdecl.write(generate_declaration(typename, None, genlist=True, + builtin_type=True)) +fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) + +# ...this doesn't work for cases where we link in multiple objects that +# have the functions defined, so we use -b option to provide control +# over these cases +if do_builtins: + fdef.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DEF")) + for typename in builtin_types: + fdef.write(generate_visit_list(typename, None)) + fdef.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DEF")) + for expr in exprs: if expr.has_key('type'): ret = generate_visit_struct(expr['type'], expr['data']) diff --git a/scripts/qapi.py b/scripts/qapi.py index afc5f32aeb..02ad668ca3 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -11,6 +11,12 @@ from ordereddict import OrderedDict +builtin_types = [ + 'str', 'int', 'number', 'bool', + 'int8', 'int16', 'int32', 'int64', + 'uint8', 'uint16', 'uint32', 'uint64' +] + def tokenize(data): while len(data): ch = data[0] @@ -242,3 +248,20 @@ def guardname(filename): for substr in [".", " ", "-"]: guard = guard.replace(substr, "_") return guard.upper() + '_H' + +def guardstart(name): + return mcgen(''' + +#ifndef %(name)s +#define %(name)s + +''', + name=guardname(name)) + +def guardend(name): + return mcgen(''' + +#endif /* %(name)s */ + +''', + name=guardname(name)) diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 955a4c0b0a..2741eef3fa 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -61,6 +61,31 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data, return v; } +/* similar to visitor_input_test_init(), but does not expect a string + * literal/format json_string argument and so can be used for + * programatically generated strings (and we can't pass in programatically + * generated strings via %s format parameters since qobject_from_jsonv() + * will wrap those in double-quotes and treat the entire object as a + * string) + */ +static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data, + const char *json_string) +{ + Visitor *v; + + data->obj = qobject_from_json(json_string); + + g_assert(data->obj != NULL); + + data->qiv = qmp_input_visitor_new(data->obj); + g_assert(data->qiv != NULL); + + v = qmp_input_get_visitor(data->qiv); + g_assert(v != NULL); + + return v; +} + static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { @@ -75,6 +100,24 @@ static void test_visitor_in_int(TestInputVisitorData *data, g_assert_cmpint(res, ==, value); } +static void test_visitor_in_int_overflow(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0; + Error *errp = NULL; + Visitor *v; + + /* this will overflow a Qint/int64, so should be deserialized into + * a QFloat/double field instead, leading to an error if we pass it + * to visit_type_int. confirm this. + */ + v = visitor_input_test_init(data, "%f", DBL_MAX); + + visit_type_int(v, &res, NULL, &errp); + g_assert(error_is_set(&errp)); + error_free(errp); +} + static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { @@ -259,6 +302,287 @@ static void test_visitor_in_union(TestInputVisitorData *data, qapi_free_UserDefUnion(tmp); } +static void test_native_list_integer_helper(TestInputVisitorData *data, + const void *unused, + UserDefNativeListUnionKind kind) +{ + UserDefNativeListUnion *cvalue = NULL; + Error *err = NULL; + Visitor *v; + GString *gstr_list = g_string_new(""); + GString *gstr_union = g_string_new(""); + int i; + + for (i = 0; i < 32; i++) { + g_string_append_printf(gstr_list, "%d", i); + if (i != 31) { + g_string_append(gstr_list, ", "); + } + } + g_string_append_printf(gstr_union, "{ 'type': '%s', 'data': [ %s ] }", + UserDefNativeListUnionKind_lookup[kind], + gstr_list->str); + v = visitor_input_test_init_raw(data, gstr_union->str); + + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); + g_assert(err == NULL); + g_assert(cvalue != NULL); + g_assert_cmpint(cvalue->kind, ==, kind); + + switch (kind) { + case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: { + intList *elem = NULL; + for (i = 0, elem = cvalue->integer; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S8: { + int8List *elem = NULL; + for (i = 0, elem = cvalue->s8; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S16: { + int16List *elem = NULL; + for (i = 0, elem = cvalue->s16; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S32: { + int32List *elem = NULL; + for (i = 0, elem = cvalue->s32; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S64: { + int64List *elem = NULL; + for (i = 0, elem = cvalue->s64; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U8: { + uint8List *elem = NULL; + for (i = 0, elem = cvalue->u8; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U16: { + uint16List *elem = NULL; + for (i = 0, elem = cvalue->u16; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U32: { + uint32List *elem = NULL; + for (i = 0, elem = cvalue->u32; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U64: { + uint64List *elem = NULL; + for (i = 0, elem = cvalue->u64; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, i); + } + break; + } + default: + g_assert(false); + } + + g_string_free(gstr_union, true); + g_string_free(gstr_list, true); + qapi_free_UserDefNativeListUnion(cvalue); +} + +static void test_visitor_in_native_list_int(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER); +} + +static void test_visitor_in_native_list_int8(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_S8); +} + +static void test_visitor_in_native_list_int16(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_S16); +} + +static void test_visitor_in_native_list_int32(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_S32); +} + +static void test_visitor_in_native_list_int64(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_S64); +} + +static void test_visitor_in_native_list_uint8(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_U8); +} + +static void test_visitor_in_native_list_uint16(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_U16); +} + +static void test_visitor_in_native_list_uint32(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_U32); +} + +static void test_visitor_in_native_list_uint64(TestInputVisitorData *data, + const void *unused) +{ + test_native_list_integer_helper(data, unused, + USER_DEF_NATIVE_LIST_UNION_KIND_U64); +} + +static void test_visitor_in_native_list_bool(TestInputVisitorData *data, + const void *unused) +{ + UserDefNativeListUnion *cvalue = NULL; + boolList *elem = NULL; + Error *err = NULL; + Visitor *v; + GString *gstr_list = g_string_new(""); + GString *gstr_union = g_string_new(""); + int i; + + for (i = 0; i < 32; i++) { + g_string_append_printf(gstr_list, "%s", + (i % 3 == 0) ? "true" : "false"); + if (i != 31) { + g_string_append(gstr_list, ", "); + } + } + g_string_append_printf(gstr_union, "{ 'type': 'boolean', 'data': [ %s ] }", + gstr_list->str); + v = visitor_input_test_init_raw(data, gstr_union->str); + + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); + g_assert(err == NULL); + g_assert(cvalue != NULL); + g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN); + + for (i = 0, elem = cvalue->boolean; elem; elem = elem->next, i++) { + g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0); + } + + g_string_free(gstr_union, true); + g_string_free(gstr_list, true); + qapi_free_UserDefNativeListUnion(cvalue); +} + +static void test_visitor_in_native_list_string(TestInputVisitorData *data, + const void *unused) +{ + UserDefNativeListUnion *cvalue = NULL; + strList *elem = NULL; + Error *err = NULL; + Visitor *v; + GString *gstr_list = g_string_new(""); + GString *gstr_union = g_string_new(""); + int i; + + for (i = 0; i < 32; i++) { + g_string_append_printf(gstr_list, "'%d'", i); + if (i != 31) { + g_string_append(gstr_list, ", "); + } + } + g_string_append_printf(gstr_union, "{ 'type': 'string', 'data': [ %s ] }", + gstr_list->str); + v = visitor_input_test_init_raw(data, gstr_union->str); + + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); + g_assert(err == NULL); + g_assert(cvalue != NULL); + g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING); + + for (i = 0, elem = cvalue->string; elem; elem = elem->next, i++) { + gchar str[8]; + sprintf(str, "%d", i); + g_assert_cmpstr(elem->value, ==, str); + } + + g_string_free(gstr_union, true); + g_string_free(gstr_list, true); + qapi_free_UserDefNativeListUnion(cvalue); +} + +#define DOUBLE_STR_MAX 16 + +static void test_visitor_in_native_list_number(TestInputVisitorData *data, + const void *unused) +{ + UserDefNativeListUnion *cvalue = NULL; + numberList *elem = NULL; + Error *err = NULL; + Visitor *v; + GString *gstr_list = g_string_new(""); + GString *gstr_union = g_string_new(""); + int i; + + for (i = 0; i < 32; i++) { + g_string_append_printf(gstr_list, "%f", (double)i / 3); + if (i != 31) { + g_string_append(gstr_list, ", "); + } + } + g_string_append_printf(gstr_union, "{ 'type': 'number', 'data': [ %s ] }", + gstr_list->str); + v = visitor_input_test_init_raw(data, gstr_union->str); + + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); + g_assert(err == NULL); + g_assert(cvalue != NULL); + g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER); + + for (i = 0, elem = cvalue->number; elem; elem = elem->next, i++) { + GString *double_expected = g_string_new(""); + GString *double_actual = g_string_new(""); + + g_string_printf(double_expected, "%.6f", (double)i / 3); + g_string_printf(double_actual, "%.6f", elem->value); + g_assert_cmpstr(double_expected->str, ==, double_actual->str); + + g_string_free(double_expected, true); + g_string_free(double_actual, true); + } + + g_string_free(gstr_union, true); + g_string_free(gstr_list, true); + qapi_free_UserDefNativeListUnion(cvalue); +} + static void input_visitor_test_add(const char *testpath, TestInputVisitorData *data, void (*test_func)(TestInputVisitorData *data, const void *user_data)) @@ -292,6 +616,8 @@ int main(int argc, char **argv) input_visitor_test_add("/visitor/input/int", &in_visitor_data, test_visitor_in_int); + input_visitor_test_add("/visitor/input/int_overflow", + &in_visitor_data, test_visitor_in_int_overflow); input_visitor_test_add("/visitor/input/bool", &in_visitor_data, test_visitor_in_bool); input_visitor_test_add("/visitor/input/number", @@ -310,6 +636,38 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_union); input_visitor_test_add("/visitor/input/errors", &in_visitor_data, test_visitor_in_errors); + input_visitor_test_add("/visitor/input/native_list/int", + &in_visitor_data, + test_visitor_in_native_list_int); + input_visitor_test_add("/visitor/input/native_list/int8", + &in_visitor_data, + test_visitor_in_native_list_int8); + input_visitor_test_add("/visitor/input/native_list/int16", + &in_visitor_data, + test_visitor_in_native_list_int16); + input_visitor_test_add("/visitor/input/native_list/int32", + &in_visitor_data, + test_visitor_in_native_list_int32); + input_visitor_test_add("/visitor/input/native_list/int64", + &in_visitor_data, + test_visitor_in_native_list_int64); + input_visitor_test_add("/visitor/input/native_list/uint8", + &in_visitor_data, + test_visitor_in_native_list_uint8); + input_visitor_test_add("/visitor/input/native_list/uint16", + &in_visitor_data, + test_visitor_in_native_list_uint16); + input_visitor_test_add("/visitor/input/native_list/uint32", + &in_visitor_data, + test_visitor_in_native_list_uint32); + input_visitor_test_add("/visitor/input/native_list/uint64", + &in_visitor_data, test_visitor_in_native_list_uint64); + input_visitor_test_add("/visitor/input/native_list/bool", + &in_visitor_data, test_visitor_in_native_list_bool); + input_visitor_test_add("/visitor/input/native_list/str", + &in_visitor_data, test_visitor_in_native_list_string); + input_visitor_test_add("/visitor/input/native_list/number", + &in_visitor_data, test_visitor_in_native_list_number); g_test_run(); diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index 71367e6efa..0942a41875 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -431,6 +431,314 @@ static void test_visitor_out_union(TestOutputVisitorData *data, QDECREF(qdict); } +static void init_native_list(UserDefNativeListUnion *cvalue) +{ + int i; + switch (cvalue->kind) { + case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: { + intList **list = &cvalue->integer; + for (i = 0; i < 32; i++) { + *list = g_new0(intList, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S8: { + int8List **list = &cvalue->s8; + for (i = 0; i < 32; i++) { + *list = g_new0(int8List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S16: { + int16List **list = &cvalue->s16; + for (i = 0; i < 32; i++) { + *list = g_new0(int16List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S32: { + int32List **list = &cvalue->s32; + for (i = 0; i < 32; i++) { + *list = g_new0(int32List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_S64: { + int64List **list = &cvalue->s64; + for (i = 0; i < 32; i++) { + *list = g_new0(int64List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U8: { + uint8List **list = &cvalue->u8; + for (i = 0; i < 32; i++) { + *list = g_new0(uint8List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U16: { + uint16List **list = &cvalue->u16; + for (i = 0; i < 32; i++) { + *list = g_new0(uint16List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U32: { + uint32List **list = &cvalue->u32; + for (i = 0; i < 32; i++) { + *list = g_new0(uint32List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_U64: { + uint64List **list = &cvalue->u64; + for (i = 0; i < 32; i++) { + *list = g_new0(uint64List, 1); + (*list)->value = i; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: { + boolList **list = &cvalue->boolean; + for (i = 0; i < 32; i++) { + *list = g_new0(boolList, 1); + (*list)->value = (i % 3 == 0); + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: { + strList **list = &cvalue->string; + for (i = 0; i < 32; i++) { + *list = g_new0(strList, 1); + (*list)->value = g_strdup_printf("%d", i); + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: { + numberList **list = &cvalue->number; + for (i = 0; i < 32; i++) { + *list = g_new0(numberList, 1); + (*list)->value = (double)i / 3; + (*list)->next = NULL; + list = &(*list)->next; + } + break; + } + default: + g_assert(false); + } +} + +static void check_native_list(QObject *qobj, + UserDefNativeListUnionKind kind) +{ + QDict *qdict; + QList *qlist; + int i; + + g_assert(qobj); + g_assert(qobject_type(qobj) == QTYPE_QDICT); + qdict = qobject_to_qdict(qobj); + g_assert(qdict); + g_assert(qdict_haskey(qdict, "data")); + qlist = qlist_copy(qobject_to_qlist(qdict_get(qdict, "data"))); + + switch (kind) { + case USER_DEF_NATIVE_LIST_UNION_KIND_S8: + case USER_DEF_NATIVE_LIST_UNION_KIND_S16: + case USER_DEF_NATIVE_LIST_UNION_KIND_S32: + case USER_DEF_NATIVE_LIST_UNION_KIND_S64: + case USER_DEF_NATIVE_LIST_UNION_KIND_U8: + case USER_DEF_NATIVE_LIST_UNION_KIND_U16: + case USER_DEF_NATIVE_LIST_UNION_KIND_U32: + case USER_DEF_NATIVE_LIST_UNION_KIND_U64: + /* all integer elements in JSON arrays get stored into QInts when + * we convert to QObjects, so we can check them all in the same + * fashion, so simply fall through here + */ + case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: + for (i = 0; i < 32; i++) { + QObject *tmp; + QInt *qvalue; + tmp = qlist_peek(qlist); + g_assert(tmp); + qvalue = qobject_to_qint(tmp); + g_assert_cmpint(qint_get_int(qvalue), ==, i); + qobject_decref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: + for (i = 0; i < 32; i++) { + QObject *tmp; + QBool *qvalue; + tmp = qlist_peek(qlist); + g_assert(tmp); + qvalue = qobject_to_qbool(tmp); + g_assert_cmpint(qbool_get_int(qvalue), ==, (i % 3 == 0) ? 1 : 0); + qobject_decref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: + for (i = 0; i < 32; i++) { + QObject *tmp; + QString *qvalue; + gchar str[8]; + tmp = qlist_peek(qlist); + g_assert(tmp); + qvalue = qobject_to_qstring(tmp); + sprintf(str, "%d", i); + g_assert_cmpstr(qstring_get_str(qvalue), ==, str); + qobject_decref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: + for (i = 0; i < 32; i++) { + QObject *tmp; + QFloat *qvalue; + GString *double_expected = g_string_new(""); + GString *double_actual = g_string_new(""); + + tmp = qlist_peek(qlist); + g_assert(tmp); + qvalue = qobject_to_qfloat(tmp); + g_string_printf(double_expected, "%.6f", (double)i / 3); + g_string_printf(double_actual, "%.6f", qfloat_get_double(qvalue)); + g_assert_cmpstr(double_actual->str, ==, double_expected->str); + + qobject_decref(qlist_pop(qlist)); + g_string_free(double_expected, true); + g_string_free(double_actual, true); + } + break; + default: + g_assert(false); + } + QDECREF(qlist); +} + +static void test_native_list(TestOutputVisitorData *data, + const void *unused, + UserDefNativeListUnionKind kind) +{ + UserDefNativeListUnion *cvalue = g_new0(UserDefNativeListUnion, 1); + Error *err = NULL; + QObject *obj; + + cvalue->kind = kind; + init_native_list(cvalue); + + visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &err); + g_assert(err == NULL); + + obj = qmp_output_get_qobject(data->qov); + check_native_list(obj, cvalue->kind); + qapi_free_UserDefNativeListUnion(cvalue); + qobject_decref(obj); +} + +static void test_visitor_out_native_list_int(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER); +} + +static void test_visitor_out_native_list_int8(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S8); +} + +static void test_visitor_out_native_list_int16(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S16); +} + +static void test_visitor_out_native_list_int32(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S32); +} + +static void test_visitor_out_native_list_int64(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S64); +} + +static void test_visitor_out_native_list_uint8(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U8); +} + +static void test_visitor_out_native_list_uint16(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U16); +} + +static void test_visitor_out_native_list_uint32(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U32); +} + +static void test_visitor_out_native_list_uint64(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U64); +} + +static void test_visitor_out_native_list_bool(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN); +} + +static void test_visitor_out_native_list_str(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_STRING); +} + +static void test_visitor_out_native_list_number(TestOutputVisitorData *data, + const void *unused) +{ + test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER); +} + static void output_visitor_test_add(const char *testpath, TestOutputVisitorData *data, void (*test_func)(TestOutputVisitorData *data, const void *user_data)) @@ -471,6 +779,30 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_list_qapi_free); output_visitor_test_add("/visitor/output/union", &out_visitor_data, test_visitor_out_union); + output_visitor_test_add("/visitor/output/native_list/int", + &out_visitor_data, test_visitor_out_native_list_int); + output_visitor_test_add("/visitor/output/native_list/int8", + &out_visitor_data, test_visitor_out_native_list_int8); + output_visitor_test_add("/visitor/output/native_list/int16", + &out_visitor_data, test_visitor_out_native_list_int16); + output_visitor_test_add("/visitor/output/native_list/int32", + &out_visitor_data, test_visitor_out_native_list_int32); + output_visitor_test_add("/visitor/output/native_list/int64", + &out_visitor_data, test_visitor_out_native_list_int64); + output_visitor_test_add("/visitor/output/native_list/uint8", + &out_visitor_data, test_visitor_out_native_list_uint8); + output_visitor_test_add("/visitor/output/native_list/uint16", + &out_visitor_data, test_visitor_out_native_list_uint16); + output_visitor_test_add("/visitor/output/native_list/uint32", + &out_visitor_data, test_visitor_out_native_list_uint32); + output_visitor_test_add("/visitor/output/native_list/uint64", + &out_visitor_data, test_visitor_out_native_list_uint64); + output_visitor_test_add("/visitor/output/native_list/bool", + &out_visitor_data, test_visitor_out_native_list_bool); + output_visitor_test_add("/visitor/output/native_list/string", + &out_visitor_data, test_visitor_out_native_list_str); + output_visitor_test_add("/visitor/output/native_list/number", + &out_visitor_data, test_visitor_out_native_list_number); g_test_run(); diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index 8c8adac6a9..ee7916b806 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -23,6 +23,25 @@ #include "qapi/qmp-output-visitor.h" #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" +#include "qapi-types.h" +#include "qapi-visit.h" +#include "qapi/dealloc-visitor.h" + +enum PrimitiveTypeKind { + PTYPE_STRING = 0, + PTYPE_BOOLEAN, + PTYPE_NUMBER, + PTYPE_INTEGER, + PTYPE_U8, + PTYPE_U16, + PTYPE_U32, + PTYPE_U64, + PTYPE_S8, + PTYPE_S16, + PTYPE_S32, + PTYPE_S64, + PTYPE_EOL, +}; typedef struct PrimitiveType { union { @@ -40,26 +59,42 @@ typedef struct PrimitiveType { int64_t s64; intmax_t max; } value; - enum { - PTYPE_STRING = 0, - PTYPE_BOOLEAN, - PTYPE_NUMBER, - PTYPE_INTEGER, - PTYPE_U8, - PTYPE_U16, - PTYPE_U32, - PTYPE_U64, - PTYPE_S8, - PTYPE_S16, - PTYPE_S32, - PTYPE_S64, - PTYPE_EOL, - } type; + enum PrimitiveTypeKind type; const char *description; } PrimitiveType; +typedef struct PrimitiveList { + union { + strList *strings; + boolList *booleans; + numberList *numbers; + intList *integers; + int8List *s8_integers; + int16List *s16_integers; + int32List *s32_integers; + int64List *s64_integers; + uint8List *u8_integers; + uint16List *u16_integers; + uint32List *u32_integers; + uint64List *u64_integers; + } value; + enum PrimitiveTypeKind type; + const char *description; +} PrimitiveList; + /* test helpers */ +typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); + +static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp) +{ + QapiDeallocVisitor *qdv = qapi_dealloc_visitor_new(); + + visit(qapi_dealloc_get_visitor(qdv), &native_in, errp); + + qapi_dealloc_visitor_cleanup(qdv); +} + static void visit_primitive_type(Visitor *v, void **native, Error **errp) { PrimitiveType *pt = *native; @@ -105,6 +140,51 @@ static void visit_primitive_type(Visitor *v, void **native, Error **errp) } } +static void visit_primitive_list(Visitor *v, void **native, Error **errp) +{ + PrimitiveList *pl = *native; + switch (pl->type) { + case PTYPE_STRING: + visit_type_strList(v, &pl->value.strings, NULL, errp); + break; + case PTYPE_BOOLEAN: + visit_type_boolList(v, &pl->value.booleans, NULL, errp); + break; + case PTYPE_NUMBER: + visit_type_numberList(v, &pl->value.numbers, NULL, errp); + break; + case PTYPE_INTEGER: + visit_type_intList(v, &pl->value.integers, NULL, errp); + break; + case PTYPE_S8: + visit_type_int8List(v, &pl->value.s8_integers, NULL, errp); + break; + case PTYPE_S16: + visit_type_int16List(v, &pl->value.s16_integers, NULL, errp); + break; + case PTYPE_S32: + visit_type_int32List(v, &pl->value.s32_integers, NULL, errp); + break; + case PTYPE_S64: + visit_type_int64List(v, &pl->value.s64_integers, NULL, errp); + break; + case PTYPE_U8: + visit_type_uint8List(v, &pl->value.u8_integers, NULL, errp); + break; + case PTYPE_U16: + visit_type_uint16List(v, &pl->value.u16_integers, NULL, errp); + break; + case PTYPE_U32: + visit_type_uint32List(v, &pl->value.u32_integers, NULL, errp); + break; + case PTYPE_U64: + visit_type_uint64List(v, &pl->value.u64_integers, NULL, errp); + break; + default: + g_assert(false); + } +} + typedef struct TestStruct { int64_t integer; @@ -206,12 +286,11 @@ static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) /* test cases */ -typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); - typedef enum VisitorCapabilities { VCAP_PRIMITIVES = 1, VCAP_STRUCTURES = 2, VCAP_LISTS = 4, + VCAP_PRIMITIVE_LISTS = 8, } VisitorCapabilities; typedef struct SerializeOps { @@ -229,17 +308,6 @@ typedef struct TestArgs { void *test_data; } TestArgs; -#define FLOAT_STRING_PRECISION 6 /* corresponding to n in %.nf formatting */ -static gsize calc_float_string_storage(double value) -{ - int whole_value = value; - gsize i = 0; - do { - i++; - } while (whole_value /= 10); - return i + 2 + FLOAT_STRING_PRECISION; -} - static void test_primitives(gconstpointer opaque) { TestArgs *args = (TestArgs *) opaque; @@ -248,7 +316,6 @@ static void test_primitives(gconstpointer opaque) PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); Error *err = NULL; void *serialize_data; - char *double1, *double2; pt_copy->type = pt->type; ops->serialize(pt, &serialize_data, visit_primitive_type, &err); @@ -260,14 +327,17 @@ static void test_primitives(gconstpointer opaque) g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); g_free((char *)pt_copy->value.string); } else if (pt->type == PTYPE_NUMBER) { + GString *double_expected = g_string_new(""); + GString *double_actual = g_string_new(""); /* we serialize with %f for our reference visitors, so rather than fuzzy * floating math to test "equality", just compare the formatted values */ - double1 = g_malloc0(calc_float_string_storage(pt->value.number)); - double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number)); - g_assert_cmpstr(double1, ==, double2); - g_free(double1); - g_free(double2); + g_string_printf(double_expected, "%.6f", pt->value.number); + g_string_printf(double_actual, "%.6f", pt_copy->value.number); + g_assert_cmpstr(double_actual->str, ==, double_expected->str); + + g_string_free(double_expected, true); + g_string_free(double_actual, true); } else if (pt->type == PTYPE_BOOLEAN) { g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max); } else { @@ -279,6 +349,328 @@ static void test_primitives(gconstpointer opaque) g_free(pt_copy); } +static void test_primitive_lists(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + PrimitiveType *pt = args->test_data; + PrimitiveList pl = { .value = { 0 } }; + PrimitiveList pl_copy = { .value = { 0 } }; + PrimitiveList *pl_copy_ptr = &pl_copy; + Error *err = NULL; + void *serialize_data; + void *cur_head = NULL; + int i; + + pl.type = pl_copy.type = pt->type; + + /* build up our list of primitive types */ + for (i = 0; i < 32; i++) { + switch (pl.type) { + case PTYPE_STRING: { + strList *tmp = g_new0(strList, 1); + tmp->value = g_strdup(pt->value.string); + if (pl.value.strings == NULL) { + pl.value.strings = tmp; + } else { + tmp->next = pl.value.strings; + pl.value.strings = tmp; + } + break; + } + case PTYPE_INTEGER: { + intList *tmp = g_new0(intList, 1); + tmp->value = pt->value.integer; + if (pl.value.integers == NULL) { + pl.value.integers = tmp; + } else { + tmp->next = pl.value.integers; + pl.value.integers = tmp; + } + break; + } + case PTYPE_S8: { + int8List *tmp = g_new0(int8List, 1); + tmp->value = pt->value.s8; + if (pl.value.s8_integers == NULL) { + pl.value.s8_integers = tmp; + } else { + tmp->next = pl.value.s8_integers; + pl.value.s8_integers = tmp; + } + break; + } + case PTYPE_S16: { + int16List *tmp = g_new0(int16List, 1); + tmp->value = pt->value.s16; + if (pl.value.s16_integers == NULL) { + pl.value.s16_integers = tmp; + } else { + tmp->next = pl.value.s16_integers; + pl.value.s16_integers = tmp; + } + break; + } + case PTYPE_S32: { + int32List *tmp = g_new0(int32List, 1); + tmp->value = pt->value.s32; + if (pl.value.s32_integers == NULL) { + pl.value.s32_integers = tmp; + } else { + tmp->next = pl.value.s32_integers; + pl.value.s32_integers = tmp; + } + break; + } + case PTYPE_S64: { + int64List *tmp = g_new0(int64List, 1); + tmp->value = pt->value.s64; + if (pl.value.s64_integers == NULL) { + pl.value.s64_integers = tmp; + } else { + tmp->next = pl.value.s64_integers; + pl.value.s64_integers = tmp; + } + break; + } + case PTYPE_U8: { + uint8List *tmp = g_new0(uint8List, 1); + tmp->value = pt->value.u8; + if (pl.value.u8_integers == NULL) { + pl.value.u8_integers = tmp; + } else { + tmp->next = pl.value.u8_integers; + pl.value.u8_integers = tmp; + } + break; + } + case PTYPE_U16: { + uint16List *tmp = g_new0(uint16List, 1); + tmp->value = pt->value.u16; + if (pl.value.u16_integers == NULL) { + pl.value.u16_integers = tmp; + } else { + tmp->next = pl.value.u16_integers; + pl.value.u16_integers = tmp; + } + break; + } + case PTYPE_U32: { + uint32List *tmp = g_new0(uint32List, 1); + tmp->value = pt->value.u32; + if (pl.value.u32_integers == NULL) { + pl.value.u32_integers = tmp; + } else { + tmp->next = pl.value.u32_integers; + pl.value.u32_integers = tmp; + } + break; + } + case PTYPE_U64: { + uint64List *tmp = g_new0(uint64List, 1); + tmp->value = pt->value.u64; + if (pl.value.u64_integers == NULL) { + pl.value.u64_integers = tmp; + } else { + tmp->next = pl.value.u64_integers; + pl.value.u64_integers = tmp; + } + break; + } + case PTYPE_NUMBER: { + numberList *tmp = g_new0(numberList, 1); + tmp->value = pt->value.number; + if (pl.value.numbers == NULL) { + pl.value.numbers = tmp; + } else { + tmp->next = pl.value.numbers; + pl.value.numbers = tmp; + } + break; + } + case PTYPE_BOOLEAN: { + boolList *tmp = g_new0(boolList, 1); + tmp->value = pt->value.boolean; + if (pl.value.booleans == NULL) { + pl.value.booleans = tmp; + } else { + tmp->next = pl.value.booleans; + pl.value.booleans = tmp; + } + break; + } + default: + g_assert(0); + } + } + + ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, &err); + ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &err); + + g_assert(err == NULL); + i = 0; + + /* compare our deserialized list of primitives to the original */ + do { + switch (pl_copy.type) { + case PTYPE_STRING: { + strList *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.strings; + } + g_assert_cmpstr(pt->value.string, ==, ptr->value); + break; + } + case PTYPE_INTEGER: { + intList *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.integers; + } + g_assert_cmpint(pt->value.integer, ==, ptr->value); + break; + } + case PTYPE_S8: { + int8List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.s8_integers; + } + g_assert_cmpint(pt->value.s8, ==, ptr->value); + break; + } + case PTYPE_S16: { + int16List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.s16_integers; + } + g_assert_cmpint(pt->value.s16, ==, ptr->value); + break; + } + case PTYPE_S32: { + int32List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.s32_integers; + } + g_assert_cmpint(pt->value.s32, ==, ptr->value); + break; + } + case PTYPE_S64: { + int64List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.s64_integers; + } + g_assert_cmpint(pt->value.s64, ==, ptr->value); + break; + } + case PTYPE_U8: { + uint8List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.u8_integers; + } + g_assert_cmpint(pt->value.u8, ==, ptr->value); + break; + } + case PTYPE_U16: { + uint16List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.u16_integers; + } + g_assert_cmpint(pt->value.u16, ==, ptr->value); + break; + } + case PTYPE_U32: { + uint32List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.u32_integers; + } + g_assert_cmpint(pt->value.u32, ==, ptr->value); + break; + } + case PTYPE_U64: { + uint64List *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.u64_integers; + } + g_assert_cmpint(pt->value.u64, ==, ptr->value); + break; + } + case PTYPE_NUMBER: { + numberList *ptr; + GString *double_expected = g_string_new(""); + GString *double_actual = g_string_new(""); + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.numbers; + } + /* we serialize with %f for our reference visitors, so rather than + * fuzzy floating math to test "equality", just compare the + * formatted values + */ + g_string_printf(double_expected, "%.6f", pt->value.number); + g_string_printf(double_actual, "%.6f", ptr->value); + g_assert_cmpstr(double_actual->str, ==, double_expected->str); + g_string_free(double_expected, true); + g_string_free(double_actual, true); + break; + } + case PTYPE_BOOLEAN: { + boolList *ptr; + if (cur_head) { + ptr = cur_head; + cur_head = ptr->next; + } else { + cur_head = ptr = pl_copy.value.booleans; + } + g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value); + break; + } + default: + g_assert(0); + } + i++; + } while (cur_head); + + g_assert_cmpint(i, ==, 33); + + ops->cleanup(serialize_data); + dealloc_helper(&pl, visit_primitive_list, &err); + g_assert(!err); + dealloc_helper(&pl_copy, visit_primitive_list, &err); + g_assert(!err); + g_free(args); +} + static void test_struct(gconstpointer opaque) { TestArgs *args = (TestArgs *) opaque; @@ -728,7 +1120,8 @@ static const SerializeOps visitors[] = { .serialize = qmp_serialize, .deserialize = qmp_deserialize, .cleanup = qmp_cleanup, - .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS + .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS | + VCAP_PRIMITIVE_LISTS }, { .type = "String", @@ -782,6 +1175,19 @@ static void add_visitor_type(const SerializeOps *ops) args->test_data = NULL; g_test_add_data_func(testname, args, test_nested_struct_list); } + + if (ops->caps & VCAP_PRIMITIVE_LISTS) { + i = 0; + while (pt_values[i].type != PTYPE_EOL) { + sprintf(testname, "%s/primitive_list/%s", testname_prefix, + pt_values[i].description); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = &pt_values[i]; + g_test_add_data_func(testname, args, test_primitive_lists); + i++; + } + } } int main(int argc, char **argv) diff --git a/ui/input.c b/ui/input.c index 8ca1a03e12..92c44ca810 100644 --- a/ui/input.c +++ b/ui/input.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qmp-commands.h" #include "qapi-types.h" +#include "ui/keymaps.h" struct QEMUPutMouseEntry { QEMUPutMouseEvent *qemu_put_mouse_event; @@ -260,10 +261,10 @@ static void free_keycodes(void) static void release_keys(void *opaque) { while (keycodes_size > 0) { - if (keycodes[--keycodes_size] & 0x80) { - kbd_put_keycode(0xe0); + if (keycodes[--keycodes_size] & SCANCODE_GREY) { + kbd_put_keycode(SCANCODE_EMUL0); } - kbd_put_keycode(keycodes[keycodes_size] | 0x80); + kbd_put_keycode(keycodes[keycodes_size] | SCANCODE_UP); } free_keycodes(); @@ -297,10 +298,10 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, return; } - if (keycode & 0x80) { - kbd_put_keycode(0xe0); + if (keycode & SCANCODE_GREY) { + kbd_put_keycode(SCANCODE_EMUL0); } - kbd_put_keycode(keycode & 0x7f); + kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1)); keycodes[keycodes_size++] = keycode; @@ -3366,8 +3366,10 @@ int main(int argc, char **argv, char **envp) break; } case QEMU_OPTION_monitor: - monitor_parse(optarg, "readline"); default_monitor = 0; + if (strncmp(optarg, "none", 4)) { + monitor_parse(optarg, "readline"); + } break; case QEMU_OPTION_qmp: monitor_parse(optarg, "control"); |