Browse Source
As the name suggests, the qapi2texi script converts JSON QAPI description into a texi file suitable for different target formats (info/man/txt/pdf/html...). It parses the following kind of blocks: Free-form: ## # = Section # == Subsection # # Some text foo with *emphasis* # 1. with a list # 2. like that # # And some code: # | $ echo foo # | -> do this # | <- get that # ## Symbol description: ## # @symbol: # # Symbol body ditto ergo sum. Foo bar # baz ding. # # @param1: the frob to frobnicate # @param2: #optional how hard to frobnicate # # Returns: the frobnicated frob. # If frob isn't frobnicatable, GenericError. # # Since: version # Notes: notes, comments can have # - itemized list # - like this # # Example: # # -> { "execute": "quit" } # <- { "return": {} } # ## That's roughly following the following EBNF grammar: api_comment = "##\n" comment "##\n" comment = freeform_comment | symbol_comment freeform_comment = { "# " text "\n" | "#\n" } symbol_comment = "# @" name ":\n" { member | tag_section | freeform_comment } member = "# @" name ':' [ text ] "\n" freeform_comment tag_section = "# " ( "Returns:", "Since:", "Note:", "Notes:", "Example:", "Examples:" ) [ text ] "\n" freeform_comment text = free text with markup Note that the grammar is ambiguous: a line "# @foo:\n" can be parsed both as freeform_comment and as symbol_comment. The actual parser recognizes symbol_comment. See docs/qapi-code-gen.txt for more details. Deficiencies and limitations: - the generated QMP documentation includes internal types - union type support is lacking - type information is lacking in generated documentation - doc comment error message positions are imprecise, they point to the beginning of the comment. - a few minor issues, all marked TODO/FIXME in the code Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20170113144135.5150-16-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [test-qapi.py tweaked to avoid trailing empty lines in .out] Signed-off-by: Markus Armbruster <armbru@redhat.com>pull/47/head
committed by
Markus Armbruster
276 changed files with 1925 additions and 127 deletions
@ -0,0 +1,271 @@ |
|||
#!/usr/bin/env python |
|||
# QAPI texi generator |
|||
# |
|||
# This work is licensed under the terms of the GNU LGPL, version 2+. |
|||
# See the COPYING file in the top-level directory. |
|||
"""This script produces the documentation of a qapi schema in texinfo format""" |
|||
import re |
|||
import sys |
|||
|
|||
import qapi |
|||
|
|||
COMMAND_FMT = """ |
|||
@deftypefn {type} {{}} {name} |
|||
|
|||
{body} |
|||
|
|||
@end deftypefn |
|||
|
|||
""".format |
|||
|
|||
ENUM_FMT = """ |
|||
@deftp Enum {name} |
|||
|
|||
{body} |
|||
|
|||
@end deftp |
|||
|
|||
""".format |
|||
|
|||
STRUCT_FMT = """ |
|||
@deftp {{{type}}} {name} |
|||
|
|||
{body} |
|||
|
|||
@end deftp |
|||
|
|||
""".format |
|||
|
|||
EXAMPLE_FMT = """@example |
|||
{code} |
|||
@end example |
|||
""".format |
|||
|
|||
|
|||
def subst_strong(doc): |
|||
"""Replaces *foo* by @strong{foo}""" |
|||
return re.sub(r'\*([^*\n]+)\*', r'@emph{\1}', doc) |
|||
|
|||
|
|||
def subst_emph(doc): |
|||
"""Replaces _foo_ by @emph{foo}""" |
|||
return re.sub(r'\b_([^_\n]+)_\b', r' @emph{\1} ', doc) |
|||
|
|||
|
|||
def subst_vars(doc): |
|||
"""Replaces @var by @code{var}""" |
|||
return re.sub(r'@([\w-]+)', r'@code{\1}', doc) |
|||
|
|||
|
|||
def subst_braces(doc): |
|||
"""Replaces {} with @{ @}""" |
|||
return doc.replace("{", "@{").replace("}", "@}") |
|||
|
|||
|
|||
def texi_example(doc): |
|||
"""Format @example""" |
|||
# TODO: Neglects to escape @ characters. |
|||
# We should probably escape them in subst_braces(), and rename the |
|||
# function to subst_special() or subs_texi_special(). If we do that, we |
|||
# need to delay it until after subst_vars() in texi_format(). |
|||
doc = subst_braces(doc).strip('\n') |
|||
return EXAMPLE_FMT(code=doc) |
|||
|
|||
|
|||
def texi_format(doc): |
|||
""" |
|||
Format documentation |
|||
|
|||
Lines starting with: |
|||
- |: generates an @example |
|||
- =: generates @section |
|||
- ==: generates @subsection |
|||
- 1. or 1): generates an @enumerate @item |
|||
- */-: generates an @itemize list |
|||
""" |
|||
lines = [] |
|||
doc = subst_braces(doc) |
|||
doc = subst_vars(doc) |
|||
doc = subst_emph(doc) |
|||
doc = subst_strong(doc) |
|||
inlist = "" |
|||
lastempty = False |
|||
for line in doc.split('\n'): |
|||
empty = line == "" |
|||
|
|||
# FIXME: Doing this in a single if / elif chain is |
|||
# problematic. For instance, a line without markup terminates |
|||
# a list if it follows a blank line (reaches the final elif), |
|||
# but a line with some *other* markup, such as a = title |
|||
# doesn't. |
|||
# |
|||
# Make sure to update section "Documentation markup" in |
|||
# docs/qapi-code-gen.txt when fixing this. |
|||
if line.startswith("| "): |
|||
line = EXAMPLE_FMT(code=line[2:]) |
|||
elif line.startswith("= "): |
|||
line = "@section " + line[2:] |
|||
elif line.startswith("== "): |
|||
line = "@subsection " + line[3:] |
|||
elif re.match(r'^([0-9]*\.) ', line): |
|||
if not inlist: |
|||
lines.append("@enumerate") |
|||
inlist = "enumerate" |
|||
line = line[line.find(" ")+1:] |
|||
lines.append("@item") |
|||
elif re.match(r'^[*-] ', line): |
|||
if not inlist: |
|||
lines.append("@itemize %s" % {'*': "@bullet", |
|||
'-': "@minus"}[line[0]]) |
|||
inlist = "itemize" |
|||
lines.append("@item") |
|||
line = line[2:] |
|||
elif lastempty and inlist: |
|||
lines.append("@end %s\n" % inlist) |
|||
inlist = "" |
|||
|
|||
lastempty = empty |
|||
lines.append(line) |
|||
|
|||
if inlist: |
|||
lines.append("@end %s\n" % inlist) |
|||
return "\n".join(lines) |
|||
|
|||
|
|||
def texi_body(doc): |
|||
""" |
|||
Format the body of a symbol documentation: |
|||
- main body |
|||
- table of arguments |
|||
- followed by "Returns/Notes/Since/Example" sections |
|||
""" |
|||
body = texi_format(str(doc.body)) + "\n" |
|||
if doc.args: |
|||
body += "@table @asis\n" |
|||
for arg, section in doc.args.iteritems(): |
|||
desc = str(section) |
|||
opt = '' |
|||
if "#optional" in desc: |
|||
desc = desc.replace("#optional", "") |
|||
opt = ' (optional)' |
|||
body += "@item @code{'%s'}%s\n%s\n" % (arg, opt, |
|||
texi_format(desc)) |
|||
body += "@end table\n" |
|||
|
|||
for section in doc.sections: |
|||
name, doc = (section.name, str(section)) |
|||
func = texi_format |
|||
if name.startswith("Example"): |
|||
func = texi_example |
|||
|
|||
if name: |
|||
# FIXME the indentation produced by @quotation in .txt and |
|||
# .html output is confusing |
|||
body += "\n@quotation %s\n%s\n@end quotation" % \ |
|||
(name, func(doc)) |
|||
else: |
|||
body += func(doc) |
|||
|
|||
return body |
|||
|
|||
|
|||
def texi_alternate(expr, doc): |
|||
"""Format an alternate to texi""" |
|||
body = texi_body(doc) |
|||
return STRUCT_FMT(type="Alternate", |
|||
name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_union(expr, doc): |
|||
"""Format a union to texi""" |
|||
discriminator = expr.get("discriminator") |
|||
if discriminator: |
|||
union = "Flat Union" |
|||
else: |
|||
union = "Simple Union" |
|||
|
|||
body = texi_body(doc) |
|||
return STRUCT_FMT(type=union, |
|||
name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_enum(expr, doc): |
|||
"""Format an enum to texi""" |
|||
for i in expr['data']: |
|||
if i not in doc.args: |
|||
doc.args[i] = '' |
|||
body = texi_body(doc) |
|||
return ENUM_FMT(name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_struct(expr, doc): |
|||
"""Format a struct to texi""" |
|||
body = texi_body(doc) |
|||
return STRUCT_FMT(type="Struct", |
|||
name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_command(expr, doc): |
|||
"""Format a command to texi""" |
|||
body = texi_body(doc) |
|||
return COMMAND_FMT(type="Command", |
|||
name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_event(expr, doc): |
|||
"""Format an event to texi""" |
|||
body = texi_body(doc) |
|||
return COMMAND_FMT(type="Event", |
|||
name=doc.symbol, |
|||
body=body) |
|||
|
|||
|
|||
def texi_expr(expr, doc): |
|||
"""Format an expr to texi""" |
|||
(kind, _) = expr.items()[0] |
|||
|
|||
fmt = {"command": texi_command, |
|||
"struct": texi_struct, |
|||
"enum": texi_enum, |
|||
"union": texi_union, |
|||
"alternate": texi_alternate, |
|||
"event": texi_event}[kind] |
|||
|
|||
return fmt(expr, doc) |
|||
|
|||
|
|||
def texi(docs): |
|||
"""Convert QAPI schema expressions to texi documentation""" |
|||
res = [] |
|||
for doc in docs: |
|||
expr = doc.expr |
|||
if not expr: |
|||
res.append(texi_body(doc)) |
|||
continue |
|||
try: |
|||
doc = texi_expr(expr, doc) |
|||
res.append(doc) |
|||
except: |
|||
print >>sys.stderr, "error at @%s" % doc.info |
|||
raise |
|||
|
|||
return '\n'.join(res) |
|||
|
|||
|
|||
def main(argv): |
|||
"""Takes schema argument, prints result to stdout""" |
|||
if len(argv) != 2: |
|||
print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0] |
|||
sys.exit(1) |
|||
|
|||
schema = qapi.QAPISchema(argv[1]) |
|||
print texi(schema.docs) |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
main(sys.argv) |
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any' |
|||
tests/qapi-schema/alternate-any.json:6: Alternate 'Alt' member 'one' cannot use type 'any' |
|||
|
|||
@ -1,4 +1,8 @@ |
|||
# we do not allow the 'any' type as an alternate branch |
|||
|
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'data': { 'one': 'any', |
|||
'two': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array |
|||
tests/qapi-schema/alternate-array.json:12: Member 'two' of alternate 'Alt' cannot be an array |
|||
|
|||
@ -1,7 +1,14 @@ |
|||
# we do not allow array branches in alternates |
|||
|
|||
## |
|||
# @One: |
|||
## |
|||
# TODO: should we support this? |
|||
{ 'struct': 'One', |
|||
'data': { 'name': 'str' } } |
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'data': { 'one': 'One', |
|||
'two': [ 'int' ] } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt' |
|||
tests/qapi-schema/alternate-base.json:11: Unknown key 'base' in alternate 'Alt' |
|||
|
|||
@ -1,6 +1,13 @@ |
|||
# we reject alternate with base type |
|||
|
|||
## |
|||
# @Base: |
|||
## |
|||
{ 'struct': 'Base', |
|||
'data': { 'string': 'str' } } |
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'base': 'Base', |
|||
'data': { 'number': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) |
|||
tests/qapi-schema/alternate-clash.json:11: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one' |
|||
tests/qapi-schema/alternate-conflict-dict.json:16: Alternate 'Alt' member 'two' can't be distinguished from member 'one' |
|||
|
|||
@ -1,8 +1,18 @@ |
|||
# we reject alternates with multiple object branches |
|||
|
|||
## |
|||
# @One: |
|||
## |
|||
{ 'struct': 'One', |
|||
'data': { 'name': 'str' } } |
|||
## |
|||
# @Two: |
|||
## |
|||
{ 'struct': 'Two', |
|||
'data': { 'value': 'int' } } |
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'data': { 'one': 'One', |
|||
'two': 'Two' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one' |
|||
tests/qapi-schema/alternate-conflict-string.json:11: Alternate 'Alt' member 'two' can't be distinguished from member 'one' |
|||
|
|||
@ -1,6 +1,13 @@ |
|||
# we reject alternates with multiple string-like branches |
|||
|
|||
## |
|||
# @Enum: |
|||
## |
|||
{ 'enum': 'Enum', |
|||
'data': [ 'hello', 'world' ] } |
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'data': { 'one': 'str', |
|||
'two': 'Enum' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' |
|||
tests/qapi-schema/alternate-empty.json:6: Alternate 'Alt' should have at least two branches in 'data' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# alternates must list at least two types to be useful |
|||
|
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', 'data': { 'i': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1' |
|||
tests/qapi-schema/alternate-nested.json:11: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1' |
|||
|
|||
@ -1,5 +1,12 @@ |
|||
# we reject a nested alternate branch |
|||
|
|||
## |
|||
# @Alt1: |
|||
## |
|||
{ 'alternate': 'Alt1', |
|||
'data': { 'name': 'str', 'value': 'int' } } |
|||
## |
|||
# @Alt2: |
|||
## |
|||
{ 'alternate': 'Alt2', |
|||
'data': { 'nested': 'Alt1', 'b': 'bool' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType' |
|||
tests/qapi-schema/alternate-unknown.json:6: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType' |
|||
|
|||
@ -1,3 +1,7 @@ |
|||
# we reject an alternate with unknown type in branch |
|||
|
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', |
|||
'data': { 'unknown': 'MissingType', 'i': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt' |
|||
tests/qapi-schema/args-alternate.json:11: 'data' for command 'oops' cannot use alternate type 'Alt' |
|||
|
|||
@ -1,3 +1,11 @@ |
|||
# we do not allow alternate arguments |
|||
|
|||
## |
|||
# @Alt: |
|||
## |
|||
{ 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } } |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': 'Alt' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any' |
|||
tests/qapi-schema/args-any.json:6: 'data' for command 'oops' cannot use built-in type 'any' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we do not allow an 'any' argument |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': 'any' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name |
|||
tests/qapi-schema/args-array-empty.json:6: Member 'empty' of 'data' for command 'oops': array type must contain single type name |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject an array for data if it does not contain a known type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': { 'empty': [ ] } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
tests/qapi-schema/args-array-unknown.json:6: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject an array for data if it does not contain a known type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should only use true value |
|||
tests/qapi-schema/args-bad-boxed.json:6: 'boxed' of command 'foo' should only use true value |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# 'boxed' should only appear with value true |
|||
|
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': 'foo', 'boxed': false } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should be a type name |
|||
tests/qapi-schema/args-boxed-anon.json:6: 'data' for command 'foo' should be a type name |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# 'boxed' can only be used with named types |
|||
|
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': 'foo', 'boxed': true, 'data': { 'string': 'str' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty type |
|||
tests/qapi-schema/args-boxed-empty.json:11: Cannot use 'boxed' with empty type |
|||
|
|||
@ -1,3 +1,11 @@ |
|||
# 'boxed' requires a non-empty type |
|||
|
|||
## |
|||
# @Empty: |
|||
## |
|||
{ 'struct': 'Empty', 'data': {} } |
|||
|
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': 'foo', 'boxed': true, 'data': 'Empty' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo' cannot use built-in type 'str' |
|||
tests/qapi-schema/args-boxed-string.json:6: 'data' for command 'foo' cannot use built-in type 'str' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# 'boxed' requires a complex (not built-in) type |
|||
|
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': 'foo', 'boxed': true, 'data': 'str' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int' |
|||
tests/qapi-schema/args-int.json:6: 'data' for command 'oops' cannot use built-in type 'int' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject commands where data is not an array or complex type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': 'int' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name |
|||
tests/qapi-schema/args-invalid.json:4: 'data' for command 'foo' should be a dictionary or type name |
|||
|
|||
@ -1,2 +1,5 @@ |
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': 'foo', |
|||
'data': false } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name |
|||
tests/qapi-schema/args-member-array-bad.json:6: Member 'member' of 'data' for command 'oops': array type must contain single type name |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject data if it does not contain a valid array type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase |
|||
tests/qapi-schema/args-member-case.json:6: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# Member names should be 'lower-case' unless the struct/command is whitelisted |
|||
|
|||
## |
|||
# @no-way-this-will-get-whitelisted: |
|||
## |
|||
{ 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
tests/qapi-schema/args-member-unknown.json:6: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject data if it does not contain a known type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': { 'member': 'NoSuchType' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) |
|||
tests/qapi-schema/args-name-clash.json:8: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) |
|||
|
|||
@ -1,4 +1,8 @@ |
|||
# C member name collision |
|||
# Reject members that clash when mapped to C names (we would have two 'a_b' |
|||
# members). |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni' |
|||
tests/qapi-schema/args-union.json:10: 'data' for command 'oops' cannot use union type 'Uni' |
|||
|
|||
@ -1,3 +1,10 @@ |
|||
# use of union arguments requires 'boxed':true |
|||
|
|||
## |
|||
# @Uni: |
|||
## |
|||
{ 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } } |
|||
## |
|||
# oops: |
|||
## |
|||
{ 'command': 'oops', 'data': 'Uni' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
tests/qapi-schema/args-unknown.json:6: 'data' for command 'oops' uses unknown type 'NoSuchType' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject data if it does not contain a known type |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': 'NoSuchType' } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union' |
|||
tests/qapi-schema/bad-base.json:10: 'base' for struct 'MyType' cannot use union type 'Union' |
|||
|
|||
@ -1,3 +1,10 @@ |
|||
# we reject a base that is not a struct |
|||
|
|||
## |
|||
# @Union: |
|||
## |
|||
{ 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } } |
|||
## |
|||
# @MyType: |
|||
## |
|||
{ 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array |
|||
tests/qapi-schema/bad-data.json:6: 'data' for command 'oops' cannot be an array |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we ensure 'data' is a dictionary for all but enums |
|||
|
|||
## |
|||
# @oops: |
|||
## |
|||
{ 'command': 'oops', 'data': [ ] } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops' |
|||
tests/qapi-schema/bad-ident.json:6: 'struct' does not allow optional name '*oops' |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject creating a type name with bad name |
|||
|
|||
## |
|||
# @*oops: |
|||
## |
|||
{ 'struct': '*oops', 'data': { 'i': 'int' } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value |
|||
tests/qapi-schema/bad-type-bool.json:6: 'struct' key must have a string value |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject an expression with a metatype that is not a string |
|||
|
|||
## |
|||
# @true: |
|||
## |
|||
{ 'struct': true, 'data': { } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value |
|||
tests/qapi-schema/bad-type-dict.json:6: 'command' key must have a string value |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject an expression with a metatype that is not a string |
|||
|
|||
## |
|||
# @foo: |
|||
## |
|||
{ 'command': { } } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself |
|||
tests/qapi-schema/base-cycle-direct.json:6: Object Loopy contains itself |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject a loop in base classes |
|||
|
|||
## |
|||
# @Loopy: |
|||
## |
|||
{ 'struct': 'Loopy', 'base': 'Loopy', 'data': {} } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself |
|||
tests/qapi-schema/base-cycle-indirect.json:6: Object Base1 contains itself |
|||
|
|||
@ -1,3 +1,10 @@ |
|||
# we reject a loop in base classes |
|||
|
|||
## |
|||
# @Base1: |
|||
## |
|||
{ 'struct': 'Base1', 'base': 'Base2', 'data': {} } |
|||
## |
|||
# @Base2: |
|||
## |
|||
{ 'struct': 'Base2', 'base': 'Base1', 'data': {} } |
|||
|
|||
@ -1 +1 @@ |
|||
tests/qapi-schema/command-int.json:2: built-in 'int' is already defined |
|||
tests/qapi-schema/command-int.json:6: built-in 'int' is already defined |
|||
|
|||
@ -1,2 +1,6 @@ |
|||
# we reject collisions between commands and types |
|||
|
|||
## |
|||
# @int: |
|||
## |
|||
{ 'command': 'int', 'data': { 'character': 'str' } } |
|||
|
|||
@ -1,4 +1,8 @@ |
|||
# Unindented comment |
|||
|
|||
## |
|||
# @Status: |
|||
## |
|||
{ 'enum': 'Status', # Comment to the right of code |
|||
# Indented comment |
|||
'data': [ 'good', 'bad', 'ugly' ] } |
|||
|
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-bad-args.json:3: The following documented members are not in the declaration: b |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,8 @@ |
|||
# Arguments listed in the doc comment must exist in the actual schema |
|||
|
|||
## |
|||
# @foo: |
|||
# @a: a |
|||
# @b: b |
|||
## |
|||
{ 'command': 'foo', 'data': {'a': 'int'} } |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-bad-symbol.json:3: Definition of 'foo' follows documentation for 'food' |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,6 @@ |
|||
# Documentation symbol mismatch with expression |
|||
|
|||
## |
|||
# @food: |
|||
## |
|||
{ 'command': 'foo', 'data': {'a': 'int'} } |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-duplicated-arg.json:6:1: 'a' parameter name duplicated |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,7 @@ |
|||
# Do not allow duplicated argument |
|||
|
|||
## |
|||
# @foo: |
|||
# @a: |
|||
# @a: |
|||
## |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-duplicated-return.json:7:1: Duplicated 'Returns' section |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,8 @@ |
|||
# Do not allow duplicated Returns section |
|||
|
|||
## |
|||
# @foo: |
|||
# |
|||
# Returns: 0 |
|||
# Returns: 1 |
|||
## |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-duplicated-since.json:7:1: Duplicated 'Since' section |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,8 @@ |
|||
# Do not allow duplicated Since section |
|||
|
|||
## |
|||
# @foo: |
|||
# |
|||
# Since: 0 |
|||
# Since: 1 |
|||
## |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-empty-arg.json:5:1: Invalid parameter name |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,6 @@ |
|||
# An invalid empty argument name |
|||
|
|||
## |
|||
# @foo: |
|||
# @: |
|||
## |
|||
@ -0,0 +1 @@ |
|||
tests/qapi-schema/doc-empty-section.json:3: Empty doc section 'Note' |
|||
@ -0,0 +1 @@ |
|||
1 |
|||
@ -0,0 +1,8 @@ |
|||
# Tagged-section must not be empty |
|||
|
|||
## |
|||
# @foo: |
|||
# |
|||
# Note: |
|||
## |
|||
{ 'command': 'foo', 'data': {'a': 'int'} } |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue