]> Git Repo - qemu.git/blob - tests/qapi-schema/test-qapi.py
block/nvme: Replace magic value by SCALE_MS definition
[qemu.git] / tests / qapi-schema / test-qapi.py
1 #!/usr/bin/env python3
2 #
3 # QAPI parser test harness
4 #
5 # Copyright (c) 2013 Red Hat Inc.
6 #
7 # Authors:
8 #  Markus Armbruster <[email protected]>
9 #
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.
12 #
13
14
15 import argparse
16 import difflib
17 import os
18 import sys
19 from io import StringIO
20
21 from qapi.error import QAPIError
22 from qapi.schema import QAPISchema, QAPISchemaVisitor
23
24
25 class QAPISchemaTestVisitor(QAPISchemaVisitor):
26
27     def visit_module(self, name):
28         print('module %s' % name)
29
30     def visit_include(self, name, info):
31         print('include %s' % name)
32
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)
42
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)
48
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)
62
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)
68
69     def visit_command(self, name, info, ifcond, features,
70                       arg_type, ret_type, gen, success_response, boxed,
71                       allow_oob, allow_preconfig):
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'
76               % (gen, success_response, boxed, allow_oob, allow_preconfig))
77         self._print_if(ifcond)
78         self._print_features(features)
79
80     def visit_event(self, name, info, ifcond, features, arg_type, boxed):
81         print('event %s %s' % (name, arg_type and arg_type.name))
82         print('    boxed=%s' % boxed)
83         self._print_if(ifcond)
84         self._print_features(features)
85
86     @staticmethod
87     def _print_variants(variants):
88         if variants:
89             print('    tag %s' % variants.tag_member.name)
90             for v in variants.variants:
91                 print('    case %s: %s' % (v.name, v.type.name))
92                 QAPISchemaTestVisitor._print_if(v.ifcond, indent=8)
93
94     @staticmethod
95     def _print_if(ifcond, indent=4):
96         if ifcond:
97             print('%sif %s' % (' ' * indent, ifcond))
98
99     @classmethod
100     def _print_features(cls, features, indent=4):
101         if features:
102             for f in features:
103                 print('%sfeature %s' % (' ' * indent, f.name))
104                 cls._print_if(f.ifcond, indent + 4)
105
106
107 def test_frontend(fname):
108     schema = QAPISchema(fname)
109     schema.visit(QAPISchemaTestVisitor())
110
111     for doc in schema.docs:
112         if doc.symbol:
113             print('doc symbol=%s' % doc.symbol)
114         else:
115             print('doc freeform')
116         print('    body=\n%s' % doc.body.text)
117         for arg, section in doc.args.items():
118             print('    arg=%s\n%s' % (arg, section.text))
119         for feat, section in doc.features.items():
120             print('    feature=%s\n%s' % (feat, section.text))
121         for section in doc.sections:
122             print('    section=%s\n%s' % (section.name, section.text))
123
124
125 def test_and_diff(test_name, dir_name, update):
126     sys.stdout = StringIO()
127     try:
128         test_frontend(os.path.join(dir_name, test_name + '.json'))
129     except QAPIError as err:
130         if err.info.fname is None:
131             print("%s" % err, file=sys.stderr)
132             return 2
133         errstr = str(err) + '\n'
134         if dir_name:
135             errstr = errstr.replace(dir_name + '/', '')
136         actual_err = errstr.splitlines(True)
137     else:
138         actual_err = []
139     finally:
140         actual_out = sys.stdout.getvalue().splitlines(True)
141         sys.stdout.close()
142         sys.stdout = sys.__stdout__
143
144     mode = 'r+' if update else 'r'
145     try:
146         outfp = open(os.path.join(dir_name, test_name + '.out'), mode)
147         errfp = open(os.path.join(dir_name, test_name + '.err'), mode)
148         expected_out = outfp.readlines()
149         expected_err = errfp.readlines()
150     except IOError as err:
151         print("%s: can't open '%s': %s"
152               % (sys.argv[0], err.filename, err.strerror),
153               file=sys.stderr)
154         return 2
155
156     if actual_out == expected_out and actual_err == expected_err:
157         return 0
158
159     print("%s %s" % (test_name, 'UPDATE' if update else 'FAIL'),
160           file=sys.stderr)
161     out_diff = difflib.unified_diff(expected_out, actual_out, outfp.name)
162     err_diff = difflib.unified_diff(expected_err, actual_err, errfp.name)
163     sys.stdout.writelines(out_diff)
164     sys.stdout.writelines(err_diff)
165
166     if not update:
167         return 1
168
169     try:
170         outfp.truncate(0)
171         outfp.seek(0)
172         outfp.writelines(actual_out)
173         errfp.truncate(0)
174         errfp.seek(0)
175         errfp.writelines(actual_err)
176     except IOError as err:
177         print("%s: can't write '%s': %s"
178               % (sys.argv[0], err.filename, err.strerror),
179               file=sys.stderr)
180         return 2
181
182     return 0
183
184
185 def main(argv):
186     parser = argparse.ArgumentParser(
187         description='QAPI schema tester')
188     parser.add_argument('-d', '--dir', action='store', default='',
189                         help="directory containing tests")
190     parser.add_argument('-u', '--update', action='store_true',
191                         help="update expected test results")
192     parser.add_argument('tests', nargs='*', metavar='TEST', action='store')
193     args = parser.parse_args()
194
195     status = 0
196     for t in args.tests:
197         (dir_name, base_name) = os.path.split(t)
198         dir_name = dir_name or args.dir
199         test_name = os.path.splitext(base_name)[0]
200         status |= test_and_diff(test_name, dir_name, args.update)
201
202     exit(status)
203
204
205 if __name__ == '__main__':
206     main(sys.argv)
207     exit(0)
This page took 0.037339 seconds and 4 git commands to generate.