]> git.proxmox.com Git - mirror_qemu.git/blobdiff - tests/qapi-schema/test-qapi.py
qapi: Improve error message for unexpected array types
[mirror_qemu.git] / tests / qapi-schema / test-qapi.py
index bad14edb476a226c8b58663ef1fe6bb303f2267f..2160cef0822de67570e9ea2b39380a0307953901 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # QAPI parser test harness
 #
 # See the COPYING file in the top-level directory.
 #
 
-from __future__ import print_function
 
 import argparse
 import difflib
 import os
 import sys
+from io import StringIO
 
 from qapi.error import QAPIError
 from qapi.schema import QAPISchema, QAPISchemaVisitor
 
-if sys.version_info[0] < 3:
-    from cStringIO import StringIO
-else:
-    from io import StringIO
-
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
 
@@ -35,14 +30,16 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
     def visit_include(self, name, info):
         print('include %s' % name)
 
-    def visit_enum_type(self, name, info, ifcond, members, prefix):
+    def visit_enum_type(self, name, info, ifcond, features, members, prefix):
         print('enum %s' % name)
         if prefix:
             print('    prefix %s' % prefix)
         for m in members:
             print('    member %s' % m.name)
             self._print_if(m.ifcond, indent=8)
+            self._print_features(m.features, indent=8)
         self._print_if(ifcond)
+        self._print_features(features)
 
     def visit_array_type(self, name, info, ifcond, element_type):
         if not info:
@@ -50,8 +47,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         print('array %s %s' % (name, element_type.name))
         self._print_if(ifcond)
 
-    def visit_object_type(self, name, info, ifcond, base, members, variants,
-                          features):
+    def visit_object_type(self, name, info, ifcond, features,
+                          base, members, variants):
         print('object %s' % name)
         if base:
             print('    base %s' % base.name)
@@ -59,30 +56,34 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             print('    member %s: %s optional=%s'
                   % (m.name, m.type.name, m.optional))
             self._print_if(m.ifcond, 8)
+            self._print_features(m.features, indent=8)
         self._print_variants(variants)
         self._print_if(ifcond)
         self._print_features(features)
 
-    def visit_alternate_type(self, name, info, ifcond, variants):
+    def visit_alternate_type(self, name, info, ifcond, features, variants):
         print('alternate %s' % name)
         self._print_variants(variants)
         self._print_if(ifcond)
+        self._print_features(features)
 
-    def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
-                      success_response, boxed, allow_oob, allow_preconfig,
-                      features):
+    def visit_command(self, name, info, ifcond, features,
+                      arg_type, ret_type, gen, success_response, boxed,
+                      allow_oob, allow_preconfig, coroutine):
         print('command %s %s -> %s'
               % (name, arg_type and arg_type.name,
                  ret_type and ret_type.name))
-        print('    gen=%s success_response=%s boxed=%s oob=%s preconfig=%s'
-              % (gen, success_response, boxed, allow_oob, allow_preconfig))
+        print('    gen=%s success_response=%s boxed=%s oob=%s preconfig=%s%s'
+              % (gen, success_response, boxed, allow_oob, allow_preconfig,
+                 " coroutine=True" if coroutine else ""))
         self._print_if(ifcond)
         self._print_features(features)
 
-    def visit_event(self, name, info, ifcond, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, features, arg_type, boxed):
         print('event %s %s' % (name, arg_type and arg_type.name))
         print('    boxed=%s' % boxed)
         self._print_if(ifcond)
+        self._print_features(features)
 
     @staticmethod
     def _print_variants(variants):
@@ -94,15 +95,24 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
 
     @staticmethod
     def _print_if(ifcond, indent=4):
-        if ifcond:
-            print('%sif %s' % (' ' * indent, ifcond))
+        # TODO Drop this hack after replacing OrderedDict by plain
+        # dict (requires Python 3.7)
+        def _massage(subcond):
+            if isinstance(subcond, str):
+                return subcond
+            if isinstance(subcond, list):
+                return [_massage(val) for val in subcond]
+            return {key: _massage(val) for key, val in subcond.items()}
+
+        if ifcond.is_present():
+            print('%sif %s' % (' ' * indent, _massage(ifcond.ifcond)))
 
     @classmethod
-    def _print_features(cls, features):
+    def _print_features(cls, features, indent=4):
         if features:
             for f in features:
-                print('    feature %s' % f.name)
-                cls._print_if(f.ifcond, 8)
+                print('%sfeature %s' % (' ' * indent, f.name))
+                cls._print_if(f.ifcond, indent + 4)
 
 
 def test_frontend(fname):
@@ -123,14 +133,22 @@ def test_frontend(fname):
             print('    section=%s\n%s' % (section.name, section.text))
 
 
+def open_test_result(dir_name, file_name, update):
+    mode = 'r+' if update else 'r'
+    try:
+        fp = open(os.path.join(dir_name, file_name), mode)
+    except FileNotFoundError:
+        if not update:
+            raise
+        fp = open(os.path.join(dir_name, file_name), 'w+')
+    return fp
+
+
 def test_and_diff(test_name, dir_name, update):
     sys.stdout = StringIO()
     try:
         test_frontend(os.path.join(dir_name, test_name + '.json'))
     except QAPIError as err:
-        if err.info.fname is None:
-            print("%s" % err, file=sys.stderr)
-            return 2
         errstr = str(err) + '\n'
         if dir_name:
             errstr = errstr.replace(dir_name + '/', '')
@@ -142,13 +160,12 @@ def test_and_diff(test_name, dir_name, update):
         sys.stdout.close()
         sys.stdout = sys.__stdout__
 
-    mode = 'r+' if update else 'r'
     try:
-        outfp = open(os.path.join(dir_name, test_name + '.out'), mode)
-        errfp = open(os.path.join(dir_name, test_name + '.err'), mode)
+        outfp = open_test_result(dir_name, test_name + '.out', update)
+        errfp = open_test_result(dir_name, test_name + '.err', update)
         expected_out = outfp.readlines()
         expected_err = errfp.readlines()
-    except IOError as err:
+    except OSError as err:
         print("%s: can't open '%s': %s"
               % (sys.argv[0], err.filename, err.strerror),
               file=sys.stderr)
@@ -174,7 +191,7 @@ def test_and_diff(test_name, dir_name, update):
         errfp.truncate(0)
         errfp.seek(0)
         errfp.writelines(actual_err)
-    except IOError as err:
+    except OSError as err:
         print("%s: can't write '%s': %s"
               % (sys.argv[0], err.filename, err.strerror),
               file=sys.stderr)