QAPI patches for 2018-06-22

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJbLQlmAAoJEDhwtADrkYZTSncQAK1jsP8crW+bgwRBPhwZgmv6
 IEWXQc9OBlVD3yrSnMsqJuFOo9vak0EThBFUPBUNSN5rQZhuwBrOyKJRcxTSEilh
 h0Wq/HxCARRdJpcPXWo7UIXgNXrk5qoUzowc6m/6ReogOoycrA4YeOLdOoy98dUv
 0a2U/EyKL/lWgioQhbnZWBEtFX1BFVztWUsG0AF6PGgbu7SZRGtw+IDQWzV7oRVN
 gsiKJYjTN7jjyxaM789TioiajMD1dFSN2V3BSqLv9LkaJ8dV69OVU5R6429EkzTF
 /BdahCtsTE7TTkXeqPqpOnrRXBYiCOeLTbi1Ub5De7wjtaLzfQW9ZolA1OxaSRWS
 AMvS92V2w6S97F0VkkfagGmqO6ypVXAjPr7a3yXHKig2DDMR5BWq10GXS7EHvn5a
 qVD4WbGxUFplxpyvbCAjZS/qV8hoDG8SsA58lUJP18z5Z6PJpCvk6bQl9XcOF+bc
 WqlcgW75Iu/ii1XZdzFylX1h9p4ox4roiZ9YBMKakb/oI8kfUHs4dL0Yz5A0aJKr
 /Vw/8TmokqkLI+PJX+6P4kGyrIVhB6x/iPDv1MXqjaEiO+tM6pMUfJvH8HtzTIay
 CJ0QNZQe2ksbV1gHZ4wGZwnGwOtOQVUmXChDVEcQbyOdlHAEGn9Zjbc1wq/wei8x
 VtA3kZn6CoIuih6vt6SO
 =Mo3y
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2018-06-22' into staging

QAPI patches for 2018-06-22

# gpg: Signature made Fri 22 Jun 2018 15:36:22 BST
# gpg:                using RSA key 3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2018-06-22:
  MAINTAINERS: Update QAPI stanza for commit fb0bc835e5
  qapi/introspect: Eliminate pointless variable in .visit_end()
  Revert commit d4e5ec877c
  qapi: Open files with encoding='utf-8'
  qapi: remove empty flat union branches and types
  qapi: allow empty branches in flat unions
  tests: Add QDict clone-flatten test
  qdict: Make qdict_flatten() shallow-clone-friendly
  qapi/events: generate event enum in main module
  qapi/visit: remove useless prefix argument

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-06-22 17:08:57 +01:00
commit 7ed14cbf3c
24 changed files with 116 additions and 190 deletions

View File

@ -1625,7 +1625,8 @@ F: tests/test-*-visitor.c
F: tests/test-qapi-*.c
F: tests/test-qmp-*.c
F: tests/test-visitor-serialization.c
F: scripts/qapi*
F: scripts/qapi-gen.py
F: scripts/qapi/*
F: docs/devel/qapi*
T: git git://repo.or.cz/qemu/armbru.git qapi-next

View File

@ -20,8 +20,6 @@ ifneq ($(wildcard config-host.mak),)
all:
include config-host.mak
PYTHON_UTF8 = LC_ALL= LANG=C LC_CTYPE=en_US.UTF-8 $(PYTHON)
git-submodule-update:
.PHONY: git-submodule-update
@ -576,7 +574,7 @@ qga/qapi-generated/qga-qapi-commands.h qga/qapi-generated/qga-qapi-commands.c \
qga/qapi-generated/qga-qapi-doc.texi: \
qga/qapi-generated/qapi-gen-timestamp ;
qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o qga/qapi-generated -p "qga-" $<, \
"GEN","$(@:%-timestamp=%)")
@>$@
@ -676,7 +674,7 @@ qapi/qapi-introspect.h qapi/qapi-introspect.c \
qapi/qapi-doc.texi: \
qapi-gen-timestamp ;
qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o "qapi" -b $<, \
"GEN","$(@:%-timestamp=%)")
@>$@

View File

@ -4166,7 +4166,6 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
switch (encrypt_info->format) {
case Q_CRYPTO_BLOCK_FORMAT_QCOW:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
qencrypt->u.aes = encrypt_info->u.qcow;
break;
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;

2
cpus.c
View File

@ -2273,8 +2273,6 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
info->value->target = target;
if (target == SYS_EMU_TARGET_S390X) {
cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
} else {
/* do nothing for @CpuInfoOther */
}
if (!cur_item) {

View File

@ -496,9 +496,11 @@ Resulting in these JSON objects:
Notice that in a flat union, the discriminator name is controlled by
the user, but because it must map to a base member with enum type, the
code generator can ensure that branches exist for all values of the
enum (although the order of the keys need not match the declaration of
the enum). In the resulting generated C data types, a flat union is
code generator ensures that branches match the existing values of the
enum. The order of the keys need not match the declaration of the enum.
The keys need not cover all possible enum values. Omitted enum values
are still valid branches that add no additional members to the data type.
In the resulting generated C data types, a flat union is
represented as a struct with the base members included directly, and
then a union of structures for each branch of the struct.

View File

@ -52,8 +52,7 @@
{ 'union': 'ImageInfoSpecificQCow2Encryption',
'base': 'ImageInfoSpecificQCow2EncryptionBase',
'discriminator': 'format',
'data': { 'aes': 'QCryptoBlockInfoQCow',
'luks': 'QCryptoBlockInfoLUKS' } }
'data': { 'luks': 'QCryptoBlockInfoLUKS' } }
##
# @ImageInfoSpecificQCow2:
@ -2877,16 +2876,6 @@
'data': { 'type': 'SshHostKeyCheckHashType',
'hash': 'str' }}
##
# @SshHostKeyDummy:
#
# For those union branches that don't need additional fields.
#
# Since: 2.12
##
{ 'struct': 'SshHostKeyDummy',
'data': {} }
##
# @SshHostKeyCheck:
#
@ -2895,9 +2884,7 @@
{ 'union': 'SshHostKeyCheck',
'base': { 'mode': 'SshHostKeyCheckMode' },
'discriminator': 'mode',
'data': { 'none': 'SshHostKeyDummy',
'hash': 'SshHostKeyHash',
'known_hosts': 'SshHostKeyDummy' } }
'data': { 'hash': 'SshHostKeyHash' } }
##
# @BlockdevOptionsSsh:
@ -4075,15 +4062,6 @@
'*subformat': 'BlockdevVpcSubformat',
'*force-size': 'bool' } }
##
# @BlockdevCreateNotSupported:
#
# This is used for all drivers that don't support creating images.
#
# Since: 2.12
##
{ 'struct': 'BlockdevCreateNotSupported', 'data': {}}
##
# @BlockdevCreateOptions:
#
@ -4098,44 +4076,20 @@
'driver': 'BlockdevDriver' },
'discriminator': 'driver',
'data': {
'blkdebug': 'BlockdevCreateNotSupported',
'blkverify': 'BlockdevCreateNotSupported',
'bochs': 'BlockdevCreateNotSupported',
'cloop': 'BlockdevCreateNotSupported',
'copy-on-read': 'BlockdevCreateNotSupported',
'dmg': 'BlockdevCreateNotSupported',
'file': 'BlockdevCreateOptionsFile',
'ftp': 'BlockdevCreateNotSupported',
'ftps': 'BlockdevCreateNotSupported',
'gluster': 'BlockdevCreateOptionsGluster',
'host_cdrom': 'BlockdevCreateNotSupported',
'host_device': 'BlockdevCreateNotSupported',
'http': 'BlockdevCreateNotSupported',
'https': 'BlockdevCreateNotSupported',
'iscsi': 'BlockdevCreateNotSupported',
'luks': 'BlockdevCreateOptionsLUKS',
'nbd': 'BlockdevCreateNotSupported',
'nfs': 'BlockdevCreateOptionsNfs',
'null-aio': 'BlockdevCreateNotSupported',
'null-co': 'BlockdevCreateNotSupported',
'nvme': 'BlockdevCreateNotSupported',
'parallels': 'BlockdevCreateOptionsParallels',
'qcow': 'BlockdevCreateOptionsQcow',
'qcow2': 'BlockdevCreateOptionsQcow2',
'qed': 'BlockdevCreateOptionsQed',
'quorum': 'BlockdevCreateNotSupported',
'raw': 'BlockdevCreateNotSupported',
'rbd': 'BlockdevCreateOptionsRbd',
'replication': 'BlockdevCreateNotSupported',
'sheepdog': 'BlockdevCreateOptionsSheepdog',
'ssh': 'BlockdevCreateOptionsSsh',
'throttle': 'BlockdevCreateNotSupported',
'vdi': 'BlockdevCreateOptionsVdi',
'vhdx': 'BlockdevCreateOptionsVhdx',
'vmdk': 'BlockdevCreateNotSupported',
'vpc': 'BlockdevCreateOptionsVpc',
'vvfat': 'BlockdevCreateNotSupported',
'vxhs': 'BlockdevCreateNotSupported'
'vpc': 'BlockdevCreateOptionsVpc'
} }
##

View File

@ -297,16 +297,6 @@
'uuid': 'str',
'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
##
# @QCryptoBlockInfoQCow:
#
# Information about the QCow block encryption options
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoQCow',
'data': { }}
##
# @QCryptoBlockInfo:
@ -318,5 +308,4 @@
{ 'union': 'QCryptoBlockInfo',
'base': 'QCryptoBlockInfoBase',
'discriminator': 'format',
'data': { 'qcow': 'QCryptoBlockInfoQCow',
'luks': 'QCryptoBlockInfoLUKS' } }
'data': { 'luks': 'QCryptoBlockInfoLUKS' } }

View File

@ -396,8 +396,7 @@
'mips': 'CpuInfoMIPS',
'tricore': 'CpuInfoTricore',
's390': 'CpuInfoS390',
'riscv': 'CpuInfoRISCV',
'other': 'CpuInfoOther' } }
'riscv': 'CpuInfoRISCV' } }
##
# @CpuInfoX86:
@ -467,16 +466,6 @@
##
{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
##
# @CpuInfoOther:
#
# No additional information is available about the virtual CPU
#
# Since: 2.6
#
##
{ 'struct': 'CpuInfoOther', 'data': { } }
##
# @CpuS390State:
#
@ -578,38 +567,7 @@
'arch' : 'CpuInfoArch',
'target' : 'SysEmuTarget' },
'discriminator' : 'target',
'data' : { 'aarch64' : 'CpuInfoOther',
'alpha' : 'CpuInfoOther',
'arm' : 'CpuInfoOther',
'cris' : 'CpuInfoOther',
'hppa' : 'CpuInfoOther',
'i386' : 'CpuInfoOther',
'lm32' : 'CpuInfoOther',
'm68k' : 'CpuInfoOther',
'microblaze' : 'CpuInfoOther',
'microblazeel' : 'CpuInfoOther',
'mips' : 'CpuInfoOther',
'mips64' : 'CpuInfoOther',
'mips64el' : 'CpuInfoOther',
'mipsel' : 'CpuInfoOther',
'moxie' : 'CpuInfoOther',
'nios2' : 'CpuInfoOther',
'or1k' : 'CpuInfoOther',
'ppc' : 'CpuInfoOther',
'ppc64' : 'CpuInfoOther',
'ppcemb' : 'CpuInfoOther',
'riscv32' : 'CpuInfoOther',
'riscv64' : 'CpuInfoOther',
's390x' : 'CpuInfoS390',
'sh4' : 'CpuInfoOther',
'sh4eb' : 'CpuInfoOther',
'sparc' : 'CpuInfoOther',
'sparc64' : 'CpuInfoOther',
'tricore' : 'CpuInfoOther',
'unicore32' : 'CpuInfoOther',
'x86_64' : 'CpuInfoOther',
'xtensa' : 'CpuInfoOther',
'xtensaeb' : 'CpuInfoOther' } }
'data' : { 's390x' : 'CpuInfoS390' } }
##
# @query-cpus-fast:

View File

@ -88,16 +88,6 @@
##
{ 'command': 'netdev_del', 'data': {'id': 'str'} }
##
# @NetdevNoneOptions:
#
# Use it alone to have zero network devices.
#
# Since: 1.2
##
{ 'struct': 'NetdevNoneOptions',
'data': { } }
##
# @NetLegacyNicOptions:
#
@ -477,7 +467,6 @@
'base': { 'id': 'str', 'type': 'NetClientDriver' },
'discriminator': 'type',
'data': {
'none': 'NetdevNoneOptions',
'nic': 'NetLegacyNicOptions',
'user': 'NetdevUserOptions',
'tap': 'NetdevTapOptions',
@ -530,7 +519,6 @@
'base': { 'type': 'NetLegacyOptionsType' },
'discriminator': 'type',
'data': {
'none': 'NetdevNoneOptions',
'nic': 'NetLegacyNicOptions',
'user': 'NetdevUserOptions',
'tap': 'NetdevTapOptions',

View File

@ -995,17 +995,6 @@
'events' : [ 'InputEvent' ] } }
##
# @DisplayNoOpts:
#
# Empty struct for displays without config options.
#
# Since: 2.12
#
##
{ 'struct' : 'DisplayNoOpts',
'data' : { } }
##
# @DisplayGTK:
#
@ -1068,10 +1057,4 @@
'*window-close' : 'bool',
'*gl' : 'DisplayGLMode' },
'discriminator' : 'type',
'data' : { 'default' : 'DisplayNoOpts',
'none' : 'DisplayNoOpts',
'gtk' : 'DisplayGTK',
'sdl' : 'DisplayNoOpts',
'egl-headless' : 'DisplayNoOpts',
'curses' : 'DisplayNoOpts',
'cocoa' : 'DisplayNoOpts' } }
'data' : { 'gtk' : 'DisplayGTK' } }

View File

@ -114,19 +114,30 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
/*
* Flatten non-empty QDict and QList recursively into @target,
* copy other objects to @target
* copy other objects to @target.
* On the root level (if @qdict == @target), remove flattened
* nested QDicts and QLists from @qdict.
*
* (Note that we do not need to remove entries from nested
* dicts or lists. Their reference count is decremented on
* the root level, so there are no leaks. In fact, if they
* have a reference count greater than one, we are probably
* well advised not to modify them altogether.)
*/
if (dict_val && qdict_size(dict_val)) {
qdict_flatten_qdict(dict_val, target,
new_key ? new_key : entry->key);
if (target == qdict) {
qdict_del(qdict, entry->key);
}
} else if (list_val && !qlist_empty(list_val)) {
qdict_flatten_qlist(list_val, target,
new_key ? new_key : entry->key);
if (target == qdict) {
qdict_del(qdict, entry->key);
}
} else if (target != qdict) {
qdict_put_obj(target, new_key, qobject_ref(value));
qdict_del(qdict, entry->key);
}
g_free(new_key);

View File

@ -16,6 +16,7 @@ import errno
import os
import re
import string
import sys
from collections import OrderedDict
builtin_types = {
@ -340,6 +341,9 @@ class QAPISchemaParser(object):
return None
try:
if sys.version_info[0] >= 3:
fobj = open(incl_fname, 'r', encoding='utf-8')
else:
fobj = open(incl_fname, 'r')
except IOError as e:
raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname))
@ -779,13 +783,6 @@ def check_union(expr, info):
"enum '%s'"
% (key, enum_define['enum']))
# If discriminator is user-defined, ensure all values are covered
if enum_define:
for value in enum_define['data']:
if value not in members.keys():
raise QAPISemError(info, "Union '%s' data missing '%s' branch"
% (name, value))
def check_alternate(expr, info):
name = expr['alternate']
@ -1357,6 +1354,14 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = seen[c_name(self._tag_name)]
assert self._tag_name == self.tag_member.name
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = set([v.name for v in self.variants])
for val in self.tag_member.type.values:
if val.name not in cases:
v = QAPISchemaObjectTypeVariant(val.name, 'q_empty')
v.set_owner(self.tag_member.owner)
self.variants.append(v)
for v in self.variants:
v.check(schema)
# Union names must match enum values; alternate names are
@ -1492,7 +1497,11 @@ class QAPISchemaEvent(QAPISchemaEntity):
class QAPISchema(object):
def __init__(self, fname):
self._fname = fname
parser = QAPISchemaParser(open(fname, 'r'))
if sys.version_info[0] >= 3:
f = open(fname, 'r', encoding='utf-8')
else:
f = open(fname, 'r')
parser = QAPISchemaParser(f)
exprs = check_exprs(parser.exprs)
self.docs = parser.docs
self._entity_list = []
@ -2006,6 +2015,9 @@ class QAPIGen(object):
if e.errno != errno.EEXIST:
raise
fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
if sys.version_info[0] >= 3:
f = open(fd, 'r+', encoding='utf-8')
else:
f = os.fdopen(fd, 'r+')
text = (self._top(fname) + self._preamble + self._body
+ self._bottom(fname))

View File

@ -180,8 +180,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
types=types))
def visit_end(self):
self._genh.add(gen_enum(self._enum_name, self._event_names))
self._genc.add(gen_enum_lookup(self._enum_name, self._event_names))
(genc, genh) = self._module[self._main_module]
genh.add(gen_enum(self._enum_name, self._event_names))
genc.add(gen_enum_lookup(self._enum_name, self._event_names))
def visit_event(self, name, info, arg_type, boxed):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))

View File

@ -75,13 +75,10 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor):
def visit_end(self):
# visit the types that are actually used
qlits = self._qlits
self._qlits = []
for typ in self._used_types:
typ.visit(self)
# generate C
# TODO can generate awfully long lines
qlits.extend(self._qlits)
name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit'
self._genh.add(mcgen('''
#include "qapi/qmp/qlit.h"
@ -93,7 +90,7 @@ extern const QLitObject %(c_name)s;
const QLitObject %(c_name)s = %(c_string)s;
''',
c_name=c_name(name),
c_string=to_qlit(qlits)))
c_string=to_qlit(self._qlits)))
self._schema = None
self._qlits = []
self._used_types = []

View File

@ -125,6 +125,8 @@ def gen_variants(variants):
c_name=c_name(variants.tag_member.name))
for var in variants.variants:
if var.type.name == 'q_empty':
continue
ret += mcgen('''
%(c_type)s %(c_name)s;
''',

View File

@ -81,14 +81,23 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_name=c_name(variants.tag_member.name))
for var in variants.variants:
case_str = c_enum_const(variants.tag_member.type.name,
var.name,
variants.tag_member.type.prefix)
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
case %(case)s:
break;
''',
case=case_str)
else:
ret += mcgen('''
case %(case)s:
visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
break;
''',
case=c_enum_const(variants.tag_member.type.name,
var.name,
variants.tag_member.type.prefix),
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
ret += mcgen('''
@ -293,7 +302,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
#include "qapi/qmp/qerror.h"
#include "%(visit)s.h"
''',
visit=visit, prefix=self._prefix))
visit=visit))
self._genh.preamble_add(mcgen('''
#include "qapi/qapi-builtin-visit.h"
#include "%(types)s.h"

View File

@ -499,7 +499,6 @@ qapi-schema += flat-union-base-any.json
qapi-schema += flat-union-base-union.json
qapi-schema += flat-union-clash-member.json
qapi-schema += flat-union-empty.json
qapi-schema += flat-union-incomplete-branch.json
qapi-schema += flat-union-inline.json
qapi-schema += flat-union-int-branch.json
qapi-schema += flat-union-invalid-branch-key.json
@ -679,13 +678,13 @@ tests/test-qapi-events.c tests/test-qapi-events.h \
tests/test-qapi-introspect.c tests/test-qapi-introspect.h: \
tests/test-qapi-gen-timestamp ;
tests/test-qapi-gen-timestamp: $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o tests -p "test-" $<, \
"GEN","$(@:%-timestamp=%)")
@>$@
tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o tests/qapi-schema -p "doc-good-" $<, \
"GEN","$@")
@mv tests/qapi-schema/doc-good-qapi-doc.texi $@
@ -979,7 +978,7 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
$(PYTHON_UTF8) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
$(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
$^ >$*.test.out 2>$*.test.err; \
echo $$? >$*.test.exit, \
"TEST","$*.out")

View File

@ -125,6 +125,38 @@ static void qdict_flatten_test(void)
qobject_unref(root);
}
static void qdict_clone_flatten_test(void)
{
QDict *dict1 = qdict_new();
QDict *dict2 = qdict_new();
QDict *cloned_dict1;
/*
* Test that we can clone and flatten
* { "a": { "b": 42 } }
* without modifying the clone.
*/
qdict_put_int(dict2, "b", 42);
qdict_put(dict1, "a", dict2);
cloned_dict1 = qdict_clone_shallow(dict1);
qdict_flatten(dict1);
g_assert(qdict_size(dict1) == 1);
g_assert(qdict_get_int(dict1, "a.b") == 42);
g_assert(qdict_size(cloned_dict1) == 1);
g_assert(qdict_get_qdict(cloned_dict1, "a") == dict2);
g_assert(qdict_size(dict2) == 1);
g_assert(qdict_get_int(dict2, "b") == 42);
qobject_unref(dict1);
qobject_unref(cloned_dict1);
}
static void qdict_array_split_test(void)
{
QDict *test_dict = qdict_new();
@ -674,6 +706,7 @@ int main(int argc, char **argv)
g_test_add_func("/public/defaults", qdict_defaults_test);
g_test_add_func("/public/flatten", qdict_flatten_test);
g_test_add_func("/public/clone_flatten", qdict_clone_flatten_test);
g_test_add_func("/public/array_split", qdict_array_split_test);
g_test_add_func("/public/array_entries", qdict_array_entries_test);
g_test_add_func("/public/join", qdict_join_test);

View File

@ -1 +0,0 @@
tests/qapi-schema/flat-union-incomplete-branch.json:6: Union 'TestUnion' data missing 'value2' branch

View File

@ -1,9 +0,0 @@
# we require all branches of the union to be covered
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'struct': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'union': 'TestUnion',
'base': { 'type': 'TestEnum' },
'discriminator': 'type',
'data': { 'value1': 'TestTypeA' } }

View File

@ -39,7 +39,7 @@
'*enum1': 'EnumOne' } } # intentional forward reference
{ 'enum': 'EnumOne',
'data': [ 'value1', 'value2', 'value3' ] }
'data': [ 'value1', 'value2', 'value3', 'value4' ] }
{ 'struct': 'UserDefZero',
'data': { 'integer': 'int' } }
@ -76,7 +76,9 @@
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
'value3' : 'UserDefB'
# 'value4' defaults to empty
} }
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',

View File

@ -23,7 +23,7 @@ object UserDefOne
base UserDefZero
member string: str optional=False
member enum1: EnumOne optional=True
enum EnumOne ['value1', 'value2', 'value3']
enum EnumOne ['value1', 'value2', 'value3', 'value4']
object UserDefZero
member integer: int optional=False
object UserDefTwoDictDict
@ -52,6 +52,7 @@ object UserDefFlatUnion
case value1: UserDefA
case value2: UserDefB
case value3: UserDefB
case value4: q_empty
object UserDefUnionBase
base UserDefZero
member string: str optional=False