Rev 3204: Relax constraint on test ids, simplify implementation and update tests. in file:///v/home/vila/src/bzr/experimental/selftest/

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon Jan 21 14:49:23 GMT 2008


At file:///v/home/vila/src/bzr/experimental/selftest/

------------------------------------------------------------
revno: 3204
revision-id:v.ladeuil+lp at free.fr-20080121144918-xx5wtw3ddfm0iauh
parent: v.ladeuil+lp at free.fr-20080121112100-8qaiys24wb2nqowe
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: selftest
timestamp: Mon 2008-01-21 15:49:18 +0100
message:
  Relax constraint on test ids, simplify implementation and update tests.
  
  * bzrlib/tests/test_selftest.py:
  (TestSelftestFiltering.test_condition_id_in_list,
  TestSelftestFiltering.test_filter_suite_by_id_list): Updated.
  (TestTestIdList): Renamed from TestTestIdListFilter and updated.
  
  * bzrlib/tests/__init__.py:
  (TestIdList): Relax the constraint on test ids, they just have to
  start with their module name.
  
  * bzrlib/doc/api/__init__.py:
  (test_suite): Adding module name in test id is now enough.
modified:
  bzrlib/doc/api/__init__.py     __init__.py-20051224020744-7b87d590843855bc
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
-------------- next part --------------
=== modified file 'bzrlib/doc/api/__init__.py'
--- a/bzrlib/doc/api/__init__.py	2008-01-21 11:18:27 +0000
+++ b/bzrlib/doc/api/__init__.py	2008-01-21 14:49:18 +0000
@@ -38,14 +38,11 @@
     scripts = [candidate for candidate in candidates
                if candidate.endswith('.txt')]
     suite = doctest.DocFileSuite(*scripts)
-    # DocFileCase reduces the test id to the base file name, we want more
+    # DocFileCase reduces the test id to the base name of the tested file, we
+    # want the module to appears there.
     for t in tests.iter_suite_tests(suite):
         def make_new_test_id():
-            # While complying with the rule that a test id is
-            # <module>.<class>.<method>[(<param>+)], this does not represent
-            # the python names for class and method but should give enough
-            # hints to find back the source of a failing test.
-            new_id = '%s.DocFileCase.DocFileTest(%s)' % ( __name__, t)
+            new_id = '%s(%s)' % ( __name__, t)
             return lambda: new_id
         t.id = make_new_test_id()
     return suite

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2008-01-21 11:18:27 +0000
+++ b/bzrlib/tests/__init__.py	2008-01-21 14:49:18 +0000
@@ -2261,14 +2261,14 @@
     return condition
 
 
-def condition_id_in_list(name_list):
+def condition_id_in_list(id_list):
     """Create a condition filter which verify that test's id in a list.
     
-    :param name: A list of test names.
+    :param name: A TestIdList object.
     :return: A callable that returns True if the test's id appears in the list.
     """
     def condition(test):
-        return test.id() in name_list
+        return id_list.test_in(test.id())
     return condition
 
 
@@ -2584,77 +2584,48 @@
     return test_list
 
 
-class TestIdListFilter(object):
-    """Test suite filter against a test id list.
+class TestIdList(object):
+    """Test id list to filter a test suite.
 
     Relying on the assumption that test ids are built as:
-    <module>.<class>.<method>[(<param>+)], this class offers methods to :
+    <module>[.<class>.<method>][(<param>+)], <module> being in python dotted
+    notation, this class offers methods to :
     - avoid building a test suite for modules not refered to in the test list,
     - keep only the tests listed from the module test suite.
     """
 
     def __init__(self, test_id_list):
-        by_modules = {}
+        # When a test suite needs to be filtered against us we compare test ids
+        # for equality, so a simple dict offers a quick and simple solution.
+        self.tests = dict().fromkeys(test_id_list, True)
+
+        # While unittest.TestCase have ids like:
+        # <module>.<class>.<method>[(<param+)],
+        # doctest.DocTestCase can have ids like:
+        # <module>
+        # <module>.<class>
+        # <module>.<function>
+        # <module>.<class>.<method>
+
+        # Since we can't predict a test class from its name only, we settle on
+        # a simple constraint: a test id always begins with its module name.
+
+        modules = {}
         for test_id in test_id_list:
-            if '(' in test_id:
-                # Get read of params in case they contain '.' chars
-                name, params = test_id.split('(')
-            else:
-                name = test_id
-            try:
-                mod_name, klass, meth_name = name.rsplit('.', 2)
-            except ValueError:
-                # Not enough components. Put the test in the "empty" module
-                # since we can't reliably find its associated module.
-                mod_name = ''
-            by_module = by_modules.get(mod_name, None)
-            if by_module is None:
-                by_modules[mod_name] = [test_id]
-            else:
-                by_module.append(test_id)
-        self.tests_by_modules = by_modules
-
-        by_bases = {}
-        for module_name in by_modules.keys():
-            base = module_name
-            while base:
-                by_base = by_bases.get(base, None)
-                if by_base is None:
-                    by_bases[base] = [module_name]
-                else:
-                    by_base.append(module_name)
-                try:
-                    base, sub_mod_name = base.rsplit('.', 1)
-                except ValueError:
-                    base = None
-        self.module_hierarchies = by_bases
-
-    def used_modules(self):
-        """Return the modules containing the test classes."""
-        return self.tests_by_modules.keys()
-
-    def get_tests(self, module_name):
-        """Return tests defined in the module itself."""
-        return self.tests_by_modules.get(module_name, [])
-
-    def get_tests_under(self, module_name):
-        """Return tests defined in the module or one of its submodules."""
-        tests_list = []
-        for mod in self.module_hierarchies.get(module_name, []):
-            tests_list.extend(self.get_tests(mod))
-        return tests_list
+            parts = test_id.split('.')
+            mod_name = parts.pop(0)
+            modules[mod_name] = True
+            for part in parts:
+                mod_name += '.' + part
+                modules[mod_name] = True
+        self.modules = modules
 
     def is_module_name_used(self, module_name):
         """Is there tests for the module or one of its sub modules."""
-        return self.module_hierarchies.has_key(module_name)
-
-    def for_module_and_below(self, module_name, suite):
-        """Filter a test suite by a module name.
-
-        Returns tests defined in a module or one of its sub modules.
-        """
-        return filter_suite_by_id_list(suite,
-                                       self.get_tests_under(module_name))
+        return self.modules.has_key(module_name)
+
+    def test_in(self, test_id):
+        return self.tests.has_key(test_id)
 
 
 def test_suite(keep_only=None):
@@ -2802,7 +2773,7 @@
     loader = TestUtil.TestLoader()
 
     if keep_only is not None:
-        id_filter = TestIdListFilter(keep_only)
+        id_filter = TestIdList(keep_only)
 
     # modules building their suite with loadTestsFromModuleNames
     if keep_only is None:
@@ -2811,7 +2782,7 @@
         for mod in [m for m in testmod_names
                     if id_filter.is_module_name_used(m)]:
             mod_suite = loader.loadTestsFromModuleNames([mod])
-            mod_suite = id_filter.for_module_and_below(mod, mod_suite)
+            mod_suite = filter_suite_by_id_list(mod_suite, id_filter)
             suite.addTest(mod_suite)
 
     # modules adapted for transport implementations
@@ -2824,7 +2795,7 @@
                     if id_filter.is_module_name_used(m)]:
             mod_suite = TestUtil.TestSuite()
             adapt_modules([mod], adapter, loader, mod_suite)
-            mod_suite = id_filter.for_module_and_below(mod, mod_suite)
+            mod_suite = filter_suite_by_id_list(mod_suite, id_filter)
             suite.addTest(mod_suite)
 
     # modules defining their own test_suite()
@@ -2833,8 +2804,7 @@
                         or id_filter.is_module_name_used(p.__name__))]:
         pack_suite = package.test_suite()
         if keep_only is not None:
-            pack_suite = id_filter.for_module_and_below(package.__name__,
-                                                        pack_suite)
+            pack_suite = filter_suite_by_id_list(pack_suite, id_filter)
         suite.addTest(pack_suite)
 
     # XXX: MODULES_TO_TEST should be obsoleted ?
@@ -2842,7 +2812,7 @@
                 if keep_only is None or id_filter.is_module_name_used(m)]:
         mod_suite = loader.loadTestsFromModule(mod)
         if keep_only is not None:
-            mod_suite = id_filter.for_module_and_below(mod, mod_suite)
+            mod_suite = filter_suite_by_id_list(mod_suite, id_filter)
         suite.addTest(mod_suite)
 
     for mod in MODULES_TO_DOCTEST:
@@ -2853,7 +2823,7 @@
             raise
         if keep_only is not None:
             # DocTests may use ids which doesn't contain the module name
-            doc_suite = filter_suite_by_id_list(doc_suite, keep_only)
+            doc_suite = filter_suite_by_id_list(doc_suite, id_filter)
         suite.addTest(doc_suite)
 
     default_encoding = sys.getdefaultencoding()
@@ -2869,8 +2839,8 @@
         else:
             if plugin_suite is not None:
                 if keep_only is not None:
-                    plugin_suite = id_filter.for_module_and_below(
-                        plugin.module.__name__, plugin_suite)
+                    plugin_suite = filter_suite_by_id_list(plugin_suite,
+                                                           id_filter)
                 suite.addTest(plugin_suite)
         if default_encoding != sys.getdefaultencoding():
             bzrlib.trace.warning(

=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py	2008-01-21 10:51:02 +0000
+++ b/bzrlib/tests/test_selftest.py	2008-01-21 14:49:18 +0000
@@ -1686,8 +1686,9 @@
     def test_condition_id_in_list(self):
         test_names = ['bzrlib.tests.test_selftest.TestSelftestFiltering.'
                       'test_condition_id_in_list']
+        id_list = tests.TestIdList(test_names)
         filtered_suite = filter_suite_by_condition(
-            self.suite, tests.condition_id_in_list(test_names))
+            self.suite, tests.condition_id_in_list(id_list))
         my_pattern = 'TestSelftestFiltering.*test_condition_id_in_list'
         re_filtered = filter_suite_by_re(self.suite, my_pattern)
         self.assertEqual(self._test_ids(re_filtered),
@@ -1739,10 +1740,10 @@
             'TestSelftestFiltering.test_filter_suite_by_re'])
 
     def test_filter_suite_by_id_list(self):
+        test_list = ['bzrlib.tests.test_selftest.'
+                     'TestSelftestFiltering.test_filter_suite_by_id_list']
         filtered_suite = tests.filter_suite_by_id_list(
-            self.suite,
-            ['bzrlib.tests.test_selftest.'
-             'TestSelftestFiltering.test_filter_suite_by_id_list'])
+            self.suite, tests.TestIdList(test_list))
         filtered_names = self._test_ids(filtered_suite)
         self.assertEqual(
             filtered_names,
@@ -1865,12 +1866,12 @@
         self.assertEqual(2, loader.loadTestsFromModule(module).countTestCases())
 
 
-class TestTestIdListFilter(tests.TestCase):
-
-    def _create_filter(self, test_list):
-        return tests.TestIdListFilter(test_list)
-
-    def _create_suite(self, id_list):
+class TestTestIdList(tests.TestCase):
+
+    def _create_id_list(self, test_list):
+        return tests.TestIdList(test_list)
+
+    def _create_suite(self, test_id_list):
 
         class Stub(TestCase):
             def test_foo(self):
@@ -1880,7 +1881,7 @@
             return lambda: id
 
         suite = TestUtil.TestSuite()
-        for id in id_list:
+        for id in test_id_list:
             t  = Stub('test_foo')
             t.id = _create_test_id(id)
             suite.addTest(t)
@@ -1891,85 +1892,34 @@
         return [t.id() for t in iter_suite_tests(test_suite)]
 
     def test_empty_list(self):
-        filter = self._create_filter([])
-        self.assertEquals([], filter.used_modules())
+        id_list = self._create_id_list([])
+        self.assertEquals({}, id_list.tests)
+        self.assertEquals({}, id_list.modules)
 
     def test_valid_list(self):
-        filter = self._create_filter(
+        id_list = self._create_id_list(
             ['mod1.cl1.meth1', 'mod1.cl1.meth2',
-             'mod1.cl2.meth1', 'mod1.cl2.meth2',
+             'mod1.func1', 'mod1.cl2.meth2',
+             'mod1.submod1',
              'mod1.submod2.cl1.meth1', 'mod1.submod2.cl2.meth2',
              ])
-        self.assertEquals(['mod1', 'mod1.submod2'], filter.used_modules())
-        self.assertEquals(['mod1.cl1.meth1', 'mod1.cl1.meth2',
-                           'mod1.cl2.meth1', 'mod1.cl2.meth2',],
-                          filter.get_tests('mod1'))
-        self.assertEquals(['mod1.submod2.cl1.meth1', 'mod1.submod2.cl2.meth2'],
-                          filter.get_tests('mod1.submod2'))
-
-    def test_get_tests_under(self):
-        filter = self._create_filter(
-            ['mod.cl1.meth1','mod.cl2.meth2',
-             'mod.submod.cl1.meth1', 'mod.submod.cl2.meth2',
-             'mod2.cl1.meth1',
-             ])
-        self.assertEquals(['mod.cl1.meth1', 'mod.cl2.meth2',],
-                          filter.get_tests('mod'))
-        self.assertEquals(['mod.submod.cl1.meth1', 'mod.submod.cl2.meth2'],
-                          filter.get_tests('mod.submod'))
-        self.assertEquals(set(['mod.cl1.meth1','mod.cl2.meth2',
-                           'mod.submod.cl1.meth1', 'mod.submod.cl2.meth2']),
-                          set(filter.get_tests_under('mod')))
-
-    def test_too_short_test_name(self):
-        filter = self._create_filter(['mod1', 'mod2.method1', 'mod3.cl1'])
-        self.assertEquals([''],filter.used_modules())
-        self.assertEquals(['mod1', 'mod2.method1', 'mod3.cl1'],
-                          filter.get_tests(''))
-
+        self.assertTrue(id_list.is_module_name_used('mod1'))
+        self.assertTrue(id_list.is_module_name_used('mod1.submod1'))
+        self.assertTrue(id_list.is_module_name_used('mod1.submod2'))
+        self.assertTrue(id_list.test_in('mod1.cl1.meth1'))
+        self.assertTrue(id_list.test_in('mod1.submod1'))
+        self.assertTrue(id_list.test_in('mod1.func1'))
 
     def test_bad_chars_in_params(self):
-        filter = self._create_filter(['mod1.cl1.meth1(xx.yy)'])
-        self.assertEquals(['mod1'], filter.used_modules())
-        self.assertEquals(['mod1.cl1.meth1(xx.yy)'],
-                          filter.get_tests('mod1'))
+        id_list = self._create_id_list(['mod1.cl1.meth1(xx.yy)'])
+        self.assertTrue(id_list.is_module_name_used('mod1'))
+        self.assertTrue(id_list.test_in('mod1.cl1.meth1(xx.yy)'))
 
     def test_module_used(self):
-        filter = self._create_filter(['mod.class.meth'])
-        self.assertTrue(filter.is_module_name_used('mod'))
-
-    def test_module_used_includes_sub_modules(self):
-        filter = self._create_filter(['mod.sub_mod.class.meth'])
-        self.assertTrue(filter.is_module_name_used('mod'))
-        self.assertTrue(filter.is_module_name_used('mod.sub_mod'))
-
-    def test_module_used_refuses_class(self):
-        filter = self._create_filter(['mod.sub_mod.class.meth'])
-        self.assertFalse(filter.is_module_name_used('mod.sub_mod.class'))
-
-    def test_filter_for_module_and_below(self):
-        test_list = ['mod1.cl1.meth1', 'mod1.cl2.meth2',
-                     'mod1.submod2.cl1.meth1',
-                     'mod2.submod2.cl1.meth2',
-                     ]
-        suite = self._create_suite(test_list)
-        filter = self._create_filter(test_list)
-        mod1_suite = filter.for_module_and_below('mod1', suite)
-        self.assertEquals(['mod1.cl1.meth1', 'mod1.cl2.meth2',
-                           'mod1.submod2.cl1.meth1'],
-                          self._test_ids(mod1_suite))
-        mod2_suite = filter.for_module_and_below('mod2', suite)
-        self.assertEquals(['mod2.submod2.cl1.meth2'],
-                          self._test_ids(mod2_suite))
-
-    def test_filter_for_module_and_below_empty_result(self):
-        test_list = ['mod1.cl1.meth1', 'mod1.cl2.meth2',
-                     'mod2.submod2.cl1.meth2',
-                     ]
-        suite = self._create_suite(test_list)
-        filter = self._create_filter(test_list)
-        mod3_suite = filter.for_module_and_below('mod3', suite)
-        self.assertEquals(0, mod3_suite.countTestCases())
+        id_list = self._create_id_list(['mod.class.meth'])
+        self.assertTrue(id_list.is_module_name_used('mod'))
+        self.assertTrue(id_list.is_module_name_used('mod.class'))
+        self.assertTrue(id_list.is_module_name_used('mod.class.meth'))
 
     def test_test_suite(self):
         # This test is slow, so we do a single test with one test in each



More information about the bazaar-commits mailing list