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>
This commit is contained in:
Anthony Liguori 2013-05-23 14:16:34 -05:00
commit 64afc2b4d4
12 changed files with 1278 additions and 57 deletions

View File

@ -178,7 +178,7 @@ Makefile: $(version-obj-y) $(version-lobj-y)
# Build libraries # Build libraries
libqemustub.a: $(stub-obj-y) 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 :\ qapi-types.c qapi-types.h :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(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 :\ qapi-visit.c qapi-visit.h :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(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 :\ qmp-commands.h qmp-marshal.c :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(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 $@") $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")

View File

@ -32,6 +32,21 @@
{ 'union': 'UserDefUnion', { 'union': 'UserDefUnion',
'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } '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 # testing commands
{ 'command': 'user_def_cmd', 'data': {} } { 'command': 'user_def_cmd', 'data': {} }
{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} } { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }

View File

@ -2528,6 +2528,7 @@ Redirect the monitor to host device @var{dev} (same devices as the
serial port). serial port).
The default device is @code{vc} in graphical mode and @code{stdio} in The default device is @code{vc} in graphical mode and @code{stdio} in
non graphical mode. non graphical mode.
Use @code{-monitor none} to disable the default monitor.
ETEXI ETEXI
DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \ DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \
"-qmp dev like -monitor but opens in 'control' mode\n", "-qmp dev like -monitor but opens in 'control' mode\n",

View File

@ -640,9 +640,29 @@ static QObject *parse_literal(JSONParserContext *ctxt)
case JSON_STRING: case JSON_STRING:
obj = QOBJECT(qstring_from_escaped_str(ctxt, token)); obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
break; break;
case JSON_INTEGER: case JSON_INTEGER: {
obj = QOBJECT(qint_from_int(strtoll(token_get_value(token), NULL, 10))); /* A possibility exists that this is a whole-valued float where the
break; * 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: case JSON_FLOAT:
/* FIXME dependent on locale */ /* FIXME dependent on locale */
obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL))); obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL)));

View File

@ -16,8 +16,21 @@ import os
import getopt import getopt
import errno 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(''' return mcgen('''
typedef struct %(name)s %(name)s; typedef struct %(name)s %(name)s;
typedef struct %(name)sList typedef struct %(name)sList
@ -164,6 +177,7 @@ void qapi_free_%(type)s(%(c_type)s obj);
def generate_type_cleanup(name): def generate_type_cleanup(name):
ret = mcgen(''' ret = mcgen('''
void qapi_free_%(type)s(%(c_type)s obj) void qapi_free_%(type)s(%(c_type)s obj)
{ {
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
@ -184,8 +198,9 @@ void qapi_free_%(type)s(%(c_type)s obj)
try: try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
["source", "header", "prefix=", "output-dir="]) ["source", "header", "builtins",
"prefix=", "output-dir="])
except getopt.GetoptError, err: except getopt.GetoptError, err:
print str(err) print str(err)
sys.exit(1) sys.exit(1)
@ -197,6 +212,7 @@ h_file = 'qapi-types.h'
do_c = False do_c = False
do_h = False do_h = False
do_builtins = False
for o, a in opts: for o, a in opts:
if o in ("-p", "--prefix"): if o in ("-p", "--prefix"):
@ -207,6 +223,8 @@ for o, a in opts:
do_c = True do_c = True
elif o in ("-h", "--header"): elif o in ("-h", "--header"):
do_h = True do_h = True
elif o in ("-b", "--builtins"):
do_builtins = True
if not do_c and not do_h: if not do_c and not do_h:
do_c = True do_c = True
@ -282,6 +300,11 @@ fdecl.write(mcgen('''
exprs = parse_schema(sys.stdin) exprs = parse_schema(sys.stdin)
exprs = filter(lambda expr: not expr.has_key('gen'), exprs) 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: for expr in exprs:
ret = "\n" ret = "\n"
if expr.has_key('type'): if expr.has_key('type'):
@ -298,6 +321,22 @@ for expr in exprs:
continue continue
fdecl.write(ret) 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: for expr in exprs:
ret = "\n" ret = "\n"
if expr.has_key('type'): if expr.has_key('type'):

View File

@ -174,7 +174,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
''', ''',
abbrev = de_camel_case(name).upper(), abbrev = de_camel_case(name).upper(),
enum = c_fun(de_camel_case(key),False).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)) c_name=c_fun(key))
ret += mcgen(''' ret += mcgen('''
@ -202,12 +202,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
return ret return ret
def generate_declaration(name, members, genlist=True): def generate_declaration(name, members, genlist=True, builtin_type=False):
ret = mcgen(''' ret = ""
if not builtin_type:
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp); void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
''', ''',
name=name) name=name)
if genlist: if genlist:
ret += mcgen(''' ret += mcgen('''
@ -235,8 +237,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e
name=name) name=name)
try: try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
["source", "header", "prefix=", "output-dir="]) ["source", "header", "builtins", "prefix=",
"output-dir="])
except getopt.GetoptError, err: except getopt.GetoptError, err:
print str(err) print str(err)
sys.exit(1) sys.exit(1)
@ -248,6 +251,7 @@ h_file = 'qapi-visit.h'
do_c = False do_c = False
do_h = False do_h = False
do_builtins = False
for o, a in opts: for o, a in opts:
if o in ("-p", "--prefix"): if o in ("-p", "--prefix"):
@ -258,6 +262,8 @@ for o, a in opts:
do_c = True do_c = True
elif o in ("-h", "--header"): elif o in ("-h", "--header"):
do_h = True do_h = True
elif o in ("-b", "--builtins"):
do_builtins = True
if not do_c and not do_h: if not do_c and not do_h:
do_c = True do_c = True
@ -324,11 +330,29 @@ fdecl.write(mcgen('''
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-types.h"
''', ''',
prefix=prefix, guard=guardname(h_file))) prefix=prefix, guard=guardname(h_file)))
exprs = parse_schema(sys.stdin) 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: for expr in exprs:
if expr.has_key('type'): if expr.has_key('type'):
ret = generate_visit_struct(expr['type'], expr['data']) ret = generate_visit_struct(expr['type'], expr['data'])

View File

@ -11,6 +11,12 @@
from ordereddict import OrderedDict from ordereddict import OrderedDict
builtin_types = [
'str', 'int', 'number', 'bool',
'int8', 'int16', 'int32', 'int64',
'uint8', 'uint16', 'uint32', 'uint64'
]
def tokenize(data): def tokenize(data):
while len(data): while len(data):
ch = data[0] ch = data[0]
@ -242,3 +248,20 @@ def guardname(filename):
for substr in [".", " ", "-"]: for substr in [".", " ", "-"]:
guard = guard.replace(substr, "_") guard = guard.replace(substr, "_")
return guard.upper() + '_H' 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))

View File

@ -61,6 +61,31 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
return v; 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, static void test_visitor_in_int(TestInputVisitorData *data,
const void *unused) const void *unused)
{ {
@ -75,6 +100,24 @@ static void test_visitor_in_int(TestInputVisitorData *data,
g_assert_cmpint(res, ==, value); 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, static void test_visitor_in_bool(TestInputVisitorData *data,
const void *unused) const void *unused)
{ {
@ -259,6 +302,287 @@ static void test_visitor_in_union(TestInputVisitorData *data,
qapi_free_UserDefUnion(tmp); 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, static void input_visitor_test_add(const char *testpath,
TestInputVisitorData *data, TestInputVisitorData *data,
void (*test_func)(TestInputVisitorData *data, const void *user_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", input_visitor_test_add("/visitor/input/int",
&in_visitor_data, test_visitor_in_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", input_visitor_test_add("/visitor/input/bool",
&in_visitor_data, test_visitor_in_bool); &in_visitor_data, test_visitor_in_bool);
input_visitor_test_add("/visitor/input/number", input_visitor_test_add("/visitor/input/number",
@ -310,6 +636,38 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_union); &in_visitor_data, test_visitor_in_union);
input_visitor_test_add("/visitor/input/errors", input_visitor_test_add("/visitor/input/errors",
&in_visitor_data, test_visitor_in_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(); g_test_run();

View File

@ -431,6 +431,314 @@ static void test_visitor_out_union(TestOutputVisitorData *data,
QDECREF(qdict); 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, static void output_visitor_test_add(const char *testpath,
TestOutputVisitorData *data, TestOutputVisitorData *data,
void (*test_func)(TestOutputVisitorData *data, const void *user_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); &out_visitor_data, test_visitor_out_list_qapi_free);
output_visitor_test_add("/visitor/output/union", output_visitor_test_add("/visitor/output/union",
&out_visitor_data, test_visitor_out_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(); g_test_run();

View File

@ -23,6 +23,25 @@
#include "qapi/qmp-output-visitor.h" #include "qapi/qmp-output-visitor.h"
#include "qapi/string-input-visitor.h" #include "qapi/string-input-visitor.h"
#include "qapi/string-output-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 { typedef struct PrimitiveType {
union { union {
@ -40,26 +59,42 @@ typedef struct PrimitiveType {
int64_t s64; int64_t s64;
intmax_t max; intmax_t max;
} value; } value;
enum { enum PrimitiveTypeKind type;
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;
const char *description; const char *description;
} PrimitiveType; } 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 */ /* 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) static void visit_primitive_type(Visitor *v, void **native, Error **errp)
{ {
PrimitiveType *pt = *native; 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 typedef struct TestStruct
{ {
int64_t integer; int64_t integer;
@ -206,12 +286,11 @@ static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
/* test cases */ /* test cases */
typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
typedef enum VisitorCapabilities { typedef enum VisitorCapabilities {
VCAP_PRIMITIVES = 1, VCAP_PRIMITIVES = 1,
VCAP_STRUCTURES = 2, VCAP_STRUCTURES = 2,
VCAP_LISTS = 4, VCAP_LISTS = 4,
VCAP_PRIMITIVE_LISTS = 8,
} VisitorCapabilities; } VisitorCapabilities;
typedef struct SerializeOps { typedef struct SerializeOps {
@ -229,17 +308,6 @@ typedef struct TestArgs {
void *test_data; void *test_data;
} TestArgs; } 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) static void test_primitives(gconstpointer opaque)
{ {
TestArgs *args = (TestArgs *) opaque; TestArgs *args = (TestArgs *) opaque;
@ -248,7 +316,6 @@ static void test_primitives(gconstpointer opaque)
PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
Error *err = NULL; Error *err = NULL;
void *serialize_data; void *serialize_data;
char *double1, *double2;
pt_copy->type = pt->type; pt_copy->type = pt->type;
ops->serialize(pt, &serialize_data, visit_primitive_type, &err); 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_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
g_free((char *)pt_copy->value.string); g_free((char *)pt_copy->value.string);
} else if (pt->type == PTYPE_NUMBER) { } 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 /* we serialize with %f for our reference visitors, so rather than fuzzy
* floating math to test "equality", just compare the formatted values * floating math to test "equality", just compare the formatted values
*/ */
double1 = g_malloc0(calc_float_string_storage(pt->value.number)); g_string_printf(double_expected, "%.6f", pt->value.number);
double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number)); g_string_printf(double_actual, "%.6f", pt_copy->value.number);
g_assert_cmpstr(double1, ==, double2); g_assert_cmpstr(double_actual->str, ==, double_expected->str);
g_free(double1);
g_free(double2); g_string_free(double_expected, true);
g_string_free(double_actual, true);
} else if (pt->type == PTYPE_BOOLEAN) { } else if (pt->type == PTYPE_BOOLEAN) {
g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max); g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
} else { } else {
@ -279,6 +349,328 @@ static void test_primitives(gconstpointer opaque)
g_free(pt_copy); 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) static void test_struct(gconstpointer opaque)
{ {
TestArgs *args = (TestArgs *) opaque; TestArgs *args = (TestArgs *) opaque;
@ -728,7 +1120,8 @@ static const SerializeOps visitors[] = {
.serialize = qmp_serialize, .serialize = qmp_serialize,
.deserialize = qmp_deserialize, .deserialize = qmp_deserialize,
.cleanup = qmp_cleanup, .cleanup = qmp_cleanup,
.caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
VCAP_PRIMITIVE_LISTS
}, },
{ {
.type = "String", .type = "String",
@ -782,6 +1175,19 @@ static void add_visitor_type(const SerializeOps *ops)
args->test_data = NULL; args->test_data = NULL;
g_test_add_data_func(testname, args, test_nested_struct_list); 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) int main(int argc, char **argv)

View File

@ -28,6 +28,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qmp-commands.h" #include "qmp-commands.h"
#include "qapi-types.h" #include "qapi-types.h"
#include "ui/keymaps.h"
struct QEMUPutMouseEntry { struct QEMUPutMouseEntry {
QEMUPutMouseEvent *qemu_put_mouse_event; QEMUPutMouseEvent *qemu_put_mouse_event;
@ -260,10 +261,10 @@ static void free_keycodes(void)
static void release_keys(void *opaque) static void release_keys(void *opaque)
{ {
while (keycodes_size > 0) { while (keycodes_size > 0) {
if (keycodes[--keycodes_size] & 0x80) { if (keycodes[--keycodes_size] & SCANCODE_GREY) {
kbd_put_keycode(0xe0); kbd_put_keycode(SCANCODE_EMUL0);
} }
kbd_put_keycode(keycodes[keycodes_size] | 0x80); kbd_put_keycode(keycodes[keycodes_size] | SCANCODE_UP);
} }
free_keycodes(); free_keycodes();
@ -297,10 +298,10 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
return; return;
} }
if (keycode & 0x80) { if (keycode & SCANCODE_GREY) {
kbd_put_keycode(0xe0); 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 = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
keycodes[keycodes_size++] = keycode; keycodes[keycodes_size++] = keycode;

4
vl.c
View File

@ -3366,8 +3366,10 @@ int main(int argc, char **argv, char **envp)
break; break;
} }
case QEMU_OPTION_monitor: case QEMU_OPTION_monitor:
monitor_parse(optarg, "readline");
default_monitor = 0; default_monitor = 0;
if (strncmp(optarg, "none", 4)) {
monitor_parse(optarg, "readline");
}
break; break;
case QEMU_OPTION_qmp: case QEMU_OPTION_qmp:
monitor_parse(optarg, "control"); monitor_parse(optarg, "control");