backup: move to block-copy
[qemu/ar7.git] / tests / qapi-schema / test-qapi.py
blobe8db9d09d914d880d1dda661f5b5cb0d325ee4f0
1 #!/usr/bin/env python3
3 # QAPI parser test harness
5 # Copyright (c) 2013 Red Hat Inc.
7 # Authors:
8 # Markus Armbruster <armbru@redhat.com>
10 # This work is licensed under the terms of the GNU GPL, version 2 or later.
11 # See the COPYING file in the top-level directory.
15 import argparse
16 import difflib
17 import os
18 import sys
19 from io import StringIO
21 from qapi.error import QAPIError
22 from qapi.schema import QAPISchema, QAPISchemaVisitor
25 class QAPISchemaTestVisitor(QAPISchemaVisitor):
27 def visit_module(self, name):
28 print('module %s' % name)
30 def visit_include(self, name, info):
31 print('include %s' % name)
33 def visit_enum_type(self, name, info, ifcond, features, members, prefix):
34 print('enum %s' % name)
35 if prefix:
36 print(' prefix %s' % prefix)
37 for m in members:
38 print(' member %s' % m.name)
39 self._print_if(m.ifcond, indent=8)
40 self._print_if(ifcond)
41 self._print_features(features)
43 def visit_array_type(self, name, info, ifcond, element_type):
44 if not info:
45 return # suppress built-in arrays
46 print('array %s %s' % (name, element_type.name))
47 self._print_if(ifcond)
49 def visit_object_type(self, name, info, ifcond, features,
50 base, members, variants):
51 print('object %s' % name)
52 if base:
53 print(' base %s' % base.name)
54 for m in members:
55 print(' member %s: %s optional=%s'
56 % (m.name, m.type.name, m.optional))
57 self._print_if(m.ifcond, 8)
58 self._print_features(m.features, indent=8)
59 self._print_variants(variants)
60 self._print_if(ifcond)
61 self._print_features(features)
63 def visit_alternate_type(self, name, info, ifcond, features, variants):
64 print('alternate %s' % name)
65 self._print_variants(variants)
66 self._print_if(ifcond)
67 self._print_features(features)
69 def visit_command(self, name, info, ifcond, features,
70 arg_type, ret_type, gen, success_response, boxed,
71 allow_oob, allow_preconfig, coroutine):
72 print('command %s %s -> %s'
73 % (name, arg_type and arg_type.name,
74 ret_type and ret_type.name))
75 print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s%s'
76 % (gen, success_response, boxed, allow_oob, allow_preconfig,
77 " coroutine=True" if coroutine else ""))
78 self._print_if(ifcond)
79 self._print_features(features)
81 def visit_event(self, name, info, ifcond, features, arg_type, boxed):
82 print('event %s %s' % (name, arg_type and arg_type.name))
83 print(' boxed=%s' % boxed)
84 self._print_if(ifcond)
85 self._print_features(features)
87 @staticmethod
88 def _print_variants(variants):
89 if variants:
90 print(' tag %s' % variants.tag_member.name)
91 for v in variants.variants:
92 print(' case %s: %s' % (v.name, v.type.name))
93 QAPISchemaTestVisitor._print_if(v.ifcond, indent=8)
95 @staticmethod
96 def _print_if(ifcond, indent=4):
97 if ifcond:
98 print('%sif %s' % (' ' * indent, ifcond))
100 @classmethod
101 def _print_features(cls, features, indent=4):
102 if features:
103 for f in features:
104 print('%sfeature %s' % (' ' * indent, f.name))
105 cls._print_if(f.ifcond, indent + 4)
108 def test_frontend(fname):
109 schema = QAPISchema(fname)
110 schema.visit(QAPISchemaTestVisitor())
112 for doc in schema.docs:
113 if doc.symbol:
114 print('doc symbol=%s' % doc.symbol)
115 else:
116 print('doc freeform')
117 print(' body=\n%s' % doc.body.text)
118 for arg, section in doc.args.items():
119 print(' arg=%s\n%s' % (arg, section.text))
120 for feat, section in doc.features.items():
121 print(' feature=%s\n%s' % (feat, section.text))
122 for section in doc.sections:
123 print(' section=%s\n%s' % (section.name, section.text))
126 def test_and_diff(test_name, dir_name, update):
127 sys.stdout = StringIO()
128 try:
129 test_frontend(os.path.join(dir_name, test_name + '.json'))
130 except QAPIError as err:
131 if err.info.fname is None:
132 print("%s" % err, file=sys.stderr)
133 return 2
134 errstr = str(err) + '\n'
135 if dir_name:
136 errstr = errstr.replace(dir_name + '/', '')
137 actual_err = errstr.splitlines(True)
138 else:
139 actual_err = []
140 finally:
141 actual_out = sys.stdout.getvalue().splitlines(True)
142 sys.stdout.close()
143 sys.stdout = sys.__stdout__
145 mode = 'r+' if update else 'r'
146 try:
147 outfp = open(os.path.join(dir_name, test_name + '.out'), mode)
148 errfp = open(os.path.join(dir_name, test_name + '.err'), mode)
149 expected_out = outfp.readlines()
150 expected_err = errfp.readlines()
151 except IOError as err:
152 print("%s: can't open '%s': %s"
153 % (sys.argv[0], err.filename, err.strerror),
154 file=sys.stderr)
155 return 2
157 if actual_out == expected_out and actual_err == expected_err:
158 return 0
160 print("%s %s" % (test_name, 'UPDATE' if update else 'FAIL'),
161 file=sys.stderr)
162 out_diff = difflib.unified_diff(expected_out, actual_out, outfp.name)
163 err_diff = difflib.unified_diff(expected_err, actual_err, errfp.name)
164 sys.stdout.writelines(out_diff)
165 sys.stdout.writelines(err_diff)
167 if not update:
168 return 1
170 try:
171 outfp.truncate(0)
172 outfp.seek(0)
173 outfp.writelines(actual_out)
174 errfp.truncate(0)
175 errfp.seek(0)
176 errfp.writelines(actual_err)
177 except IOError as err:
178 print("%s: can't write '%s': %s"
179 % (sys.argv[0], err.filename, err.strerror),
180 file=sys.stderr)
181 return 2
183 return 0
186 def main(argv):
187 parser = argparse.ArgumentParser(
188 description='QAPI schema tester')
189 parser.add_argument('-d', '--dir', action='store', default='',
190 help="directory containing tests")
191 parser.add_argument('-u', '--update', action='store_true',
192 help="update expected test results")
193 parser.add_argument('tests', nargs='*', metavar='TEST', action='store')
194 args = parser.parse_args()
196 status = 0
197 for t in args.tests:
198 (dir_name, base_name) = os.path.split(t)
199 dir_name = dir_name or args.dir
200 test_name = os.path.splitext(base_name)[0]
201 status |= test_and_diff(test_name, dir_name, args.update)
203 exit(status)
206 if __name__ == '__main__':
207 main(sys.argv)
208 exit(0)