]> xenbits.xensource.com Git - osstest/qemu.git/commitdiff
qapi: Test for various name collisions
authorEric Blake <eblake@redhat.com>
Tue, 29 Sep 2015 22:21:03 +0000 (16:21 -0600)
committerMarkus Armbruster <armbru@redhat.com>
Mon, 12 Oct 2015 16:44:54 +0000 (18:44 +0200)
Expose some weaknesses in the generator: we don't always forbid
the generation of structs that contain multiple members that map
to the same C or QMP name.  This has already been marked FIXME in
qapi.py in commit d90675f, but having more tests will make sure
future patches produce desired behavior; and updating existing
patches to better document things doesn't hurt, either.  Some of
these collisions are already caught in the old-style parser
checks, but ultimately we want all collisions to be caught in the
new-style QAPISchema*.check() methods.

This patch focuses on C struct members, and does not consider
collisions between commands and events (affecting C function
names), or even collisions between generated C type names with
user type names (for things like automatic FOOList struct
representing array types or FOOKind for an implicit enum).

There are two types of struct collisions we want to catch:
 1) Collision between two keys in a JSON object. qapi.py prevents
    that within a single struct (see test duplicate-key), but it is
    possible to have collisions between a type's members and its
    base type's members (existing tests struct-base-clash,
    struct-base-clash-deep), and its flat union variant members
    (renamed test flat-union-clash-member).
 2) Collision between two members of the C struct that is generated
    for a given QAPI type:
    a) Multiple QAPI names map to the same C name (new test
       args-name-clash)
    b) A QAPI name maps to a C name that is used for another purpose
       (new tests flat-union-clash-branch, struct-base-clash-base,
       union-clash-data). We already fixed some such cases in commit
       0f61af3e and 1e6c1616, but more remain.
    c) Two C names generated for other purposes clash
       (updated test alternate-clash, new test union-clash-branches,
       union-clash-type, flat-union-clash-type)

Ultimately, if we need to have a flat union where a tag value
clashes with a base member name, we could change the generator to
name the union (using 'foo.u.value' rather than 'foo.value') or
otherwise munge the C name corresponding to tag values.  But
unless such a need arises, it will probably be easier to just
forbid these collisions.

Some of these negative tests will be deleted later, and positive
tests added to qapi-schema-test.json in their place, when the
generator code is reworked to avoid particular code generation
collisions in class 2).

[Note that viewing this patch with git rename detection enabled
may see some confusion due to renaming some tests while adding
others, but where the content is similar enough that git picks
the wrong pre- and post-patch files to associate]

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1443565276-4535-6-git-send-email-eblake@redhat.com>
[Improve commit message and comments a bit, drop an unrelated test]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
49 files changed:
tests/Makefile
tests/qapi-schema/alternate-clash.err
tests/qapi-schema/alternate-clash.json
tests/qapi-schema/args-name-clash.err [new file with mode: 0644]
tests/qapi-schema/args-name-clash.exit [new file with mode: 0644]
tests/qapi-schema/args-name-clash.json [new file with mode: 0644]
tests/qapi-schema/args-name-clash.out [new file with mode: 0644]
tests/qapi-schema/duplicate-key.err
tests/qapi-schema/duplicate-key.json
tests/qapi-schema/flat-union-base-union.err
tests/qapi-schema/flat-union-base-union.json
tests/qapi-schema/flat-union-branch-clash.err [deleted file]
tests/qapi-schema/flat-union-branch-clash.exit [deleted file]
tests/qapi-schema/flat-union-branch-clash.json [deleted file]
tests/qapi-schema/flat-union-branch-clash.out [deleted file]
tests/qapi-schema/flat-union-clash-branch.err [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-branch.exit [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-branch.json [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-branch.out [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-member.err [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-member.exit [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-member.json [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-member.out [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-type.err [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-type.exit [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-type.json [new file with mode: 0644]
tests/qapi-schema/flat-union-clash-type.out [new file with mode: 0644]
tests/qapi-schema/qapi-schema-test.json
tests/qapi-schema/qapi-schema-test.out
tests/qapi-schema/struct-base-clash-base.err [new file with mode: 0644]
tests/qapi-schema/struct-base-clash-base.exit [new file with mode: 0644]
tests/qapi-schema/struct-base-clash-base.json [new file with mode: 0644]
tests/qapi-schema/struct-base-clash-base.out [new file with mode: 0644]
tests/qapi-schema/struct-base-clash-deep.err
tests/qapi-schema/struct-base-clash-deep.json
tests/qapi-schema/struct-base-clash.err
tests/qapi-schema/struct-base-clash.json
tests/qapi-schema/union-clash-branches.err [new file with mode: 0644]
tests/qapi-schema/union-clash-branches.exit [new file with mode: 0644]
tests/qapi-schema/union-clash-branches.json [new file with mode: 0644]
tests/qapi-schema/union-clash-branches.out [new file with mode: 0644]
tests/qapi-schema/union-clash-data.err [new file with mode: 0644]
tests/qapi-schema/union-clash-data.exit [new file with mode: 0644]
tests/qapi-schema/union-clash-data.json [new file with mode: 0644]
tests/qapi-schema/union-clash-data.out [new file with mode: 0644]
tests/qapi-schema/union-clash-type.err [new file with mode: 0644]
tests/qapi-schema/union-clash-type.exit [new file with mode: 0644]
tests/qapi-schema/union-clash-type.json [new file with mode: 0644]
tests/qapi-schema/union-clash-type.out [new file with mode: 0644]

index 164dea3cb82e83d8b116bd06e166d3b3c201532b..49fdbe28aa1af5ec7d1c3271e5a8948410b02409 100644 (file)
@@ -241,6 +241,7 @@ qapi-schema += args-invalid.json
 qapi-schema += args-member-array-bad.json
 qapi-schema += args-member-array.json
 qapi-schema += args-member-unknown.json
+qapi-schema += args-name-clash.json
 qapi-schema += args-union.json
 qapi-schema += args-unknown.json
 qapi-schema += bad-base.json
@@ -276,7 +277,9 @@ qapi-schema += flat-union-bad-base.json
 qapi-schema += flat-union-bad-discriminator.json
 qapi-schema += flat-union-base-any.json
 qapi-schema += flat-union-base-union.json
-qapi-schema += flat-union-branch-clash.json
+qapi-schema += flat-union-clash-branch.json
+qapi-schema += flat-union-clash-member.json
+qapi-schema += flat-union-clash-type.json
 qapi-schema += flat-union-inline.json
 qapi-schema += flat-union-int-branch.json
 qapi-schema += flat-union-invalid-branch-key.json
@@ -318,6 +321,7 @@ qapi-schema += returns-dict.json
 qapi-schema += returns-int.json
 qapi-schema += returns-unknown.json
 qapi-schema += returns-whitelist.json
+qapi-schema += struct-base-clash-base.json
 qapi-schema += struct-base-clash-deep.json
 qapi-schema += struct-base-clash.json
 qapi-schema += struct-data-invalid.json
@@ -331,6 +335,9 @@ qapi-schema += unclosed-string.json
 qapi-schema += unicode-str.json
 qapi-schema += union-bad-branch.json
 qapi-schema += union-base-no-discriminator.json
+qapi-schema += union-clash-branches.json
+qapi-schema += union-clash-data.json
+qapi-schema += union-clash-type.json
 qapi-schema += union-invalid-base.json
 qapi-schema += union-max.json
 qapi-schema += union-optional-branch.json
index 51bea3e2724ddfd14fe8bdd4fdeef94c72fc1c2f..a475ab63437370f830ace301de694cd8ca214c3d 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/alternate-clash.json:2: Alternate 'Alt1' member 'ONE' clashes with 'one'
+tests/qapi-schema/alternate-clash.json:7: Alternate 'Alt1' member 'a_b' clashes with 'a-b'
index 39479353bb1a53301734cf6476c62bca2fa286c4..6d73bc527b9a7f4594e375e6a802f72cbf6bfb93 100644 (file)
@@ -1,3 +1,8 @@
-# we detect C enum collisions in an alternate
+# Alternate branch name collision
+# Reject an alternate that would result in a collision in generated C
+# names (this would try to generate two enum values 'ALT1_KIND_A_B').
+# TODO: In the future, if alternates are simplified to not generate
+# the implicit Alt1Kind enum, we would still have a collision with the
+# resulting C union trying to have two members named 'a_b'.
 { 'alternate': 'Alt1',
-  'data': { 'one': 'str', 'ONE': 'int' } }
+  'data': { 'a-b': 'str', 'a_b': 'int' } }
diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/args-name-clash.exit b/tests/qapi-schema/args-name-clash.exit
new file mode 100644 (file)
index 0000000..573541a
--- /dev/null
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/args-name-clash.json b/tests/qapi-schema/args-name-clash.json
new file mode 100644 (file)
index 0000000..9e8f889
--- /dev/null
@@ -0,0 +1,5 @@
+# C member name collision
+# FIXME - This parses, but fails to compile, because the C struct is given
+# two 'a_b' members.  Either reject this at parse time, or munge the C names
+# to avoid the collision.
+{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
diff --git a/tests/qapi-schema/args-name-clash.out b/tests/qapi-schema/args-name-clash.out
new file mode 100644 (file)
index 0000000..9b2f6e4
--- /dev/null
@@ -0,0 +1,6 @@
+object :empty
+object :obj-oops-arg
+    member a-b: str optional=False
+    member a_b: str optional=False
+command oops :obj-oops-arg -> None
+   gen=True success_response=True
index 768b276f806392e8d520d0de70a0d17a5164c1c1..6d02f83538865f9a56fedab66be768295774f19e 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/duplicate-key.json:2:10: Duplicate key "key"
+tests/qapi-schema/duplicate-key.json:3:10: Duplicate key "key"
index 1b55d88107c339a8e1faf41e4fac41979efe364e..14ac0e8a4022a2c78472d2a1db0a40f9c03fe325 100644 (file)
@@ -1,2 +1,3 @@
+# QAPI cannot include the same key more than once in any {}
 { 'key': 'value',
   'key': 'value' }
index ede9859a398e2b1e3fb2c227f053ea4225d2117c..28725ed1e3f292f64e30264c49b3208319a2454d 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/flat-union-base-union.json:11: Base 'UnionBase' is not a valid struct
+tests/qapi-schema/flat-union-base-union.json:14: Base 'UnionBase' is not a valid struct
index 6a8ea687a9ea13d42c2ce1344962673d364e3e73..98b4eba181e4426b32728b0916d2175184d89db3 100644 (file)
@@ -1,4 +1,7 @@
-# we require the base to be a struct
+# For now, we require the base to be a struct without variants
+# TODO: It would be possible to allow a union as a base, as long as all
+# permutations of QMP names exposed by base do not clash with any QMP
+# member names added by local variants.
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
 { 'struct': 'TestTypeA',
diff --git a/tests/qapi-schema/flat-union-branch-clash.err b/tests/qapi-schema/flat-union-branch-clash.err
deleted file mode 100644 (file)
index f112766..0000000
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/flat-union-branch-clash.json:10: Member name 'name' of branch 'value1' clashes with base 'Base'
diff --git a/tests/qapi-schema/flat-union-branch-clash.exit b/tests/qapi-schema/flat-union-branch-clash.exit
deleted file mode 100644 (file)
index d00491f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/flat-union-branch-clash.json b/tests/qapi-schema/flat-union-branch-clash.json
deleted file mode 100644 (file)
index 8fb054f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# we check for no duplicate keys between branches and base
-{ 'enum': 'TestEnum',
-  'data': [ 'value1', 'value2' ] }
-{ 'struct': 'Base',
-  'data': { 'enum1': 'TestEnum', '*name': 'str' } }
-{ 'struct': 'Branch1',
-  'data': { 'name': 'str' } }
-{ 'struct': 'Branch2',
-  'data': { 'value': 'int' } }
-{ 'union': 'TestUnion',
-  'base': 'Base',
-  'discriminator': 'enum1',
-  'data': { 'value1': 'Branch1',
-            'value2': 'Branch2' } }
diff --git a/tests/qapi-schema/flat-union-branch-clash.out b/tests/qapi-schema/flat-union-branch-clash.out
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/qapi-schema/flat-union-clash-branch.err b/tests/qapi-schema/flat-union-clash-branch.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/flat-union-clash-branch.exit b/tests/qapi-schema/flat-union-clash-branch.exit
new file mode 100644 (file)
index 0000000..573541a
--- /dev/null
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/flat-union-clash-branch.json b/tests/qapi-schema/flat-union-clash-branch.json
new file mode 100644 (file)
index 0000000..e593336
--- /dev/null
@@ -0,0 +1,18 @@
+# Flat union branch name collision
+# FIXME: this parses, but then fails to compile due to a duplicate 'c_d'
+# (one from the base member, the other from the branch name).  We should
+# either reject the collision at parse time, or munge the generated branch
+# name to allow this to compile.
+{ 'enum': 'TestEnum',
+  'data': [ 'base', 'c-d' ] }
+{ 'struct': 'Base',
+  'data': { 'enum1': 'TestEnum', '*c_d': 'str' } }
+{ 'struct': 'Branch1',
+  'data': { 'string': 'str' } }
+{ 'struct': 'Branch2',
+  'data': { 'value': 'int' } }
+{ 'union': 'TestUnion',
+  'base': 'Base',
+  'discriminator': 'enum1',
+  'data': { 'base': 'Branch1',
+            'c-d': 'Branch2' } }
diff --git a/tests/qapi-schema/flat-union-clash-branch.out b/tests/qapi-schema/flat-union-clash-branch.out
new file mode 100644 (file)
index 0000000..8e0da73
--- /dev/null
@@ -0,0 +1,14 @@
+object :empty
+object Base
+    member enum1: TestEnum optional=False
+    member c_d: str optional=True
+object Branch1
+    member string: str optional=False
+object Branch2
+    member value: int optional=False
+enum TestEnum ['base', 'c-d']
+object TestUnion
+    base Base
+    tag enum1
+    case base: Branch1
+    case c-d: Branch2
diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err
new file mode 100644 (file)
index 0000000..2f0397a
--- /dev/null
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-clash-member.json:11: Member name 'name' of branch 'value1' clashes with base 'Base'
diff --git a/tests/qapi-schema/flat-union-clash-member.exit b/tests/qapi-schema/flat-union-clash-member.exit
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-clash-member.json b/tests/qapi-schema/flat-union-clash-member.json
new file mode 100644 (file)
index 0000000..9efc771
--- /dev/null
@@ -0,0 +1,15 @@
+# We check for no duplicate keys between branch members and base
+# base's member 'name' clashes with Branch1's
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+{ 'struct': 'Base',
+  'data': { 'enum1': 'TestEnum', '*name': 'str' } }
+{ 'struct': 'Branch1',
+  'data': { 'name': 'str' } }
+{ 'struct': 'Branch2',
+  'data': { 'value': 'int' } }
+{ 'union': 'TestUnion',
+  'base': 'Base',
+  'discriminator': 'enum1',
+  'data': { 'value1': 'Branch1',
+            'value2': 'Branch2' } }
diff --git a/tests/qapi-schema/flat-union-clash-member.out b/tests/qapi-schema/flat-union-clash-member.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/flat-union-clash-type.err b/tests/qapi-schema/flat-union-clash-type.err
new file mode 100644 (file)
index 0000000..6e64d1d
--- /dev/null
@@ -0,0 +1,16 @@
+Traceback (most recent call last):
+  File "tests/qapi-schema/test-qapi.py", line 55, in <module>
+    schema = QAPISchema(sys.argv[1])
+  File "scripts/qapi.py", line 1116, in __init__
+    self.check()
+  File "scripts/qapi.py", line 1299, in check
+    ent.check(self)
+  File "scripts/qapi.py", line 962, in check
+    self.variants.check(schema, members, seen)
+  File "scripts/qapi.py", line 1024, in check
+    v.check(schema, self.tag_member.type, vseen)
+  File "scripts/qapi.py", line 1032, in check
+    QAPISchemaObjectTypeMember.check(self, schema, [], seen)
+  File "scripts/qapi.py", line 994, in check
+    assert self.name not in seen
+AssertionError
diff --git a/tests/qapi-schema/flat-union-clash-type.exit b/tests/qapi-schema/flat-union-clash-type.exit
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-clash-type.json b/tests/qapi-schema/flat-union-clash-type.json
new file mode 100644 (file)
index 0000000..3db6ea0
--- /dev/null
@@ -0,0 +1,16 @@
+# Flat union branch 'type'
+# FIXME: this triggers an assertion failure. But even with that fixed,
+# we would have a clash in generated C, between the member 'type'
+# inherited from 'Base' and the branch name 'type' within the
+# union. We should either reject this, or munge the generated C to let
+# it compile.
+{ 'enum': 'TestEnum',
+  'data': [ 'type' ] }
+{ 'struct': 'Base',
+  'data': { 'type': 'TestEnum' } }
+{ 'struct': 'Branch1',
+  'data': { 'string': 'str' } }
+{ 'union': 'TestUnion',
+  'base': 'Base',
+  'discriminator': 'type',
+  'data': { 'type': 'Branch1' } }
diff --git a/tests/qapi-schema/flat-union-clash-type.out b/tests/qapi-schema/flat-union-clash-type.out
new file mode 100644 (file)
index 0000000..e69de29
index 6897a6ea391a85e5752368ecabff32c8e9d62b2d..c51133808391c663a076083cf1151349adcda557 100644 (file)
             'dict1': 'UserDefTwoDict' } }
 
 # for testing unions
+# Among other things, test that a name collision between branches does
+# not cause any problems (since only one branch can be in use at a time),
+# by intentionally using two branches that both have a C member 'a_b'
 { 'struct': 'UserDefA',
-  'data': { 'boolean': 'bool' } }
+  'data': { 'boolean': 'bool', '*a_b': 'int' } }
 
 { 'struct': 'UserDefB',
-  'data': { 'intb': 'int' } }
+  'data': { 'intb': 'int', '*a-b': 'bool' } }
 
 { 'union': 'UserDefFlatUnion',
   'base': 'UserDefUnionBase',   # intentional forward reference
index 1f6e858def72398d15ab092df9b7a9627cdc867e..28a0b3c1dfff3ce0545b3059149409ed50ee58c7 100644 (file)
@@ -71,6 +71,7 @@ enum QEnumTwo ['value1', 'value2']
     prefix QENUM_TWO
 object UserDefA
     member boolean: bool optional=False
+    member a_b: int optional=True
 alternate UserDefAlternate
     case uda: UserDefA
     case s: str
@@ -78,6 +79,7 @@ alternate UserDefAlternate
 enum UserDefAlternateKind ['uda', 's', 'i']
 object UserDefB
     member intb: int optional=False
+    member a-b: bool optional=True
 object UserDefC
     member string1: str optional=False
     member string2: str optional=False
diff --git a/tests/qapi-schema/struct-base-clash-base.err b/tests/qapi-schema/struct-base-clash-base.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/struct-base-clash-base.exit b/tests/qapi-schema/struct-base-clash-base.exit
new file mode 100644 (file)
index 0000000..573541a
--- /dev/null
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/struct-base-clash-base.json b/tests/qapi-schema/struct-base-clash-base.json
new file mode 100644 (file)
index 0000000..0c84025
--- /dev/null
@@ -0,0 +1,9 @@
+# Struct member 'base'
+# FIXME: this parses, but then fails to compile due to a duplicate 'base'
+# (one explicit in QMP, the other used to box the base class members).
+# We should either reject the collision at parse time, or change the
+# generated struct to allow this to compile.
+{ 'struct': 'Base', 'data': {} }
+{ 'struct': 'Sub',
+  'base': 'Base',
+  'data': { 'base': 'str' } }
diff --git a/tests/qapi-schema/struct-base-clash-base.out b/tests/qapi-schema/struct-base-clash-base.out
new file mode 100644 (file)
index 0000000..e69a416
--- /dev/null
@@ -0,0 +1,5 @@
+object :empty
+object Base
+object Sub
+    base Base
+    member base: str optional=False
index e3e9f8d289b8fef2f7cd23372813d19846acff5d..f7a25a3b358396e027914c4466f96ae49da9ffa1 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash-deep.json:7: Member name 'name' clashes with base 'Base'
+tests/qapi-schema/struct-base-clash-deep.json:10: Member name 'name' clashes with base 'Base'
index 552fe94317a85463ea05a8d7d65d384b9811d1aa..fa873ab5d4e8a75cac7049f391b8185c1f61afde 100644 (file)
@@ -1,4 +1,7 @@
-# we check for no duplicate keys with indirect base
+# Reject attempts to duplicate QMP members
+# Here, 'name' would have to appear twice on the wire, locally and
+# indirectly for the grandparent base; the collision doesn't care that
+# one instance is optional.
 { 'struct': 'Base',
   'data': { 'name': 'str' } }
 { 'struct': 'Mid',
index 3ac37fb26a4d5ddea24b92305d1a152c3cddf4ed..3a9f66b04d4e9466a5c9ca61b4f4160eea5ed3b2 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash.json:4: Member name 'name' clashes with base 'Base'
+tests/qapi-schema/struct-base-clash.json:5: Member name 'name' clashes with base 'Base'
index f2afc9b6f660dd05a700bca31ff57760b070f0c3..11aec80fe53191cf53b793199c3e353356042cde 100644 (file)
@@ -1,4 +1,5 @@
-# we check for no duplicate keys with base
+# Reject attempts to duplicate QMP members
+# Here, 'name' would have to appear twice on the wire, locally and for base.
 { 'struct': 'Base',
   'data': { 'name': 'str' } }
 { 'struct': 'Sub',
diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err
new file mode 100644 (file)
index 0000000..005c48d
--- /dev/null
@@ -0,0 +1 @@
+tests/qapi-schema/union-clash-branches.json:4: Union 'TestUnion' member 'a_b' clashes with 'a-b'
diff --git a/tests/qapi-schema/union-clash-branches.exit b/tests/qapi-schema/union-clash-branches.exit
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-clash-branches.json b/tests/qapi-schema/union-clash-branches.json
new file mode 100644 (file)
index 0000000..31d135f
--- /dev/null
@@ -0,0 +1,5 @@
+# Union branch name collision
+# Reject a union that would result in a collision in generated C names (this
+# would try to generate two enum values 'TEST_UNION_KIND_A_B').
+{ 'union': 'TestUnion',
+  'data': { 'a-b': 'int', 'a_b': 'str' } }
diff --git a/tests/qapi-schema/union-clash-branches.out b/tests/qapi-schema/union-clash-branches.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/union-clash-data.err b/tests/qapi-schema/union-clash-data.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/qapi-schema/union-clash-data.exit b/tests/qapi-schema/union-clash-data.exit
new file mode 100644 (file)
index 0000000..573541a
--- /dev/null
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/union-clash-data.json b/tests/qapi-schema/union-clash-data.json
new file mode 100644 (file)
index 0000000..7308e69
--- /dev/null
@@ -0,0 +1,7 @@
+# Union branch 'data'
+# FIXME: this parses, but then fails to compile due to a duplicate 'data'
+# (one from the branch name, another as a filler to avoid an empty union).
+# we should either detect the collision at parse time, or change the
+# generated struct to allow this to compile.
+{ 'union': 'TestUnion',
+  'data': { 'data': 'int' } }
diff --git a/tests/qapi-schema/union-clash-data.out b/tests/qapi-schema/union-clash-data.out
new file mode 100644 (file)
index 0000000..6277239
--- /dev/null
@@ -0,0 +1,6 @@
+object :empty
+object :obj-int-wrapper
+    member data: int optional=False
+object TestUnion
+    case data: :obj-int-wrapper
+enum TestUnionKind ['data']
diff --git a/tests/qapi-schema/union-clash-type.err b/tests/qapi-schema/union-clash-type.err
new file mode 100644 (file)
index 0000000..6e64d1d
--- /dev/null
@@ -0,0 +1,16 @@
+Traceback (most recent call last):
+  File "tests/qapi-schema/test-qapi.py", line 55, in <module>
+    schema = QAPISchema(sys.argv[1])
+  File "scripts/qapi.py", line 1116, in __init__
+    self.check()
+  File "scripts/qapi.py", line 1299, in check
+    ent.check(self)
+  File "scripts/qapi.py", line 962, in check
+    self.variants.check(schema, members, seen)
+  File "scripts/qapi.py", line 1024, in check
+    v.check(schema, self.tag_member.type, vseen)
+  File "scripts/qapi.py", line 1032, in check
+    QAPISchemaObjectTypeMember.check(self, schema, [], seen)
+  File "scripts/qapi.py", line 994, in check
+    assert self.name not in seen
+AssertionError
diff --git a/tests/qapi-schema/union-clash-type.exit b/tests/qapi-schema/union-clash-type.exit
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-clash-type.json b/tests/qapi-schema/union-clash-type.json
new file mode 100644 (file)
index 0000000..52c21f7
--- /dev/null
@@ -0,0 +1,10 @@
+# Union branch 'type'
+# FIXME: this triggers an assertion failure. But even with that fixed,
+# we would have a clash in generated C, between the simple union's
+# implicit tag member 'kind' and the branch name 'kind' within the
+# union. We should either reject this, or munge the generated C to let
+# it compile.
+# TODO: Even when the generated C is switched to use 'type' rather than
+# 'kind', to match the QMP spelling, the collision should still be detected.
+{ 'union': 'TestUnion',
+  'data': { 'kind': 'int', 'type': 'str' } }
diff --git a/tests/qapi-schema/union-clash-type.out b/tests/qapi-schema/union-clash-type.out
new file mode 100644 (file)
index 0000000..e69de29