Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging

* remotes/qmp-unstable/queue/qmp:
  tests: test-qmp-commands: Fix double free
  qapi script: do not add "_" for every capitalized char in enum
  qapi script: do not allow string discriminator
  qapi: convert BlockdevOptions to use enum discriminator
  qapi script: support enum type as discriminator in union
  qapi script: use same function to generate enum string
  qapi script: code move for generate_enum_name()
  qapi script: check correctness of union
  qapi script: remember line number in schema parsing
  qapi script: add check for duplicated key
  qapi script: remember explicitly defined enum values

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-03-12 10:47:07 +00:00
commit 613c12ec28
43 changed files with 379 additions and 68 deletions

View File

@ -123,11 +123,12 @@ And it looks like this on the wire:
Flat union types avoid the nesting on the wire. They are used whenever a Flat union types avoid the nesting on the wire. They are used whenever a
specific field of the base type is declared as the discriminator ('type' is specific field of the base type is declared as the discriminator ('type' is
then no longer generated). The discriminator must always be a string field. then no longer generated). The discriminator must be of enumeration type.
The above example can then be modified as follows: The above example can then be modified as follows:
{ 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] }
{ 'type': 'BlockdevCommonOptions', { 'type': 'BlockdevCommonOptions',
'data': { 'driver': 'str', 'readonly': 'bool' } } 'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions', { 'union': 'BlockdevOptions',
'base': 'BlockdevCommonOptions', 'base': 'BlockdevCommonOptions',
'discriminator': 'driver', 'discriminator': 'driver',

View File

@ -159,7 +159,7 @@ void qerror_report_err(Error *err);
ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax" ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax"
#define QERR_KVM_MISSING_CAP \ #define QERR_KVM_MISSING_CAP \
ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable" ERROR_CLASS_KVM_MISSING_CAP, "Using KVM without %s, %s unavailable"
#define QERR_MIGRATION_ACTIVE \ #define QERR_MIGRATION_ACTIVE \
ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress" ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress"

View File

@ -4248,6 +4248,18 @@
'*direct': 'bool', '*direct': 'bool',
'*no-flush': 'bool' } } '*no-flush': 'bool' } }
##
# @BlockdevDriver
#
# Drivers that are supported in block device operations.
#
# Since: 2.0
##
{ 'enum': 'BlockdevDriver',
'data': [ 'file', 'http', 'https', 'ftp', 'ftps', 'tftp', 'vvfat', 'blkdebug',
'blkverify', 'bochs', 'cloop', 'cow', 'dmg', 'parallels', 'qcow',
'qcow2', 'qed', 'raw', 'vdi', 'vhdx', 'vmdk', 'vpc', 'quorum' ] }
## ##
# @BlockdevOptionsBase # @BlockdevOptionsBase
# #
@ -4272,7 +4284,7 @@
# Since: 1.7 # Since: 1.7
## ##
{ 'type': 'BlockdevOptionsBase', { 'type': 'BlockdevOptionsBase',
'data': { 'driver': 'str', 'data': { 'driver': 'BlockdevDriver',
'*id': 'str', '*id': 'str',
'*node-name': 'str', '*node-name': 'str',
'*discard': 'BlockdevDiscardOptions', '*discard': 'BlockdevDiscardOptions',

View File

@ -127,16 +127,6 @@ const char *%(name)s_lookup[] = {
''') ''')
return ret return ret
def generate_enum_name(name):
if name.isupper():
return c_fun(name, False)
new_name = ''
for c in c_fun(name, False):
if c.isupper():
new_name += '_'
new_name += c
return new_name.lstrip('_').upper()
def generate_enum(name, values): def generate_enum(name, values):
lookup_decl = mcgen(''' lookup_decl = mcgen('''
extern const char *%(name)s_lookup[]; extern const char *%(name)s_lookup[];
@ -154,11 +144,11 @@ typedef enum %(name)s
i = 0 i = 0
for value in enum_values: for value in enum_values:
enum_full_value = generate_enum_full_value(name, value)
enum_decl += mcgen(''' enum_decl += mcgen('''
%(abbrev)s_%(value)s = %(i)d, %(enum_full_value)s = %(i)d,
''', ''',
abbrev=de_camel_case(name).upper(), enum_full_value = enum_full_value,
value=generate_enum_name(value),
i=i) i=i)
i += 1 i += 1
@ -211,14 +201,21 @@ def generate_union(expr):
base = expr.get('base') base = expr.get('base')
discriminator = expr.get('discriminator') discriminator = expr.get('discriminator')
enum_define = discriminator_find_enum_define(expr)
if enum_define:
discriminator_type_name = enum_define['enum_name']
else:
discriminator_type_name = '%sKind' % (name)
ret = mcgen(''' ret = mcgen('''
struct %(name)s struct %(name)s
{ {
%(name)sKind kind; %(discriminator_type_name)s kind;
union { union {
void *data; void *data;
''', ''',
name=name) name=name,
discriminator_type_name=discriminator_type_name)
for key in typeinfo: for key in typeinfo:
ret += mcgen(''' ret += mcgen('''
@ -399,8 +396,11 @@ for expr in exprs:
fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
elif expr.has_key('union'): elif expr.has_key('union'):
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
enum_define = discriminator_find_enum_define(expr)
if not enum_define:
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) fdef.write(generate_enum_lookup('%sKind' % expr['union'],
expr['data'].keys()))
if expr.get('discriminator') == {}: if expr.get('discriminator') == {}:
fdef.write(generate_anon_union_qtypes(expr)) fdef.write(generate_anon_union_qtypes(expr))
else: else:

View File

@ -214,18 +214,22 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
''', ''',
name=name) name=name)
# For anon union, always use the default enum type automatically generated
# as "'%sKind' % (name)"
disc_type = '%sKind' % (name)
for key in members: for key in members:
assert (members[key] in builtin_types assert (members[key] in builtin_types
or find_struct(members[key]) or find_struct(members[key])
or find_union(members[key])), "Invalid anonymous union member" or find_union(members[key])), "Invalid anonymous union member"
enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(abbrev)s_KIND_%(enum)s: case %(enum_full_value)s:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break; break;
''', ''',
abbrev = de_camel_case(name).upper(), enum_full_value = enum_full_value,
enum = c_fun(de_camel_case(key),False).upper(),
c_type = type_name(members[key]), c_type = type_name(members[key]),
c_name = c_fun(key)) c_name = c_fun(key))
@ -255,7 +259,16 @@ def generate_visit_union(expr):
assert not base assert not base
return generate_visit_anon_union(name, members) return generate_visit_anon_union(name, members)
enum_define = discriminator_find_enum_define(expr)
if enum_define:
# Use the enum type as discriminator
ret = ""
disc_type = enum_define['enum_name']
else:
# There will always be a discriminator in the C switch code, by default it
# is an enum type generated silently as "'%sKind' % (name)"
ret = generate_visit_enum('%sKind' % name, members.keys()) ret = generate_visit_enum('%sKind' % name, members.keys())
disc_type = '%sKind' % (name)
if base: if base:
base_fields = find_struct(base)['data'] base_fields = find_struct(base)['data']
@ -291,15 +304,16 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
pop_indent() pop_indent()
if not discriminator: if not discriminator:
desc_type = "type" disc_key = "type"
else: else:
desc_type = discriminator disc_key = discriminator
ret += mcgen(''' ret += mcgen('''
visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err); visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
if (!err) { if (!err) {
switch ((*obj)->kind) { switch ((*obj)->kind) {
''', ''',
name=name, type=desc_type) disc_type = disc_type,
disc_key = disc_key)
for key in members: for key in members:
if not discriminator: if not discriminator:
@ -313,13 +327,13 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
visit_end_implicit_struct(m, &err); visit_end_implicit_struct(m, &err);
}''' }'''
enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(abbrev)s_KIND_%(enum)s: case %(enum_full_value)s:
''' + fmt + ''' ''' + fmt + '''
break; break;
''', ''',
abbrev = de_camel_case(name).upper(), enum_full_value = enum_full_value,
enum = c_fun(de_camel_case(key),False).upper(),
c_type=type_name(members[key]), c_type=type_name(members[key]),
c_name=c_fun(key)) c_name=c_fun(key))
@ -510,7 +524,11 @@ for expr in exprs:
ret += generate_visit_list(expr['union'], expr['data']) ret += generate_visit_list(expr['union'], expr['data'])
fdef.write(ret) fdef.write(ret)
ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys()) enum_define = discriminator_find_enum_define(expr)
ret = ""
if not enum_define:
ret = generate_decl_enum('%sKind' % expr['union'],
expr['data'].keys())
ret += generate_declaration(expr['union'], expr['data']) ret += generate_declaration(expr['union'], expr['data'])
fdecl.write(ret) fdecl.write(ret)
elif expr.has_key('enum'): elif expr.has_key('enum'):

View File

@ -39,12 +39,10 @@ class QAPISchemaError(Exception):
def __init__(self, schema, msg): def __init__(self, schema, msg):
self.fp = schema.fp self.fp = schema.fp
self.msg = msg self.msg = msg
self.line = self.col = 1
for ch in schema.src[0:schema.pos]:
if ch == '\n':
self.line += 1
self.col = 1 self.col = 1
elif ch == '\t': self.line = schema.line
for ch in schema.src[schema.line_pos:schema.pos]:
if ch == '\t':
self.col = (self.col + 7) % 8 + 1 self.col = (self.col + 7) % 8 + 1
else: else:
self.col += 1 self.col += 1
@ -52,6 +50,15 @@ class QAPISchemaError(Exception):
def __str__(self): def __str__(self):
return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg) return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
class QAPIExprError(Exception):
def __init__(self, expr_info, msg):
self.fp = expr_info['fp']
self.line = expr_info['line']
self.msg = msg
def __str__(self):
return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
class QAPISchema: class QAPISchema:
def __init__(self, fp): def __init__(self, fp):
@ -60,11 +67,16 @@ class QAPISchema:
if self.src == '' or self.src[-1] != '\n': if self.src == '' or self.src[-1] != '\n':
self.src += '\n' self.src += '\n'
self.cursor = 0 self.cursor = 0
self.line = 1
self.line_pos = 0
self.exprs = [] self.exprs = []
self.accept() self.accept()
while self.tok != None: while self.tok != None:
self.exprs.append(self.get_expr(False)) expr_info = {'fp': fp, 'line': self.line}
expr_elem = {'expr': self.get_expr(False),
'info': expr_info}
self.exprs.append(expr_elem)
def accept(self): def accept(self):
while True: while True:
@ -100,6 +112,8 @@ class QAPISchema:
if self.cursor == len(self.src): if self.cursor == len(self.src):
self.tok = None self.tok = None
return return
self.line += 1
self.line_pos = self.cursor
elif not self.tok.isspace(): elif not self.tok.isspace():
raise QAPISchemaError(self, 'Stray "%s"' % self.tok) raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
@ -116,6 +130,8 @@ class QAPISchema:
if self.tok != ':': if self.tok != ':':
raise QAPISchemaError(self, 'Expected ":"') raise QAPISchemaError(self, 'Expected ":"')
self.accept() self.accept()
if key in expr:
raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
expr[key] = self.get_expr(True) expr[key] = self.get_expr(True)
if self.tok == '}': if self.tok == '}':
self.accept() self.accept()
@ -158,6 +174,95 @@ class QAPISchema:
raise QAPISchemaError(self, 'Expected "{", "[" or string') raise QAPISchemaError(self, 'Expected "{", "[" or string')
return expr return expr
def find_base_fields(base):
base_struct_define = find_struct(base)
if not base_struct_define:
return None
return base_struct_define['data']
# Return the discriminator enum define if discriminator is specified as an
# enum type, otherwise return None.
def discriminator_find_enum_define(expr):
base = expr.get('base')
discriminator = expr.get('discriminator')
if not (discriminator and base):
return None
base_fields = find_base_fields(base)
if not base_fields:
return None
discriminator_type = base_fields.get(discriminator)
if not discriminator_type:
return None
return find_enum(discriminator_type)
def check_union(expr, expr_info):
name = expr['union']
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
# If the object has a member 'base', its value must name a complex type.
if base:
base_fields = find_base_fields(base)
if not base_fields:
raise QAPIExprError(expr_info,
"Base '%s' is not a valid type"
% base)
# If the union object has no member 'discriminator', it's an
# ordinary union.
if not discriminator:
enum_define = None
# Else if the value of member 'discriminator' is {}, it's an
# anonymous union.
elif discriminator == {}:
enum_define = None
# Else, it's a flat union.
else:
# The object must have a member 'base'.
if not base:
raise QAPIExprError(expr_info,
"Flat union '%s' must have a base field"
% name)
# The value of member 'discriminator' must name a member of the
# base type.
discriminator_type = base_fields.get(discriminator)
if not discriminator_type:
raise QAPIExprError(expr_info,
"Discriminator '%s' is not a member of base "
"type '%s'"
% (discriminator, base))
enum_define = find_enum(discriminator_type)
# Do not allow string discriminator
if not enum_define:
raise QAPIExprError(expr_info,
"Discriminator '%s' must be of enumeration "
"type" % discriminator)
# Check every branch
for (key, value) in members.items():
# If this named member's value names an enum type, then all members
# of 'data' must also be members of the enum type.
if enum_define and not key in enum_define['enum_values']:
raise QAPIExprError(expr_info,
"Discriminator value '%s' is not found in "
"enum '%s'" %
(key, enum_define["enum_name"]))
# Todo: add checking for values. Key is checked as above, value can be
# also checked here, but we need more functions to handle array case.
def check_exprs(schema):
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('union'):
check_union(expr, expr_elem['info'])
def parse_schema(fp): def parse_schema(fp):
try: try:
schema = QAPISchema(fp) schema = QAPISchema(fp)
@ -167,16 +272,29 @@ def parse_schema(fp):
exprs = [] exprs = []
for expr in schema.exprs: for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('enum'): if expr.has_key('enum'):
add_enum(expr['enum']) add_enum(expr['enum'], expr['data'])
elif expr.has_key('union'): elif expr.has_key('union'):
add_union(expr) add_union(expr)
add_enum('%sKind' % expr['union'])
elif expr.has_key('type'): elif expr.has_key('type'):
add_struct(expr) add_struct(expr)
exprs.append(expr) exprs.append(expr)
# Try again for hidden UnionKind enum
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('union'):
if not discriminator_find_enum_define(expr):
add_enum('%sKind' % expr['union'])
try:
check_exprs(schema)
except QAPIExprError, e:
print >>sys.stderr, e
exit(1)
return exprs return exprs
def parse_args(typeinfo): def parse_args(typeinfo):
@ -289,13 +407,19 @@ def find_union(name):
return union return union
return None return None
def add_enum(name): def add_enum(name, enum_values = None):
global enum_types global enum_types
enum_types.append(name) enum_types.append({"enum_name": name, "enum_values": enum_values})
def find_enum(name):
global enum_types
for enum in enum_types:
if enum['enum_name'] == name:
return enum
return None
def is_enum(name): def is_enum(name):
global enum_types return find_enum(name) != None
return (name in enum_types)
def c_type(name): def c_type(name):
if name == 'str': if name == 'str':
@ -373,3 +497,30 @@ def guardend(name):
''', ''',
name=guardname(name)) name=guardname(name))
# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
# ENUM24_Name -> ENUM24_NAME
def _generate_enum_string(value):
c_fun_str = c_fun(value, False)
if value.isupper():
return c_fun_str
new_name = ''
l = len(c_fun_str)
for i in range(l):
c = c_fun_str[i]
# When c is upper and no "_" appears before, do more checks
if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
# Case 1: next string is lower
# Case 2: previous string is digit
if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
c_fun_str[i - 1].isdigit():
new_name += '_'
new_name += c
return new_name.lstrip('_').upper()
def generate_enum_full_value(enum_name, enum_value):
abbrev_string = _generate_enum_string(enum_name)
value_string = _generate_enum_string(enum_value)
return "%s_%s" % (abbrev_string, value_string)

View File

@ -315,7 +315,7 @@ typedef struct X86RegisterInfo32 {
} X86RegisterInfo32; } X86RegisterInfo32;
#define REGISTER(reg) \ #define REGISTER(reg) \
[R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg } [R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg }
X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
REGISTER(EAX), REGISTER(EAX),
REGISTER(ECX), REGISTER(ECX),

View File

@ -142,7 +142,11 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
missing-comma-object.json non-objects.json \ missing-comma-object.json non-objects.json \
qapi-schema-test.json quoted-structural-chars.json \ qapi-schema-test.json quoted-structural-chars.json \
trailing-comma-list.json trailing-comma-object.json \ trailing-comma-list.json trailing-comma-object.json \
unclosed-list.json unclosed-object.json unclosed-string.json) unclosed-list.json unclosed-object.json unclosed-string.json \
duplicate-key.json union-invalid-base.json flat-union-no-base.json \
flat-union-invalid-discriminator.json \
flat-union-invalid-branch-key.json flat-union-reverse-define.json \
flat-union-string-discriminator.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h

View File

@ -1,3 +1,3 @@
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] [OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
['Status'] [{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
[] []

View File

@ -0,0 +1 @@
<stdin>:2:10: Duplicate key "key"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'key': 'value',
'key': 'value' }

View File

View File

@ -0,0 +1 @@
<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,17 @@
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'type': 'TestBase',
'data': { 'enum1': 'TestEnum' } }
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
'base': 'TestBase',
'discriminator': 'enum1',
'data': { 'value_wrong': 'TestTypeA',
'value2': 'TestTypeB' } }

View File

@ -0,0 +1 @@
<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,17 @@
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'type': 'TestBase',
'data': { 'enum1': 'TestEnum' } }
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
'base': 'TestBase',
'discriminator': 'enum_wrong',
'data': { 'value1': 'TestTypeA',
'value2': 'TestTypeB' } }

View File

@ -0,0 +1 @@
<stdin>:7: Flat union 'TestUnion' must have a base field

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,10 @@
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
'discriminator': 'enum1',
'data': { 'value1': 'TestTypeA',
'value2': 'TestTypeB' } }

View File

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,17 @@
{ 'union': 'TestUnion',
'base': 'TestBase',
'discriminator': 'enum1',
'data': { 'value1': 'TestTypeA',
'value2': 'TestTypeB' } }
{ 'type': 'TestBase',
'data': { 'enum1': 'TestEnum' } }
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }

View File

@ -0,0 +1,9 @@
[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]),
OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]),
OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}]
[OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]

View File

@ -0,0 +1 @@
<stdin>:13: Discriminator 'kind' must be of enumeration type

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,17 @@
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'type': 'TestBase',
'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
'base': 'TestBase',
'discriminator': 'kind',
'data': { 'kind1': 'TestTypeA',
'kind2': 'TestTypeB' } }

View File

@ -37,10 +37,13 @@
'base': 'UserDefZero', 'base': 'UserDefZero',
'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }
{ 'type': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
{ 'union': 'UserDefFlatUnion', { 'union': 'UserDefFlatUnion',
'base': 'UserDefOne', 'base': 'UserDefUnionBase',
'discriminator': 'string', 'discriminator': 'enum1',
'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } 'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } }
# FIXME generated struct UserDefFlatUnion has members for direct base # FIXME generated struct UserDefFlatUnion has members for direct base
# UserDefOne, but lacks members for indirect base UserDefZero # UserDefOne, but lacks members for indirect base UserDefZero

View File

@ -7,7 +7,8 @@
OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefOne'), ('discriminator', 'string'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]), OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]),
OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
@ -15,11 +16,10 @@
OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]),
OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]), OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]),
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]
['EnumOne', [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
'UserDefUnionKind', {'enum_name': 'UserDefUnionKind', 'enum_values': None},
'UserDefFlatUnionKind', {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None},
'UserDefAnonUnionKind', {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}]
'UserDefNativeListUnionKind']
[OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), [OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
OrderedDict([('type', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('type', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('type', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), OrderedDict([('type', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
@ -27,4 +27,5 @@
OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]

View File

@ -0,0 +1 @@
<stdin>:7: Base 'TestBaseWrong' is not a valid type

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,10 @@
{ 'type': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'type': 'TestTypeB',
'data': { 'integer': 'int' } }
{ 'union': 'TestUnion',
'base': 'TestBaseWrong',
'data': { 'value1': 'TestTypeA',
'value2': 'TestTypeB' } }

View File

View File

@ -141,7 +141,7 @@ static void test_dispatch_cmd_io(void)
ret3 = qobject_to_qint(test_qmp_dispatch(req)); ret3 = qobject_to_qint(test_qmp_dispatch(req));
assert(qint_get_int(ret3) == 66); assert(qint_get_int(ret3) == 66);
QDECREF(ret); QDECREF(ret3);
QDECREF(req); QDECREF(req);
} }

View File

@ -146,7 +146,10 @@ static void test_validate_union_flat(TestInputVisitorData *data,
Visitor *v; Visitor *v;
Error *errp = NULL; Error *errp = NULL;
v = validate_test_init(data, "{ 'string': 'a', 'boolean': true }"); v = validate_test_init(data,
"{ 'enum1': 'value1', "
"'string': 'str', "
"'boolean': true }");
/* TODO when generator bug is fixed, add 'integer': 41 */ /* TODO when generator bug is fixed, add 'integer': 41 */
visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp);

View File

@ -310,14 +310,18 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
Error *err = NULL; Error *err = NULL;
UserDefFlatUnion *tmp; UserDefFlatUnion *tmp;
v = visitor_input_test_init(data, "{ 'string': 'a', 'boolean': true }"); v = visitor_input_test_init(data,
"{ 'enum1': 'value1', "
"'string': 'str', "
"'boolean': true }");
/* TODO when generator bug is fixed, add 'integer': 41 */ /* TODO when generator bug is fixed, add 'integer': 41 */
visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
g_assert(err == NULL); g_assert(err == NULL);
g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_A); g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1);
g_assert_cmpstr(tmp->string, ==, "str");
/* TODO g_assert_cmpint(tmp->integer, ==, 41); */ /* TODO g_assert_cmpint(tmp->integer, ==, 41); */
g_assert_cmpint(tmp->a->boolean, ==, true); g_assert_cmpint(tmp->value1->boolean, ==, true);
qapi_free_UserDefFlatUnion(tmp); qapi_free_UserDefFlatUnion(tmp);
} }

View File

@ -449,10 +449,11 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
Error *err = NULL; Error *err = NULL;
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
tmp->kind = USER_DEF_UNION_KIND_A; tmp->kind = ENUM_ONE_VALUE1;
tmp->a = g_malloc0(sizeof(UserDefA)); tmp->string = g_strdup("str");
tmp->value1 = g_malloc0(sizeof(UserDefA));
/* TODO when generator bug is fixed: tmp->integer = 41; */ /* TODO when generator bug is fixed: tmp->integer = 41; */
tmp->a->boolean = true; tmp->value1->boolean = true;
visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err); visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err);
g_assert(err == NULL); g_assert(err == NULL);
@ -461,7 +462,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
g_assert(qobject_type(arg) == QTYPE_QDICT); g_assert(qobject_type(arg) == QTYPE_QDICT);
qdict = qobject_to_qdict(arg); qdict = qobject_to_qdict(arg);
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "a"); g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
/* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */ /* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);