* [PATCH v3 0/3] qapi: allow unions to contain further unions
@ 2023-04-20 10:26 Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 1/3] qapi: support updating expected test output via make Daniel P. Berrangé
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-20 10:26 UTC (permalink / raw)
To: qemu-devel
Cc: Het Gala, Markus Armbruster, Eric Blake, Michael Roth,
Daniel P. Berrangé
Currently it is not possible for a union type to contain a
further union as one (or more) of its branches. This relaxes
that restriction and adds the calls needed to validate field
name uniqueness as unions are flattened.
In v3:
* Use markus' suggestion for improved error messages
* Set env var default in argparse directly
In v2:
* Improve specificity of type/members descriptions for
error reporting scenarios
* Make it easier to regenerate qapi test output
* Move expected "good data" into qapi-schema-test.json
* Add description to "bad data" test files
* Add unit tests to cover union-in-union serialization
/ deserialization to/from JSON
Daniel P. Berrangé (3):
qapi: support updating expected test output via make
qapi: improve specificity of type/member descriptions
qapi: allow unions to contain further unions
scripts/qapi/schema.py | 15 +++--
tests/qapi-schema/meson.build | 2 +
tests/qapi-schema/qapi-schema-test.json | 32 ++++++++++
tests/qapi-schema/qapi-schema-test.out | 29 ++++++++++
tests/qapi-schema/test-qapi.py | 1 +
.../union-invalid-union-subfield.err | 2 +
.../union-invalid-union-subfield.json | 30 ++++++++++
.../union-invalid-union-subfield.out | 0
.../union-invalid-union-subtype.err | 2 +
.../union-invalid-union-subtype.json | 29 ++++++++++
.../union-invalid-union-subtype.out | 0
tests/unit/test-qobject-input-visitor.c | 47 +++++++++++++++
tests/unit/test-qobject-output-visitor.c | 58 +++++++++++++++++++
13 files changed, 242 insertions(+), 5 deletions(-)
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.err
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.json
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.out
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.err
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.json
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.out
--
2.40.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/3] qapi: support updating expected test output via make
2023-04-20 10:26 [PATCH v3 0/3] qapi: allow unions to contain further unions Daniel P. Berrangé
@ 2023-04-20 10:26 ` Daniel P. Berrangé
2023-04-24 11:39 ` Markus Armbruster
2023-04-20 10:26 ` [PATCH v3 2/3] qapi: improve specificity of type/member descriptions Daniel P. Berrangé
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-20 10:26 UTC (permalink / raw)
To: qemu-devel
Cc: Het Gala, Markus Armbruster, Eric Blake, Michael Roth,
Daniel P. Berrangé
It is possible to pass --update to tests/qapi-schema/test-qapi.py
to make it update the output files on error. This is inconvenient
to achieve though when test-qapi.py is run indirectly by make/meson.
Instead simply allow for an env variable to be set:
$ QAPI_TEST_UPDATE= make check-qapi-schema
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
tests/qapi-schema/test-qapi.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 2160cef082..d58c31f539 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -206,6 +206,7 @@ def main(argv):
parser.add_argument('-d', '--dir', action='store', default='',
help="directory containing tests")
parser.add_argument('-u', '--update', action='store_true',
+ default='QAPI_TEST_UPDATE' in os.environ,
help="update expected test results")
parser.add_argument('tests', nargs='*', metavar='TEST', action='store')
args = parser.parse_args()
--
2.40.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/3] qapi: improve specificity of type/member descriptions
2023-04-20 10:26 [PATCH v3 0/3] qapi: allow unions to contain further unions Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 1/3] qapi: support updating expected test output via make Daniel P. Berrangé
@ 2023-04-20 10:26 ` Daniel P. Berrangé
2023-04-24 11:38 ` Markus Armbruster
2023-04-20 10:26 ` [PATCH v3 3/3] qapi: allow unions to contain further unions Daniel P. Berrangé
2023-04-25 13:28 ` [PATCH v3 0/3] " Markus Armbruster
3 siblings, 1 reply; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-20 10:26 UTC (permalink / raw)
To: qemu-devel
Cc: Het Gala, Markus Armbruster, Eric Blake, Michael Roth,
Daniel P. Berrangé
When describing member types always include the context of the
containing type. Although this is often redundant, in some cases
it will help to reduce ambiguity.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
scripts/qapi/schema.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 207e4d71f3..da04b97ded 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -697,6 +697,7 @@ def connect_doc(self, doc):
def describe(self, info):
role = self.role
+ meta = 'type'
defined_in = self.defined_in
assert defined_in
@@ -708,13 +709,17 @@ def describe(self, info):
# Implicit type created for a command's dict 'data'
assert role == 'member'
role = 'parameter'
+ meta = 'command'
+ defined_in = defined_in[:-4]
elif defined_in.endswith('-base'):
# Implicit type created for a union's dict 'base'
role = 'base ' + role
+ defined_in = defined_in[:-5]
else:
assert False
- elif defined_in != info.defn_name:
- return "%s '%s' of type '%s'" % (role, self.name, defined_in)
+
+ if defined_in != info.defn_name:
+ return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
return "%s '%s'" % (role, self.name)
--
2.40.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/3] qapi: allow unions to contain further unions
2023-04-20 10:26 [PATCH v3 0/3] qapi: allow unions to contain further unions Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 1/3] qapi: support updating expected test output via make Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 2/3] qapi: improve specificity of type/member descriptions Daniel P. Berrangé
@ 2023-04-20 10:26 ` Daniel P. Berrangé
2023-04-25 13:28 ` [PATCH v3 0/3] " Markus Armbruster
3 siblings, 0 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-20 10:26 UTC (permalink / raw)
To: qemu-devel
Cc: Het Gala, Markus Armbruster, Eric Blake, Michael Roth,
Daniel P. Berrangé
This extends the QAPI schema validation to permit unions inside unions,
provided the checks for clashing fields pass.
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
scripts/qapi/schema.py | 6 +-
tests/qapi-schema/meson.build | 2 +
tests/qapi-schema/qapi-schema-test.json | 32 ++++++++++
tests/qapi-schema/qapi-schema-test.out | 29 ++++++++++
.../union-invalid-union-subfield.err | 2 +
.../union-invalid-union-subfield.json | 30 ++++++++++
.../union-invalid-union-subfield.out | 0
.../union-invalid-union-subtype.err | 2 +
.../union-invalid-union-subtype.json | 29 ++++++++++
.../union-invalid-union-subtype.out | 0
tests/unit/test-qobject-input-visitor.c | 47 +++++++++++++++
tests/unit/test-qobject-output-visitor.c | 58 +++++++++++++++++++
12 files changed, 234 insertions(+), 3 deletions(-)
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.err
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.json
create mode 100644 tests/qapi-schema/union-invalid-union-subfield.out
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.err
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.json
create mode 100644 tests/qapi-schema/union-invalid-union-subtype.out
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index da04b97ded..edb09f2ed2 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -465,9 +465,10 @@ def check(self, schema):
# on behalf of info, which is not necessarily self.info
def check_clash(self, info, seen):
assert self._checked
- assert not self.variants # not implemented
for m in self.members:
m.check_clash(info, seen)
+ if self.variants:
+ self.variants.check_clash(info, seen)
def connect_doc(self, doc=None):
super().connect_doc(doc)
@@ -652,8 +653,7 @@ def check(self, schema, seen):
self.info,
"branch '%s' is not a value of %s"
% (v.name, self.tag_member.type.describe()))
- if (not isinstance(v.type, QAPISchemaObjectType)
- or v.type.variants):
+ if not isinstance(v.type, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"%s cannot use %s"
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index d85b14f28c..1591eb322b 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -194,6 +194,8 @@ schemas = [
'union-invalid-data.json',
'union-invalid-discriminator.json',
'union-invalid-if-discriminator.json',
+ 'union-invalid-union-subfield.json',
+ 'union-invalid-union-subtype.json',
'union-no-base.json',
'union-optional-discriminator.json',
'union-string-discriminator.json',
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index ba7302f42b..40f1a3d88d 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -114,6 +114,38 @@
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
+# this tests that unions can contain other unions in their branches
+{ 'enum': 'TestUnionEnum',
+ 'data': [ 'value-a', 'value-b' ] }
+
+{ 'enum': 'TestUnionEnumA',
+ 'data': [ 'value-a1', 'value-a2' ] }
+
+{ 'struct': 'TestUnionTypeA1',
+ 'data': { 'integer': 'int',
+ 'name': 'str'} }
+
+{ 'struct': 'TestUnionTypeA2',
+ 'data': { 'integer': 'int',
+ 'size': 'int' } }
+
+{ 'union': 'TestUnionTypeA',
+ 'base': { 'type-a': 'TestUnionEnumA' },
+ 'discriminator': 'type-a',
+ 'data': { 'value-a1': 'TestUnionTypeA1',
+ 'value-a2': 'TestUnionTypeA2' } }
+
+{ 'struct': 'TestUnionTypeB',
+ 'data': { 'integer': 'int',
+ 'onoff': 'bool' } }
+
+{ 'union': 'TestUnionInUnion',
+ 'base': { 'type': 'TestUnionEnum' },
+ 'discriminator': 'type',
+ 'data': { 'value-a': 'TestUnionTypeA',
+ 'value-b': 'TestUnionTypeB' } }
+
+
# for testing use of 'number' within alternates
{ 'alternate': 'AltEnumBool', 'data': { 'e': 'EnumOne', 'b': 'bool' } }
{ 'alternate': 'AltEnumNum', 'data': { 'e': 'EnumOne', 'n': 'number' } }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 043d75c655..9fe1038944 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -105,6 +105,35 @@ alternate UserDefAlternate
object UserDefC
member string1: str optional=False
member string2: str optional=False
+enum TestUnionEnum
+ member value-a
+ member value-b
+enum TestUnionEnumA
+ member value-a1
+ member value-a2
+object TestUnionTypeA1
+ member integer: int optional=False
+ member name: str optional=False
+object TestUnionTypeA2
+ member integer: int optional=False
+ member size: int optional=False
+object q_obj_TestUnionTypeA-base
+ member type-a: TestUnionEnumA optional=False
+object TestUnionTypeA
+ base q_obj_TestUnionTypeA-base
+ tag type-a
+ case value-a1: TestUnionTypeA1
+ case value-a2: TestUnionTypeA2
+object TestUnionTypeB
+ member integer: int optional=False
+ member onoff: bool optional=False
+object q_obj_TestUnionInUnion-base
+ member type: TestUnionEnum optional=False
+object TestUnionInUnion
+ base q_obj_TestUnionInUnion-base
+ tag type
+ case value-a: TestUnionTypeA
+ case value-b: TestUnionTypeB
alternate AltEnumBool
tag type
case e: EnumOne
diff --git a/tests/qapi-schema/union-invalid-union-subfield.err b/tests/qapi-schema/union-invalid-union-subfield.err
new file mode 100644
index 0000000000..91aa87bcd8
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-union-subfield.err
@@ -0,0 +1,2 @@
+union-invalid-union-subfield.json: In union 'TestUnion':
+union-invalid-union-subfield.json:25: member 'teeth' of type 'TestTypeFish' collides with base member 'teeth'
diff --git a/tests/qapi-schema/union-invalid-union-subfield.json b/tests/qapi-schema/union-invalid-union-subfield.json
new file mode 100644
index 0000000000..e1639d3a96
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-union-subfield.json
@@ -0,0 +1,30 @@
+# Clash between common member and union variant's variant member
+# Base's member 'teeth' clashes with TestTypeFish's
+
+{ 'enum': 'TestEnum',
+ 'data': [ 'animals', 'plants' ] }
+
+{ 'enum': 'TestAnimals',
+ 'data': [ 'fish', 'birds'] }
+
+{ 'struct': 'TestTypeFish',
+ 'data': { 'scales': 'int', 'teeth': 'int' } }
+
+{ 'struct': 'TestTypeBirds',
+ 'data': { 'feathers': 'int' } }
+
+{ 'union': 'TestTypeAnimals',
+ 'base': { 'atype': 'TestAnimals' },
+ 'discriminator': 'atype',
+ 'data': { 'fish': 'TestTypeFish',
+ 'birds': 'TestTypeBirds' } }
+
+{ 'struct': 'TestTypePlants',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': { 'type': 'TestEnum',
+ 'teeth': 'int' },
+ 'discriminator': 'type',
+ 'data': { 'animals': 'TestTypeAnimals',
+ 'plants': 'TestTypePlants' } }
diff --git a/tests/qapi-schema/union-invalid-union-subfield.out b/tests/qapi-schema/union-invalid-union-subfield.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/union-invalid-union-subtype.err b/tests/qapi-schema/union-invalid-union-subtype.err
new file mode 100644
index 0000000000..3538dc2e70
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-union-subtype.err
@@ -0,0 +1,2 @@
+union-invalid-union-subtype.json: In union 'TestUnion':
+union-invalid-union-subtype.json:25: base member 'type' of type 'TestTypeA' collides with base member 'type'
diff --git a/tests/qapi-schema/union-invalid-union-subtype.json b/tests/qapi-schema/union-invalid-union-subtype.json
new file mode 100644
index 0000000000..ce1de51d8d
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-union-subtype.json
@@ -0,0 +1,29 @@
+# Clash between common member and union variant's common member
+# Base's member 'type' clashes with TestTypeA's
+
+{ 'enum': 'TestEnum',
+ 'data': [ 'value-a', 'value-b' ] }
+
+{ 'enum': 'TestEnumA',
+ 'data': [ 'value-a1', 'value-a2' ] }
+
+{ 'struct': 'TestTypeA1',
+ 'data': { 'integer': 'int' } }
+
+{ 'struct': 'TestTypeA2',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestTypeA',
+ 'base': { 'type': 'TestEnumA' },
+ 'discriminator': 'type',
+ 'data': { 'value-a1': 'TestTypeA1',
+ 'value-a2': 'TestTypeA2' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': { 'type': 'TestEnum' },
+ 'discriminator': 'type',
+ 'data': { 'value-a': 'TestTypeA',
+ 'value-b': 'TestTypeB' } }
diff --git a/tests/qapi-schema/union-invalid-union-subtype.out b/tests/qapi-schema/union-invalid-union-subtype.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c
index 77fbf985be..9b3e2dbe14 100644
--- a/tests/unit/test-qobject-input-visitor.c
+++ b/tests/unit/test-qobject-input-visitor.c
@@ -706,6 +706,51 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
g_assert(&base->enum1 == &tmp->enum1);
}
+static void test_visitor_in_union_in_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ Visitor *v;
+ g_autoptr(TestUnionInUnion) tmp = NULL;
+
+ v = visitor_input_test_init(data,
+ "{ 'type': 'value-a', "
+ " 'type-a': 'value-a1', "
+ " 'integer': 2, "
+ " 'name': 'fish' }");
+
+ visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
+ g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A1);
+ g_assert_cmpint(tmp->u.value_a.u.value_a1.integer, ==, 2);
+ g_assert_cmpint(strcmp(tmp->u.value_a.u.value_a1.name, "fish"), ==, 0);
+
+ qapi_free_TestUnionInUnion(tmp);
+
+ v = visitor_input_test_init(data,
+ "{ 'type': 'value-a', "
+ " 'type-a': 'value-a2', "
+ " 'integer': 1729, "
+ " 'size': 87539319 }");
+
+ visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
+ g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A2);
+ g_assert_cmpint(tmp->u.value_a.u.value_a2.integer, ==, 1729);
+ g_assert_cmpint(tmp->u.value_a.u.value_a2.size, ==, 87539319);
+
+ qapi_free_TestUnionInUnion(tmp);
+
+ v = visitor_input_test_init(data,
+ "{ 'type': 'value-b', "
+ " 'integer': 1729, "
+ " 'onoff': true }");
+
+ visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
+ g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_B);
+ g_assert_cmpint(tmp->u.value_b.integer, ==, 1729);
+ g_assert_cmpint(tmp->u.value_b.onoff, ==, true);
+}
+
static void test_visitor_in_alternate(TestInputVisitorData *data,
const void *unused)
{
@@ -1216,6 +1261,8 @@ int main(int argc, char **argv)
NULL, test_visitor_in_null);
input_visitor_test_add("/visitor/input/union-flat",
NULL, test_visitor_in_union_flat);
+ input_visitor_test_add("/visitor/input/union-in-union",
+ NULL, test_visitor_in_union_in_union);
input_visitor_test_add("/visitor/input/alternate",
NULL, test_visitor_in_alternate);
input_visitor_test_add("/visitor/input/errors",
diff --git a/tests/unit/test-qobject-output-visitor.c b/tests/unit/test-qobject-output-visitor.c
index 7f054289fe..1535b3ad17 100644
--- a/tests/unit/test-qobject-output-visitor.c
+++ b/tests/unit/test-qobject-output-visitor.c
@@ -352,6 +352,62 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
qapi_free_UserDefFlatUnion(tmp);
}
+static void test_visitor_out_union_in_union(TestOutputVisitorData *data,
+ const void *unused)
+{
+ QDict *qdict;
+
+ TestUnionInUnion *tmp = g_new0(TestUnionInUnion, 1);
+ tmp->type = TEST_UNION_ENUM_VALUE_A;
+ tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A1;
+ tmp->u.value_a.u.value_a1.integer = 42;
+ tmp->u.value_a.u.value_a1.name = g_strdup("fish");
+
+ visit_type_TestUnionInUnion(data->ov, NULL, &tmp, &error_abort);
+ qdict = qobject_to(QDict, visitor_get(data));
+ g_assert(qdict);
+ g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "value-a");
+ g_assert_cmpstr(qdict_get_str(qdict, "type-a"), ==, "value-a1");
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
+ g_assert_cmpstr(qdict_get_str(qdict, "name"), ==, "fish");
+
+ qapi_free_TestUnionInUnion(tmp);
+
+
+ visitor_reset(data);
+ tmp = g_new0(TestUnionInUnion, 1);
+ tmp->type = TEST_UNION_ENUM_VALUE_A;
+ tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A2;
+ tmp->u.value_a.u.value_a2.integer = 1729;
+ tmp->u.value_a.u.value_a2.size = 87539319;
+
+ visit_type_TestUnionInUnion(data->ov, NULL, &tmp, &error_abort);
+ qdict = qobject_to(QDict, visitor_get(data));
+ g_assert(qdict);
+ g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "value-a");
+ g_assert_cmpstr(qdict_get_str(qdict, "type-a"), ==, "value-a2");
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1729);
+ g_assert_cmpint(qdict_get_int(qdict, "size"), ==, 87539319);
+
+ qapi_free_TestUnionInUnion(tmp);
+
+
+ visitor_reset(data);
+ tmp = g_new0(TestUnionInUnion, 1);
+ tmp->type = TEST_UNION_ENUM_VALUE_B;
+ tmp->u.value_b.integer = 1729;
+ tmp->u.value_b.onoff = true;
+
+ visit_type_TestUnionInUnion(data->ov, NULL, &tmp, &error_abort);
+ qdict = qobject_to(QDict, visitor_get(data));
+ g_assert(qdict);
+ g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "value-b");
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1729);
+ g_assert_cmpint(qdict_get_bool(qdict, "onoff"), ==, true);
+
+ qapi_free_TestUnionInUnion(tmp);
+}
+
static void test_visitor_out_alternate(TestOutputVisitorData *data,
const void *unused)
{
@@ -586,6 +642,8 @@ int main(int argc, char **argv)
&out_visitor_data, test_visitor_out_list_qapi_free);
output_visitor_test_add("/visitor/output/union-flat",
&out_visitor_data, test_visitor_out_union_flat);
+ output_visitor_test_add("/visitor/output/union-in-union",
+ &out_visitor_data, test_visitor_out_union_in_union);
output_visitor_test_add("/visitor/output/alternate",
&out_visitor_data, test_visitor_out_alternate);
output_visitor_test_add("/visitor/output/null",
--
2.40.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/3] qapi: improve specificity of type/member descriptions
2023-04-20 10:26 ` [PATCH v3 2/3] qapi: improve specificity of type/member descriptions Daniel P. Berrangé
@ 2023-04-24 11:38 ` Markus Armbruster
2023-04-25 12:32 ` Daniel P. Berrangé
0 siblings, 1 reply; 10+ messages in thread
From: Markus Armbruster @ 2023-04-24 11:38 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
Daniel P. Berrangé <berrange@redhat.com> writes:
> When describing member types always include the context of the
> containing type. Although this is often redundant, in some cases
> it will help to reduce ambiguity.
This is no longer true. It was in v2. Suggest:
Error messages describe object members, enumeration values, features,
and variants like ROLE 'NAME', where ROLE is "member", "value",
"feature", or "branch", respectively. When the member is defined in
another type, e.g. inherited from a base type, we add "of type
'TYPE'". Example: test case struct-base-clash-deep reports a member
of type 'Sub' clashing with a member of its base type 'Base' as
struct-base-clash-deep.json: In struct 'Sub':
struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base'
Members of implicitly defined types need special treatment. We don't
want to add "of type 'TYPE'" for them, because their named are made up
and mean nothing to the user. Instead, we describe members of an
implicitly defined base type as "base member 'NAME'", and command and
event parameters as "parameter 'NAME'". Example: test case
union-bad-base reports member of a variant's type clashing with a
member of its implicitly defined base type as
union-bad-base.json: In union 'TestUnion':
union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string'
The next commit will permit unions as variant types. "base member
'NAME' would then be ambigious: is it the union's base, or is it the
union's variant's base? One of its test cases would report a clash
between two such bases as "base member 'type' collides with base
member 'type'". Confusing.
Refine the special treatment: add "of TYPE" even for implicitly
defined types, but massage TYPE and ROLE so they make sense for the
user.
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> scripts/qapi/schema.py | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
> index 207e4d71f3..da04b97ded 100644
> --- a/scripts/qapi/schema.py
> +++ b/scripts/qapi/schema.py
> @@ -697,6 +697,7 @@ def connect_doc(self, doc):
>
> def describe(self, info):
> role = self.role
> + meta = 'type'
> defined_in = self.defined_in
> assert defined_in
>
> @@ -708,13 +709,17 @@ def describe(self, info):
> # Implicit type created for a command's dict 'data'
> assert role == 'member'
> role = 'parameter'
> + meta = 'command'
> + defined_in = defined_in[:-4]
> elif defined_in.endswith('-base'):
> # Implicit type created for a union's dict 'base'
> role = 'base ' + role
> + defined_in = defined_in[:-5]
> else:
> assert False
> - elif defined_in != info.defn_name:
> - return "%s '%s' of type '%s'" % (role, self.name, defined_in)
> +
> + if defined_in != info.defn_name:
> + return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
> return "%s '%s'" % (role, self.name)
Since I rewrote both the patch and the commit message, would you like me
to take the blame and claim authorship?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/3] qapi: support updating expected test output via make
2023-04-20 10:26 ` [PATCH v3 1/3] qapi: support updating expected test output via make Daniel P. Berrangé
@ 2023-04-24 11:39 ` Markus Armbruster
0 siblings, 0 replies; 10+ messages in thread
From: Markus Armbruster @ 2023-04-24 11:39 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
Daniel P. Berrangé <berrange@redhat.com> writes:
> It is possible to pass --update to tests/qapi-schema/test-qapi.py
> to make it update the output files on error. This is inconvenient
> to achieve though when test-qapi.py is run indirectly by make/meson.
>
> Instead simply allow for an env variable to be set:
>
> $ QAPI_TEST_UPDATE= make check-qapi-schema
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> tests/qapi-schema/test-qapi.py | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
> index 2160cef082..d58c31f539 100755
> --- a/tests/qapi-schema/test-qapi.py
> +++ b/tests/qapi-schema/test-qapi.py
> @@ -206,6 +206,7 @@ def main(argv):
> parser.add_argument('-d', '--dir', action='store', default='',
> help="directory containing tests")
> parser.add_argument('-u', '--update', action='store_true',
> + default='QAPI_TEST_UPDATE' in os.environ,
> help="update expected test results")
> parser.add_argument('tests', nargs='*', metavar='TEST', action='store')
> args = parser.parse_args()
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/3] qapi: improve specificity of type/member descriptions
2023-04-24 11:38 ` Markus Armbruster
@ 2023-04-25 12:32 ` Daniel P. Berrangé
2023-04-25 13:17 ` Markus Armbruster
0 siblings, 1 reply; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-25 12:32 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
On Mon, Apr 24, 2023 at 01:38:21PM +0200, Markus Armbruster wrote:
> Daniel P. Berrangé <berrange@redhat.com> writes:
>
> > When describing member types always include the context of the
> > containing type. Although this is often redundant, in some cases
> > it will help to reduce ambiguity.
>
> This is no longer true. It was in v2. Suggest:
>
> Error messages describe object members, enumeration values, features,
> and variants like ROLE 'NAME', where ROLE is "member", "value",
> "feature", or "branch", respectively. When the member is defined in
> another type, e.g. inherited from a base type, we add "of type
> 'TYPE'". Example: test case struct-base-clash-deep reports a member
> of type 'Sub' clashing with a member of its base type 'Base' as
>
> struct-base-clash-deep.json: In struct 'Sub':
> struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base'
>
> Members of implicitly defined types need special treatment. We don't
> want to add "of type 'TYPE'" for them, because their named are made up
> and mean nothing to the user. Instead, we describe members of an
> implicitly defined base type as "base member 'NAME'", and command and
> event parameters as "parameter 'NAME'". Example: test case
> union-bad-base reports member of a variant's type clashing with a
> member of its implicitly defined base type as
>
> union-bad-base.json: In union 'TestUnion':
> union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string'
>
> The next commit will permit unions as variant types. "base member
> 'NAME' would then be ambigious: is it the union's base, or is it the
> union's variant's base? One of its test cases would report a clash
> between two such bases as "base member 'type' collides with base
> member 'type'". Confusing.
>
> Refine the special treatment: add "of TYPE" even for implicitly
> defined types, but massage TYPE and ROLE so they make sense for the
> user.
>
> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> > ---
> > scripts/qapi/schema.py | 9 +++++++--
> > 1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
> > index 207e4d71f3..da04b97ded 100644
> > --- a/scripts/qapi/schema.py
> > +++ b/scripts/qapi/schema.py
> > @@ -697,6 +697,7 @@ def connect_doc(self, doc):
> >
> > def describe(self, info):
> > role = self.role
> > + meta = 'type'
> > defined_in = self.defined_in
> > assert defined_in
> >
> > @@ -708,13 +709,17 @@ def describe(self, info):
> > # Implicit type created for a command's dict 'data'
> > assert role == 'member'
> > role = 'parameter'
> > + meta = 'command'
> > + defined_in = defined_in[:-4]
> > elif defined_in.endswith('-base'):
> > # Implicit type created for a union's dict 'base'
> > role = 'base ' + role
> > + defined_in = defined_in[:-5]
> > else:
> > assert False
> > - elif defined_in != info.defn_name:
> > - return "%s '%s' of type '%s'" % (role, self.name, defined_in)
> > +
> > + if defined_in != info.defn_name:
> > + return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
> > return "%s '%s'" % (role, self.name)
>
> Since I rewrote both the patch and the commit message, would you like me
> to take the blame and claim authorship?
Yes, I should have credited you as the author here since it was just
taking your proposed code. The suggested commit message looks fine too
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/3] qapi: improve specificity of type/member descriptions
2023-04-25 12:32 ` Daniel P. Berrangé
@ 2023-04-25 13:17 ` Markus Armbruster
2023-04-25 13:21 ` Daniel P. Berrangé
0 siblings, 1 reply; 10+ messages in thread
From: Markus Armbruster @ 2023-04-25 13:17 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
Daniel P. Berrangé <berrange@redhat.com> writes:
> On Mon, Apr 24, 2023 at 01:38:21PM +0200, Markus Armbruster wrote:
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>>
>> > When describing member types always include the context of the
>> > containing type. Although this is often redundant, in some cases
>> > it will help to reduce ambiguity.
>>
>> This is no longer true. It was in v2. Suggest:
>>
>> Error messages describe object members, enumeration values, features,
>> and variants like ROLE 'NAME', where ROLE is "member", "value",
>> "feature", or "branch", respectively. When the member is defined in
>> another type, e.g. inherited from a base type, we add "of type
>> 'TYPE'". Example: test case struct-base-clash-deep reports a member
>> of type 'Sub' clashing with a member of its base type 'Base' as
>>
>> struct-base-clash-deep.json: In struct 'Sub':
>> struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base'
>>
>> Members of implicitly defined types need special treatment. We don't
>> want to add "of type 'TYPE'" for them, because their named are made up
>> and mean nothing to the user. Instead, we describe members of an
>> implicitly defined base type as "base member 'NAME'", and command and
>> event parameters as "parameter 'NAME'". Example: test case
>> union-bad-base reports member of a variant's type clashing with a
>> member of its implicitly defined base type as
>>
>> union-bad-base.json: In union 'TestUnion':
>> union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string'
>>
>> The next commit will permit unions as variant types. "base member
>> 'NAME' would then be ambigious: is it the union's base, or is it the
>> union's variant's base? One of its test cases would report a clash
>> between two such bases as "base member 'type' collides with base
>> member 'type'". Confusing.
>>
>> Refine the special treatment: add "of TYPE" even for implicitly
>> defined types, but massage TYPE and ROLE so they make sense for the
>> user.
>>
>> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
>> > ---
>> > scripts/qapi/schema.py | 9 +++++++--
>> > 1 file changed, 7 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
>> > index 207e4d71f3..da04b97ded 100644
>> > --- a/scripts/qapi/schema.py
>> > +++ b/scripts/qapi/schema.py
>> > @@ -697,6 +697,7 @@ def connect_doc(self, doc):
>> >
>> > def describe(self, info):
>> > role = self.role
>> > + meta = 'type'
>> > defined_in = self.defined_in
>> > assert defined_in
>> >
>> > @@ -708,13 +709,17 @@ def describe(self, info):
>> > # Implicit type created for a command's dict 'data'
>> > assert role == 'member'
>> > role = 'parameter'
>> > + meta = 'command'
>> > + defined_in = defined_in[:-4]
>> > elif defined_in.endswith('-base'):
>> > # Implicit type created for a union's dict 'base'
>> > role = 'base ' + role
>> > + defined_in = defined_in[:-5]
>> > else:
>> > assert False
>> > - elif defined_in != info.defn_name:
>> > - return "%s '%s' of type '%s'" % (role, self.name, defined_in)
>> > +
>> > + if defined_in != info.defn_name:
>> > + return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
>> > return "%s '%s'" % (role, self.name)
>>
>> Since I rewrote both the patch and the commit message, would you like me
>> to take the blame and claim authorship?
>
> Yes, I should have credited you as the author here since it was just
> taking your proposed code. The suggested commit message looks fine too
Thanks! May I add your R-by in my tree?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/3] qapi: improve specificity of type/member descriptions
2023-04-25 13:17 ` Markus Armbruster
@ 2023-04-25 13:21 ` Daniel P. Berrangé
0 siblings, 0 replies; 10+ messages in thread
From: Daniel P. Berrangé @ 2023-04-25 13:21 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
On Tue, Apr 25, 2023 at 03:17:52PM +0200, Markus Armbruster wrote:
> Daniel P. Berrangé <berrange@redhat.com> writes:
>
> > On Mon, Apr 24, 2023 at 01:38:21PM +0200, Markus Armbruster wrote:
> >> Daniel P. Berrangé <berrange@redhat.com> writes:
> >>
> >> > When describing member types always include the context of the
> >> > containing type. Although this is often redundant, in some cases
> >> > it will help to reduce ambiguity.
> >>
> >> This is no longer true. It was in v2. Suggest:
> >>
> >> Error messages describe object members, enumeration values, features,
> >> and variants like ROLE 'NAME', where ROLE is "member", "value",
> >> "feature", or "branch", respectively. When the member is defined in
> >> another type, e.g. inherited from a base type, we add "of type
> >> 'TYPE'". Example: test case struct-base-clash-deep reports a member
> >> of type 'Sub' clashing with a member of its base type 'Base' as
> >>
> >> struct-base-clash-deep.json: In struct 'Sub':
> >> struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base'
> >>
> >> Members of implicitly defined types need special treatment. We don't
> >> want to add "of type 'TYPE'" for them, because their named are made up
> >> and mean nothing to the user. Instead, we describe members of an
> >> implicitly defined base type as "base member 'NAME'", and command and
> >> event parameters as "parameter 'NAME'". Example: test case
> >> union-bad-base reports member of a variant's type clashing with a
> >> member of its implicitly defined base type as
> >>
> >> union-bad-base.json: In union 'TestUnion':
> >> union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string'
> >>
> >> The next commit will permit unions as variant types. "base member
> >> 'NAME' would then be ambigious: is it the union's base, or is it the
> >> union's variant's base? One of its test cases would report a clash
> >> between two such bases as "base member 'type' collides with base
> >> member 'type'". Confusing.
> >>
> >> Refine the special treatment: add "of TYPE" even for implicitly
> >> defined types, but massage TYPE and ROLE so they make sense for the
> >> user.
> >>
> >> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> >> > ---
> >> > scripts/qapi/schema.py | 9 +++++++--
> >> > 1 file changed, 7 insertions(+), 2 deletions(-)
> >> >
> >> > diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
> >> > index 207e4d71f3..da04b97ded 100644
> >> > --- a/scripts/qapi/schema.py
> >> > +++ b/scripts/qapi/schema.py
> >> > @@ -697,6 +697,7 @@ def connect_doc(self, doc):
> >> >
> >> > def describe(self, info):
> >> > role = self.role
> >> > + meta = 'type'
> >> > defined_in = self.defined_in
> >> > assert defined_in
> >> >
> >> > @@ -708,13 +709,17 @@ def describe(self, info):
> >> > # Implicit type created for a command's dict 'data'
> >> > assert role == 'member'
> >> > role = 'parameter'
> >> > + meta = 'command'
> >> > + defined_in = defined_in[:-4]
> >> > elif defined_in.endswith('-base'):
> >> > # Implicit type created for a union's dict 'base'
> >> > role = 'base ' + role
> >> > + defined_in = defined_in[:-5]
> >> > else:
> >> > assert False
> >> > - elif defined_in != info.defn_name:
> >> > - return "%s '%s' of type '%s'" % (role, self.name, defined_in)
> >> > +
> >> > + if defined_in != info.defn_name:
> >> > + return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
> >> > return "%s '%s'" % (role, self.name)
> >>
> >> Since I rewrote both the patch and the commit message, would you like me
> >> to take the blame and claim authorship?
> >
> > Yes, I should have credited you as the author here since it was just
> > taking your proposed code. The suggested commit message looks fine too
>
> Thanks! May I add your R-by in my tree?
Certainly
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/3] qapi: allow unions to contain further unions
2023-04-20 10:26 [PATCH v3 0/3] qapi: allow unions to contain further unions Daniel P. Berrangé
` (2 preceding siblings ...)
2023-04-20 10:26 ` [PATCH v3 3/3] qapi: allow unions to contain further unions Daniel P. Berrangé
@ 2023-04-25 13:28 ` Markus Armbruster
3 siblings, 0 replies; 10+ messages in thread
From: Markus Armbruster @ 2023-04-25 13:28 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, Het Gala, Eric Blake, Michael Roth
Daniel P. Berrangé <berrange@redhat.com> writes:
> Currently it is not possible for a union type to contain a
> further union as one (or more) of its branches. This relaxes
> that restriction and adds the calls needed to validate field
> name uniqueness as unions are flattened.
Queued. Thanks!
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-04-25 13:29 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-20 10:26 [PATCH v3 0/3] qapi: allow unions to contain further unions Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 1/3] qapi: support updating expected test output via make Daniel P. Berrangé
2023-04-24 11:39 ` Markus Armbruster
2023-04-20 10:26 ` [PATCH v3 2/3] qapi: improve specificity of type/member descriptions Daniel P. Berrangé
2023-04-24 11:38 ` Markus Armbruster
2023-04-25 12:32 ` Daniel P. Berrangé
2023-04-25 13:17 ` Markus Armbruster
2023-04-25 13:21 ` Daniel P. Berrangé
2023-04-20 10:26 ` [PATCH v3 3/3] qapi: allow unions to contain further unions Daniel P. Berrangé
2023-04-25 13:28 ` [PATCH v3 0/3] " Markus Armbruster
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).