[gobject-introspection] tests: Refactor test_parser and test_patterns to use unittest.TestSuite



commit 42bb69a6a2f12165a9758b192e80da089e00ab5c
Author: Simon Feltman <sfeltman src gnome org>
Date:   Wed Dec 18 18:21:55 2013 -0800

    tests: Refactor test_parser and test_patterns to use unittest.TestSuite
    
    Update both test_parser.py and test_patterns.py to dynamically generate
    TestCase sub-classes rather than modify a statically defined one.
    Use unittest.TestSuite to queue up the generated test cases via the
    "load_tests" hook.
    Use underscores instead of periods as a seperator for dynamically generated
    test cases and methods to match Python identifiers.
    Beyond general cleanup, these changes will help the ability to specify
    Python tests individually.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=720713

 tests/scanner/annotationparser/test_parser.py   |   54 ++++++++++-
 tests/scanner/annotationparser/test_patterns.py |  115 ++++++++++++++---------
 2 files changed, 119 insertions(+), 50 deletions(-)
---
diff --git a/tests/scanner/annotationparser/test_parser.py b/tests/scanner/annotationparser/test_parser.py
index ef4d746..79cc862 100644
--- a/tests/scanner/annotationparser/test_parser.py
+++ b/tests/scanner/annotationparser/test_parser.py
@@ -380,8 +380,7 @@ class TestCommentBlock(unittest.TestCase):
         return retval
 
 
-def create_tests(logger, tests_dir, tests_file):
-    tests_name = os.path.relpath(tests_file[:-4], tests_dir).replace('/', '.').replace('\\', '.')
+def create_test_case(logger, tests_dir, tests_file):
     tests_tree = etree.parse(tests_file).getroot()
 
     fix_cdata_elements = tests_tree.findall(ns('{}test/{}input'))
@@ -393,17 +392,27 @@ def create_tests(logger, tests_dir, tests_file):
             element.text = element.text.replace('{{?', '<!')
             element.text = element.text.replace('}}', '>')
 
+    test_methods = {}
     for counter, test in enumerate(tests_tree.findall(ns('{}test'))):
-        test_name = 'test_%s.%03d' % (tests_name, counter + 1)
+        test_name = 'test_%03d' % (counter + 1)
         test_method = TestCommentBlock.__create_test__(logger, test)
-        setattr(TestCommentBlock, test_name, test_method)
+        test_method.__name__ = test_name
+        test_methods[test_name] = test_method
 
+    # Dynamically generate a new subclass of TestCommentBlock in TitleCase
+    # with generated test methods.
+    test_class_name = os.path.relpath(tests_file[:-4], tests_dir)
+    test_class_name = test_class_name.replace('/', ' ').replace('\\', ' ').replace('.', ' ')
+    test_class_name = 'Test' + test_class_name.title().replace(' ', '')
+    return type(test_class_name, (TestCommentBlock,), test_methods)
 
-if __name__ == '__main__':
+
+def create_test_cases():
     # Initialize message logger
     namespace = Namespace('Test', '1.0')
     logger = MessageLogger.get(namespace=namespace)
     logger.enable_warnings((WARNING, ERROR, FATAL))
+    test_cases = {}
 
     # Load test cases from disc
     tests_dir = os.path.dirname(os.path.abspath(__file__))
@@ -413,7 +422,40 @@ if __name__ == '__main__':
             tests_file = os.path.join(dirpath, filename)
             if os.path.basename(tests_file).endswith('.xml'):
                 validate(tests_file)
-                create_tests(logger, tests_dir, tests_file)
+                test_case = create_test_case(logger, tests_dir, tests_file)
+                test_cases[test_case.__name__] = test_case
+
+    return test_cases
+
+
+# We currently need to push all the new test cases into the modules globals
+# in order for parameterized tests to work. Ideally all that should be needed
+# is the "load_tests" hook, but this does not work in the case were the tests
+# are run in parameterized mode, e.g: python -m unittest test_parser.Test...
+_all_tests = create_test_cases()
+globals().update(_all_tests)
+
+
+# Hook function for Python test loader.
+def load_tests(loader, tests, pattern):
+    suite = unittest.TestSuite()
+    # add standard tests from module
+    suite.addTests(tests)
+
+    # Initialize message logger
+    namespace = Namespace('Test', '1.0')
+    logger = MessageLogger.get(namespace=namespace)
+    logger.enable_warnings((WARNING, ERROR, FATAL))
 
+    # Load test cases from disc
+    tests_dir = os.path.dirname(os.path.abspath(__file__))
+
+    for name, test_case in _all_tests.iteritems():
+        tests = loader.loadTestsFromTestCase(test_case)
+        suite.addTests(tests)
+    return suite
+
+
+if __name__ == '__main__':
     # Run test suite
     unittest.main()
diff --git a/tests/scanner/annotationparser/test_patterns.py b/tests/scanner/annotationparser/test_patterns.py
index d5da82b..774d674 100644
--- a/tests/scanner/annotationparser/test_patterns.py
+++ b/tests/scanner/annotationparser/test_patterns.py
@@ -36,7 +36,7 @@ from giscanner.annotationparser import (COMMENT_BLOCK_START_RE, COMMENT_BLOCK_EN
                                         SECTION_RE, SYMBOL_RE, PROPERTY_RE,
                                         SIGNAL_RE, PARAMETER_RE, TAG_RE,
                                         TAG_VALUE_VERSION_RE, TAG_VALUE_STABILITY_RE)
-from unittest import (TestCase, main)
+import unittest
 
 
 comment_start_tests = [
@@ -858,59 +858,86 @@ tag_value_stability_tests = [
           'description': 'xyz: abc'})]
 
 
-def create_tests(tests_name, testcases):
+def create_test_method(testcase):
+    def do_test(self):
+        (program, text, expected) = testcase
+
+        match = program.match(text)
+
+        if match is not None:
+            msg = 'Test matched pattern but specifies no expected named groups.'
+            self.assertTrue(isinstance(expected, dict), msg)
+
+            for group in match.groupdict().keys():
+                msg = 'Test case is missing expected results for named group "%s".' % (group)
+                self.assertTrue(group in expected.keys(), msg)
+
+        if expected is None:
+            msg = 'Program matched text but shouldn\'t:\n"%s"'
+            self.assertTrue(match is None, msg % (text, ))
+        else:
+            msg = 'Program should match text but didn\'t:\n"%s"'
+            self.assertTrue(match is not None, msg % (text, ))
+
+            for key, value in expected.items():
+                msg = 'expected "%s" for "%s" but match returned "%s"'
+                msg = msg % (value, key, match.group(key))
+                self.assertEqual(match.group(key), value, msg)
+
+    return do_test
+
+
+def create_test_case(tests_class_name, testcases):
+    test_methods = {}
     for (index, testcase) in enumerate(testcases):
-        real_test_name = '%s_%03d' % (tests_name, index)
+        test_method_name = 'test_%03d' % index
+
+        test_method = create_test_method(testcase)
+        test_method.__name__ = test_method_name
+        test_methods[test_method_name] = test_method
 
-        test_method = TestProgram.__create_test__(testcase)
-        test_method.__name__ = real_test_name
-        setattr(TestProgram, real_test_name, test_method)
+    return type(tests_class_name, (unittest.TestCase,), test_methods)
 
 
-class TestProgram(TestCase):
-    @classmethod
-    def __create_test__(cls, testcase):
-        def do_test(self):
-            (program, text, expected) = testcase
+def create_test_cases():
+    test_cases = {}
+    for name, test_data in (('TestCommentStart', comment_start_tests),
+                            ('TestCommentEnd', comment_end_tests),
+                            ('TestCommentAsterisk', comment_asterisk_tests),
+                            ('TestIndentaton', indentaton_tests),
+                            ('TestEmptyLine', empty_line_tests),
+                            ('TestIdentifierSection', identifier_section_tests),
+                            ('TestIdentifierSymbol', identifier_symbol_tests),
+                            ('TestIdentifierProperty', identifier_property_tests),
+                            ('TestIdentifierSignal', identifier_signal_tests),
+                            ('TestParameter', parameter_tests),
+                            ('TestTag', tag_tests),
+                            ('TestTagValueVersion', tag_value_version_tests),
+                            ('TestTagValueStability', tag_value_stability_tests)):
+        test_cases[name] = create_test_case(name, test_data)
 
-            match = program.match(text)
+    return test_cases
 
-            if match is not None:
-                msg = 'Test matched pattern but specifies no expected named groups.'
-                self.assertTrue(isinstance(expected, dict), msg)
 
-                for group in match.groupdict().keys():
-                    msg = 'Test case is missing expected results for named group "%s".' % (group)
-                    self.assertTrue(group in expected.keys(), msg)
+# We currently need to push all the new test cases into the modules globals
+# in order for parameterized tests to work. Ideally all that should be needed
+# is the "load_tests" hook, but this does not work in the case were the tests
+# are run in parameterized mode, e.g: python -m unittest test_parser.Test...
+_all_tests = create_test_cases()
+globals().update(_all_tests)
 
-            if expected is None:
-                msg = 'Program matched text but shouldn\'t:\n"%s"'
-                self.assertTrue(match is None, msg % (text, ))
-            else:
-                msg = 'Program should match text but didn\'t:\n"%s"'
-                self.assertTrue(match is not None, msg % (text, ))
 
-                for key, value in expected.items():
-                    msg = 'expected "%s" for "%s" but match returned "%s"'
-                    msg = msg % (value, key, match.group(key))
-                    self.assertEqual(match.group(key), value, msg)
+# Hook function for Python test loader.
+def load_tests(loader, tests, pattern):
+    suite = unittest.TestSuite()
+    # add standard tests from module
+    suite.addTests(tests)
 
-        return do_test
+    for name, test_case in _all_tests.iteritems():
+        tests = loader.loadTestsFromTestCase(test_case)
+        suite.addTests(tests)
+    return suite
 
 
 if __name__ == '__main__':
-    create_tests('test_comment_start', comment_start_tests)
-    create_tests('test_comment_end', comment_end_tests)
-    create_tests('test_comment_asterisk', comment_asterisk_tests)
-    create_tests('test_indentaton', indentaton_tests)
-    create_tests('test_empty_line', empty_line_tests)
-    create_tests('test_identifier_section', identifier_section_tests)
-    create_tests('test_identifier_symbol', identifier_symbol_tests)
-    create_tests('test_identifier_property', identifier_property_tests)
-    create_tests('test_identifier_signal', identifier_signal_tests)
-    create_tests('test_parameter', parameter_tests)
-    create_tests('test_tag', tag_tests)
-    create_tests('test_tag_value_version', tag_value_version_tests)
-    create_tests('test_tag_value_stability', tag_value_stability_tests)
-
-    main()
+    unittest.main()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]