...
...
12
I've changed impl such that we expose all features to the code
12
I've changed impl such that we expose all features to the code
13
regardless of whether they are special, and don't require any pragma.
13
regardless of whether they are special, and don't require any pragma.
14
14
15
I've split it from the QGA patches since it makes more sense to work
15
I've split it from the QGA patches since it makes more sense to work
16
on this bit in isolation.
16
on this bit in isolation.
17
18
Changed in v3:
19
20
* "make -C python check-tox" is now clean
21
* Added test case for "too many features" error scenario
22
* Don't sort the features enum, just rely on ordered dict
23
* Add 'features' accessor on QAPISchema instead of touching
24
private data via 'schema._features.values()'
17
25
18
Changed in v2:
26
Changed in v2:
19
27
20
* Reference QapiSpecialFeature enums constants when defining
28
* Reference QapiSpecialFeature enums constants when defining
21
QapiFeature enums constants for deprecated & unstable
29
QapiFeature enums constants for deprecated & unstable
...
...
33
qapi: cope with feature names containing a '-'
41
qapi: cope with feature names containing a '-'
34
qapi: change 'unsigned special_features' to 'uint64_t features'
42
qapi: change 'unsigned special_features' to 'uint64_t features'
35
qapi: rename 'special_features' to 'features'
43
qapi: rename 'special_features' to 'features'
36
qapi: expose all schema features to code
44
qapi: expose all schema features to code
37
45
38
include/qapi/compat-policy.h | 2 +-
46
include/qapi/compat-policy.h | 2 +-
39
include/qapi/qmp/dispatch.h | 4 +--
47
include/qapi/qmp/dispatch.h | 4 +-
40
include/qapi/util.h | 2 +-
48
include/qapi/util.h | 2 +-
41
include/qapi/visitor-impl.h | 4 +--
49
include/qapi/visitor-impl.h | 4 +-
42
include/qapi/visitor.h | 12 +++----
50
include/qapi/visitor.h | 12 +++---
43
meson.build | 1 +
51
meson.build | 1 +
44
qapi/qapi-forward-visitor.c | 8 ++---
52
qapi/qapi-forward-visitor.c | 8 ++--
45
qapi/qapi-util.c | 6 ++--
53
qapi/qapi-util.c | 6 +--
46
qapi/qapi-visit-core.c | 12 +++----
54
qapi/qapi-visit-core.c | 12 +++---
47
qapi/qmp-dispatch.c | 2 +-
55
qapi/qmp-dispatch.c | 2 +-
48
qapi/qmp-registry.c | 4 +--
56
qapi/qmp-registry.c | 4 +-
49
qapi/qobject-input-visitor.c | 4 +--
57
qapi/qobject-input-visitor.c | 4 +-
50
qapi/qobject-output-visitor.c | 6 ++--
58
qapi/qobject-output-visitor.c | 6 +--
51
scripts/qapi/commands.py | 5 +--
59
scripts/qapi/commands.py | 5 ++-
52
scripts/qapi/features.py | 62 +++++++++++++++++++++++++++++++++++
60
scripts/qapi/features.py | 51 ++++++++++++++++++++++++
53
scripts/qapi/gen.py | 9 ++---
61
scripts/qapi/gen.py | 9 +++--
54
scripts/qapi/main.py | 2 ++
62
scripts/qapi/main.py | 2 +
55
scripts/qapi/schema.py | 19 ++++++++++-
63
scripts/qapi/schema.py | 30 +++++++++++++-
56
scripts/qapi/types.py | 18 +++++-----
64
scripts/qapi/types.py | 19 +++++----
57
scripts/qapi/visit.py | 17 +++++-----
65
scripts/qapi/visit.py | 17 ++++----
58
20 files changed, 143 insertions(+), 56 deletions(-)
66
tests/meson.build | 2 +
67
tests/qapi-schema/features-too-many.err | 2 +
68
tests/qapi-schema/features-too-many.json | 13 ++++++
69
tests/qapi-schema/features-too-many.out | 0
70
tests/qapi-schema/meson.build | 1 +
71
25 files changed, 162 insertions(+), 56 deletions(-)
59
create mode 100644 scripts/qapi/features.py
72
create mode 100644 scripts/qapi/features.py
73
create mode 100644 tests/qapi-schema/features-too-many.err
74
create mode 100644 tests/qapi-schema/features-too-many.json
75
create mode 100644 tests/qapi-schema/features-too-many.out
60
76
61
--
77
--
62
2.46.0
78
2.46.0
63
79
64
80
diff view generated by jsdifflib
1
When we shortly expose all feature names to code, it will be valid to
1
When we shortly expose all feature names to code, it will be valid to
2
include a '-', which must be translated to a '_' for the enum constants.
2
include a '-', which must be translated to a '_' for the enum constants.
3
3
4
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
4
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
5
---
5
---
6
scripts/qapi/gen.py | 3 ++-
6
scripts/qapi/gen.py | 3 ++-
7
1 file changed, 2 insertions(+), 1 deletion(-)
7
1 file changed, 2 insertions(+), 1 deletion(-)
8
8
9
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
9
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
10
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
11
--- a/scripts/qapi/gen.py
11
--- a/scripts/qapi/gen.py
12
+++ b/scripts/qapi/gen.py
12
+++ b/scripts/qapi/gen.py
13
@@ -XXX,XX +XXX,XX @@
13
@@ -XXX,XX +XXX,XX @@
14
)
14
)
15
15
16
from .common import (
16
from .common import (
17
+ c_enum_const,
17
+ c_enum_const,
18
c_fname,
18
c_fname,
19
c_name,
19
c_name,
20
guardend,
20
guardend,
21
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
22
22
23
23
24
def gen_special_features(features: Sequence[QAPISchemaFeature]) -> str:
24
def gen_special_features(features: Sequence[QAPISchemaFeature]) -> str:
25
- special_features = [f"1u << QAPI_{feat.name.upper()}"
25
- special_features = [f"1u << QAPI_{feat.name.upper()}"
26
+ special_features = [f"1u << {c_enum_const('qapi', feat.name)}"
26
+ special_features = [f"1u << {c_enum_const('qapi', feat.name)}"
27
for feat in features if feat.is_special()]
27
for feat in features if feat.is_special()]
28
return ' | '.join(special_features) or '0'
28
return ' | '.join(special_features) or '0'
29
29
30
--
30
--
31
2.46.0
31
2.46.0
32
32
33
33
diff view generated by jsdifflib
...
...
4
4
5
This special casing of internal features is going to be removed, so
5
This special casing of internal features is going to be removed, so
6
prepare for that by renaming to 'features'. Using a fixed size type
6
prepare for that by renaming to 'features'. Using a fixed size type
7
is also best practice for bit fields.
7
is also best practice for bit fields.
8
8
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
10
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
10
---
11
---
11
include/qapi/compat-policy.h | 2 +-
12
include/qapi/compat-policy.h | 2 +-
12
include/qapi/qmp/dispatch.h | 4 ++--
13
include/qapi/qmp/dispatch.h | 4 ++--
13
include/qapi/util.h | 2 +-
14
include/qapi/util.h | 2 +-
...
...
diff view generated by jsdifflib
1
This updates the QAPI code generation to refer to 'features' instead
1
This updates the QAPI code generation to refer to 'features' instead
2
of 'special_features', in preparation for generalizing their exposure.
2
of 'special_features', in preparation for generalizing their exposure.
3
3
4
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
4
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
5
---
5
---
6
scripts/qapi/commands.py | 4 ++--
6
scripts/qapi/commands.py | 4 ++--
7
scripts/qapi/gen.py | 6 +++---
7
scripts/qapi/gen.py | 8 ++++----
8
scripts/qapi/types.py | 10 +++++-----
8
scripts/qapi/types.py | 10 +++++-----
9
scripts/qapi/visit.py | 14 +++++++-------
9
scripts/qapi/visit.py | 14 +++++++-------
10
4 files changed, 17 insertions(+), 17 deletions(-)
10
4 files changed, 18 insertions(+), 18 deletions(-)
11
11
12
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
12
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
13
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
14
--- a/scripts/qapi/commands.py
14
--- a/scripts/qapi/commands.py
15
+++ b/scripts/qapi/commands.py
15
+++ b/scripts/qapi/commands.py
...
...
39
from .source import QAPISourceInfo
39
from .source import QAPISourceInfo
40
40
41
41
42
-def gen_special_features(features: Sequence[QAPISchemaFeature]) -> str:
42
-def gen_special_features(features: Sequence[QAPISchemaFeature]) -> str:
43
- special_features = [f"1u << {c_enum_const('qapi', feat.name)}"
43
- special_features = [f"1u << {c_enum_const('qapi', feat.name)}"
44
- for feat in features if feat.is_special()]
45
- return ' | '.join(special_features) or '0'
44
+def gen_features(features: Sequence[QAPISchemaFeature]) -> str:
46
+def gen_features(features: Sequence[QAPISchemaFeature]) -> str:
45
+ features = [f"1u << {c_enum_const('qapi', feat.name)}"
47
+ featenum = [f"1u << {c_enum_const('qapi', feat.name)}"
46
for feat in features if feat.is_special()]
48
+ for feat in features if feat.is_special()]
47
- return ' | '.join(special_features) or '0'
49
+ return ' | '.join(featenum) or '0'
48
+ return ' | '.join(features) or '0'
49
50
50
51
51
class QAPIGen:
52
class QAPIGen:
52
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
53
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
53
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
...
...
diff view generated by jsdifflib
...
...
8
retains compatibility with common code that references the features
8
retains compatibility with common code that references the features
9
via the QapiSpecialFeatures constants.
9
via the QapiSpecialFeatures constants.
10
10
11
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
11
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
12
---
12
---
13
meson.build | 1 +
13
meson.build | 1 +
14
scripts/qapi/commands.py | 1 +
14
scripts/qapi/commands.py | 1 +
15
scripts/qapi/features.py | 62 ++++++++++++++++++++++++++++++++++++++++
15
scripts/qapi/features.py | 51 ++++++++++++++++++++++++
16
scripts/qapi/gen.py | 4 +--
16
scripts/qapi/gen.py | 6 +--
17
scripts/qapi/main.py | 2 ++
17
scripts/qapi/main.py | 2 +
18
scripts/qapi/schema.py | 19 +++++++++++-
18
scripts/qapi/schema.py | 30 +++++++++++++-
19
scripts/qapi/types.py | 6 ++--
19
scripts/qapi/types.py | 7 +++-
20
scripts/qapi/visit.py | 3 +-
20
scripts/qapi/visit.py | 3 +-
21
8 files changed, 92 insertions(+), 6 deletions(-)
21
tests/meson.build | 2 +
22
tests/qapi-schema/features-too-many.err | 2 +
23
tests/qapi-schema/features-too-many.json | 13 ++++++
24
tests/qapi-schema/features-too-many.out | 0
25
tests/qapi-schema/meson.build | 1 +
26
13 files changed, 112 insertions(+), 7 deletions(-)
22
create mode 100644 scripts/qapi/features.py
27
create mode 100644 scripts/qapi/features.py
28
create mode 100644 tests/qapi-schema/features-too-many.err
29
create mode 100644 tests/qapi-schema/features-too-many.json
30
create mode 100644 tests/qapi-schema/features-too-many.out
23
31
24
diff --git a/meson.build b/meson.build
32
diff --git a/meson.build b/meson.build
25
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
26
--- a/meson.build
34
--- a/meson.build
27
+++ b/meson.build
35
+++ b/meson.build
...
...
50
index XXXXXXX..XXXXXXX
58
index XXXXXXX..XXXXXXX
51
--- /dev/null
59
--- /dev/null
52
+++ b/scripts/qapi/features.py
60
+++ b/scripts/qapi/features.py
53
@@ -XXX,XX +XXX,XX @@
61
@@ -XXX,XX +XXX,XX @@
54
+"""
62
+"""
55
+QAPI types generator
63
+QAPI features generator
56
+
64
+
57
+Copyright 2024 Red Hat
65
+Copyright 2024 Red Hat
58
+
66
+
59
+This work is licensed under the terms of the GNU GPL, version 2.
67
+This work is licensed under the terms of the GNU GPL, version 2.
60
+# See the COPYING file in the top-level directory.
68
+# See the COPYING file in the top-level directory.
61
+"""
69
+"""
62
+
70
+
63
+from typing import List, Optional
71
+from typing import Dict
64
+
72
+
65
+from .common import c_enum_const, mcgen, c_name
73
+from .common import c_enum_const, c_name
66
+from .gen import QAPISchemaMonolithicCVisitor
74
+from .gen import QAPISchemaMonolithicCVisitor
67
+from .schema import (
75
+from .schema import (
68
+ QAPISchema,
76
+ QAPISchema,
69
+ QAPISchemaFeature,
77
+ QAPISchemaFeature,
70
+)
78
+)
71
+from .source import QAPISourceInfo
72
+
79
+
73
+
80
+
74
+class QAPISchemaGenFeatureVisitor(QAPISchemaMonolithicCVisitor):
81
+class QAPISchemaGenFeatureVisitor(QAPISchemaMonolithicCVisitor):
75
+
82
+
76
+ def __init__(self, prefix: str):
83
+ def __init__(self, prefix: str):
77
+ super().__init__(
84
+ super().__init__(
78
+ prefix, 'qapi-features',
85
+ prefix, 'qapi-features',
79
+ ' * Schema-defined QAPI features',
86
+ ' * Schema-defined QAPI features',
80
+ __doc__)
87
+ __doc__)
81
+
88
+
82
+ self.features = {}
89
+ self.features: Dict[str, QAPISchemaFeature] = {}
83
+
90
+
84
+ def visit_begin(self, schema: QAPISchema):
91
+ def visit_begin(self, schema: QAPISchema) -> None:
85
+ self.features = schema._feature_dict
92
+ self.features = schema.features()
93
+ self._genh.add("#include \"qapi/util.h\"\n\n")
86
+
94
+
87
+ def visit_end(self) -> None:
95
+ def visit_end(self) -> None:
88
+ features = [
89
+ self.features[f]
90
+ for f in QAPISchemaFeature.SPECIAL_NAMES
91
+ ]
92
+
93
+ features.extend(
94
+ sorted(
95
+ filter(lambda f: not f.is_special(),
96
+ self.features.values()),
97
+ key=lambda f: f.name)
98
+ )
99
+
100
+ self._genh.add("typedef enum {\n")
96
+ self._genh.add("typedef enum {\n")
101
+ for f in features:
97
+ for f in self.features:
102
+ self._genh.add(f" {c_enum_const('qapi_feature', f.name)}")
98
+ self._genh.add(f" {c_enum_const('qapi_feature', f.name)}")
103
+ if f.name in QAPISchemaFeature.SPECIAL_NAMES:
99
+ if f.name in QAPISchemaFeature.SPECIAL_NAMES:
104
+ self._genh.add(f" = {c_enum_const('qapi', f.name)},\n" )
100
+ self._genh.add(f" = {c_enum_const('qapi', f.name)},\n")
105
+ else:
101
+ else:
106
+ self._genh.add(",\n")
102
+ self._genh.add(",\n")
107
+
103
+
108
+ self._genh.add("} " + c_name('QapiFeature') + ";\n")
104
+ self._genh.add("} " + c_name('QapiFeature') + ";\n")
105
+
109
+
106
+
110
+def gen_features(schema: QAPISchema,
107
+def gen_features(schema: QAPISchema,
111
+ output_dir: str,
108
+ output_dir: str,
112
+ prefix: str) -> None:
109
+ prefix: str) -> None:
113
+ vis = QAPISchemaGenFeatureVisitor(prefix)
110
+ vis = QAPISchemaGenFeatureVisitor(prefix)
...
...
119
+++ b/scripts/qapi/gen.py
116
+++ b/scripts/qapi/gen.py
120
@@ -XXX,XX +XXX,XX @@
117
@@ -XXX,XX +XXX,XX @@
121
118
122
119
123
def gen_features(features: Sequence[QAPISchemaFeature]) -> str:
120
def gen_features(features: Sequence[QAPISchemaFeature]) -> str:
124
- features = [f"1u << {c_enum_const('qapi', feat.name)}"
121
- featenum = [f"1u << {c_enum_const('qapi', feat.name)}"
125
- for feat in features if feat.is_special()]
122
- for feat in features if feat.is_special()]
126
+ features = [f"1u << {c_enum_const('qapi_feature', feat.name)}"
123
- return ' | '.join(featenum) or '0'
127
+ for feat in features]
124
+ feats = [f"1u << {c_enum_const('qapi_feature', feat.name)}"
128
return ' | '.join(features) or '0'
125
+ for feat in features]
129
126
+ return ' | '.join(feats) or '0'
130
127
128
129
class QAPIGen:
131
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
130
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
132
index XXXXXXX..XXXXXXX 100644
131
index XXXXXXX..XXXXXXX 100644
133
--- a/scripts/qapi/main.py
132
--- a/scripts/qapi/main.py
134
+++ b/scripts/qapi/main.py
133
+++ b/scripts/qapi/main.py
135
@@ -XXX,XX +XXX,XX @@
134
@@ -XXX,XX +XXX,XX @@
...
...
167
class QAPISchemaObjectTypeMember(QAPISchemaMember):
166
class QAPISchemaObjectTypeMember(QAPISchemaMember):
168
@@ -XXX,XX +XXX,XX @@ def __init__(self, fname: str):
167
@@ -XXX,XX +XXX,XX @@ def __init__(self, fname: str):
169
self._entity_list: List[QAPISchemaEntity] = []
168
self._entity_list: List[QAPISchemaEntity] = []
170
self._entity_dict: Dict[str, QAPISchemaDefinition] = {}
169
self._entity_dict: Dict[str, QAPISchemaDefinition] = {}
171
self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict()
170
self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict()
172
+ self._feature_dict: Dict[str, QAPISchemaFeature] = {}
171
+ # NB, values in the dict will identify the first encountered
173
+
172
+ # usage of a named feature only
173
+ self._feature_dict: Dict[str, QAPISchemaFeature] = OrderedDict()
174
+
175
+ # All schemas get the names defined in the QapiSpecialFeature enum.
176
+ # Use of OrderedDict ensures they are emitted first when generating
177
+ # the enum definition, thus matching QapiSpecialFeature.
174
+ for f in QAPISchemaFeature.SPECIAL_NAMES:
178
+ for f in QAPISchemaFeature.SPECIAL_NAMES:
175
+ self._feature_dict[f] = QAPISchemaFeature(f, "special feature")
179
+ self._feature_dict[f] = QAPISchemaFeature(f, None)
176
+
180
+
177
self._schema_dir = os.path.dirname(fname)
181
self._schema_dir = os.path.dirname(fname)
178
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
182
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
179
self._make_module(fname)
183
self._make_module(fname)
184
@@ -XXX,XX +XXX,XX @@ def __init__(self, fname: str):
185
self._def_exprs(exprs)
186
self.check()
187
188
+ def features(self) -> List[QAPISchemaFeature]:
189
+ return self._feature_dict.values()
190
+
191
def _def_entity(self, ent: QAPISchemaEntity) -> None:
192
self._entity_list.append(ent)
193
180
@@ -XXX,XX +XXX,XX @@ def _make_features(
194
@@ -XXX,XX +XXX,XX @@ def _make_features(
181
) -> List[QAPISchemaFeature]:
195
) -> List[QAPISchemaFeature]:
182
if features is None:
196
if features is None:
183
return []
197
return []
184
+
198
+
185
+ for f in features:
199
+ for f in features:
186
+ feat = QAPISchemaFeature(f['name'], info)
200
+ feat = QAPISchemaFeature(f['name'], info)
187
+ if feat.name not in self._feature_dict:
201
+ if feat.name not in self._feature_dict:
188
+ if len(self._feature_dict) == 64:
189
+ raise Exception("Maximum of 64 schema features is permitted")
190
+
191
+ self._feature_dict[feat.name] = feat
202
+ self._feature_dict[feat.name] = feat
192
+
203
+
193
return [QAPISchemaFeature(f['name'], info,
204
return [QAPISchemaFeature(f['name'], info,
194
QAPISchemaIfCond(f.get('if')))
205
QAPISchemaIfCond(f.get('if')))
195
for f in features]
206
for f in features]
207
@@ -XXX,XX +XXX,XX @@ def check(self) -> None:
208
for doc in self.docs:
209
doc.check()
210
211
+ features = list(self._feature_dict.values())
212
+ if len(features) > 64:
213
+ raise QAPISemError(
214
+ features[64].info,
215
+ "Maximum of 64 schema features is permitted")
216
+
217
def visit(self, visitor: QAPISchemaVisitor) -> None:
218
visitor.visit_begin(self)
219
for mod in self._module_dict.values():
196
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
220
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
197
index XXXXXXX..XXXXXXX 100644
221
index XXXXXXX..XXXXXXX 100644
198
--- a/scripts/qapi/types.py
222
--- a/scripts/qapi/types.py
199
+++ b/scripts/qapi/types.py
223
+++ b/scripts/qapi/types.py
200
@@ -XXX,XX +XXX,XX @@ def _begin_user_module(self, name: str) -> None:
224
@@ -XXX,XX +XXX,XX @@ def _begin_user_module(self, name: str) -> None:
201
#include "qapi/dealloc-visitor.h"
225
#include "qapi/dealloc-visitor.h"
202
#include "%(types)s.h"
226
#include "%(types)s.h"
203
#include "%(visit)s.h"
227
#include "%(visit)s.h"
204
+#include "%(prefix)sqapi-features.h"
228
+#include "%(prefix)sqapi-features.h"
205
''',
229
''',
206
- types=types, visit=visit))
230
- types=types, visit=visit))
207
+ types=types, visit=visit, prefix=self._prefix))
231
+ types=types, visit=visit,
232
+ prefix=self._prefix))
208
self._genh.preamble_add(mcgen('''
233
self._genh.preamble_add(mcgen('''
209
#include "qapi/qapi-builtin-types.h"
234
#include "qapi/qapi-builtin-types.h"
210
-'''))
235
-'''))
211
+''',
236
+''',
212
+ prefix=self._prefix))
237
+ prefix=self._prefix))
...
...
226
- visit=visit))
251
- visit=visit))
227
+ visit=visit, prefix=self._prefix))
252
+ visit=visit, prefix=self._prefix))
228
self._genh.preamble_add(mcgen('''
253
self._genh.preamble_add(mcgen('''
229
#include "qapi/qapi-builtin-visit.h"
254
#include "qapi/qapi-builtin-visit.h"
230
#include "%(types)s.h"
255
#include "%(types)s.h"
256
diff --git a/tests/meson.build b/tests/meson.build
257
index XXXXXXX..XXXXXXX 100644
258
--- a/tests/meson.build
259
+++ b/tests/meson.build
260
@@ -XXX,XX +XXX,XX @@ test_qapi_outputs = [
261
'test-qapi-events-sub-sub-module.h',
262
'test-qapi-events.c',
263
'test-qapi-events.h',
264
+ 'test-qapi-features.c',
265
+ 'test-qapi-features.h',
266
'test-qapi-init-commands.c',
267
'test-qapi-init-commands.h',
268
'test-qapi-introspect.c',
269
diff --git a/tests/qapi-schema/features-too-many.err b/tests/qapi-schema/features-too-many.err
270
new file mode 100644
271
index XXXXXXX..XXXXXXX
272
--- /dev/null
273
+++ b/tests/qapi-schema/features-too-many.err
274
@@ -XXX,XX +XXX,XX @@
275
+features-too-many.json: In command 'go-fish':
276
+features-too-many.json:2: Maximum of 64 schema features is permitted
277
diff --git a/tests/qapi-schema/features-too-many.json b/tests/qapi-schema/features-too-many.json
278
new file mode 100644
279
index XXXXXXX..XXXXXXX
280
--- /dev/null
281
+++ b/tests/qapi-schema/features-too-many.json
282
@@ -XXX,XX +XXX,XX @@
283
+# Max 64 features, with 2 specials, so 63rd custom is invalid
284
+{ 'command': 'go-fish',
285
+ 'features': [
286
+ 'f00', 'f01', 'f02', 'f03', 'f04', 'f05', 'f06', 'f07',
287
+ 'f08', 'f09', 'f0a', 'f0b', 'f0c', 'f0d', 'f0e', 'f0f',
288
+ 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17',
289
+ 'f18', 'f19', 'f1a', 'f1b', 'f1c', 'f1d', 'f1e', 'f1f',
290
+ 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26', 'f27',
291
+ 'f28', 'f29', 'f2a', 'f2b', 'f2c', 'f2d', 'f2e', 'f2f',
292
+ 'f30', 'f31', 'f32', 'f33', 'f34', 'f35', 'f36', 'f37',
293
+ 'f38', 'f39', 'f3a', 'f3b', 'f3c', 'f3d', 'f3e'
294
+ ]
295
+}
296
diff --git a/tests/qapi-schema/features-too-many.out b/tests/qapi-schema/features-too-many.out
297
new file mode 100644
298
index XXXXXXX..XXXXXXX
299
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
300
index XXXXXXX..XXXXXXX 100644
301
--- a/tests/qapi-schema/meson.build
302
+++ b/tests/qapi-schema/meson.build
303
@@ -XXX,XX +XXX,XX @@ schemas = [
304
'event-case.json',
305
'event-member-invalid-dict.json',
306
'event-nest-struct.json',
307
+ 'features-too-many.json',
308
'features-bad-type.json',
309
'features-deprecated-type.json',
310
'features-duplicate-name.json',
231
--
311
--
232
2.46.0
312
2.46.0
233
313
234
314
diff view generated by jsdifflib