summaryrefslogtreecommitdiffstats
path: root/src/tests/qapi-schema
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/qapi-schema')
-rw-r--r--src/tests/qapi-schema/alternate-array.err1
-rw-r--r--src/tests/qapi-schema/alternate-array.exit1
-rw-r--r--src/tests/qapi-schema/alternate-array.json7
-rw-r--r--src/tests/qapi-schema/alternate-array.out0
-rw-r--r--src/tests/qapi-schema/alternate-base.err1
-rw-r--r--src/tests/qapi-schema/alternate-base.exit1
-rw-r--r--src/tests/qapi-schema/alternate-base.json6
-rw-r--r--src/tests/qapi-schema/alternate-base.out0
-rw-r--r--src/tests/qapi-schema/alternate-clash.err1
-rw-r--r--src/tests/qapi-schema/alternate-clash.exit1
-rw-r--r--src/tests/qapi-schema/alternate-clash.json8
-rw-r--r--src/tests/qapi-schema/alternate-clash.out0
-rw-r--r--src/tests/qapi-schema/alternate-conflict-dict.err1
-rw-r--r--src/tests/qapi-schema/alternate-conflict-dict.exit1
-rw-r--r--src/tests/qapi-schema/alternate-conflict-dict.json8
-rw-r--r--src/tests/qapi-schema/alternate-conflict-dict.out0
-rw-r--r--src/tests/qapi-schema/alternate-conflict-string.err1
-rw-r--r--src/tests/qapi-schema/alternate-conflict-string.exit1
-rw-r--r--src/tests/qapi-schema/alternate-conflict-string.json6
-rw-r--r--src/tests/qapi-schema/alternate-conflict-string.out0
-rw-r--r--src/tests/qapi-schema/alternate-empty.err0
-rw-r--r--src/tests/qapi-schema/alternate-empty.exit1
-rw-r--r--src/tests/qapi-schema/alternate-empty.json2
-rw-r--r--src/tests/qapi-schema/alternate-empty.out4
-rw-r--r--src/tests/qapi-schema/alternate-nested.err1
-rw-r--r--src/tests/qapi-schema/alternate-nested.exit1
-rw-r--r--src/tests/qapi-schema/alternate-nested.json5
-rw-r--r--src/tests/qapi-schema/alternate-nested.out0
-rw-r--r--src/tests/qapi-schema/alternate-unknown.err1
-rw-r--r--src/tests/qapi-schema/alternate-unknown.exit1
-rw-r--r--src/tests/qapi-schema/alternate-unknown.json3
-rw-r--r--src/tests/qapi-schema/alternate-unknown.out0
-rw-r--r--src/tests/qapi-schema/args-alternate.err1
-rw-r--r--src/tests/qapi-schema/args-alternate.exit1
-rw-r--r--src/tests/qapi-schema/args-alternate.json3
-rw-r--r--src/tests/qapi-schema/args-alternate.out0
-rw-r--r--src/tests/qapi-schema/args-any.err1
-rw-r--r--src/tests/qapi-schema/args-any.exit1
-rw-r--r--src/tests/qapi-schema/args-any.json2
-rw-r--r--src/tests/qapi-schema/args-any.out0
-rw-r--r--src/tests/qapi-schema/args-array-empty.err1
-rw-r--r--src/tests/qapi-schema/args-array-empty.exit1
-rw-r--r--src/tests/qapi-schema/args-array-empty.json2
-rw-r--r--src/tests/qapi-schema/args-array-empty.out0
-rw-r--r--src/tests/qapi-schema/args-array-unknown.err1
-rw-r--r--src/tests/qapi-schema/args-array-unknown.exit1
-rw-r--r--src/tests/qapi-schema/args-array-unknown.json2
-rw-r--r--src/tests/qapi-schema/args-array-unknown.out0
-rw-r--r--src/tests/qapi-schema/args-int.err1
-rw-r--r--src/tests/qapi-schema/args-int.exit1
-rw-r--r--src/tests/qapi-schema/args-int.json2
-rw-r--r--src/tests/qapi-schema/args-int.out0
-rw-r--r--src/tests/qapi-schema/args-invalid.err1
-rw-r--r--src/tests/qapi-schema/args-invalid.exit1
-rw-r--r--src/tests/qapi-schema/args-invalid.json2
-rw-r--r--src/tests/qapi-schema/args-invalid.out0
-rw-r--r--src/tests/qapi-schema/args-member-array-bad.err1
-rw-r--r--src/tests/qapi-schema/args-member-array-bad.exit1
-rw-r--r--src/tests/qapi-schema/args-member-array-bad.json2
-rw-r--r--src/tests/qapi-schema/args-member-array-bad.out0
-rw-r--r--src/tests/qapi-schema/args-member-unknown.err1
-rw-r--r--src/tests/qapi-schema/args-member-unknown.exit1
-rw-r--r--src/tests/qapi-schema/args-member-unknown.json2
-rw-r--r--src/tests/qapi-schema/args-member-unknown.out0
-rw-r--r--src/tests/qapi-schema/args-name-clash.err0
-rw-r--r--src/tests/qapi-schema/args-name-clash.exit1
-rw-r--r--src/tests/qapi-schema/args-name-clash.json5
-rw-r--r--src/tests/qapi-schema/args-name-clash.out6
-rw-r--r--src/tests/qapi-schema/args-union.err1
-rw-r--r--src/tests/qapi-schema/args-union.exit1
-rw-r--r--src/tests/qapi-schema/args-union.json4
-rw-r--r--src/tests/qapi-schema/args-union.out0
-rw-r--r--src/tests/qapi-schema/args-unknown.err1
-rw-r--r--src/tests/qapi-schema/args-unknown.exit1
-rw-r--r--src/tests/qapi-schema/args-unknown.json2
-rw-r--r--src/tests/qapi-schema/args-unknown.out0
-rw-r--r--src/tests/qapi-schema/bad-base.err1
-rw-r--r--src/tests/qapi-schema/bad-base.exit1
-rw-r--r--src/tests/qapi-schema/bad-base.json3
-rw-r--r--src/tests/qapi-schema/bad-base.out0
-rw-r--r--src/tests/qapi-schema/bad-data.err1
-rw-r--r--src/tests/qapi-schema/bad-data.exit1
-rw-r--r--src/tests/qapi-schema/bad-data.json2
-rw-r--r--src/tests/qapi-schema/bad-data.out0
-rw-r--r--src/tests/qapi-schema/bad-ident.err1
-rw-r--r--src/tests/qapi-schema/bad-ident.exit1
-rw-r--r--src/tests/qapi-schema/bad-ident.json2
-rw-r--r--src/tests/qapi-schema/bad-ident.out0
-rw-r--r--src/tests/qapi-schema/bad-type-bool.err1
-rw-r--r--src/tests/qapi-schema/bad-type-bool.exit1
-rw-r--r--src/tests/qapi-schema/bad-type-bool.json2
-rw-r--r--src/tests/qapi-schema/bad-type-bool.out0
-rw-r--r--src/tests/qapi-schema/bad-type-dict.err1
-rw-r--r--src/tests/qapi-schema/bad-type-dict.exit1
-rw-r--r--src/tests/qapi-schema/bad-type-dict.json2
-rw-r--r--src/tests/qapi-schema/bad-type-dict.out0
-rw-r--r--src/tests/qapi-schema/bad-type-int.err1
-rw-r--r--src/tests/qapi-schema/bad-type-int.exit1
-rw-r--r--src/tests/qapi-schema/bad-type-int.json3
-rw-r--r--src/tests/qapi-schema/bad-type-int.out0
-rw-r--r--src/tests/qapi-schema/command-int.err1
-rw-r--r--src/tests/qapi-schema/command-int.exit1
-rw-r--r--src/tests/qapi-schema/command-int.json2
-rw-r--r--src/tests/qapi-schema/command-int.out0
-rw-r--r--src/tests/qapi-schema/comments.err0
-rw-r--r--src/tests/qapi-schema/comments.exit1
-rw-r--r--src/tests/qapi-schema/comments.json4
-rw-r--r--src/tests/qapi-schema/comments.out2
-rw-r--r--src/tests/qapi-schema/double-data.err1
-rw-r--r--src/tests/qapi-schema/double-data.exit1
-rw-r--r--src/tests/qapi-schema/double-data.json2
-rw-r--r--src/tests/qapi-schema/double-data.out0
-rw-r--r--src/tests/qapi-schema/double-type.err1
-rw-r--r--src/tests/qapi-schema/double-type.exit1
-rw-r--r--src/tests/qapi-schema/double-type.json2
-rw-r--r--src/tests/qapi-schema/double-type.out0
-rw-r--r--src/tests/qapi-schema/duplicate-key.err1
-rw-r--r--src/tests/qapi-schema/duplicate-key.exit1
-rw-r--r--src/tests/qapi-schema/duplicate-key.json3
-rw-r--r--src/tests/qapi-schema/duplicate-key.out0
-rw-r--r--src/tests/qapi-schema/empty.err0
-rw-r--r--src/tests/qapi-schema/empty.exit1
-rw-r--r--src/tests/qapi-schema/empty.json0
-rw-r--r--src/tests/qapi-schema/empty.out1
-rw-r--r--src/tests/qapi-schema/enum-bad-name.err1
-rw-r--r--src/tests/qapi-schema/enum-bad-name.exit1
-rw-r--r--src/tests/qapi-schema/enum-bad-name.json2
-rw-r--r--src/tests/qapi-schema/enum-bad-name.out0
-rw-r--r--src/tests/qapi-schema/enum-bad-prefix.err1
-rw-r--r--src/tests/qapi-schema/enum-bad-prefix.exit1
-rw-r--r--src/tests/qapi-schema/enum-bad-prefix.json2
-rw-r--r--src/tests/qapi-schema/enum-bad-prefix.out0
-rw-r--r--src/tests/qapi-schema/enum-clash-member.err1
-rw-r--r--src/tests/qapi-schema/enum-clash-member.exit1
-rw-r--r--src/tests/qapi-schema/enum-clash-member.json2
-rw-r--r--src/tests/qapi-schema/enum-clash-member.out0
-rw-r--r--src/tests/qapi-schema/enum-dict-member.err1
-rw-r--r--src/tests/qapi-schema/enum-dict-member.exit1
-rw-r--r--src/tests/qapi-schema/enum-dict-member.json2
-rw-r--r--src/tests/qapi-schema/enum-dict-member.out0
-rw-r--r--src/tests/qapi-schema/enum-int-member.err1
-rw-r--r--src/tests/qapi-schema/enum-int-member.exit1
-rw-r--r--src/tests/qapi-schema/enum-int-member.json3
-rw-r--r--src/tests/qapi-schema/enum-int-member.out0
-rw-r--r--src/tests/qapi-schema/enum-max-member.err1
-rw-r--r--src/tests/qapi-schema/enum-max-member.exit1
-rw-r--r--src/tests/qapi-schema/enum-max-member.json3
-rw-r--r--src/tests/qapi-schema/enum-max-member.out0
-rw-r--r--src/tests/qapi-schema/enum-missing-data.err1
-rw-r--r--src/tests/qapi-schema/enum-missing-data.exit1
-rw-r--r--src/tests/qapi-schema/enum-missing-data.json2
-rw-r--r--src/tests/qapi-schema/enum-missing-data.out0
-rw-r--r--src/tests/qapi-schema/enum-wrong-data.err1
-rw-r--r--src/tests/qapi-schema/enum-wrong-data.exit1
-rw-r--r--src/tests/qapi-schema/enum-wrong-data.json2
-rw-r--r--src/tests/qapi-schema/enum-wrong-data.out0
-rw-r--r--src/tests/qapi-schema/escape-outside-string.err1
-rw-r--r--src/tests/qapi-schema/escape-outside-string.exit1
-rw-r--r--src/tests/qapi-schema/escape-outside-string.json3
-rw-r--r--src/tests/qapi-schema/escape-outside-string.out0
-rw-r--r--src/tests/qapi-schema/escape-too-big.err1
-rw-r--r--src/tests/qapi-schema/escape-too-big.exit1
-rw-r--r--src/tests/qapi-schema/escape-too-big.json3
-rw-r--r--src/tests/qapi-schema/escape-too-big.out0
-rw-r--r--src/tests/qapi-schema/escape-too-short.err1
-rw-r--r--src/tests/qapi-schema/escape-too-short.exit1
-rw-r--r--src/tests/qapi-schema/escape-too-short.json3
-rw-r--r--src/tests/qapi-schema/escape-too-short.out0
-rw-r--r--src/tests/qapi-schema/event-case.err0
-rw-r--r--src/tests/qapi-schema/event-case.exit1
-rw-r--r--src/tests/qapi-schema/event-case.json3
-rw-r--r--src/tests/qapi-schema/event-case.out2
-rw-r--r--src/tests/qapi-schema/event-max.err1
-rw-r--r--src/tests/qapi-schema/event-max.exit1
-rw-r--r--src/tests/qapi-schema/event-max.json2
-rw-r--r--src/tests/qapi-schema/event-max.out0
-rw-r--r--src/tests/qapi-schema/event-nest-struct.err1
-rw-r--r--src/tests/qapi-schema/event-nest-struct.exit1
-rw-r--r--src/tests/qapi-schema/event-nest-struct.json2
-rw-r--r--src/tests/qapi-schema/event-nest-struct.out0
-rw-r--r--src/tests/qapi-schema/flat-union-array-branch.err1
-rw-r--r--src/tests/qapi-schema/flat-union-array-branch.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-array-branch.json12
-rw-r--r--src/tests/qapi-schema/flat-union-array-branch.out0
-rw-r--r--src/tests/qapi-schema/flat-union-bad-base.err1
-rw-r--r--src/tests/qapi-schema/flat-union-bad-base.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-bad-base.json13
-rw-r--r--src/tests/qapi-schema/flat-union-bad-base.out0
-rw-r--r--src/tests/qapi-schema/flat-union-bad-discriminator.err1
-rw-r--r--src/tests/qapi-schema/flat-union-bad-discriminator.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-bad-discriminator.json15
-rw-r--r--src/tests/qapi-schema/flat-union-bad-discriminator.out0
-rw-r--r--src/tests/qapi-schema/flat-union-base-any.err1
-rw-r--r--src/tests/qapi-schema/flat-union-base-any.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-base-any.json12
-rw-r--r--src/tests/qapi-schema/flat-union-base-any.out0
-rw-r--r--src/tests/qapi-schema/flat-union-base-union.err1
-rw-r--r--src/tests/qapi-schema/flat-union-base-union.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-base-union.json18
-rw-r--r--src/tests/qapi-schema/flat-union-base-union.out0
-rw-r--r--src/tests/qapi-schema/flat-union-clash-branch.err0
-rw-r--r--src/tests/qapi-schema/flat-union-clash-branch.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-clash-branch.json18
-rw-r--r--src/tests/qapi-schema/flat-union-clash-branch.out14
-rw-r--r--src/tests/qapi-schema/flat-union-clash-member.err1
-rw-r--r--src/tests/qapi-schema/flat-union-clash-member.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-clash-member.json15
-rw-r--r--src/tests/qapi-schema/flat-union-clash-member.out0
-rw-r--r--src/tests/qapi-schema/flat-union-clash-type.err1
-rw-r--r--src/tests/qapi-schema/flat-union-clash-type.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-clash-type.json14
-rw-r--r--src/tests/qapi-schema/flat-union-clash-type.out0
-rw-r--r--src/tests/qapi-schema/flat-union-empty.err0
-rw-r--r--src/tests/qapi-schema/flat-union-empty.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-empty.json4
-rw-r--r--src/tests/qapi-schema/flat-union-empty.out7
-rw-r--r--src/tests/qapi-schema/flat-union-inline.err1
-rw-r--r--src/tests/qapi-schema/flat-union-inline.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-inline.json11
-rw-r--r--src/tests/qapi-schema/flat-union-inline.out0
-rw-r--r--src/tests/qapi-schema/flat-union-int-branch.err1
-rw-r--r--src/tests/qapi-schema/flat-union-int-branch.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-int-branch.json12
-rw-r--r--src/tests/qapi-schema/flat-union-int-branch.out0
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-branch-key.err1
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-branch-key.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-branch-key.json17
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-branch-key.out0
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-discriminator.err1
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-discriminator.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-discriminator.json17
-rw-r--r--src/tests/qapi-schema/flat-union-invalid-discriminator.out0
-rw-r--r--src/tests/qapi-schema/flat-union-no-base.err1
-rw-r--r--src/tests/qapi-schema/flat-union-no-base.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-no-base.json12
-rw-r--r--src/tests/qapi-schema/flat-union-no-base.out0
-rw-r--r--src/tests/qapi-schema/flat-union-optional-discriminator.err1
-rw-r--r--src/tests/qapi-schema/flat-union-optional-discriminator.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-optional-discriminator.json10
-rw-r--r--src/tests/qapi-schema/flat-union-optional-discriminator.out0
-rw-r--r--src/tests/qapi-schema/flat-union-string-discriminator.err1
-rw-r--r--src/tests/qapi-schema/flat-union-string-discriminator.exit1
-rw-r--r--src/tests/qapi-schema/flat-union-string-discriminator.json17
-rw-r--r--src/tests/qapi-schema/flat-union-string-discriminator.out0
-rw-r--r--src/tests/qapi-schema/funny-char.err1
-rw-r--r--src/tests/qapi-schema/funny-char.exit1
-rw-r--r--src/tests/qapi-schema/funny-char.json2
-rw-r--r--src/tests/qapi-schema/funny-char.out0
-rw-r--r--src/tests/qapi-schema/ident-with-escape.err0
-rw-r--r--src/tests/qapi-schema/ident-with-escape.exit1
-rw-r--r--src/tests/qapi-schema/ident-with-escape.json4
-rw-r--r--src/tests/qapi-schema/ident-with-escape.out5
-rw-r--r--src/tests/qapi-schema/include-before-err.err1
-rw-r--r--src/tests/qapi-schema/include-before-err.exit1
-rw-r--r--src/tests/qapi-schema/include-before-err.json2
-rw-r--r--src/tests/qapi-schema/include-before-err.out0
-rw-r--r--src/tests/qapi-schema/include-cycle-b.json1
-rw-r--r--src/tests/qapi-schema/include-cycle-c.json1
-rw-r--r--src/tests/qapi-schema/include-cycle.err3
-rw-r--r--src/tests/qapi-schema/include-cycle.exit1
-rw-r--r--src/tests/qapi-schema/include-cycle.json1
-rw-r--r--src/tests/qapi-schema/include-cycle.out0
-rw-r--r--src/tests/qapi-schema/include-format-err.err1
-rw-r--r--src/tests/qapi-schema/include-format-err.exit1
-rw-r--r--src/tests/qapi-schema/include-format-err.json2
-rw-r--r--src/tests/qapi-schema/include-format-err.out0
-rw-r--r--src/tests/qapi-schema/include-nested-err.err2
-rw-r--r--src/tests/qapi-schema/include-nested-err.exit1
-rw-r--r--src/tests/qapi-schema/include-nested-err.json1
-rw-r--r--src/tests/qapi-schema/include-nested-err.out0
-rw-r--r--src/tests/qapi-schema/include-no-file.err1
-rw-r--r--src/tests/qapi-schema/include-no-file.exit1
-rw-r--r--src/tests/qapi-schema/include-no-file.json1
-rw-r--r--src/tests/qapi-schema/include-no-file.out0
-rw-r--r--src/tests/qapi-schema/include-non-file.err1
-rw-r--r--src/tests/qapi-schema/include-non-file.exit1
-rw-r--r--src/tests/qapi-schema/include-non-file.json1
-rw-r--r--src/tests/qapi-schema/include-non-file.out0
-rw-r--r--src/tests/qapi-schema/include-relpath-sub.json2
-rw-r--r--src/tests/qapi-schema/include-relpath.err0
-rw-r--r--src/tests/qapi-schema/include-relpath.exit1
-rw-r--r--src/tests/qapi-schema/include-relpath.json1
-rw-r--r--src/tests/qapi-schema/include-relpath.out2
-rw-r--r--src/tests/qapi-schema/include-repetition-sub.json2
-rw-r--r--src/tests/qapi-schema/include-repetition.err0
-rw-r--r--src/tests/qapi-schema/include-repetition.exit1
-rw-r--r--src/tests/qapi-schema/include-repetition.json3
-rw-r--r--src/tests/qapi-schema/include-repetition.out2
-rw-r--r--src/tests/qapi-schema/include-self-cycle.err1
-rw-r--r--src/tests/qapi-schema/include-self-cycle.exit1
-rw-r--r--src/tests/qapi-schema/include-self-cycle.json1
-rw-r--r--src/tests/qapi-schema/include-self-cycle.out0
-rw-r--r--src/tests/qapi-schema/include-simple-sub.json2
-rw-r--r--src/tests/qapi-schema/include-simple.err0
-rw-r--r--src/tests/qapi-schema/include-simple.exit1
-rw-r--r--src/tests/qapi-schema/include-simple.json1
-rw-r--r--src/tests/qapi-schema/include-simple.out2
-rw-r--r--src/tests/qapi-schema/include/relpath.json1
-rw-r--r--src/tests/qapi-schema/indented-expr.err0
-rw-r--r--src/tests/qapi-schema/indented-expr.exit1
-rw-r--r--src/tests/qapi-schema/indented-expr.json2
-rw-r--r--src/tests/qapi-schema/indented-expr.out5
-rw-r--r--src/tests/qapi-schema/leading-comma-list.err1
-rw-r--r--src/tests/qapi-schema/leading-comma-list.exit1
-rw-r--r--src/tests/qapi-schema/leading-comma-list.json2
-rw-r--r--src/tests/qapi-schema/leading-comma-list.out0
-rw-r--r--src/tests/qapi-schema/leading-comma-object.err1
-rw-r--r--src/tests/qapi-schema/leading-comma-object.exit1
-rw-r--r--src/tests/qapi-schema/leading-comma-object.json2
-rw-r--r--src/tests/qapi-schema/leading-comma-object.out0
-rw-r--r--src/tests/qapi-schema/missing-colon.err1
-rw-r--r--src/tests/qapi-schema/missing-colon.exit1
-rw-r--r--src/tests/qapi-schema/missing-colon.json2
-rw-r--r--src/tests/qapi-schema/missing-colon.out0
-rw-r--r--src/tests/qapi-schema/missing-comma-list.err1
-rw-r--r--src/tests/qapi-schema/missing-comma-list.exit1
-rw-r--r--src/tests/qapi-schema/missing-comma-list.json2
-rw-r--r--src/tests/qapi-schema/missing-comma-list.out0
-rw-r--r--src/tests/qapi-schema/missing-comma-object.err1
-rw-r--r--src/tests/qapi-schema/missing-comma-object.exit1
-rw-r--r--src/tests/qapi-schema/missing-comma-object.json2
-rw-r--r--src/tests/qapi-schema/missing-comma-object.out0
-rw-r--r--src/tests/qapi-schema/missing-type.err1
-rw-r--r--src/tests/qapi-schema/missing-type.exit1
-rw-r--r--src/tests/qapi-schema/missing-type.json2
-rw-r--r--src/tests/qapi-schema/missing-type.out0
-rw-r--r--src/tests/qapi-schema/nested-struct-data.err1
-rw-r--r--src/tests/qapi-schema/nested-struct-data.exit1
-rw-r--r--src/tests/qapi-schema/nested-struct-data.json3
-rw-r--r--src/tests/qapi-schema/nested-struct-data.out0
-rw-r--r--src/tests/qapi-schema/non-objects.err1
-rw-r--r--src/tests/qapi-schema/non-objects.exit1
-rw-r--r--src/tests/qapi-schema/non-objects.json2
-rw-r--r--src/tests/qapi-schema/non-objects.out0
-rw-r--r--src/tests/qapi-schema/qapi-schema-test.err0
-rw-r--r--src/tests/qapi-schema/qapi-schema-test.exit1
-rw-r--r--src/tests/qapi-schema/qapi-schema-test.json173
-rw-r--r--src/tests/qapi-schema/qapi-schema-test.out207
-rw-r--r--src/tests/qapi-schema/quoted-structural-chars.err1
-rw-r--r--src/tests/qapi-schema/quoted-structural-chars.exit1
-rw-r--r--src/tests/qapi-schema/quoted-structural-chars.json1
-rw-r--r--src/tests/qapi-schema/quoted-structural-chars.out0
-rw-r--r--src/tests/qapi-schema/redefined-builtin.err1
-rw-r--r--src/tests/qapi-schema/redefined-builtin.exit1
-rw-r--r--src/tests/qapi-schema/redefined-builtin.json2
-rw-r--r--src/tests/qapi-schema/redefined-builtin.out0
-rw-r--r--src/tests/qapi-schema/redefined-command.err1
-rw-r--r--src/tests/qapi-schema/redefined-command.exit1
-rw-r--r--src/tests/qapi-schema/redefined-command.json3
-rw-r--r--src/tests/qapi-schema/redefined-command.out0
-rw-r--r--src/tests/qapi-schema/redefined-event.err1
-rw-r--r--src/tests/qapi-schema/redefined-event.exit1
-rw-r--r--src/tests/qapi-schema/redefined-event.json3
-rw-r--r--src/tests/qapi-schema/redefined-event.out0
-rw-r--r--src/tests/qapi-schema/redefined-type.err1
-rw-r--r--src/tests/qapi-schema/redefined-type.exit1
-rw-r--r--src/tests/qapi-schema/redefined-type.json3
-rw-r--r--src/tests/qapi-schema/redefined-type.out0
-rw-r--r--src/tests/qapi-schema/reserved-command-q.err1
-rw-r--r--src/tests/qapi-schema/reserved-command-q.exit1
-rw-r--r--src/tests/qapi-schema/reserved-command-q.json5
-rw-r--r--src/tests/qapi-schema/reserved-command-q.out0
-rw-r--r--src/tests/qapi-schema/reserved-member-has.err1
-rw-r--r--src/tests/qapi-schema/reserved-member-has.exit1
-rw-r--r--src/tests/qapi-schema/reserved-member-has.json5
-rw-r--r--src/tests/qapi-schema/reserved-member-has.out0
-rw-r--r--src/tests/qapi-schema/reserved-member-q.err1
-rw-r--r--src/tests/qapi-schema/reserved-member-q.exit1
-rw-r--r--src/tests/qapi-schema/reserved-member-q.json4
-rw-r--r--src/tests/qapi-schema/reserved-member-q.out0
-rw-r--r--src/tests/qapi-schema/reserved-member-u.err1
-rw-r--r--src/tests/qapi-schema/reserved-member-u.exit1
-rw-r--r--src/tests/qapi-schema/reserved-member-u.json7
-rw-r--r--src/tests/qapi-schema/reserved-member-u.out0
-rw-r--r--src/tests/qapi-schema/reserved-type-kind.err1
-rw-r--r--src/tests/qapi-schema/reserved-type-kind.exit1
-rw-r--r--src/tests/qapi-schema/reserved-type-kind.json2
-rw-r--r--src/tests/qapi-schema/reserved-type-kind.out0
-rw-r--r--src/tests/qapi-schema/reserved-type-list.err1
-rw-r--r--src/tests/qapi-schema/reserved-type-list.exit1
-rw-r--r--src/tests/qapi-schema/reserved-type-list.json5
-rw-r--r--src/tests/qapi-schema/reserved-type-list.out0
-rw-r--r--src/tests/qapi-schema/returns-alternate.err1
-rw-r--r--src/tests/qapi-schema/returns-alternate.exit1
-rw-r--r--src/tests/qapi-schema/returns-alternate.json3
-rw-r--r--src/tests/qapi-schema/returns-alternate.out0
-rw-r--r--src/tests/qapi-schema/returns-array-bad.err1
-rw-r--r--src/tests/qapi-schema/returns-array-bad.exit1
-rw-r--r--src/tests/qapi-schema/returns-array-bad.json2
-rw-r--r--src/tests/qapi-schema/returns-array-bad.out0
-rw-r--r--src/tests/qapi-schema/returns-dict.err1
-rw-r--r--src/tests/qapi-schema/returns-dict.exit1
-rw-r--r--src/tests/qapi-schema/returns-dict.json2
-rw-r--r--src/tests/qapi-schema/returns-dict.out0
-rw-r--r--src/tests/qapi-schema/returns-unknown.err1
-rw-r--r--src/tests/qapi-schema/returns-unknown.exit1
-rw-r--r--src/tests/qapi-schema/returns-unknown.json2
-rw-r--r--src/tests/qapi-schema/returns-unknown.out0
-rw-r--r--src/tests/qapi-schema/returns-whitelist.err1
-rw-r--r--src/tests/qapi-schema/returns-whitelist.exit1
-rw-r--r--src/tests/qapi-schema/returns-whitelist.json11
-rw-r--r--src/tests/qapi-schema/returns-whitelist.out0
-rw-r--r--src/tests/qapi-schema/struct-base-clash-deep.err1
-rw-r--r--src/tests/qapi-schema/struct-base-clash-deep.exit1
-rw-r--r--src/tests/qapi-schema/struct-base-clash-deep.json12
-rw-r--r--src/tests/qapi-schema/struct-base-clash-deep.out0
-rw-r--r--src/tests/qapi-schema/struct-base-clash.err1
-rw-r--r--src/tests/qapi-schema/struct-base-clash.exit1
-rw-r--r--src/tests/qapi-schema/struct-base-clash.json7
-rw-r--r--src/tests/qapi-schema/struct-base-clash.out0
-rw-r--r--src/tests/qapi-schema/struct-data-invalid.err1
-rw-r--r--src/tests/qapi-schema/struct-data-invalid.exit1
-rw-r--r--src/tests/qapi-schema/struct-data-invalid.json2
-rw-r--r--src/tests/qapi-schema/struct-data-invalid.out0
-rw-r--r--src/tests/qapi-schema/struct-member-invalid.err1
-rw-r--r--src/tests/qapi-schema/struct-member-invalid.exit1
-rw-r--r--src/tests/qapi-schema/struct-member-invalid.json2
-rw-r--r--src/tests/qapi-schema/struct-member-invalid.out0
-rw-r--r--src/tests/qapi-schema/test-qapi.py56
-rw-r--r--src/tests/qapi-schema/trailing-comma-list.err1
-rw-r--r--src/tests/qapi-schema/trailing-comma-list.exit1
-rw-r--r--src/tests/qapi-schema/trailing-comma-list.json2
-rw-r--r--src/tests/qapi-schema/trailing-comma-list.out0
-rw-r--r--src/tests/qapi-schema/trailing-comma-object.err1
-rw-r--r--src/tests/qapi-schema/trailing-comma-object.exit1
-rw-r--r--src/tests/qapi-schema/trailing-comma-object.json2
-rw-r--r--src/tests/qapi-schema/trailing-comma-object.out0
-rw-r--r--src/tests/qapi-schema/type-bypass-bad-gen.err1
-rw-r--r--src/tests/qapi-schema/type-bypass-bad-gen.exit1
-rw-r--r--src/tests/qapi-schema/type-bypass-bad-gen.json2
-rw-r--r--src/tests/qapi-schema/type-bypass-bad-gen.out0
-rw-r--r--src/tests/qapi-schema/unclosed-list.err1
-rw-r--r--src/tests/qapi-schema/unclosed-list.exit1
-rw-r--r--src/tests/qapi-schema/unclosed-list.json1
-rw-r--r--src/tests/qapi-schema/unclosed-list.out0
-rw-r--r--src/tests/qapi-schema/unclosed-object.err1
-rw-r--r--src/tests/qapi-schema/unclosed-object.exit1
-rw-r--r--src/tests/qapi-schema/unclosed-object.json1
-rw-r--r--src/tests/qapi-schema/unclosed-object.out0
-rw-r--r--src/tests/qapi-schema/unclosed-string.err1
-rw-r--r--src/tests/qapi-schema/unclosed-string.exit1
-rw-r--r--src/tests/qapi-schema/unclosed-string.json2
-rw-r--r--src/tests/qapi-schema/unclosed-string.out0
-rw-r--r--src/tests/qapi-schema/unicode-str.err1
-rw-r--r--src/tests/qapi-schema/unicode-str.exit1
-rw-r--r--src/tests/qapi-schema/unicode-str.json2
-rw-r--r--src/tests/qapi-schema/unicode-str.out0
-rw-r--r--src/tests/qapi-schema/union-bad-branch.err1
-rw-r--r--src/tests/qapi-schema/union-bad-branch.exit1
-rw-r--r--src/tests/qapi-schema/union-bad-branch.json8
-rw-r--r--src/tests/qapi-schema/union-bad-branch.out0
-rw-r--r--src/tests/qapi-schema/union-base-no-discriminator.err1
-rw-r--r--src/tests/qapi-schema/union-base-no-discriminator.exit1
-rw-r--r--src/tests/qapi-schema/union-base-no-discriminator.json14
-rw-r--r--src/tests/qapi-schema/union-base-no-discriminator.out0
-rw-r--r--src/tests/qapi-schema/union-clash-branches.err1
-rw-r--r--src/tests/qapi-schema/union-clash-branches.exit1
-rw-r--r--src/tests/qapi-schema/union-clash-branches.json5
-rw-r--r--src/tests/qapi-schema/union-clash-branches.out0
-rw-r--r--src/tests/qapi-schema/union-clash-data.err0
-rw-r--r--src/tests/qapi-schema/union-clash-data.exit1
-rw-r--r--src/tests/qapi-schema/union-clash-data.json7
-rw-r--r--src/tests/qapi-schema/union-clash-data.out6
-rw-r--r--src/tests/qapi-schema/union-clash-type.err1
-rw-r--r--src/tests/qapi-schema/union-clash-type.exit1
-rw-r--r--src/tests/qapi-schema/union-clash-type.json9
-rw-r--r--src/tests/qapi-schema/union-clash-type.out0
-rw-r--r--src/tests/qapi-schema/union-empty.err0
-rw-r--r--src/tests/qapi-schema/union-empty.exit1
-rw-r--r--src/tests/qapi-schema/union-empty.json2
-rw-r--r--src/tests/qapi-schema/union-empty.out3
-rw-r--r--src/tests/qapi-schema/union-invalid-base.err1
-rw-r--r--src/tests/qapi-schema/union-invalid-base.exit1
-rw-r--r--src/tests/qapi-schema/union-invalid-base.json12
-rw-r--r--src/tests/qapi-schema/union-invalid-base.out0
-rw-r--r--src/tests/qapi-schema/union-max.err1
-rw-r--r--src/tests/qapi-schema/union-max.exit1
-rw-r--r--src/tests/qapi-schema/union-max.json3
-rw-r--r--src/tests/qapi-schema/union-max.out0
-rw-r--r--src/tests/qapi-schema/union-optional-branch.err1
-rw-r--r--src/tests/qapi-schema/union-optional-branch.exit1
-rw-r--r--src/tests/qapi-schema/union-optional-branch.json2
-rw-r--r--src/tests/qapi-schema/union-optional-branch.out0
-rw-r--r--src/tests/qapi-schema/union-unknown.err1
-rw-r--r--src/tests/qapi-schema/union-unknown.exit1
-rw-r--r--src/tests/qapi-schema/union-unknown.json3
-rw-r--r--src/tests/qapi-schema/union-unknown.out0
-rw-r--r--src/tests/qapi-schema/unknown-escape.err1
-rw-r--r--src/tests/qapi-schema/unknown-escape.exit1
-rw-r--r--src/tests/qapi-schema/unknown-escape.json3
-rw-r--r--src/tests/qapi-schema/unknown-escape.out0
-rw-r--r--src/tests/qapi-schema/unknown-expr-key.err1
-rw-r--r--src/tests/qapi-schema/unknown-expr-key.exit1
-rw-r--r--src/tests/qapi-schema/unknown-expr-key.json2
-rw-r--r--src/tests/qapi-schema/unknown-expr-key.out0
495 files changed, 1293 insertions, 0 deletions
diff --git a/src/tests/qapi-schema/alternate-array.err b/src/tests/qapi-schema/alternate-array.err
new file mode 100644
index 0000000..7b930c6
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-array.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array
diff --git a/src/tests/qapi-schema/alternate-array.exit b/src/tests/qapi-schema/alternate-array.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-array.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-array.json b/src/tests/qapi-schema/alternate-array.json
new file mode 100644
index 0000000..f241aac
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-array.json
@@ -0,0 +1,7 @@
+# we do not allow array branches in alternates
+# TODO: should we support this?
+{ 'struct': 'One',
+ 'data': { 'name': 'str' } }
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'One',
+ 'two': [ 'int' ] } }
diff --git a/src/tests/qapi-schema/alternate-array.out b/src/tests/qapi-schema/alternate-array.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-array.out
diff --git a/src/tests/qapi-schema/alternate-base.err b/src/tests/qapi-schema/alternate-base.err
new file mode 100644
index 0000000..30d8a34
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-base.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
diff --git a/src/tests/qapi-schema/alternate-base.exit b/src/tests/qapi-schema/alternate-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-base.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-base.json b/src/tests/qapi-schema/alternate-base.json
new file mode 100644
index 0000000..529430ec
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-base.json
@@ -0,0 +1,6 @@
+# we reject alternate with base type
+{ 'struct': 'Base',
+ 'data': { 'string': 'str' } }
+{ 'alternate': 'Alt',
+ 'base': 'Base',
+ 'data': { 'number': 'int' } }
diff --git a/src/tests/qapi-schema/alternate-base.out b/src/tests/qapi-schema/alternate-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-base.out
diff --git a/src/tests/qapi-schema/alternate-clash.err b/src/tests/qapi-schema/alternate-clash.err
new file mode 100644
index 0000000..a475ab6
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-clash.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-clash.json:7: Alternate 'Alt1' member 'a_b' clashes with 'a-b'
diff --git a/src/tests/qapi-schema/alternate-clash.exit b/src/tests/qapi-schema/alternate-clash.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-clash.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-clash.json b/src/tests/qapi-schema/alternate-clash.json
new file mode 100644
index 0000000..6d73bc5
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-clash.json
@@ -0,0 +1,8 @@
+# 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': { 'a-b': 'str', 'a_b': 'int' } }
diff --git a/src/tests/qapi-schema/alternate-clash.out b/src/tests/qapi-schema/alternate-clash.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-clash.out
diff --git a/src/tests/qapi-schema/alternate-conflict-dict.err b/src/tests/qapi-schema/alternate-conflict-dict.err
new file mode 100644
index 0000000..0f411f4
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/src/tests/qapi-schema/alternate-conflict-dict.exit b/src/tests/qapi-schema/alternate-conflict-dict.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-conflict-dict.json b/src/tests/qapi-schema/alternate-conflict-dict.json
new file mode 100644
index 0000000..d566cca
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-dict.json
@@ -0,0 +1,8 @@
+# we reject alternates with multiple object branches
+{ 'struct': 'One',
+ 'data': { 'name': 'str' } }
+{ 'struct': 'Two',
+ 'data': { 'value': 'int' } }
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'One',
+ 'two': 'Two' } }
diff --git a/src/tests/qapi-schema/alternate-conflict-dict.out b/src/tests/qapi-schema/alternate-conflict-dict.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-dict.out
diff --git a/src/tests/qapi-schema/alternate-conflict-string.err b/src/tests/qapi-schema/alternate-conflict-string.err
new file mode 100644
index 0000000..fc523b0
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-string.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/src/tests/qapi-schema/alternate-conflict-string.exit b/src/tests/qapi-schema/alternate-conflict-string.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-string.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-conflict-string.json b/src/tests/qapi-schema/alternate-conflict-string.json
new file mode 100644
index 0000000..72f04a8
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-string.json
@@ -0,0 +1,6 @@
+# we reject alternates with multiple string-like branches
+{ 'enum': 'Enum',
+ 'data': [ 'hello', 'world' ] }
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'str',
+ 'two': 'Enum' } }
diff --git a/src/tests/qapi-schema/alternate-conflict-string.out b/src/tests/qapi-schema/alternate-conflict-string.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-conflict-string.out
diff --git a/src/tests/qapi-schema/alternate-empty.err b/src/tests/qapi-schema/alternate-empty.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-empty.err
diff --git a/src/tests/qapi-schema/alternate-empty.exit b/src/tests/qapi-schema/alternate-empty.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-empty.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/alternate-empty.json b/src/tests/qapi-schema/alternate-empty.json
new file mode 100644
index 0000000..db3820f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-empty.json
@@ -0,0 +1,2 @@
+# FIXME - alternates should list at least two types to be useful
+{ 'alternate': 'Alt', 'data': { 'i': 'int' } }
diff --git a/src/tests/qapi-schema/alternate-empty.out b/src/tests/qapi-schema/alternate-empty.out
new file mode 100644
index 0000000..0f153b6
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-empty.out
@@ -0,0 +1,4 @@
+object :empty
+alternate Alt
+ case i: int
+enum AltKind ['i']
diff --git a/src/tests/qapi-schema/alternate-nested.err b/src/tests/qapi-schema/alternate-nested.err
new file mode 100644
index 0000000..4d1187e
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-nested.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1'
diff --git a/src/tests/qapi-schema/alternate-nested.exit b/src/tests/qapi-schema/alternate-nested.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-nested.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-nested.json b/src/tests/qapi-schema/alternate-nested.json
new file mode 100644
index 0000000..8e22186
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-nested.json
@@ -0,0 +1,5 @@
+# we reject a nested alternate branch
+{ 'alternate': 'Alt1',
+ 'data': { 'name': 'str', 'value': 'int' } }
+{ 'alternate': 'Alt2',
+ 'data': { 'nested': 'Alt1', 'b': 'bool' } }
diff --git a/src/tests/qapi-schema/alternate-nested.out b/src/tests/qapi-schema/alternate-nested.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-nested.out
diff --git a/src/tests/qapi-schema/alternate-unknown.err b/src/tests/qapi-schema/alternate-unknown.err
new file mode 100644
index 0000000..dea45dc
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType'
diff --git a/src/tests/qapi-schema/alternate-unknown.exit b/src/tests/qapi-schema/alternate-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/alternate-unknown.json b/src/tests/qapi-schema/alternate-unknown.json
new file mode 100644
index 0000000..08c80dc
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-unknown.json
@@ -0,0 +1,3 @@
+# we reject an alternate with unknown type in branch
+{ 'alternate': 'Alt',
+ 'data': { 'unknown': 'MissingType', 'i': 'int' } }
diff --git a/src/tests/qapi-schema/alternate-unknown.out b/src/tests/qapi-schema/alternate-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/alternate-unknown.out
diff --git a/src/tests/qapi-schema/args-alternate.err b/src/tests/qapi-schema/args-alternate.err
new file mode 100644
index 0000000..3086eae
--- /dev/null
+++ b/src/tests/qapi-schema/args-alternate.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt'
diff --git a/src/tests/qapi-schema/args-alternate.exit b/src/tests/qapi-schema/args-alternate.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-alternate.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-alternate.json b/src/tests/qapi-schema/args-alternate.json
new file mode 100644
index 0000000..69e94d4
--- /dev/null
+++ b/src/tests/qapi-schema/args-alternate.json
@@ -0,0 +1,3 @@
+# we do not allow alternate arguments
+{ 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } }
+{ 'command': 'oops', 'data': 'Alt' }
diff --git a/src/tests/qapi-schema/args-alternate.out b/src/tests/qapi-schema/args-alternate.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-alternate.out
diff --git a/src/tests/qapi-schema/args-any.err b/src/tests/qapi-schema/args-any.err
new file mode 100644
index 0000000..bf9b5e0
--- /dev/null
+++ b/src/tests/qapi-schema/args-any.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
diff --git a/src/tests/qapi-schema/args-any.exit b/src/tests/qapi-schema/args-any.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-any.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-any.json b/src/tests/qapi-schema/args-any.json
new file mode 100644
index 0000000..58fe5e4
--- /dev/null
+++ b/src/tests/qapi-schema/args-any.json
@@ -0,0 +1,2 @@
+# we do not allow an 'any' argument
+{ 'command': 'oops', 'data': 'any' }
diff --git a/src/tests/qapi-schema/args-any.out b/src/tests/qapi-schema/args-any.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-any.out
diff --git a/src/tests/qapi-schema/args-array-empty.err b/src/tests/qapi-schema/args-array-empty.err
new file mode 100644
index 0000000..cb7ed33
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name
diff --git a/src/tests/qapi-schema/args-array-empty.exit b/src/tests/qapi-schema/args-array-empty.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-empty.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-array-empty.json b/src/tests/qapi-schema/args-array-empty.json
new file mode 100644
index 0000000..652dcfb
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-empty.json
@@ -0,0 +1,2 @@
+# we reject an array for data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'empty': [ ] } }
diff --git a/src/tests/qapi-schema/args-array-empty.out b/src/tests/qapi-schema/args-array-empty.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-empty.out
diff --git a/src/tests/qapi-schema/args-array-unknown.err b/src/tests/qapi-schema/args-array-unknown.err
new file mode 100644
index 0000000..cd7a0f9
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/src/tests/qapi-schema/args-array-unknown.exit b/src/tests/qapi-schema/args-array-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-array-unknown.json b/src/tests/qapi-schema/args-array-unknown.json
new file mode 100644
index 0000000..6f3e883
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-unknown.json
@@ -0,0 +1,2 @@
+# we reject an array for data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } }
diff --git a/src/tests/qapi-schema/args-array-unknown.out b/src/tests/qapi-schema/args-array-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-array-unknown.out
diff --git a/src/tests/qapi-schema/args-int.err b/src/tests/qapi-schema/args-int.err
new file mode 100644
index 0000000..dc1d250
--- /dev/null
+++ b/src/tests/qapi-schema/args-int.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'
diff --git a/src/tests/qapi-schema/args-int.exit b/src/tests/qapi-schema/args-int.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-int.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-int.json b/src/tests/qapi-schema/args-int.json
new file mode 100644
index 0000000..a334d92
--- /dev/null
+++ b/src/tests/qapi-schema/args-int.json
@@ -0,0 +1,2 @@
+# we reject commands where data is not an array or complex type
+{ 'command': 'oops', 'data': 'int' }
diff --git a/src/tests/qapi-schema/args-int.out b/src/tests/qapi-schema/args-int.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-int.out
diff --git a/src/tests/qapi-schema/args-invalid.err b/src/tests/qapi-schema/args-invalid.err
new file mode 100644
index 0000000..fe1e949
--- /dev/null
+++ b/src/tests/qapi-schema/args-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name
diff --git a/src/tests/qapi-schema/args-invalid.exit b/src/tests/qapi-schema/args-invalid.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-invalid.json b/src/tests/qapi-schema/args-invalid.json
new file mode 100644
index 0000000..db09813
--- /dev/null
+++ b/src/tests/qapi-schema/args-invalid.json
@@ -0,0 +1,2 @@
+{ 'command': 'foo',
+ 'data': false }
diff --git a/src/tests/qapi-schema/args-invalid.out b/src/tests/qapi-schema/args-invalid.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-invalid.out
diff --git a/src/tests/qapi-schema/args-member-array-bad.err b/src/tests/qapi-schema/args-member-array-bad.err
new file mode 100644
index 0000000..881b4d9
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-array-bad.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name
diff --git a/src/tests/qapi-schema/args-member-array-bad.exit b/src/tests/qapi-schema/args-member-array-bad.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-array-bad.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-member-array-bad.json b/src/tests/qapi-schema/args-member-array-bad.json
new file mode 100644
index 0000000..b2ff144
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-array-bad.json
@@ -0,0 +1,2 @@
+# we reject data if it does not contain a valid array type
+{ 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } }
diff --git a/src/tests/qapi-schema/args-member-array-bad.out b/src/tests/qapi-schema/args-member-array-bad.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-array-bad.out
diff --git a/src/tests/qapi-schema/args-member-unknown.err b/src/tests/qapi-schema/args-member-unknown.err
new file mode 100644
index 0000000..f6f8282
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/src/tests/qapi-schema/args-member-unknown.exit b/src/tests/qapi-schema/args-member-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-member-unknown.json b/src/tests/qapi-schema/args-member-unknown.json
new file mode 100644
index 0000000..342a41e
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-unknown.json
@@ -0,0 +1,2 @@
+# we reject data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'member': 'NoSuchType' } }
diff --git a/src/tests/qapi-schema/args-member-unknown.out b/src/tests/qapi-schema/args-member-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-member-unknown.out
diff --git a/src/tests/qapi-schema/args-name-clash.err b/src/tests/qapi-schema/args-name-clash.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-name-clash.err
diff --git a/src/tests/qapi-schema/args-name-clash.exit b/src/tests/qapi-schema/args-name-clash.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/args-name-clash.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/args-name-clash.json b/src/tests/qapi-schema/args-name-clash.json
new file mode 100644
index 0000000..9e8f889
--- /dev/null
+++ b/src/tests/qapi-schema/args-name-clash.json
@@ -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/src/tests/qapi-schema/args-name-clash.out b/src/tests/qapi-schema/args-name-clash.out
new file mode 100644
index 0000000..9b2f6e4
--- /dev/null
+++ b/src/tests/qapi-schema/args-name-clash.out
@@ -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
diff --git a/src/tests/qapi-schema/args-union.err b/src/tests/qapi-schema/args-union.err
new file mode 100644
index 0000000..1d693d7
--- /dev/null
+++ b/src/tests/qapi-schema/args-union.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-union.json:4: 'data' for command 'oops' cannot use union type 'Uni'
diff --git a/src/tests/qapi-schema/args-union.exit b/src/tests/qapi-schema/args-union.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-union.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-union.json b/src/tests/qapi-schema/args-union.json
new file mode 100644
index 0000000..7bdcbb7
--- /dev/null
+++ b/src/tests/qapi-schema/args-union.json
@@ -0,0 +1,4 @@
+# we do not allow union arguments
+# TODO should we support this?
+{ 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
+{ 'command': 'oops', 'data': 'Uni' }
diff --git a/src/tests/qapi-schema/args-union.out b/src/tests/qapi-schema/args-union.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-union.out
diff --git a/src/tests/qapi-schema/args-unknown.err b/src/tests/qapi-schema/args-unknown.err
new file mode 100644
index 0000000..4d91ec8
--- /dev/null
+++ b/src/tests/qapi-schema/args-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/src/tests/qapi-schema/args-unknown.exit b/src/tests/qapi-schema/args-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/args-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/args-unknown.json b/src/tests/qapi-schema/args-unknown.json
new file mode 100644
index 0000000..32aba43
--- /dev/null
+++ b/src/tests/qapi-schema/args-unknown.json
@@ -0,0 +1,2 @@
+# we reject data if it does not contain a known type
+{ 'command': 'oops', 'data': 'NoSuchType' }
diff --git a/src/tests/qapi-schema/args-unknown.out b/src/tests/qapi-schema/args-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/args-unknown.out
diff --git a/src/tests/qapi-schema/bad-base.err b/src/tests/qapi-schema/bad-base.err
new file mode 100644
index 0000000..154274b
--- /dev/null
+++ b/src/tests/qapi-schema/bad-base.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union'
diff --git a/src/tests/qapi-schema/bad-base.exit b/src/tests/qapi-schema/bad-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-base.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-base.json b/src/tests/qapi-schema/bad-base.json
new file mode 100644
index 0000000..a634331
--- /dev/null
+++ b/src/tests/qapi-schema/bad-base.json
@@ -0,0 +1,3 @@
+# we reject a base that is not a struct
+{ 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } }
+{ 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } }
diff --git a/src/tests/qapi-schema/bad-base.out b/src/tests/qapi-schema/bad-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-base.out
diff --git a/src/tests/qapi-schema/bad-data.err b/src/tests/qapi-schema/bad-data.err
new file mode 100644
index 0000000..8523ac4
--- /dev/null
+++ b/src/tests/qapi-schema/bad-data.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array
diff --git a/src/tests/qapi-schema/bad-data.exit b/src/tests/qapi-schema/bad-data.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-data.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-data.json b/src/tests/qapi-schema/bad-data.json
new file mode 100644
index 0000000..832eeb7
--- /dev/null
+++ b/src/tests/qapi-schema/bad-data.json
@@ -0,0 +1,2 @@
+# we ensure 'data' is a dictionary for all but enums
+{ 'command': 'oops', 'data': [ ] }
diff --git a/src/tests/qapi-schema/bad-data.out b/src/tests/qapi-schema/bad-data.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-data.out
diff --git a/src/tests/qapi-schema/bad-ident.err b/src/tests/qapi-schema/bad-ident.err
new file mode 100644
index 0000000..c419060
--- /dev/null
+++ b/src/tests/qapi-schema/bad-ident.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops'
diff --git a/src/tests/qapi-schema/bad-ident.exit b/src/tests/qapi-schema/bad-ident.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-ident.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-ident.json b/src/tests/qapi-schema/bad-ident.json
new file mode 100644
index 0000000..763627a
--- /dev/null
+++ b/src/tests/qapi-schema/bad-ident.json
@@ -0,0 +1,2 @@
+# we reject creating a type name with bad name
+{ 'struct': '*oops', 'data': { 'i': 'int' } }
diff --git a/src/tests/qapi-schema/bad-ident.out b/src/tests/qapi-schema/bad-ident.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-ident.out
diff --git a/src/tests/qapi-schema/bad-type-bool.err b/src/tests/qapi-schema/bad-type-bool.err
new file mode 100644
index 0000000..62fd70b
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-bool.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value
diff --git a/src/tests/qapi-schema/bad-type-bool.exit b/src/tests/qapi-schema/bad-type-bool.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-bool.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-type-bool.json b/src/tests/qapi-schema/bad-type-bool.json
new file mode 100644
index 0000000..bde17b5
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-bool.json
@@ -0,0 +1,2 @@
+# we reject an expression with a metatype that is not a string
+{ 'struct': true, 'data': { } }
diff --git a/src/tests/qapi-schema/bad-type-bool.out b/src/tests/qapi-schema/bad-type-bool.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-bool.out
diff --git a/src/tests/qapi-schema/bad-type-dict.err b/src/tests/qapi-schema/bad-type-dict.err
new file mode 100644
index 0000000..0b2a2ae
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value
diff --git a/src/tests/qapi-schema/bad-type-dict.exit b/src/tests/qapi-schema/bad-type-dict.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-type-dict.json b/src/tests/qapi-schema/bad-type-dict.json
new file mode 100644
index 0000000..2a91b24
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-dict.json
@@ -0,0 +1,2 @@
+# we reject an expression with a metatype that is not a string
+{ 'command': { } }
diff --git a/src/tests/qapi-schema/bad-type-dict.out b/src/tests/qapi-schema/bad-type-dict.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-dict.out
diff --git a/src/tests/qapi-schema/bad-type-int.err b/src/tests/qapi-schema/bad-type-int.err
new file mode 100644
index 0000000..da89895
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-int.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-type-int.json:3:13: Stray "1"
diff --git a/src/tests/qapi-schema/bad-type-int.exit b/src/tests/qapi-schema/bad-type-int.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-int.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/bad-type-int.json b/src/tests/qapi-schema/bad-type-int.json
new file mode 100644
index 0000000..56fc6f8
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-int.json
@@ -0,0 +1,3 @@
+# we reject an expression with a metatype that is not a string
+# FIXME: once the parser understands integer inputs, improve the error message
+{ 'struct': 1, 'data': { } }
diff --git a/src/tests/qapi-schema/bad-type-int.out b/src/tests/qapi-schema/bad-type-int.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/bad-type-int.out
diff --git a/src/tests/qapi-schema/command-int.err b/src/tests/qapi-schema/command-int.err
new file mode 100644
index 0000000..0f93006
--- /dev/null
+++ b/src/tests/qapi-schema/command-int.err
@@ -0,0 +1 @@
+tests/qapi-schema/command-int.json:2: built-in 'int' is already defined
diff --git a/src/tests/qapi-schema/command-int.exit b/src/tests/qapi-schema/command-int.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/command-int.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/command-int.json b/src/tests/qapi-schema/command-int.json
new file mode 100644
index 0000000..9a62554
--- /dev/null
+++ b/src/tests/qapi-schema/command-int.json
@@ -0,0 +1,2 @@
+# we reject collisions between commands and types
+{ 'command': 'int', 'data': { 'character': 'str' } }
diff --git a/src/tests/qapi-schema/command-int.out b/src/tests/qapi-schema/command-int.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/command-int.out
diff --git a/src/tests/qapi-schema/comments.err b/src/tests/qapi-schema/comments.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/comments.err
diff --git a/src/tests/qapi-schema/comments.exit b/src/tests/qapi-schema/comments.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/comments.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/comments.json b/src/tests/qapi-schema/comments.json
new file mode 100644
index 0000000..e643f3a
--- /dev/null
+++ b/src/tests/qapi-schema/comments.json
@@ -0,0 +1,4 @@
+# Unindented comment
+{ 'enum': 'Status', # Comment to the right of code
+ # Indented comment
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/comments.out b/src/tests/qapi-schema/comments.out
new file mode 100644
index 0000000..9e2c656
--- /dev/null
+++ b/src/tests/qapi-schema/comments.out
@@ -0,0 +1,2 @@
+object :empty
+enum Status ['good', 'bad', 'ugly']
diff --git a/src/tests/qapi-schema/double-data.err b/src/tests/qapi-schema/double-data.err
new file mode 100644
index 0000000..cc765c4
--- /dev/null
+++ b/src/tests/qapi-schema/double-data.err
@@ -0,0 +1 @@
+tests/qapi-schema/double-data.json:2:41: Duplicate key "data"
diff --git a/src/tests/qapi-schema/double-data.exit b/src/tests/qapi-schema/double-data.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/double-data.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/double-data.json b/src/tests/qapi-schema/double-data.json
new file mode 100644
index 0000000..e76b519
--- /dev/null
+++ b/src/tests/qapi-schema/double-data.json
@@ -0,0 +1,2 @@
+# we reject an expression with duplicate top-level keys
+{ 'struct': 'bar', 'data': { }, 'data': { 'string': 'str'} }
diff --git a/src/tests/qapi-schema/double-data.out b/src/tests/qapi-schema/double-data.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/double-data.out
diff --git a/src/tests/qapi-schema/double-type.err b/src/tests/qapi-schema/double-type.err
new file mode 100644
index 0000000..f9613c6
--- /dev/null
+++ b/src/tests/qapi-schema/double-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar'
diff --git a/src/tests/qapi-schema/double-type.exit b/src/tests/qapi-schema/double-type.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/double-type.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/double-type.json b/src/tests/qapi-schema/double-type.json
new file mode 100644
index 0000000..911fa7a
--- /dev/null
+++ b/src/tests/qapi-schema/double-type.json
@@ -0,0 +1,2 @@
+# we reject an expression with ambiguous metatype
+{ 'command': 'foo', 'struct': 'bar', 'data': { } }
diff --git a/src/tests/qapi-schema/double-type.out b/src/tests/qapi-schema/double-type.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/double-type.out
diff --git a/src/tests/qapi-schema/duplicate-key.err b/src/tests/qapi-schema/duplicate-key.err
new file mode 100644
index 0000000..6d02f83
--- /dev/null
+++ b/src/tests/qapi-schema/duplicate-key.err
@@ -0,0 +1 @@
+tests/qapi-schema/duplicate-key.json:3:10: Duplicate key "key"
diff --git a/src/tests/qapi-schema/duplicate-key.exit b/src/tests/qapi-schema/duplicate-key.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/duplicate-key.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/duplicate-key.json b/src/tests/qapi-schema/duplicate-key.json
new file mode 100644
index 0000000..14ac0e8
--- /dev/null
+++ b/src/tests/qapi-schema/duplicate-key.json
@@ -0,0 +1,3 @@
+# QAPI cannot include the same key more than once in any {}
+{ 'key': 'value',
+ 'key': 'value' }
diff --git a/src/tests/qapi-schema/duplicate-key.out b/src/tests/qapi-schema/duplicate-key.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/duplicate-key.out
diff --git a/src/tests/qapi-schema/empty.err b/src/tests/qapi-schema/empty.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/empty.err
diff --git a/src/tests/qapi-schema/empty.exit b/src/tests/qapi-schema/empty.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/empty.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/empty.json b/src/tests/qapi-schema/empty.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/empty.json
diff --git a/src/tests/qapi-schema/empty.out b/src/tests/qapi-schema/empty.out
new file mode 100644
index 0000000..272b161
--- /dev/null
+++ b/src/tests/qapi-schema/empty.out
@@ -0,0 +1 @@
+object :empty
diff --git a/src/tests/qapi-schema/enum-bad-name.err b/src/tests/qapi-schema/enum-bad-name.err
new file mode 100644
index 0000000..9c3c100
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-name.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses invalid name 'not^possible'
diff --git a/src/tests/qapi-schema/enum-bad-name.exit b/src/tests/qapi-schema/enum-bad-name.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-name.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-bad-name.json b/src/tests/qapi-schema/enum-bad-name.json
new file mode 100644
index 0000000..8506562
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-name.json
@@ -0,0 +1,2 @@
+# we ensure all enum names can map to C
+{ 'enum': 'MyEnum', 'data': [ 'not^possible' ] }
diff --git a/src/tests/qapi-schema/enum-bad-name.out b/src/tests/qapi-schema/enum-bad-name.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-name.out
diff --git a/src/tests/qapi-schema/enum-bad-prefix.err b/src/tests/qapi-schema/enum-bad-prefix.err
new file mode 100644
index 0000000..399f5f7
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-prefix.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix'
diff --git a/src/tests/qapi-schema/enum-bad-prefix.exit b/src/tests/qapi-schema/enum-bad-prefix.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-prefix.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-bad-prefix.json b/src/tests/qapi-schema/enum-bad-prefix.json
new file mode 100644
index 0000000..996f628
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-prefix.json
@@ -0,0 +1,2 @@
+# The prefix must be a string type
+{ 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] }
diff --git a/src/tests/qapi-schema/enum-bad-prefix.out b/src/tests/qapi-schema/enum-bad-prefix.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-bad-prefix.out
diff --git a/src/tests/qapi-schema/enum-clash-member.err b/src/tests/qapi-schema/enum-clash-member.err
new file mode 100644
index 0000000..48bd136
--- /dev/null
+++ b/src/tests/qapi-schema/enum-clash-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-clash-member.json:2: Enum 'MyEnum' member 'ONE' clashes with 'one'
diff --git a/src/tests/qapi-schema/enum-clash-member.exit b/src/tests/qapi-schema/enum-clash-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-clash-member.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-clash-member.json b/src/tests/qapi-schema/enum-clash-member.json
new file mode 100644
index 0000000..b7dc02a
--- /dev/null
+++ b/src/tests/qapi-schema/enum-clash-member.json
@@ -0,0 +1,2 @@
+# we reject enums where members will clash when mapped to C enum
+{ 'enum': 'MyEnum', 'data': [ 'one', 'ONE' ] }
diff --git a/src/tests/qapi-schema/enum-clash-member.out b/src/tests/qapi-schema/enum-clash-member.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-clash-member.out
diff --git a/src/tests/qapi-schema/enum-dict-member.err b/src/tests/qapi-schema/enum-dict-member.err
new file mode 100644
index 0000000..8ca146e
--- /dev/null
+++ b/src/tests/qapi-schema/enum-dict-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
diff --git a/src/tests/qapi-schema/enum-dict-member.exit b/src/tests/qapi-schema/enum-dict-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-dict-member.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-dict-member.json b/src/tests/qapi-schema/enum-dict-member.json
new file mode 100644
index 0000000..79672e0
--- /dev/null
+++ b/src/tests/qapi-schema/enum-dict-member.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string
+{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/src/tests/qapi-schema/enum-dict-member.out b/src/tests/qapi-schema/enum-dict-member.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-dict-member.out
diff --git a/src/tests/qapi-schema/enum-int-member.err b/src/tests/qapi-schema/enum-int-member.err
new file mode 100644
index 0000000..071c521
--- /dev/null
+++ b/src/tests/qapi-schema/enum-int-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-int-member.json:3:31: Stray "1"
diff --git a/src/tests/qapi-schema/enum-int-member.exit b/src/tests/qapi-schema/enum-int-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-int-member.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-int-member.json b/src/tests/qapi-schema/enum-int-member.json
new file mode 100644
index 0000000..6c9c32e
--- /dev/null
+++ b/src/tests/qapi-schema/enum-int-member.json
@@ -0,0 +1,3 @@
+# we reject any enum member that is not a string
+# FIXME: once the parser understands integer inputs, improve the error message
+{ 'enum': 'MyEnum', 'data': [ 1 ] }
diff --git a/src/tests/qapi-schema/enum-int-member.out b/src/tests/qapi-schema/enum-int-member.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-int-member.out
diff --git a/src/tests/qapi-schema/enum-max-member.err b/src/tests/qapi-schema/enum-max-member.err
new file mode 100644
index 0000000..f77837f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-max-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-max-member.json:3: Enum 'MyEnum' member 'max' clashes with '(automatic)'
diff --git a/src/tests/qapi-schema/enum-max-member.exit b/src/tests/qapi-schema/enum-max-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-max-member.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-max-member.json b/src/tests/qapi-schema/enum-max-member.json
new file mode 100644
index 0000000..4bcda0b
--- /dev/null
+++ b/src/tests/qapi-schema/enum-max-member.json
@@ -0,0 +1,3 @@
+# we reject user-supplied 'max' for clashing with implicit enum end
+# TODO: should we instead munge the implicit value to avoid the clash?
+{ 'enum': 'MyEnum', 'data': [ 'max' ] }
diff --git a/src/tests/qapi-schema/enum-max-member.out b/src/tests/qapi-schema/enum-max-member.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-max-member.out
diff --git a/src/tests/qapi-schema/enum-missing-data.err b/src/tests/qapi-schema/enum-missing-data.err
new file mode 100644
index 0000000..ba4873a
--- /dev/null
+++ b/src/tests/qapi-schema/enum-missing-data.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum'
diff --git a/src/tests/qapi-schema/enum-missing-data.exit b/src/tests/qapi-schema/enum-missing-data.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-missing-data.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-missing-data.json b/src/tests/qapi-schema/enum-missing-data.json
new file mode 100644
index 0000000..558fd35
--- /dev/null
+++ b/src/tests/qapi-schema/enum-missing-data.json
@@ -0,0 +1,2 @@
+# we require that all QAPI enums have a data array
+{ 'enum': 'MyEnum' }
diff --git a/src/tests/qapi-schema/enum-missing-data.out b/src/tests/qapi-schema/enum-missing-data.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-missing-data.out
diff --git a/src/tests/qapi-schema/enum-wrong-data.err b/src/tests/qapi-schema/enum-wrong-data.err
new file mode 100644
index 0000000..11b4347
--- /dev/null
+++ b/src/tests/qapi-schema/enum-wrong-data.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array for 'data'
diff --git a/src/tests/qapi-schema/enum-wrong-data.exit b/src/tests/qapi-schema/enum-wrong-data.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/enum-wrong-data.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/enum-wrong-data.json b/src/tests/qapi-schema/enum-wrong-data.json
new file mode 100644
index 0000000..7b3e255
--- /dev/null
+++ b/src/tests/qapi-schema/enum-wrong-data.json
@@ -0,0 +1,2 @@
+# we require that all qapi enums have an array for data
+{ 'enum': 'MyEnum', 'data': { 'value': 'str' } }
diff --git a/src/tests/qapi-schema/enum-wrong-data.out b/src/tests/qapi-schema/enum-wrong-data.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/enum-wrong-data.out
diff --git a/src/tests/qapi-schema/escape-outside-string.err b/src/tests/qapi-schema/escape-outside-string.err
new file mode 100644
index 0000000..b9b8837
--- /dev/null
+++ b/src/tests/qapi-schema/escape-outside-string.err
@@ -0,0 +1 @@
+tests/qapi-schema/escape-outside-string.json:3:27: Stray "\"
diff --git a/src/tests/qapi-schema/escape-outside-string.exit b/src/tests/qapi-schema/escape-outside-string.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/escape-outside-string.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/escape-outside-string.json b/src/tests/qapi-schema/escape-outside-string.json
new file mode 100644
index 0000000..482f795
--- /dev/null
+++ b/src/tests/qapi-schema/escape-outside-string.json
@@ -0,0 +1,3 @@
+# escape sequences are permitted only inside strings
+# { 'command': 'foo', 'data': {} }
+{ 'command': 'foo', 'data'\u003a{} }
diff --git a/src/tests/qapi-schema/escape-outside-string.out b/src/tests/qapi-schema/escape-outside-string.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/escape-outside-string.out
diff --git a/src/tests/qapi-schema/escape-too-big.err b/src/tests/qapi-schema/escape-too-big.err
new file mode 100644
index 0000000..d9aeb5d
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-big.err
@@ -0,0 +1 @@
+tests/qapi-schema/escape-too-big.json:3:14: For now, \u escape only supports non-zero values up to \u007f
diff --git a/src/tests/qapi-schema/escape-too-big.exit b/src/tests/qapi-schema/escape-too-big.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-big.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/escape-too-big.json b/src/tests/qapi-schema/escape-too-big.json
new file mode 100644
index 0000000..62bcecd
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-big.json
@@ -0,0 +1,3 @@
+# we don't support full Unicode strings, yet
+# { 'command': 'é' }
+{ 'command': '\u00e9' }
diff --git a/src/tests/qapi-schema/escape-too-big.out b/src/tests/qapi-schema/escape-too-big.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-big.out
diff --git a/src/tests/qapi-schema/escape-too-short.err b/src/tests/qapi-schema/escape-too-short.err
new file mode 100644
index 0000000..934de59
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-short.err
@@ -0,0 +1 @@
+tests/qapi-schema/escape-too-short.json:3:14: \u escape needs 4 hex digits
diff --git a/src/tests/qapi-schema/escape-too-short.exit b/src/tests/qapi-schema/escape-too-short.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-short.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/escape-too-short.json b/src/tests/qapi-schema/escape-too-short.json
new file mode 100644
index 0000000..6cb1dec
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-short.json
@@ -0,0 +1,3 @@
+# the \u escape requires 4 hex digits
+# { 'command': 'a' }
+{ 'command': '\u61' }
diff --git a/src/tests/qapi-schema/escape-too-short.out b/src/tests/qapi-schema/escape-too-short.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/escape-too-short.out
diff --git a/src/tests/qapi-schema/event-case.err b/src/tests/qapi-schema/event-case.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/event-case.err
diff --git a/src/tests/qapi-schema/event-case.exit b/src/tests/qapi-schema/event-case.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/event-case.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/event-case.json b/src/tests/qapi-schema/event-case.json
new file mode 100644
index 0000000..3a92d8b
--- /dev/null
+++ b/src/tests/qapi-schema/event-case.json
@@ -0,0 +1,3 @@
+# TODO: might be nice to enforce naming conventions; but until then this works
+# even though events should usually be ALL_CAPS
+{ 'event': 'oops' }
diff --git a/src/tests/qapi-schema/event-case.out b/src/tests/qapi-schema/event-case.out
new file mode 100644
index 0000000..cdfd264
--- /dev/null
+++ b/src/tests/qapi-schema/event-case.out
@@ -0,0 +1,2 @@
+object :empty
+event oops None
diff --git a/src/tests/qapi-schema/event-max.err b/src/tests/qapi-schema/event-max.err
new file mode 100644
index 0000000..c856534
--- /dev/null
+++ b/src/tests/qapi-schema/event-max.err
@@ -0,0 +1 @@
+tests/qapi-schema/event-max.json:2: Event name 'MAX' cannot be created
diff --git a/src/tests/qapi-schema/event-max.exit b/src/tests/qapi-schema/event-max.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/event-max.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/event-max.json b/src/tests/qapi-schema/event-max.json
new file mode 100644
index 0000000..f3d7de2
--- /dev/null
+++ b/src/tests/qapi-schema/event-max.json
@@ -0,0 +1,2 @@
+# an event named 'MAX' would conflict with implicit C enum
+{ 'event': 'MAX' }
diff --git a/src/tests/qapi-schema/event-max.out b/src/tests/qapi-schema/event-max.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/event-max.out
diff --git a/src/tests/qapi-schema/event-nest-struct.err b/src/tests/qapi-schema/event-nest-struct.err
new file mode 100644
index 0000000..5a42701
--- /dev/null
+++ b/src/tests/qapi-schema/event-nest-struct.err
@@ -0,0 +1 @@
+tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name
diff --git a/src/tests/qapi-schema/event-nest-struct.exit b/src/tests/qapi-schema/event-nest-struct.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/event-nest-struct.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/event-nest-struct.json b/src/tests/qapi-schema/event-nest-struct.json
new file mode 100644
index 0000000..ee6f3ec
--- /dev/null
+++ b/src/tests/qapi-schema/event-nest-struct.json
@@ -0,0 +1,2 @@
+{ 'event': 'EVENT_A',
+ 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/src/tests/qapi-schema/event-nest-struct.out b/src/tests/qapi-schema/event-nest-struct.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/event-nest-struct.out
diff --git a/src/tests/qapi-schema/flat-union-array-branch.err b/src/tests/qapi-schema/flat-union-array-branch.err
new file mode 100644
index 0000000..8ea91ea
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-array-branch.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of union 'TestUnion' cannot be an array
diff --git a/src/tests/qapi-schema/flat-union-array-branch.exit b/src/tests/qapi-schema/flat-union-array-branch.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-array-branch.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-array-branch.json b/src/tests/qapi-schema/flat-union-array-branch.json
new file mode 100644
index 0000000..0b98820
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-array-branch.json
@@ -0,0 +1,12 @@
+# we require flat union branches to be a struct
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'Base',
+ 'data': { 'enum1': 'TestEnum' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'TestUnion',
+ 'base': 'Base',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': ['TestTypeB'],
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-array-branch.out b/src/tests/qapi-schema/flat-union-array-branch.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-array-branch.out
diff --git a/src/tests/qapi-schema/flat-union-bad-base.err b/src/tests/qapi-schema/flat-union-bad-base.err
new file mode 100644
index 0000000..79b8a71
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-base.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-bad-base.json:9: 'base' for union 'TestUnion' should be a type name
diff --git a/src/tests/qapi-schema/flat-union-bad-base.exit b/src/tests/qapi-schema/flat-union-bad-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-base.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-bad-base.json b/src/tests/qapi-schema/flat-union-bad-base.json
new file mode 100644
index 0000000..e2e622b
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-base.json
@@ -0,0 +1,13 @@
+# we require the base to be an existing struct
+# TODO: should we allow an anonymous inline base type?
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'TestUnion',
+ 'base': { 'enum1': 'TestEnum', 'kind': 'str' },
+ 'discriminator': 'enum1',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-bad-base.out b/src/tests/qapi-schema/flat-union-bad-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-base.out
diff --git a/src/tests/qapi-schema/flat-union-bad-discriminator.err b/src/tests/qapi-schema/flat-union-bad-discriminator.err
new file mode 100644
index 0000000..c38cc8e
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of flat union 'TestUnion' requires a string name
diff --git a/src/tests/qapi-schema/flat-union-bad-discriminator.exit b/src/tests/qapi-schema/flat-union-bad-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-bad-discriminator.json b/src/tests/qapi-schema/flat-union-bad-discriminator.json
new file mode 100644
index 0000000..cd10b9d
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-discriminator.json
@@ -0,0 +1,15 @@
+# we require the discriminator to be a string naming a base-type member
+# this tests the old syntax for anonymous unions before we added alternates
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'TestBase',
+ 'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'TestUnion',
+ 'base': 'TestBase',
+ 'discriminator': {},
+ 'data': { 'kind1': 'TestTypeA',
+ 'kind2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-bad-discriminator.out b/src/tests/qapi-schema/flat-union-bad-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-bad-discriminator.out
diff --git a/src/tests/qapi-schema/flat-union-base-any.err b/src/tests/qapi-schema/flat-union-base-any.err
new file mode 100644
index 0000000..646f1c9
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-any.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any'
diff --git a/src/tests/qapi-schema/flat-union-base-any.exit b/src/tests/qapi-schema/flat-union-base-any.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-any.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-base-any.json b/src/tests/qapi-schema/flat-union-base-any.json
new file mode 100644
index 0000000..fe66b71
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-any.json
@@ -0,0 +1,12 @@
+# we require the base to be an existing struct
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'TestUnion',
+ 'base': 'any',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-base-any.out b/src/tests/qapi-schema/flat-union-base-any.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-any.out
diff --git a/src/tests/qapi-schema/flat-union-base-union.err b/src/tests/qapi-schema/flat-union-base-union.err
new file mode 100644
index 0000000..f138395
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-union.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase'
diff --git a/src/tests/qapi-schema/flat-union-base-union.exit b/src/tests/qapi-schema/flat-union-base-union.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-union.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-base-union.json b/src/tests/qapi-schema/flat-union-base-union.json
new file mode 100644
index 0000000..98b4eba
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-union.json
@@ -0,0 +1,18 @@
+# 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',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'UnionBase',
+ 'data': { 'kind1': 'TestTypeA',
+ 'kind2': 'TestTypeB' } }
+{ 'union': 'TestUnion',
+ 'base': 'UnionBase',
+ 'discriminator': 'type',
+ 'data': { 'kind1': 'TestTypeA',
+ 'kind2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-base-union.out b/src/tests/qapi-schema/flat-union-base-union.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-base-union.out
diff --git a/src/tests/qapi-schema/flat-union-clash-branch.err b/src/tests/qapi-schema/flat-union-clash-branch.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-branch.err
diff --git a/src/tests/qapi-schema/flat-union-clash-branch.exit b/src/tests/qapi-schema/flat-union-clash-branch.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-branch.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/flat-union-clash-branch.json b/src/tests/qapi-schema/flat-union-clash-branch.json
new file mode 100644
index 0000000..e593336
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-branch.json
@@ -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/src/tests/qapi-schema/flat-union-clash-branch.out b/src/tests/qapi-schema/flat-union-clash-branch.out
new file mode 100644
index 0000000..8e0da73
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-branch.out
@@ -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/src/tests/qapi-schema/flat-union-clash-member.err b/src/tests/qapi-schema/flat-union-clash-member.err
new file mode 100644
index 0000000..2f0397a
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-member.err
@@ -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/src/tests/qapi-schema/flat-union-clash-member.exit b/src/tests/qapi-schema/flat-union-clash-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-member.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-clash-member.json b/src/tests/qapi-schema/flat-union-clash-member.json
new file mode 100644
index 0000000..9efc771
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-member.json
@@ -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/src/tests/qapi-schema/flat-union-clash-member.out b/src/tests/qapi-schema/flat-union-clash-member.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-member.out
diff --git a/src/tests/qapi-schema/flat-union-clash-type.err b/src/tests/qapi-schema/flat-union-clash-type.err
new file mode 100644
index 0000000..b44dd40
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-clash-type.json:11: Discriminator name 'type' collides with enum value in 'TestEnum'
diff --git a/src/tests/qapi-schema/flat-union-clash-type.exit b/src/tests/qapi-schema/flat-union-clash-type.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-type.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-clash-type.json b/src/tests/qapi-schema/flat-union-clash-type.json
new file mode 100644
index 0000000..8f710f0
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-type.json
@@ -0,0 +1,14 @@
+# Flat union branch 'type'
+# Reject this, because we would have a clash in generated C, between the
+# outer tag 'type' and the branch name 'type' within the union.
+# TODO: We could munge the generated C branch name 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/src/tests/qapi-schema/flat-union-clash-type.out b/src/tests/qapi-schema/flat-union-clash-type.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-clash-type.out
diff --git a/src/tests/qapi-schema/flat-union-empty.err b/src/tests/qapi-schema/flat-union-empty.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-empty.err
diff --git a/src/tests/qapi-schema/flat-union-empty.exit b/src/tests/qapi-schema/flat-union-empty.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-empty.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/flat-union-empty.json b/src/tests/qapi-schema/flat-union-empty.json
new file mode 100644
index 0000000..67dd297
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-empty.json
@@ -0,0 +1,4 @@
+# FIXME - flat unions should not be empty
+{ 'enum': 'Empty', 'data': [ ] }
+{ 'struct': 'Base', 'data': { 'type': 'Empty' } }
+{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
diff --git a/src/tests/qapi-schema/flat-union-empty.out b/src/tests/qapi-schema/flat-union-empty.out
new file mode 100644
index 0000000..0e0665a
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-empty.out
@@ -0,0 +1,7 @@
+object :empty
+object Base
+ member type: Empty optional=False
+enum Empty []
+object Union
+ base Base
+ tag type
diff --git a/src/tests/qapi-schema/flat-union-inline.err b/src/tests/qapi-schema/flat-union-inline.err
new file mode 100644
index 0000000..2333358
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-inline.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name
diff --git a/src/tests/qapi-schema/flat-union-inline.exit b/src/tests/qapi-schema/flat-union-inline.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-inline.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-inline.json b/src/tests/qapi-schema/flat-union-inline.json
new file mode 100644
index 0000000..62c7cda
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-inline.json
@@ -0,0 +1,11 @@
+# we require branches to be a struct name
+# TODO: should we allow anonymous inline branch types?
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'Base',
+ 'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
+{ 'union': 'TestUnion',
+ 'base': 'Base',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': { 'string': 'str' },
+ 'value2': { 'integer': 'int' } } }
diff --git a/src/tests/qapi-schema/flat-union-inline.out b/src/tests/qapi-schema/flat-union-inline.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-inline.out
diff --git a/src/tests/qapi-schema/flat-union-int-branch.err b/src/tests/qapi-schema/flat-union-int-branch.err
new file mode 100644
index 0000000..faf0157
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-int-branch.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union 'TestUnion' cannot use built-in type 'int'
diff --git a/src/tests/qapi-schema/flat-union-int-branch.exit b/src/tests/qapi-schema/flat-union-int-branch.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-int-branch.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-int-branch.json b/src/tests/qapi-schema/flat-union-int-branch.json
new file mode 100644
index 0000000..9370c34
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-int-branch.json
@@ -0,0 +1,12 @@
+# we require flat union branches to be a struct
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'Base',
+ 'data': { 'enum1': 'TestEnum' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'union': 'TestUnion',
+ 'base': 'Base',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': 'int',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-int-branch.out b/src/tests/qapi-schema/flat-union-int-branch.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-int-branch.out
diff --git a/src/tests/qapi-schema/flat-union-invalid-branch-key.err b/src/tests/qapi-schema/flat-union-invalid-branch-key.err
new file mode 100644
index 0000000..ccf72d2
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-branch-key.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
diff --git a/src/tests/qapi-schema/flat-union-invalid-branch-key.exit b/src/tests/qapi-schema/flat-union-invalid-branch-key.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-branch-key.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-invalid-branch-key.json b/src/tests/qapi-schema/flat-union-invalid-branch-key.json
new file mode 100644
index 0000000..95ff774
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-branch-key.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+
+{ 'struct': 'TestBase',
+ 'data': { 'enum1': 'TestEnum' } }
+
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'TestBase',
+ 'discriminator': 'enum1',
+ 'data': { 'value_wrong': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-invalid-branch-key.out b/src/tests/qapi-schema/flat-union-invalid-branch-key.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-branch-key.out
diff --git a/src/tests/qapi-schema/flat-union-invalid-discriminator.err b/src/tests/qapi-schema/flat-union-invalid-discriminator.err
new file mode 100644
index 0000000..5f40556
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base struct 'TestBase'
diff --git a/src/tests/qapi-schema/flat-union-invalid-discriminator.exit b/src/tests/qapi-schema/flat-union-invalid-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-invalid-discriminator.json b/src/tests/qapi-schema/flat-union-invalid-discriminator.json
new file mode 100644
index 0000000..48b94c3
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+
+{ 'struct': 'TestBase',
+ 'data': { 'enum1': 'TestEnum' } }
+
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'TestBase',
+ 'discriminator': 'enum_wrong',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-invalid-discriminator.out b/src/tests/qapi-schema/flat-union-invalid-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-invalid-discriminator.out
diff --git a/src/tests/qapi-schema/flat-union-no-base.err b/src/tests/qapi-schema/flat-union-no-base.err
new file mode 100644
index 0000000..841c93b
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-no-base.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base
diff --git a/src/tests/qapi-schema/flat-union-no-base.exit b/src/tests/qapi-schema/flat-union-no-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-no-base.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-no-base.json b/src/tests/qapi-schema/flat-union-no-base.json
new file mode 100644
index 0000000..ffc4c6f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-no-base.json
@@ -0,0 +1,12 @@
+# flat unions require a base
+# TODO: simple unions should be able to use an enum discriminator
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+{ 'enum': 'Enum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'union': 'TestUnion',
+ 'discriminator': 'Enum',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-no-base.out b/src/tests/qapi-schema/flat-union-no-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-no-base.out
diff --git a/src/tests/qapi-schema/flat-union-optional-discriminator.err b/src/tests/qapi-schema/flat-union-optional-discriminator.err
new file mode 100644
index 0000000..aaabedb
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-optional-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
diff --git a/src/tests/qapi-schema/flat-union-optional-discriminator.exit b/src/tests/qapi-schema/flat-union-optional-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-optional-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-optional-discriminator.json b/src/tests/qapi-schema/flat-union-optional-discriminator.json
new file mode 100644
index 0000000..08a8f7e
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-optional-discriminator.json
@@ -0,0 +1,10 @@
+# we require the discriminator to be non-optional
+{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
+{ 'struct': 'Base',
+ 'data': { '*switch': 'Enum' } }
+{ 'struct': 'Branch', 'data': { 'name': 'str' } }
+{ 'union': 'MyUnion',
+ 'base': 'Base',
+ 'discriminator': '*switch',
+ 'data': { 'one': 'Branch',
+ 'two': 'Branch' } }
diff --git a/src/tests/qapi-schema/flat-union-optional-discriminator.out b/src/tests/qapi-schema/flat-union-optional-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-optional-discriminator.out
diff --git a/src/tests/qapi-schema/flat-union-string-discriminator.err b/src/tests/qapi-schema/flat-union-string-discriminator.err
new file mode 100644
index 0000000..200016b
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-string-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type
diff --git a/src/tests/qapi-schema/flat-union-string-discriminator.exit b/src/tests/qapi-schema/flat-union-string-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-string-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/flat-union-string-discriminator.json b/src/tests/qapi-schema/flat-union-string-discriminator.json
new file mode 100644
index 0000000..8af6033
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-string-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+
+{ 'struct': 'TestBase',
+ 'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
+
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'TestBase',
+ 'discriminator': 'kind',
+ 'data': { 'kind1': 'TestTypeA',
+ 'kind2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/flat-union-string-discriminator.out b/src/tests/qapi-schema/flat-union-string-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/flat-union-string-discriminator.out
diff --git a/src/tests/qapi-schema/funny-char.err b/src/tests/qapi-schema/funny-char.err
new file mode 100644
index 0000000..bfc890c
--- /dev/null
+++ b/src/tests/qapi-schema/funny-char.err
@@ -0,0 +1 @@
+tests/qapi-schema/funny-char.json:2:36: Stray ";"
diff --git a/src/tests/qapi-schema/funny-char.exit b/src/tests/qapi-schema/funny-char.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/funny-char.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/funny-char.json b/src/tests/qapi-schema/funny-char.json
new file mode 100644
index 0000000..d4973a2
--- /dev/null
+++ b/src/tests/qapi-schema/funny-char.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ]; }
diff --git a/src/tests/qapi-schema/funny-char.out b/src/tests/qapi-schema/funny-char.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/funny-char.out
diff --git a/src/tests/qapi-schema/ident-with-escape.err b/src/tests/qapi-schema/ident-with-escape.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/ident-with-escape.err
diff --git a/src/tests/qapi-schema/ident-with-escape.exit b/src/tests/qapi-schema/ident-with-escape.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/ident-with-escape.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/ident-with-escape.json b/src/tests/qapi-schema/ident-with-escape.json
new file mode 100644
index 0000000..5661750
--- /dev/null
+++ b/src/tests/qapi-schema/ident-with-escape.json
@@ -0,0 +1,4 @@
+# we allow escape sequences in strings, if they map back to ASCII
+# { 'command': 'fooA', 'data': { 'bar1': 'str' } }
+{ 'c\u006fmmand': '\u0066\u006f\u006FA',
+ 'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } }
diff --git a/src/tests/qapi-schema/ident-with-escape.out b/src/tests/qapi-schema/ident-with-escape.out
new file mode 100644
index 0000000..f4542b1
--- /dev/null
+++ b/src/tests/qapi-schema/ident-with-escape.out
@@ -0,0 +1,5 @@
+object :empty
+object :obj-fooA-arg
+ member bar1: str optional=False
+command fooA :obj-fooA-arg -> None
+ gen=True success_response=True
diff --git a/src/tests/qapi-schema/include-before-err.err b/src/tests/qapi-schema/include-before-err.err
new file mode 100644
index 0000000..5565275
--- /dev/null
+++ b/src/tests/qapi-schema/include-before-err.err
@@ -0,0 +1 @@
+tests/qapi-schema/include-before-err.json:2:13: Expected ":"
diff --git a/src/tests/qapi-schema/include-before-err.exit b/src/tests/qapi-schema/include-before-err.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-before-err.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-before-err.json b/src/tests/qapi-schema/include-before-err.json
new file mode 100644
index 0000000..afb6cb6
--- /dev/null
+++ b/src/tests/qapi-schema/include-before-err.json
@@ -0,0 +1,2 @@
+{ 'include': 'include-simple-sub.json' }
+{ 'command' 'missing-colon' }
diff --git a/src/tests/qapi-schema/include-before-err.out b/src/tests/qapi-schema/include-before-err.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-before-err.out
diff --git a/src/tests/qapi-schema/include-cycle-b.json b/src/tests/qapi-schema/include-cycle-b.json
new file mode 100644
index 0000000..4fa985d
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle-b.json
@@ -0,0 +1 @@
+{ 'include': 'include-cycle-c.json' }
diff --git a/src/tests/qapi-schema/include-cycle-c.json b/src/tests/qapi-schema/include-cycle-c.json
new file mode 100644
index 0000000..d12b592
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle-c.json
@@ -0,0 +1 @@
+{ 'include': 'include-cycle.json' }
diff --git a/src/tests/qapi-schema/include-cycle.err b/src/tests/qapi-schema/include-cycle.err
new file mode 100644
index 0000000..bdcd07d
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle.err
@@ -0,0 +1,3 @@
+In file included from tests/qapi-schema/include-cycle.json:1:
+In file included from tests/qapi-schema/include-cycle-b.json:1:
+tests/qapi-schema/include-cycle-c.json:1: Inclusion loop for include-cycle.json
diff --git a/src/tests/qapi-schema/include-cycle.exit b/src/tests/qapi-schema/include-cycle.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-cycle.json b/src/tests/qapi-schema/include-cycle.json
new file mode 100644
index 0000000..6fcf1eb
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle.json
@@ -0,0 +1 @@
+{ 'include': 'include-cycle-b.json' }
diff --git a/src/tests/qapi-schema/include-cycle.out b/src/tests/qapi-schema/include-cycle.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-cycle.out
diff --git a/src/tests/qapi-schema/include-format-err.err b/src/tests/qapi-schema/include-format-err.err
new file mode 100644
index 0000000..721ff4e
--- /dev/null
+++ b/src/tests/qapi-schema/include-format-err.err
@@ -0,0 +1 @@
+tests/qapi-schema/include-format-err.json:1: Invalid 'include' directive
diff --git a/src/tests/qapi-schema/include-format-err.exit b/src/tests/qapi-schema/include-format-err.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-format-err.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-format-err.json b/src/tests/qapi-schema/include-format-err.json
new file mode 100644
index 0000000..44980f0
--- /dev/null
+++ b/src/tests/qapi-schema/include-format-err.json
@@ -0,0 +1,2 @@
+{ 'include': 'include-simple-sub.json',
+ 'foo': 'bar' }
diff --git a/src/tests/qapi-schema/include-format-err.out b/src/tests/qapi-schema/include-format-err.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-format-err.out
diff --git a/src/tests/qapi-schema/include-nested-err.err b/src/tests/qapi-schema/include-nested-err.err
new file mode 100644
index 0000000..1b7b227
--- /dev/null
+++ b/src/tests/qapi-schema/include-nested-err.err
@@ -0,0 +1,2 @@
+In file included from tests/qapi-schema/include-nested-err.json:1:
+tests/qapi-schema/missing-colon.json:1:10: Expected ":"
diff --git a/src/tests/qapi-schema/include-nested-err.exit b/src/tests/qapi-schema/include-nested-err.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-nested-err.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-nested-err.json b/src/tests/qapi-schema/include-nested-err.json
new file mode 100644
index 0000000..5631e56
--- /dev/null
+++ b/src/tests/qapi-schema/include-nested-err.json
@@ -0,0 +1 @@
+{ 'include': 'missing-colon.json' }
diff --git a/src/tests/qapi-schema/include-nested-err.out b/src/tests/qapi-schema/include-nested-err.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-nested-err.out
diff --git a/src/tests/qapi-schema/include-no-file.err b/src/tests/qapi-schema/include-no-file.err
new file mode 100644
index 0000000..d5b9b22
--- /dev/null
+++ b/src/tests/qapi-schema/include-no-file.err
@@ -0,0 +1 @@
+tests/qapi-schema/include-no-file.json:1: No such file or directory: include-no-file-sub.json
diff --git a/src/tests/qapi-schema/include-no-file.exit b/src/tests/qapi-schema/include-no-file.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-no-file.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-no-file.json b/src/tests/qapi-schema/include-no-file.json
new file mode 100644
index 0000000..9249ebd
--- /dev/null
+++ b/src/tests/qapi-schema/include-no-file.json
@@ -0,0 +1 @@
+{ 'include': 'include-no-file-sub.json' }
diff --git a/src/tests/qapi-schema/include-no-file.out b/src/tests/qapi-schema/include-no-file.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-no-file.out
diff --git a/src/tests/qapi-schema/include-non-file.err b/src/tests/qapi-schema/include-non-file.err
new file mode 100644
index 0000000..faae1ea
--- /dev/null
+++ b/src/tests/qapi-schema/include-non-file.err
@@ -0,0 +1 @@
+tests/qapi-schema/include-non-file.json:1: Value of 'include' must be a string
diff --git a/src/tests/qapi-schema/include-non-file.exit b/src/tests/qapi-schema/include-non-file.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-non-file.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-non-file.json b/src/tests/qapi-schema/include-non-file.json
new file mode 100644
index 0000000..4711aa4
--- /dev/null
+++ b/src/tests/qapi-schema/include-non-file.json
@@ -0,0 +1 @@
+{ 'include': {} }
diff --git a/src/tests/qapi-schema/include-non-file.out b/src/tests/qapi-schema/include-non-file.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-non-file.out
diff --git a/src/tests/qapi-schema/include-relpath-sub.json b/src/tests/qapi-schema/include-relpath-sub.json
new file mode 100644
index 0000000..4bd4af4
--- /dev/null
+++ b/src/tests/qapi-schema/include-relpath-sub.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/include-relpath.err b/src/tests/qapi-schema/include-relpath.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-relpath.err
diff --git a/src/tests/qapi-schema/include-relpath.exit b/src/tests/qapi-schema/include-relpath.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/include-relpath.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/include-relpath.json b/src/tests/qapi-schema/include-relpath.json
new file mode 100644
index 0000000..05018f3
--- /dev/null
+++ b/src/tests/qapi-schema/include-relpath.json
@@ -0,0 +1 @@
+{ 'include': 'include/relpath.json' }
diff --git a/src/tests/qapi-schema/include-relpath.out b/src/tests/qapi-schema/include-relpath.out
new file mode 100644
index 0000000..9e2c656
--- /dev/null
+++ b/src/tests/qapi-schema/include-relpath.out
@@ -0,0 +1,2 @@
+object :empty
+enum Status ['good', 'bad', 'ugly']
diff --git a/src/tests/qapi-schema/include-repetition-sub.json b/src/tests/qapi-schema/include-repetition-sub.json
new file mode 100644
index 0000000..6bfffdf
--- /dev/null
+++ b/src/tests/qapi-schema/include-repetition-sub.json
@@ -0,0 +1,2 @@
+{ 'include': 'comments.json' }
+{ 'include': 'comments.json' }
diff --git a/src/tests/qapi-schema/include-repetition.err b/src/tests/qapi-schema/include-repetition.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-repetition.err
diff --git a/src/tests/qapi-schema/include-repetition.exit b/src/tests/qapi-schema/include-repetition.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/include-repetition.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/include-repetition.json b/src/tests/qapi-schema/include-repetition.json
new file mode 100644
index 0000000..ec329dd
--- /dev/null
+++ b/src/tests/qapi-schema/include-repetition.json
@@ -0,0 +1,3 @@
+{ 'include': 'comments.json' }
+{ 'include': 'include-repetition-sub.json' }
+{ 'include': 'comments.json' }
diff --git a/src/tests/qapi-schema/include-repetition.out b/src/tests/qapi-schema/include-repetition.out
new file mode 100644
index 0000000..9e2c656
--- /dev/null
+++ b/src/tests/qapi-schema/include-repetition.out
@@ -0,0 +1,2 @@
+object :empty
+enum Status ['good', 'bad', 'ugly']
diff --git a/src/tests/qapi-schema/include-self-cycle.err b/src/tests/qapi-schema/include-self-cycle.err
new file mode 100644
index 0000000..981742a
--- /dev/null
+++ b/src/tests/qapi-schema/include-self-cycle.err
@@ -0,0 +1 @@
+tests/qapi-schema/include-self-cycle.json:1: Inclusion loop for include-self-cycle.json
diff --git a/src/tests/qapi-schema/include-self-cycle.exit b/src/tests/qapi-schema/include-self-cycle.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/include-self-cycle.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/include-self-cycle.json b/src/tests/qapi-schema/include-self-cycle.json
new file mode 100644
index 0000000..55fb1b5
--- /dev/null
+++ b/src/tests/qapi-schema/include-self-cycle.json
@@ -0,0 +1 @@
+{ 'include': 'include-self-cycle.json' }
diff --git a/src/tests/qapi-schema/include-self-cycle.out b/src/tests/qapi-schema/include-self-cycle.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-self-cycle.out
diff --git a/src/tests/qapi-schema/include-simple-sub.json b/src/tests/qapi-schema/include-simple-sub.json
new file mode 100644
index 0000000..4bd4af4
--- /dev/null
+++ b/src/tests/qapi-schema/include-simple-sub.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/include-simple.err b/src/tests/qapi-schema/include-simple.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/include-simple.err
diff --git a/src/tests/qapi-schema/include-simple.exit b/src/tests/qapi-schema/include-simple.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/include-simple.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/include-simple.json b/src/tests/qapi-schema/include-simple.json
new file mode 100644
index 0000000..1dd391a
--- /dev/null
+++ b/src/tests/qapi-schema/include-simple.json
@@ -0,0 +1 @@
+{ 'include': 'include-simple-sub.json' }
diff --git a/src/tests/qapi-schema/include-simple.out b/src/tests/qapi-schema/include-simple.out
new file mode 100644
index 0000000..9e2c656
--- /dev/null
+++ b/src/tests/qapi-schema/include-simple.out
@@ -0,0 +1,2 @@
+object :empty
+enum Status ['good', 'bad', 'ugly']
diff --git a/src/tests/qapi-schema/include/relpath.json b/src/tests/qapi-schema/include/relpath.json
new file mode 100644
index 0000000..45dee24
--- /dev/null
+++ b/src/tests/qapi-schema/include/relpath.json
@@ -0,0 +1 @@
+{ 'include': '../include-relpath-sub.json' }
diff --git a/src/tests/qapi-schema/indented-expr.err b/src/tests/qapi-schema/indented-expr.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/indented-expr.err
diff --git a/src/tests/qapi-schema/indented-expr.exit b/src/tests/qapi-schema/indented-expr.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/indented-expr.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/indented-expr.json b/src/tests/qapi-schema/indented-expr.json
new file mode 100644
index 0000000..7115d31
--- /dev/null
+++ b/src/tests/qapi-schema/indented-expr.json
@@ -0,0 +1,2 @@
+{ 'command' : 'eins' }
+ { 'command' : 'zwei' }
diff --git a/src/tests/qapi-schema/indented-expr.out b/src/tests/qapi-schema/indented-expr.out
new file mode 100644
index 0000000..226d300
--- /dev/null
+++ b/src/tests/qapi-schema/indented-expr.out
@@ -0,0 +1,5 @@
+object :empty
+command eins None -> None
+ gen=True success_response=True
+command zwei None -> None
+ gen=True success_response=True
diff --git a/src/tests/qapi-schema/leading-comma-list.err b/src/tests/qapi-schema/leading-comma-list.err
new file mode 100644
index 0000000..f5c870b
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null"
diff --git a/src/tests/qapi-schema/leading-comma-list.exit b/src/tests/qapi-schema/leading-comma-list.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-list.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/leading-comma-list.json b/src/tests/qapi-schema/leading-comma-list.json
new file mode 100644
index 0000000..c5ba501
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-list.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ , 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/leading-comma-list.out b/src/tests/qapi-schema/leading-comma-list.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-list.out
diff --git a/src/tests/qapi-schema/leading-comma-object.err b/src/tests/qapi-schema/leading-comma-object.err
new file mode 100644
index 0000000..f767b95
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-object.err
@@ -0,0 +1 @@
+tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}"
diff --git a/src/tests/qapi-schema/leading-comma-object.exit b/src/tests/qapi-schema/leading-comma-object.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-object.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/leading-comma-object.json b/src/tests/qapi-schema/leading-comma-object.json
new file mode 100644
index 0000000..c89023f
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-object.json
@@ -0,0 +1,2 @@
+{ , 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/leading-comma-object.out b/src/tests/qapi-schema/leading-comma-object.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/leading-comma-object.out
diff --git a/src/tests/qapi-schema/missing-colon.err b/src/tests/qapi-schema/missing-colon.err
new file mode 100644
index 0000000..d9d66b3
--- /dev/null
+++ b/src/tests/qapi-schema/missing-colon.err
@@ -0,0 +1 @@
+tests/qapi-schema/missing-colon.json:1:10: Expected ":"
diff --git a/src/tests/qapi-schema/missing-colon.exit b/src/tests/qapi-schema/missing-colon.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/missing-colon.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/missing-colon.json b/src/tests/qapi-schema/missing-colon.json
new file mode 100644
index 0000000..6fc27ce
--- /dev/null
+++ b/src/tests/qapi-schema/missing-colon.json
@@ -0,0 +1,2 @@
+{ 'enum' 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/missing-colon.out b/src/tests/qapi-schema/missing-colon.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/missing-colon.out
diff --git a/src/tests/qapi-schema/missing-comma-list.err b/src/tests/qapi-schema/missing-comma-list.err
new file mode 100644
index 0000000..e73d277
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/missing-comma-list.json:2:20: Expected "," or "]"
diff --git a/src/tests/qapi-schema/missing-comma-list.exit b/src/tests/qapi-schema/missing-comma-list.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-list.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/missing-comma-list.json b/src/tests/qapi-schema/missing-comma-list.json
new file mode 100644
index 0000000..1af39b2
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-list.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good' 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/missing-comma-list.out b/src/tests/qapi-schema/missing-comma-list.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-list.out
diff --git a/src/tests/qapi-schema/missing-comma-object.err b/src/tests/qapi-schema/missing-comma-object.err
new file mode 100644
index 0000000..52b3a8a
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-object.err
@@ -0,0 +1 @@
+tests/qapi-schema/missing-comma-object.json:2:3: Expected "," or "}"
diff --git a/src/tests/qapi-schema/missing-comma-object.exit b/src/tests/qapi-schema/missing-comma-object.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-object.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/missing-comma-object.json b/src/tests/qapi-schema/missing-comma-object.json
new file mode 100644
index 0000000..50f5178
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-object.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status'
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/src/tests/qapi-schema/missing-comma-object.out b/src/tests/qapi-schema/missing-comma-object.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/missing-comma-object.out
diff --git a/src/tests/qapi-schema/missing-type.err b/src/tests/qapi-schema/missing-type.err
new file mode 100644
index 0000000..b3e7b14
--- /dev/null
+++ b/src/tests/qapi-schema/missing-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/missing-type.json:2: Expression is missing metatype
diff --git a/src/tests/qapi-schema/missing-type.exit b/src/tests/qapi-schema/missing-type.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/missing-type.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/missing-type.json b/src/tests/qapi-schema/missing-type.json
new file mode 100644
index 0000000..ff5349d
--- /dev/null
+++ b/src/tests/qapi-schema/missing-type.json
@@ -0,0 +1,2 @@
+# we reject an expression with missing metatype
+{ 'data': { } }
diff --git a/src/tests/qapi-schema/missing-type.out b/src/tests/qapi-schema/missing-type.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/missing-type.out
diff --git a/src/tests/qapi-schema/nested-struct-data.err b/src/tests/qapi-schema/nested-struct-data.err
new file mode 100644
index 0000000..da767ba
--- /dev/null
+++ b/src/tests/qapi-schema/nested-struct-data.err
@@ -0,0 +1 @@
+tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name
diff --git a/src/tests/qapi-schema/nested-struct-data.exit b/src/tests/qapi-schema/nested-struct-data.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/nested-struct-data.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/nested-struct-data.json b/src/tests/qapi-schema/nested-struct-data.json
new file mode 100644
index 0000000..efbe773
--- /dev/null
+++ b/src/tests/qapi-schema/nested-struct-data.json
@@ -0,0 +1,3 @@
+# inline subtypes collide with our desired future use of defaults
+{ 'command': 'foo',
+ 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/src/tests/qapi-schema/nested-struct-data.out b/src/tests/qapi-schema/nested-struct-data.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/nested-struct-data.out
diff --git a/src/tests/qapi-schema/non-objects.err b/src/tests/qapi-schema/non-objects.err
new file mode 100644
index 0000000..334f0c9
--- /dev/null
+++ b/src/tests/qapi-schema/non-objects.err
@@ -0,0 +1 @@
+tests/qapi-schema/non-objects.json:1:1: Expected "{"
diff --git a/src/tests/qapi-schema/non-objects.exit b/src/tests/qapi-schema/non-objects.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/non-objects.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/non-objects.json b/src/tests/qapi-schema/non-objects.json
new file mode 100644
index 0000000..f3fa851
--- /dev/null
+++ b/src/tests/qapi-schema/non-objects.json
@@ -0,0 +1,2 @@
+'string'
+[ ]
diff --git a/src/tests/qapi-schema/non-objects.out b/src/tests/qapi-schema/non-objects.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/non-objects.out
diff --git a/src/tests/qapi-schema/qapi-schema-test.err b/src/tests/qapi-schema/qapi-schema-test.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/qapi-schema-test.err
diff --git a/src/tests/qapi-schema/qapi-schema-test.exit b/src/tests/qapi-schema/qapi-schema-test.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/qapi-schema-test.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/qapi-schema-test.json b/src/tests/qapi-schema/qapi-schema-test.json
new file mode 100644
index 0000000..44638da
--- /dev/null
+++ b/src/tests/qapi-schema/qapi-schema-test.json
@@ -0,0 +1,173 @@
+# *-*- Mode: Python -*-*
+
+# This file is a stress test of supported qapi constructs that must
+# parse and compile correctly.
+
+{ 'struct': 'TestStruct',
+ 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
+
+# for testing enums
+{ 'struct': 'NestedEnumsOne',
+ 'data': { 'enum1': 'EnumOne', # Intentional forward reference
+ '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# An empty enum, although unusual, is currently acceptable
+{ 'enum': 'MyEnum', 'data': [ ] }
+
+# Likewise for an empty struct, including an empty base
+{ 'struct': 'Empty1', 'data': { } }
+{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
+
+# for testing override of default naming heuristic
+{ 'enum': 'QEnumTwo',
+ 'prefix': 'QENUM_TWO',
+ 'data': [ 'value1', 'value2' ] }
+
+# for testing nested structs
+{ 'struct': 'UserDefOne',
+ 'base': 'UserDefZero', # intentional forward reference
+ 'data': { 'string': 'str',
+ '*enum1': 'EnumOne' } } # intentional forward reference
+
+{ 'enum': 'EnumOne',
+ 'data': [ 'value1', 'value2', 'value3' ] }
+
+{ 'struct': 'UserDefZero',
+ 'data': { 'integer': 'int' } }
+
+{ 'struct': 'UserDefTwoDictDict',
+ 'data': { 'userdef': 'UserDefOne', 'string': 'str' } }
+
+{ 'struct': 'UserDefTwoDict',
+ 'data': { 'string1': 'str',
+ 'dict2': 'UserDefTwoDictDict',
+ '*dict3': 'UserDefTwoDictDict' } }
+
+{ 'struct': 'UserDefTwo',
+ 'data': { 'string0': 'str',
+ 'dict1': 'UserDefTwoDict' } }
+
+# dummy struct to force generation of array types not otherwise mentioned
+{ 'struct': 'ForceArrays',
+ 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'],
+ 'unused3':['TestStruct'] } }
+
+# 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', '*a_b': 'int' } }
+
+{ 'struct': 'UserDefB',
+ 'data': { 'intb': 'int', '*a-b': 'bool' } }
+
+{ 'union': 'UserDefFlatUnion',
+ 'base': 'UserDefUnionBase', # intentional forward reference
+ 'discriminator': 'enum1',
+ 'data': { 'value1' : 'UserDefA',
+ 'value2' : 'UserDefB',
+ 'value3' : 'UserDefB' } }
+
+{ 'struct': 'UserDefUnionBase',
+ 'base': 'UserDefZero',
+ 'data': { 'string': 'str', 'enum1': 'EnumOne' } }
+
+# this variant of UserDefFlatUnion defaults to a union that uses fields with
+# allocated types to test corner cases in the cleanup/dealloc visitor
+{ 'union': 'UserDefFlatUnion2',
+ 'base': 'UserDefUnionBase',
+ 'discriminator': 'enum1',
+ 'data': { 'value1' : 'UserDefC', # intentional forward reference
+ 'value2' : 'UserDefB',
+ 'value3' : 'UserDefA' } }
+
+{ 'alternate': 'UserDefAlternate',
+ 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
+
+{ 'struct': 'UserDefC',
+ 'data': { 'string1': 'str', 'string2': 'str' } }
+
+# for testing use of 'number' within alternates
+{ 'alternate': 'AltStrBool', 'data': { 's': 'str', 'b': 'bool' } }
+{ 'alternate': 'AltStrNum', 'data': { 's': 'str', 'n': 'number' } }
+{ 'alternate': 'AltNumStr', 'data': { 'n': 'number', 's': 'str' } }
+{ 'alternate': 'AltStrInt', 'data': { 's': 'str', 'i': 'int' } }
+{ 'alternate': 'AltIntNum', 'data': { 'i': 'int', 'n': 'number' } }
+{ 'alternate': 'AltNumInt', 'data': { 'n': 'number', 'i': 'int' } }
+
+# for testing native lists
+{ 'union': 'UserDefNativeListUnion',
+ 'data': { 'integer': ['int'],
+ 's8': ['int8'],
+ 's16': ['int16'],
+ 's32': ['int32'],
+ 's64': ['int64'],
+ 'u8': ['uint8'],
+ 'u16': ['uint16'],
+ 'u32': ['uint32'],
+ 'u64': ['uint64'],
+ 'number': ['number'],
+ 'boolean': ['bool'],
+ 'string': ['str'],
+ 'sizes': ['size'],
+ 'any': ['any'] } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2',
+ 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
+ 'returns': 'UserDefTwo' }
+
+# Returning a non-dictionary requires a name from the whitelist
+{ 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
+ 'returns': 'int' }
+{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
+
+# For testing integer range flattening in opts-visitor. The following schema
+# corresponds to the option format:
+#
+# -userdef i64=3-6,i64=-5--1,u64=2,u16=1,u16=7-12
+#
+# For simplicity, this example doesn't use [type=]discriminator nor optargs
+# specific to discriminator values.
+{ 'struct': 'UserDefOptions',
+ 'data': {
+ '*i64' : [ 'int' ],
+ '*u64' : [ 'uint64' ],
+ '*u16' : [ 'uint16' ],
+ '*i64x': 'int' ,
+ '*u64x': 'uint64' } }
+
+# testing event
+{ 'struct': 'EventStructOne',
+ 'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }
+
+{ 'event': 'EVENT_A' }
+{ 'event': 'EVENT_B',
+ 'data': { } }
+{ 'event': 'EVENT_C',
+ 'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } }
+{ 'event': 'EVENT_D',
+ 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }
+
+# test that we correctly compile downstream extensions
+{ 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] }
+{ 'struct': '__org.qemu_x-Base',
+ 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
+{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
+ 'data': { '__org.qemu_x-member2': 'str' } }
+{ 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } }
+{ 'struct': '__org.qemu_x-Struct2',
+ 'data': { 'array': ['__org.qemu_x-Union1'] } }
+{ 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base',
+ 'discriminator': '__org.qemu_x-member1',
+ 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } }
+{ 'alternate': '__org.qemu_x-Alt',
+ 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
+{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
+{ 'command': '__org.qemu_x-command',
+ 'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
+ 'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
+ 'returns': '__org.qemu_x-Union1' }
diff --git a/src/tests/qapi-schema/qapi-schema-test.out b/src/tests/qapi-schema/qapi-schema-test.out
new file mode 100644
index 0000000..e20a823
--- /dev/null
+++ b/src/tests/qapi-schema/qapi-schema-test.out
@@ -0,0 +1,207 @@
+object :empty
+object :obj-EVENT_C-arg
+ member a: int optional=True
+ member b: UserDefOne optional=True
+ member c: str optional=False
+object :obj-EVENT_D-arg
+ member a: EventStructOne optional=False
+ member b: str optional=False
+ member c: str optional=True
+ member enum3: EnumOne optional=True
+object :obj-__org.qemu_x-command-arg
+ member a: __org.qemu_x-EnumList optional=False
+ member b: __org.qemu_x-StructList optional=False
+ member c: __org.qemu_x-Union2 optional=False
+ member d: __org.qemu_x-Alt optional=False
+object :obj-anyList-wrapper
+ member data: anyList optional=False
+object :obj-boolList-wrapper
+ member data: boolList optional=False
+object :obj-guest-get-time-arg
+ member a: int optional=False
+ member b: int optional=True
+object :obj-guest-sync-arg
+ member arg: any optional=False
+object :obj-int16List-wrapper
+ member data: int16List optional=False
+object :obj-int32List-wrapper
+ member data: int32List optional=False
+object :obj-int64List-wrapper
+ member data: int64List optional=False
+object :obj-int8List-wrapper
+ member data: int8List optional=False
+object :obj-intList-wrapper
+ member data: intList optional=False
+object :obj-numberList-wrapper
+ member data: numberList optional=False
+object :obj-sizeList-wrapper
+ member data: sizeList optional=False
+object :obj-str-wrapper
+ member data: str optional=False
+object :obj-strList-wrapper
+ member data: strList optional=False
+object :obj-uint16List-wrapper
+ member data: uint16List optional=False
+object :obj-uint32List-wrapper
+ member data: uint32List optional=False
+object :obj-uint64List-wrapper
+ member data: uint64List optional=False
+object :obj-uint8List-wrapper
+ member data: uint8List optional=False
+object :obj-user_def_cmd1-arg
+ member ud1a: UserDefOne optional=False
+object :obj-user_def_cmd2-arg
+ member ud1a: UserDefOne optional=False
+ member ud1b: UserDefOne optional=True
+alternate AltIntNum
+ case i: int
+ case n: number
+enum AltIntNumKind ['i', 'n']
+alternate AltNumInt
+ case n: number
+ case i: int
+enum AltNumIntKind ['n', 'i']
+alternate AltNumStr
+ case n: number
+ case s: str
+enum AltNumStrKind ['n', 's']
+alternate AltStrBool
+ case s: str
+ case b: bool
+enum AltStrBoolKind ['s', 'b']
+alternate AltStrInt
+ case s: str
+ case i: int
+enum AltStrIntKind ['s', 'i']
+alternate AltStrNum
+ case s: str
+ case n: number
+enum AltStrNumKind ['s', 'n']
+event EVENT_A None
+event EVENT_B None
+event EVENT_C :obj-EVENT_C-arg
+event EVENT_D :obj-EVENT_D-arg
+object Empty1
+object Empty2
+ base Empty1
+enum EnumOne ['value1', 'value2', 'value3']
+object EventStructOne
+ member struct1: UserDefOne optional=False
+ member string: str optional=False
+ member enum2: EnumOne optional=True
+object ForceArrays
+ member unused1: UserDefOneList optional=False
+ member unused2: UserDefTwoList optional=False
+ member unused3: TestStructList optional=False
+enum MyEnum []
+object NestedEnumsOne
+ member enum1: EnumOne optional=False
+ member enum2: EnumOne optional=True
+ member enum3: EnumOne optional=False
+ member enum4: EnumOne optional=True
+enum QEnumTwo ['value1', 'value2']
+ prefix QENUM_TWO
+object TestStruct
+ member integer: int optional=False
+ member boolean: bool optional=False
+ member string: str optional=False
+object UserDefA
+ member boolean: bool optional=False
+ member a_b: int optional=True
+alternate UserDefAlternate
+ case uda: UserDefA
+ case s: str
+ case i: int
+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
+object UserDefFlatUnion
+ base UserDefUnionBase
+ tag enum1
+ case value1: UserDefA
+ case value2: UserDefB
+ case value3: UserDefB
+object UserDefFlatUnion2
+ base UserDefUnionBase
+ tag enum1
+ case value1: UserDefC
+ case value2: UserDefB
+ case value3: UserDefA
+object UserDefNativeListUnion
+ case integer: :obj-intList-wrapper
+ case s8: :obj-int8List-wrapper
+ case s16: :obj-int16List-wrapper
+ case s32: :obj-int32List-wrapper
+ case s64: :obj-int64List-wrapper
+ case u8: :obj-uint8List-wrapper
+ case u16: :obj-uint16List-wrapper
+ case u32: :obj-uint32List-wrapper
+ case u64: :obj-uint64List-wrapper
+ case number: :obj-numberList-wrapper
+ case boolean: :obj-boolList-wrapper
+ case string: :obj-strList-wrapper
+ case sizes: :obj-sizeList-wrapper
+ case any: :obj-anyList-wrapper
+enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
+object UserDefOne
+ base UserDefZero
+ member string: str optional=False
+ member enum1: EnumOne optional=True
+object UserDefOptions
+ member i64: intList optional=True
+ member u64: uint64List optional=True
+ member u16: uint16List optional=True
+ member i64x: int optional=True
+ member u64x: uint64 optional=True
+object UserDefTwo
+ member string0: str optional=False
+ member dict1: UserDefTwoDict optional=False
+object UserDefTwoDict
+ member string1: str optional=False
+ member dict2: UserDefTwoDictDict optional=False
+ member dict3: UserDefTwoDictDict optional=True
+object UserDefTwoDictDict
+ member userdef: UserDefOne optional=False
+ member string: str optional=False
+object UserDefUnionBase
+ base UserDefZero
+ member string: str optional=False
+ member enum1: EnumOne optional=False
+object UserDefZero
+ member integer: int optional=False
+event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
+alternate __org.qemu_x-Alt
+ case __org.qemu_x-branch: str
+ case b: __org.qemu_x-Base
+enum __org.qemu_x-AltKind ['__org.qemu_x-branch', 'b']
+object __org.qemu_x-Base
+ member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
+enum __org.qemu_x-Enum ['__org.qemu_x-value']
+object __org.qemu_x-Struct
+ base __org.qemu_x-Base
+ member __org.qemu_x-member2: str optional=False
+object __org.qemu_x-Struct2
+ member array: __org.qemu_x-Union1List optional=False
+object __org.qemu_x-Union1
+ case __org.qemu_x-branch: :obj-str-wrapper
+enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
+object __org.qemu_x-Union2
+ base __org.qemu_x-Base
+ tag __org.qemu_x-member1
+ case __org.qemu_x-value: __org.qemu_x-Struct2
+command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
+ gen=True success_response=True
+command guest-get-time :obj-guest-get-time-arg -> int
+ gen=True success_response=True
+command guest-sync :obj-guest-sync-arg -> any
+ gen=True success_response=True
+command user_def_cmd None -> None
+ gen=True success_response=True
+command user_def_cmd1 :obj-user_def_cmd1-arg -> None
+ gen=True success_response=True
+command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
+ gen=True success_response=True
diff --git a/src/tests/qapi-schema/quoted-structural-chars.err b/src/tests/qapi-schema/quoted-structural-chars.err
new file mode 100644
index 0000000..9b18384
--- /dev/null
+++ b/src/tests/qapi-schema/quoted-structural-chars.err
@@ -0,0 +1 @@
+tests/qapi-schema/quoted-structural-chars.json:1:1: Expected "{"
diff --git a/src/tests/qapi-schema/quoted-structural-chars.exit b/src/tests/qapi-schema/quoted-structural-chars.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/quoted-structural-chars.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/quoted-structural-chars.json b/src/tests/qapi-schema/quoted-structural-chars.json
new file mode 100644
index 0000000..9fe657a
--- /dev/null
+++ b/src/tests/qapi-schema/quoted-structural-chars.json
@@ -0,0 +1 @@
+'{' 'key1' ':' 'value1' ',' 'key2' ':' '[' ']' '}'
diff --git a/src/tests/qapi-schema/quoted-structural-chars.out b/src/tests/qapi-schema/quoted-structural-chars.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/quoted-structural-chars.out
diff --git a/src/tests/qapi-schema/redefined-builtin.err b/src/tests/qapi-schema/redefined-builtin.err
new file mode 100644
index 0000000..b275722
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-builtin.err
@@ -0,0 +1 @@
+tests/qapi-schema/redefined-builtin.json:2: built-in 'size' is already defined
diff --git a/src/tests/qapi-schema/redefined-builtin.exit b/src/tests/qapi-schema/redefined-builtin.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-builtin.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/redefined-builtin.json b/src/tests/qapi-schema/redefined-builtin.json
new file mode 100644
index 0000000..45b8a55
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-builtin.json
@@ -0,0 +1,2 @@
+# we reject types that duplicate builtin names
+{ 'struct': 'size', 'data': { 'myint': 'size' } }
diff --git a/src/tests/qapi-schema/redefined-builtin.out b/src/tests/qapi-schema/redefined-builtin.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-builtin.out
diff --git a/src/tests/qapi-schema/redefined-command.err b/src/tests/qapi-schema/redefined-command.err
new file mode 100644
index 0000000..82ae256
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-command.err
@@ -0,0 +1 @@
+tests/qapi-schema/redefined-command.json:3: command 'foo' is already defined
diff --git a/src/tests/qapi-schema/redefined-command.exit b/src/tests/qapi-schema/redefined-command.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-command.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/redefined-command.json b/src/tests/qapi-schema/redefined-command.json
new file mode 100644
index 0000000..247e401
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-command.json
@@ -0,0 +1,3 @@
+# we reject commands defined more than once
+{ 'command': 'foo', 'data': { 'one': 'str' } }
+{ 'command': 'foo', 'data': { '*two': 'str' } }
diff --git a/src/tests/qapi-schema/redefined-command.out b/src/tests/qapi-schema/redefined-command.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-command.out
diff --git a/src/tests/qapi-schema/redefined-event.err b/src/tests/qapi-schema/redefined-event.err
new file mode 100644
index 0000000..35429cb
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-event.err
@@ -0,0 +1 @@
+tests/qapi-schema/redefined-event.json:3: event 'EVENT_A' is already defined
diff --git a/src/tests/qapi-schema/redefined-event.exit b/src/tests/qapi-schema/redefined-event.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-event.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/redefined-event.json b/src/tests/qapi-schema/redefined-event.json
new file mode 100644
index 0000000..7717e91
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-event.json
@@ -0,0 +1,3 @@
+# we reject duplicate events
+{ 'event': 'EVENT_A', 'data': { 'myint': 'int' } }
+{ 'event': 'EVENT_A', 'data': { 'myint': 'int' } }
diff --git a/src/tests/qapi-schema/redefined-event.out b/src/tests/qapi-schema/redefined-event.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-event.out
diff --git a/src/tests/qapi-schema/redefined-type.err b/src/tests/qapi-schema/redefined-type.err
new file mode 100644
index 0000000..06ea78c
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/redefined-type.json:3: struct 'foo' is already defined
diff --git a/src/tests/qapi-schema/redefined-type.exit b/src/tests/qapi-schema/redefined-type.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-type.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/redefined-type.json b/src/tests/qapi-schema/redefined-type.json
new file mode 100644
index 0000000..a09e768
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-type.json
@@ -0,0 +1,3 @@
+# we reject types defined more than once
+{ 'struct': 'foo', 'data': { 'one': 'str' } }
+{ 'enum': 'foo', 'data': [ 'two' ] }
diff --git a/src/tests/qapi-schema/redefined-type.out b/src/tests/qapi-schema/redefined-type.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/redefined-type.out
diff --git a/src/tests/qapi-schema/reserved-command-q.err b/src/tests/qapi-schema/reserved-command-q.err
new file mode 100644
index 0000000..f939e04
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-command-q.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix'
diff --git a/src/tests/qapi-schema/reserved-command-q.exit b/src/tests/qapi-schema/reserved-command-q.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-command-q.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-command-q.json b/src/tests/qapi-schema/reserved-command-q.json
new file mode 100644
index 0000000..99f8aae
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-command-q.json
@@ -0,0 +1,5 @@
+# C entity name collision
+# We reject names like 'q-unix', because they can collide with the mangled
+# name for 'unix' in generated C.
+{ 'command': 'unix' }
+{ 'command': 'q-unix' }
diff --git a/src/tests/qapi-schema/reserved-command-q.out b/src/tests/qapi-schema/reserved-command-q.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-command-q.out
diff --git a/src/tests/qapi-schema/reserved-member-has.err b/src/tests/qapi-schema/reserved-member-has.err
new file mode 100644
index 0000000..e755771
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-has.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a'
diff --git a/src/tests/qapi-schema/reserved-member-has.exit b/src/tests/qapi-schema/reserved-member-has.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-has.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-member-has.json b/src/tests/qapi-schema/reserved-member-has.json
new file mode 100644
index 0000000..45b9109
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-has.json
@@ -0,0 +1,5 @@
+# C member name collision
+# We reject names like 'has-a', because they can collide with the flag
+# for an optional 'a' in generated C.
+# TODO we could munge the optional flag name to avoid the collision.
+{ 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
diff --git a/src/tests/qapi-schema/reserved-member-has.out b/src/tests/qapi-schema/reserved-member-has.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-has.out
diff --git a/src/tests/qapi-schema/reserved-member-q.err b/src/tests/qapi-schema/reserved-member-q.err
new file mode 100644
index 0000000..f3d5dd7
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-q.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
diff --git a/src/tests/qapi-schema/reserved-member-q.exit b/src/tests/qapi-schema/reserved-member-q.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-q.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-member-q.json b/src/tests/qapi-schema/reserved-member-q.json
new file mode 100644
index 0000000..62fed8f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-q.json
@@ -0,0 +1,4 @@
+# C member name collision
+# We reject names like 'q-unix', because they can collide with the mangled
+# name for 'unix' in generated C.
+{ 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
diff --git a/src/tests/qapi-schema/reserved-member-q.out b/src/tests/qapi-schema/reserved-member-q.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-q.out
diff --git a/src/tests/qapi-schema/reserved-member-u.err b/src/tests/qapi-schema/reserved-member-u.err
new file mode 100644
index 0000000..87d4229
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-u.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u'
diff --git a/src/tests/qapi-schema/reserved-member-u.exit b/src/tests/qapi-schema/reserved-member-u.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-u.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-member-u.json b/src/tests/qapi-schema/reserved-member-u.json
new file mode 100644
index 0000000..1eaf0f3
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-u.json
@@ -0,0 +1,7 @@
+# Potential C member name collision
+# We reject use of 'u' as a member name, to allow it for internal use in
+# putting union branch members in a separate namespace from QMP members.
+# This is true even for non-unions, because it is possible to convert a
+# struct to flat union while remaining backwards compatible in QMP.
+# TODO - we could munge the member name to 'q_u' to avoid the collision
+{ 'struct': 'Oops', 'data': { 'u': 'str' } }
diff --git a/src/tests/qapi-schema/reserved-member-u.out b/src/tests/qapi-schema/reserved-member-u.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-member-u.out
diff --git a/src/tests/qapi-schema/reserved-type-kind.err b/src/tests/qapi-schema/reserved-type-kind.err
new file mode 100644
index 0000000..0a38efa
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-kind.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind'
diff --git a/src/tests/qapi-schema/reserved-type-kind.exit b/src/tests/qapi-schema/reserved-type-kind.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-kind.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-type-kind.json b/src/tests/qapi-schema/reserved-type-kind.json
new file mode 100644
index 0000000..9ecaba1
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-kind.json
@@ -0,0 +1,2 @@
+# we reject types that would conflict with implicit union enum
+{ 'enum': 'UnionKind', 'data': [ 'oops' ] }
diff --git a/src/tests/qapi-schema/reserved-type-kind.out b/src/tests/qapi-schema/reserved-type-kind.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-kind.out
diff --git a/src/tests/qapi-schema/reserved-type-list.err b/src/tests/qapi-schema/reserved-type-list.err
new file mode 100644
index 0000000..4510fa6
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List'
diff --git a/src/tests/qapi-schema/reserved-type-list.exit b/src/tests/qapi-schema/reserved-type-list.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-list.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/reserved-type-list.json b/src/tests/qapi-schema/reserved-type-list.json
new file mode 100644
index 0000000..98d53bf
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-list.json
@@ -0,0 +1,5 @@
+# Potential C name collision
+# We reserve names ending in 'List' for use by array types.
+# TODO - we could choose array names to avoid collision with user types,
+# in order to let this compile
+{ 'struct': 'FooList', 'data': { 's': 'str' } }
diff --git a/src/tests/qapi-schema/reserved-type-list.out b/src/tests/qapi-schema/reserved-type-list.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/reserved-type-list.out
diff --git a/src/tests/qapi-schema/returns-alternate.err b/src/tests/qapi-schema/returns-alternate.err
new file mode 100644
index 0000000..dfbb419
--- /dev/null
+++ b/src/tests/qapi-schema/returns-alternate.err
@@ -0,0 +1 @@
+tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt'
diff --git a/src/tests/qapi-schema/returns-alternate.exit b/src/tests/qapi-schema/returns-alternate.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-alternate.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/returns-alternate.json b/src/tests/qapi-schema/returns-alternate.json
new file mode 100644
index 0000000..972390c
--- /dev/null
+++ b/src/tests/qapi-schema/returns-alternate.json
@@ -0,0 +1,3 @@
+# we reject returns if it is an alternate type
+{ 'alternate': 'Alt', 'data': { 'a': 'int', 'b': 'str' } }
+{ 'command': 'oops', 'returns': 'Alt' }
diff --git a/src/tests/qapi-schema/returns-alternate.out b/src/tests/qapi-schema/returns-alternate.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/returns-alternate.out
diff --git a/src/tests/qapi-schema/returns-array-bad.err b/src/tests/qapi-schema/returns-array-bad.err
new file mode 100644
index 0000000..138095c
--- /dev/null
+++ b/src/tests/qapi-schema/returns-array-bad.err
@@ -0,0 +1 @@
+tests/qapi-schema/returns-array-bad.json:2: 'returns' for command 'oops': array type must contain single type name
diff --git a/src/tests/qapi-schema/returns-array-bad.exit b/src/tests/qapi-schema/returns-array-bad.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-array-bad.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/returns-array-bad.json b/src/tests/qapi-schema/returns-array-bad.json
new file mode 100644
index 0000000..09b0b1f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-array-bad.json
@@ -0,0 +1,2 @@
+# we reject an array return that is not a single type
+{ 'command': 'oops', 'returns': [ 'str', 'str' ] }
diff --git a/src/tests/qapi-schema/returns-array-bad.out b/src/tests/qapi-schema/returns-array-bad.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/returns-array-bad.out
diff --git a/src/tests/qapi-schema/returns-dict.err b/src/tests/qapi-schema/returns-dict.err
new file mode 100644
index 0000000..eb2d0c4
--- /dev/null
+++ b/src/tests/qapi-schema/returns-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name
diff --git a/src/tests/qapi-schema/returns-dict.exit b/src/tests/qapi-schema/returns-dict.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/returns-dict.json b/src/tests/qapi-schema/returns-dict.json
new file mode 100644
index 0000000..1cfef3e
--- /dev/null
+++ b/src/tests/qapi-schema/returns-dict.json
@@ -0,0 +1,2 @@
+# we reject inline struct return type
+{ 'command': 'oops', 'returns': { 'a': 'str' } }
diff --git a/src/tests/qapi-schema/returns-dict.out b/src/tests/qapi-schema/returns-dict.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/returns-dict.out
diff --git a/src/tests/qapi-schema/returns-unknown.err b/src/tests/qapi-schema/returns-unknown.err
new file mode 100644
index 0000000..1f43e3a
--- /dev/null
+++ b/src/tests/qapi-schema/returns-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/returns-unknown.json:2: 'returns' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/src/tests/qapi-schema/returns-unknown.exit b/src/tests/qapi-schema/returns-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/returns-unknown.json b/src/tests/qapi-schema/returns-unknown.json
new file mode 100644
index 0000000..25bd498
--- /dev/null
+++ b/src/tests/qapi-schema/returns-unknown.json
@@ -0,0 +1,2 @@
+# we reject returns if it does not contain a known type
+{ 'command': 'oops', 'returns': 'NoSuchType' }
diff --git a/src/tests/qapi-schema/returns-unknown.out b/src/tests/qapi-schema/returns-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/returns-unknown.out
diff --git a/src/tests/qapi-schema/returns-whitelist.err b/src/tests/qapi-schema/returns-whitelist.err
new file mode 100644
index 0000000..f47c1ee
--- /dev/null
+++ b/src/tests/qapi-schema/returns-whitelist.err
@@ -0,0 +1 @@
+tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
diff --git a/src/tests/qapi-schema/returns-whitelist.exit b/src/tests/qapi-schema/returns-whitelist.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/returns-whitelist.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/returns-whitelist.json b/src/tests/qapi-schema/returns-whitelist.json
new file mode 100644
index 0000000..e8b3cea
--- /dev/null
+++ b/src/tests/qapi-schema/returns-whitelist.json
@@ -0,0 +1,11 @@
+# we enforce that 'returns' be a dict or array of dict unless whitelisted
+{ 'command': 'human-monitor-command',
+ 'data': {'command-line': 'str', '*cpu-index': 'int'},
+ 'returns': 'str' }
+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] }
+{ 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
+{ 'command': 'guest-get-time',
+ 'returns': 'int' }
+
+{ 'command': 'no-way-this-will-get-whitelisted',
+ 'returns': [ 'int' ] }
diff --git a/src/tests/qapi-schema/returns-whitelist.out b/src/tests/qapi-schema/returns-whitelist.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/returns-whitelist.out
diff --git a/src/tests/qapi-schema/struct-base-clash-deep.err b/src/tests/qapi-schema/struct-base-clash-deep.err
new file mode 100644
index 0000000..f7a25a3
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash-deep.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-base-clash-deep.json:10: Member name 'name' clashes with base 'Base'
diff --git a/src/tests/qapi-schema/struct-base-clash-deep.exit b/src/tests/qapi-schema/struct-base-clash-deep.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash-deep.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/struct-base-clash-deep.json b/src/tests/qapi-schema/struct-base-clash-deep.json
new file mode 100644
index 0000000..fa873ab
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash-deep.json
@@ -0,0 +1,12 @@
+# 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',
+ 'base': 'Base',
+ 'data': { 'value': 'int' } }
+{ 'struct': 'Sub',
+ 'base': 'Mid',
+ 'data': { '*name': 'str' } }
diff --git a/src/tests/qapi-schema/struct-base-clash-deep.out b/src/tests/qapi-schema/struct-base-clash-deep.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash-deep.out
diff --git a/src/tests/qapi-schema/struct-base-clash.err b/src/tests/qapi-schema/struct-base-clash.err
new file mode 100644
index 0000000..3a9f66b
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-base-clash.json:5: Member name 'name' clashes with base 'Base'
diff --git a/src/tests/qapi-schema/struct-base-clash.exit b/src/tests/qapi-schema/struct-base-clash.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/struct-base-clash.json b/src/tests/qapi-schema/struct-base-clash.json
new file mode 100644
index 0000000..11aec80
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash.json
@@ -0,0 +1,7 @@
+# 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',
+ 'base': 'Base',
+ 'data': { 'name': 'str' } }
diff --git a/src/tests/qapi-schema/struct-base-clash.out b/src/tests/qapi-schema/struct-base-clash.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/struct-base-clash.out
diff --git a/src/tests/qapi-schema/struct-data-invalid.err b/src/tests/qapi-schema/struct-data-invalid.err
new file mode 100644
index 0000000..6644f4c
--- /dev/null
+++ b/src/tests/qapi-schema/struct-data-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name
diff --git a/src/tests/qapi-schema/struct-data-invalid.exit b/src/tests/qapi-schema/struct-data-invalid.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/struct-data-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/struct-data-invalid.json b/src/tests/qapi-schema/struct-data-invalid.json
new file mode 100644
index 0000000..9adbc3b
--- /dev/null
+++ b/src/tests/qapi-schema/struct-data-invalid.json
@@ -0,0 +1,2 @@
+{ 'struct': 'foo',
+ 'data': false }
diff --git a/src/tests/qapi-schema/struct-data-invalid.out b/src/tests/qapi-schema/struct-data-invalid.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/struct-data-invalid.out
diff --git a/src/tests/qapi-schema/struct-member-invalid.err b/src/tests/qapi-schema/struct-member-invalid.err
new file mode 100644
index 0000000..69a326d
--- /dev/null
+++ b/src/tests/qapi-schema/struct-member-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name
diff --git a/src/tests/qapi-schema/struct-member-invalid.exit b/src/tests/qapi-schema/struct-member-invalid.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/struct-member-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/struct-member-invalid.json b/src/tests/qapi-schema/struct-member-invalid.json
new file mode 100644
index 0000000..8f172f7
--- /dev/null
+++ b/src/tests/qapi-schema/struct-member-invalid.json
@@ -0,0 +1,2 @@
+{ 'struct': 'foo',
+ 'data': { 'a': false } }
diff --git a/src/tests/qapi-schema/struct-member-invalid.out b/src/tests/qapi-schema/struct-member-invalid.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/struct-member-invalid.out
diff --git a/src/tests/qapi-schema/test-qapi.py b/src/tests/qapi-schema/test-qapi.py
new file mode 100644
index 0000000..649677e
--- /dev/null
+++ b/src/tests/qapi-schema/test-qapi.py
@@ -0,0 +1,56 @@
+#
+# QAPI parser test harness
+#
+# Copyright (c) 2013 Red Hat Inc.
+#
+# Authors:
+# Markus Armbruster <armbru@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+
+from qapi import *
+from pprint import pprint
+import os
+import sys
+
+
+class QAPISchemaTestVisitor(QAPISchemaVisitor):
+ def visit_enum_type(self, name, info, values, prefix):
+ print 'enum %s %s' % (name, values)
+ if prefix:
+ print ' prefix %s' % prefix
+
+ def visit_object_type(self, name, info, base, members, variants):
+ print 'object %s' % name
+ if base:
+ print ' base %s' % base.name
+ for m in members:
+ print ' member %s: %s optional=%s' % \
+ (m.name, m.type.name, m.optional)
+ self._print_variants(variants)
+
+ def visit_alternate_type(self, name, info, variants):
+ print 'alternate %s' % name
+ self._print_variants(variants)
+
+ def visit_command(self, name, info, arg_type, ret_type,
+ gen, success_response):
+ print 'command %s %s -> %s' % \
+ (name, arg_type and arg_type.name, ret_type and ret_type.name)
+ print ' gen=%s success_response=%s' % (gen, success_response)
+
+ def visit_event(self, name, info, arg_type):
+ print 'event %s %s' % (name, arg_type and arg_type.name)
+
+ @staticmethod
+ def _print_variants(variants):
+ if variants:
+ if variants.tag_name:
+ print ' tag %s' % variants.tag_name
+ for v in variants.variants:
+ print ' case %s: %s' % (v.name, v.type.name)
+
+schema = QAPISchema(sys.argv[1])
+schema.visit(QAPISchemaTestVisitor())
diff --git a/src/tests/qapi-schema/trailing-comma-list.err b/src/tests/qapi-schema/trailing-comma-list.err
new file mode 100644
index 0000000..24c24b0
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[" or string
diff --git a/src/tests/qapi-schema/trailing-comma-list.exit b/src/tests/qapi-schema/trailing-comma-list.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-list.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/trailing-comma-list.json b/src/tests/qapi-schema/trailing-comma-list.json
new file mode 100644
index 0000000..9b0c8bd
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-list.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly', ] }
diff --git a/src/tests/qapi-schema/trailing-comma-list.out b/src/tests/qapi-schema/trailing-comma-list.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-list.out
diff --git a/src/tests/qapi-schema/trailing-comma-object.err b/src/tests/qapi-schema/trailing-comma-object.err
new file mode 100644
index 0000000..30bce5e
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-object.err
@@ -0,0 +1 @@
+tests/qapi-schema/trailing-comma-object.json:2:38: Expected string
diff --git a/src/tests/qapi-schema/trailing-comma-object.exit b/src/tests/qapi-schema/trailing-comma-object.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-object.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/trailing-comma-object.json b/src/tests/qapi-schema/trailing-comma-object.json
new file mode 100644
index 0000000..bbaea55
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-object.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ], }
diff --git a/src/tests/qapi-schema/trailing-comma-object.out b/src/tests/qapi-schema/trailing-comma-object.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/trailing-comma-object.out
diff --git a/src/tests/qapi-schema/type-bypass-bad-gen.err b/src/tests/qapi-schema/type-bypass-bad-gen.err
new file mode 100644
index 0000000..a83c3c6
--- /dev/null
+++ b/src/tests/qapi-schema/type-bypass-bad-gen.err
@@ -0,0 +1 @@
+tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value
diff --git a/src/tests/qapi-schema/type-bypass-bad-gen.exit b/src/tests/qapi-schema/type-bypass-bad-gen.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/type-bypass-bad-gen.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/type-bypass-bad-gen.json b/src/tests/qapi-schema/type-bypass-bad-gen.json
new file mode 100644
index 0000000..e8dec34
--- /dev/null
+++ b/src/tests/qapi-schema/type-bypass-bad-gen.json
@@ -0,0 +1,2 @@
+# 'gen' should only appear with value false
+{ 'command': 'foo', 'gen': 'whatever' }
diff --git a/src/tests/qapi-schema/type-bypass-bad-gen.out b/src/tests/qapi-schema/type-bypass-bad-gen.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/type-bypass-bad-gen.out
diff --git a/src/tests/qapi-schema/unclosed-list.err b/src/tests/qapi-schema/unclosed-list.err
new file mode 100644
index 0000000..fb41a86
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/unclosed-list.json:1:20: Expected "," or "]"
diff --git a/src/tests/qapi-schema/unclosed-list.exit b/src/tests/qapi-schema/unclosed-list.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-list.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unclosed-list.json b/src/tests/qapi-schema/unclosed-list.json
new file mode 100644
index 0000000..e3e9566
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-list.json
@@ -0,0 +1 @@
+{ 'key': [ 'value' }
diff --git a/src/tests/qapi-schema/unclosed-list.out b/src/tests/qapi-schema/unclosed-list.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-list.out
diff --git a/src/tests/qapi-schema/unclosed-object.err b/src/tests/qapi-schema/unclosed-object.err
new file mode 100644
index 0000000..db3deed
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-object.err
@@ -0,0 +1 @@
+tests/qapi-schema/unclosed-object.json:1:21: Expected "," or "}"
diff --git a/src/tests/qapi-schema/unclosed-object.exit b/src/tests/qapi-schema/unclosed-object.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-object.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unclosed-object.json b/src/tests/qapi-schema/unclosed-object.json
new file mode 100644
index 0000000..8ac069d
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-object.json
@@ -0,0 +1 @@
+{ 'key': [ 'value' ]
diff --git a/src/tests/qapi-schema/unclosed-object.out b/src/tests/qapi-schema/unclosed-object.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-object.out
diff --git a/src/tests/qapi-schema/unclosed-string.err b/src/tests/qapi-schema/unclosed-string.err
new file mode 100644
index 0000000..12b1870
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-string.err
@@ -0,0 +1 @@
+tests/qapi-schema/unclosed-string.json:1:11: Missing terminating "'"
diff --git a/src/tests/qapi-schema/unclosed-string.exit b/src/tests/qapi-schema/unclosed-string.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-string.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unclosed-string.json b/src/tests/qapi-schema/unclosed-string.json
new file mode 100644
index 0000000..8c16b6b
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-string.json
@@ -0,0 +1,2 @@
+{ 'text': 'lorem ips
+}
diff --git a/src/tests/qapi-schema/unclosed-string.out b/src/tests/qapi-schema/unclosed-string.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unclosed-string.out
diff --git a/src/tests/qapi-schema/unicode-str.err b/src/tests/qapi-schema/unicode-str.err
new file mode 100644
index 0000000..f621cd6
--- /dev/null
+++ b/src/tests/qapi-schema/unicode-str.err
@@ -0,0 +1 @@
+tests/qapi-schema/unicode-str.json:2: 'command' uses invalid name 'é'
diff --git a/src/tests/qapi-schema/unicode-str.exit b/src/tests/qapi-schema/unicode-str.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unicode-str.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unicode-str.json b/src/tests/qapi-schema/unicode-str.json
new file mode 100644
index 0000000..5253a1b
--- /dev/null
+++ b/src/tests/qapi-schema/unicode-str.json
@@ -0,0 +1,2 @@
+# we don't support full Unicode strings, yet
+{ 'command': 'é' }
diff --git a/src/tests/qapi-schema/unicode-str.out b/src/tests/qapi-schema/unicode-str.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unicode-str.out
diff --git a/src/tests/qapi-schema/union-bad-branch.err b/src/tests/qapi-schema/union-bad-branch.err
new file mode 100644
index 0000000..8822735
--- /dev/null
+++ b/src/tests/qapi-schema/union-bad-branch.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-bad-branch.json:6: Union 'MyUnion' member 'ONE' clashes with 'one'
diff --git a/src/tests/qapi-schema/union-bad-branch.exit b/src/tests/qapi-schema/union-bad-branch.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-bad-branch.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-bad-branch.json b/src/tests/qapi-schema/union-bad-branch.json
new file mode 100644
index 0000000..913aa38
--- /dev/null
+++ b/src/tests/qapi-schema/union-bad-branch.json
@@ -0,0 +1,8 @@
+# we reject normal unions where branches would collide in C
+{ 'struct': 'One',
+ 'data': { 'string': 'str' } }
+{ 'struct': 'Two',
+ 'data': { 'number': 'int' } }
+{ 'union': 'MyUnion',
+ 'data': { 'one': 'One',
+ 'ONE': 'Two' } }
diff --git a/src/tests/qapi-schema/union-bad-branch.out b/src/tests/qapi-schema/union-bad-branch.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-bad-branch.out
diff --git a/src/tests/qapi-schema/union-base-no-discriminator.err b/src/tests/qapi-schema/union-base-no-discriminator.err
new file mode 100644
index 0000000..8b7a242
--- /dev/null
+++ b/src/tests/qapi-schema/union-base-no-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base
diff --git a/src/tests/qapi-schema/union-base-no-discriminator.exit b/src/tests/qapi-schema/union-base-no-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-base-no-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-base-no-discriminator.json b/src/tests/qapi-schema/union-base-no-discriminator.json
new file mode 100644
index 0000000..1409cf5
--- /dev/null
+++ b/src/tests/qapi-schema/union-base-no-discriminator.json
@@ -0,0 +1,14 @@
+# we reject simple unions with a base (or flat unions without discriminator)
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'struct': 'Base',
+ 'data': { 'string': 'str' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'Base',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/union-base-no-discriminator.out b/src/tests/qapi-schema/union-base-no-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-base-no-discriminator.out
diff --git a/src/tests/qapi-schema/union-clash-branches.err b/src/tests/qapi-schema/union-clash-branches.err
new file mode 100644
index 0000000..005c48d
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-branches.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-clash-branches.json:4: Union 'TestUnion' member 'a_b' clashes with 'a-b'
diff --git a/src/tests/qapi-schema/union-clash-branches.exit b/src/tests/qapi-schema/union-clash-branches.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-branches.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-clash-branches.json b/src/tests/qapi-schema/union-clash-branches.json
new file mode 100644
index 0000000..31d135f
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-branches.json
@@ -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/src/tests/qapi-schema/union-clash-branches.out b/src/tests/qapi-schema/union-clash-branches.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-branches.out
diff --git a/src/tests/qapi-schema/union-clash-data.err b/src/tests/qapi-schema/union-clash-data.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-data.err
diff --git a/src/tests/qapi-schema/union-clash-data.exit b/src/tests/qapi-schema/union-clash-data.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-data.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/union-clash-data.json b/src/tests/qapi-schema/union-clash-data.json
new file mode 100644
index 0000000..7308e69
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-data.json
@@ -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/src/tests/qapi-schema/union-clash-data.out b/src/tests/qapi-schema/union-clash-data.out
new file mode 100644
index 0000000..6277239
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-data.out
@@ -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/src/tests/qapi-schema/union-clash-type.err b/src/tests/qapi-schema/union-clash-type.err
new file mode 100644
index 0000000..a5dead1
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-type.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-clash-type.json:8: Union 'TestUnion' member 'kind' clashes with '(automatic)'
diff --git a/src/tests/qapi-schema/union-clash-type.exit b/src/tests/qapi-schema/union-clash-type.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-type.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-clash-type.json b/src/tests/qapi-schema/union-clash-type.json
new file mode 100644
index 0000000..cfc256b
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-type.json
@@ -0,0 +1,9 @@
+# Union branch 'type'
+# Reject this, because 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.
+# 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.
+# Or, we could munge the branch name to allow compilation.
+{ 'union': 'TestUnion',
+ 'data': { 'kind': 'int', 'type': 'str' } }
diff --git a/src/tests/qapi-schema/union-clash-type.out b/src/tests/qapi-schema/union-clash-type.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-clash-type.out
diff --git a/src/tests/qapi-schema/union-empty.err b/src/tests/qapi-schema/union-empty.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-empty.err
diff --git a/src/tests/qapi-schema/union-empty.exit b/src/tests/qapi-schema/union-empty.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/src/tests/qapi-schema/union-empty.exit
@@ -0,0 +1 @@
+0
diff --git a/src/tests/qapi-schema/union-empty.json b/src/tests/qapi-schema/union-empty.json
new file mode 100644
index 0000000..1785007
--- /dev/null
+++ b/src/tests/qapi-schema/union-empty.json
@@ -0,0 +1,2 @@
+# FIXME - unions should not be empty
+{ 'union': 'Union', 'data': { } }
diff --git a/src/tests/qapi-schema/union-empty.out b/src/tests/qapi-schema/union-empty.out
new file mode 100644
index 0000000..8b5a7bf
--- /dev/null
+++ b/src/tests/qapi-schema/union-empty.out
@@ -0,0 +1,3 @@
+object :empty
+object Union
+enum UnionKind []
diff --git a/src/tests/qapi-schema/union-invalid-base.err b/src/tests/qapi-schema/union-invalid-base.err
new file mode 100644
index 0000000..03d7b97
--- /dev/null
+++ b/src/tests/qapi-schema/union-invalid-base.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int'
diff --git a/src/tests/qapi-schema/union-invalid-base.exit b/src/tests/qapi-schema/union-invalid-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-invalid-base.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-invalid-base.json b/src/tests/qapi-schema/union-invalid-base.json
new file mode 100644
index 0000000..92be39d
--- /dev/null
+++ b/src/tests/qapi-schema/union-invalid-base.json
@@ -0,0 +1,12 @@
+# a union base type must be a struct
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'int',
+ 'discriminator': 'int',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/src/tests/qapi-schema/union-invalid-base.out b/src/tests/qapi-schema/union-invalid-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-invalid-base.out
diff --git a/src/tests/qapi-schema/union-max.err b/src/tests/qapi-schema/union-max.err
new file mode 100644
index 0000000..55ce439
--- /dev/null
+++ b/src/tests/qapi-schema/union-max.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-max.json:2: Union 'Union' member 'max' clashes with '(automatic)'
diff --git a/src/tests/qapi-schema/union-max.exit b/src/tests/qapi-schema/union-max.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-max.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-max.json b/src/tests/qapi-schema/union-max.json
new file mode 100644
index 0000000..d6ad986
--- /dev/null
+++ b/src/tests/qapi-schema/union-max.json
@@ -0,0 +1,3 @@
+# we reject 'max' branch in a union, for collision with C enum
+{ 'union': 'Union',
+ 'data': { 'max': 'int' } }
diff --git a/src/tests/qapi-schema/union-max.out b/src/tests/qapi-schema/union-max.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-max.out
diff --git a/src/tests/qapi-schema/union-optional-branch.err b/src/tests/qapi-schema/union-optional-branch.err
new file mode 100644
index 0000000..3ada133
--- /dev/null
+++ b/src/tests/qapi-schema/union-optional-branch.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-optional-branch.json:2: Member of union 'Union' does not allow optional name '*a'
diff --git a/src/tests/qapi-schema/union-optional-branch.exit b/src/tests/qapi-schema/union-optional-branch.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-optional-branch.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-optional-branch.json b/src/tests/qapi-schema/union-optional-branch.json
new file mode 100644
index 0000000..591615f
--- /dev/null
+++ b/src/tests/qapi-schema/union-optional-branch.json
@@ -0,0 +1,2 @@
+# union branches cannot be optional
+{ 'union': 'Union', 'data': { '*a': 'int', 'b': 'str' } }
diff --git a/src/tests/qapi-schema/union-optional-branch.out b/src/tests/qapi-schema/union-optional-branch.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-optional-branch.out
diff --git a/src/tests/qapi-schema/union-unknown.err b/src/tests/qapi-schema/union-unknown.err
new file mode 100644
index 0000000..54fe456
--- /dev/null
+++ b/src/tests/qapi-schema/union-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-unknown.json:2: Member 'unknown' of union 'Union' uses unknown type 'MissingType'
diff --git a/src/tests/qapi-schema/union-unknown.exit b/src/tests/qapi-schema/union-unknown.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/union-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/union-unknown.json b/src/tests/qapi-schema/union-unknown.json
new file mode 100644
index 0000000..aa7e814
--- /dev/null
+++ b/src/tests/qapi-schema/union-unknown.json
@@ -0,0 +1,3 @@
+# we reject a union with unknown type in branch
+{ 'union': 'Union',
+ 'data': { 'unknown': 'MissingType' } }
diff --git a/src/tests/qapi-schema/union-unknown.out b/src/tests/qapi-schema/union-unknown.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/union-unknown.out
diff --git a/src/tests/qapi-schema/unknown-escape.err b/src/tests/qapi-schema/unknown-escape.err
new file mode 100644
index 0000000..000e30d
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-escape.err
@@ -0,0 +1 @@
+tests/qapi-schema/unknown-escape.json:3:21: Unknown escape \x
diff --git a/src/tests/qapi-schema/unknown-escape.exit b/src/tests/qapi-schema/unknown-escape.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-escape.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unknown-escape.json b/src/tests/qapi-schema/unknown-escape.json
new file mode 100644
index 0000000..8e6891e
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-escape.json
@@ -0,0 +1,3 @@
+# we only recognize JSON escape sequences, plus our \' extension (no \x)
+# { 'command': 'foo', 'data': {} }
+{ 'command': 'foo', 'dat\x61':{} }
diff --git a/src/tests/qapi-schema/unknown-escape.out b/src/tests/qapi-schema/unknown-escape.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-escape.out
diff --git a/src/tests/qapi-schema/unknown-expr-key.err b/src/tests/qapi-schema/unknown-expr-key.err
new file mode 100644
index 0000000..12f5ed5
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-expr-key.err
@@ -0,0 +1 @@
+tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar'
diff --git a/src/tests/qapi-schema/unknown-expr-key.exit b/src/tests/qapi-schema/unknown-expr-key.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-expr-key.exit
@@ -0,0 +1 @@
+1
diff --git a/src/tests/qapi-schema/unknown-expr-key.json b/src/tests/qapi-schema/unknown-expr-key.json
new file mode 100644
index 0000000..3b2be00
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-expr-key.json
@@ -0,0 +1,2 @@
+# we reject an expression with unknown top-level keys
+{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } }
diff --git a/src/tests/qapi-schema/unknown-expr-key.out b/src/tests/qapi-schema/unknown-expr-key.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/qapi-schema/unknown-expr-key.out
OpenPOWER on IntegriCloud