Rev 4922: (jam) Add bzrlib.tests.permute_for_extension to simplify extension in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Dec 23 05:04:15 GMT 2009
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 4922 [merge]
revision-id: pqm at pqm.ubuntu.com-20091223050412-z05afly8exkncg8b
parent: pqm at pqm.ubuntu.com-20091223014722-dzs9ez4fhetyixha
parent: john at arbash-meinel.com-20091223041934-zbixrn1cg015bqq4
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2009-12-23 05:04:12 +0000
message:
(jam) Add bzrlib.tests.permute_for_extension to simplify extension
testing.
renamed:
bzrlib/tests/test_bencode.py => bzrlib/tests/test__bencode.py test_bencode.py-20070806225234-s51cnnkh6raytxti-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/test__annotator.py test__annotator.py-20090617192546-21fnjrg2s2c16uem-2
bzrlib/tests/test__chk_map.py test__chk_map.py-20090309114220-1kurz7oez2gwqtcf-2
bzrlib/tests/test__chunks_to_lines.py test__chunks_to_line-20081211024848-6uc3mtuje8j14l60-2
bzrlib/tests/test__rio.py test__rio.py-20090514191748-cy74k8yj46gzoeq6-1
bzrlib/tests/test__static_tuple.py test__keys_type.py-20090908204220-aa346ccw4l37jzt7-2
doc/developers/testing.txt testing.txt-20080812140359-i70zzh6v2z7grqex-1
bzrlib/tests/test__bencode.py test_bencode.py-20070806225234-s51cnnkh6raytxti-1
=== modified file 'NEWS'
--- a/NEWS 2009-12-22 23:47:22 +0000
+++ b/NEWS 2009-12-23 05:04:12 +0000
@@ -23,6 +23,12 @@
``locations.conf`` or ``branch.conf``.
(Ted Gould, Matthew Fuller, Vincent Ladeuil)
+* ``bzrlib.tests.permute_for_extension`` is a helper that simplifies
+ running all tests in the current module, once against a pure python
+ implementation, and once against an extension (pyrex/C) implementation.
+ It can be used to dramatically simplify the implementation of
+ ``load_tests``. (John Arbash Meinel)
+
Bug Fixes
*********
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2009-12-23 00:15:34 +0000
+++ b/bzrlib/tests/__init__.py 2009-12-23 05:04:12 +0000
@@ -3575,6 +3575,7 @@
'bzrlib.tests.per_versionedfile',
'bzrlib.tests.per_workingtree',
'bzrlib.tests.test__annotator',
+ 'bzrlib.tests.test__bencode',
'bzrlib.tests.test__chk_map',
'bzrlib.tests.test__dirstate_helpers',
'bzrlib.tests.test__groupcompress',
@@ -3588,7 +3589,6 @@
'bzrlib.tests.test_api',
'bzrlib.tests.test_atomicfile',
'bzrlib.tests.test_bad_files',
- 'bzrlib.tests.test_bencode',
'bzrlib.tests.test_bisect_multi',
'bzrlib.tests.test_branch',
'bzrlib.tests.test_branchbuilder',
@@ -3956,6 +3956,47 @@
return new_test
+def permute_tests_for_extension(standard_tests, loader, py_module_name,
+ ext_module_name):
+ """Helper for permutating tests against an extension module.
+
+ This is meant to be used inside a modules 'load_tests()' function. It will
+ create 2 scenarios, and cause all tests in the 'standard_tests' to be run
+ against both implementations. Setting 'test.module' to the appropriate
+ module. See bzrlib.tests.test__chk_map.load_tests as an example.
+
+ :param standard_tests: A test suite to permute
+ :param loader: A TestLoader
+ :param py_module_name: The python path to a python module that can always
+ be loaded, and will be considered the 'python' implementation. (eg
+ 'bzrlib._chk_map_py')
+ :param ext_module_name: The python path to an extension module. If the
+ module cannot be loaded, a single test will be added, which notes that
+ the module is not available. If it can be loaded, all standard_tests
+ will be run against that module.
+ :return: (suite, feature) suite is a test-suite that has all the permuted
+ tests. feature is the Feature object that can be used to determine if
+ the module is available.
+ """
+
+ py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
+ scenarios = [
+ ('python', {'module': py_module}),
+ ]
+ suite = loader.suiteClass()
+ feature = ModuleAvailableFeature(ext_module_name)
+ if feature.available():
+ scenarios.append(('C', {'module': feature.module}))
+ else:
+ # the compiled module isn't available, so we add a failing test
+ class FailWithoutFeature(TestCase):
+ def test_fail(self):
+ self.requireFeature(feature)
+ suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
+ result = multiply_tests(standard_tests, scenarios, suite)
+ return result, feature
+
+
def _rmtree_temp_dir(dirname, test_id=None):
# If LANG=C we probably have created some bogus paths
# which rmtree(unicode) will fail to delete
=== modified file 'bzrlib/tests/test__annotator.py'
--- a/bzrlib/tests/test__annotator.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__annotator.py 2009-12-22 16:47:36 +0000
@@ -28,24 +28,9 @@
def load_tests(standard_tests, module, loader):
"""Parameterize tests for all versions of groupcompress."""
- scenarios = [
- ('python', {'module': _annotator_py}),
- ]
- suite = loader.suiteClass()
- if compiled_annotator_feature.available():
- scenarios.append(('C', {'module': compiled_annotator_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_annotator_feature)
- suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
- result = tests.multiply_tests(standard_tests, scenarios, suite)
- return result
-
-
-compiled_annotator_feature = tests.ModuleAvailableFeature(
- 'bzrlib._annotator_pyx')
+ suite, _ = tests.permute_tests_for_extension(standard_tests, loader,
+ 'bzrlib._annotator_py', 'bzrlib._annotator_pyx')
+ return suite
class TestAnnotator(tests.TestCaseWithMemoryTransport):
=== renamed file 'bzrlib/tests/test_bencode.py' => 'bzrlib/tests/test__bencode.py'
--- a/bzrlib/tests/test_bencode.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__bencode.py 2009-12-23 04:19:34 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 Canonical Ltd
+# Copyright (C) 2007, 2009 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,35 +19,21 @@
from bzrlib import tests
def load_tests(standard_tests, module, loader):
- # parameterize all tests in this module
- suite = loader.suiteClass()
- import bzrlib.util._bencode_py as py_module
- scenarios = [('python', {'bencode': py_module})]
- if compiled_bencode_feature.available():
- scenarios.append(('C', {'bencode': compiled_bencode_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_bencode_feature)
- suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
- tests.multiply_tests(standard_tests, scenarios, suite)
+ suite, _ = tests.permute_tests_for_extension(standard_tests, loader,
+ 'bzrlib.util._bencode_py', 'bzrlib._bencode_pyx')
return suite
-compiled_bencode_feature = tests.ModuleAvailableFeature('bzrlib._bencode_pyx')
-
-
class TestBencodeDecode(tests.TestCase):
- bencode = None
+ module = None
def _check(self, expected, source):
- self.assertEquals(expected, self.bencode.bdecode(source))
+ self.assertEquals(expected, self.module.bdecode(source))
def _run_check_error(self, exc, bad):
"""Check that bdecoding a string raises a particular exception."""
- self.assertRaises(exc, self.bencode.bdecode, bad)
+ self.assertRaises(exc, self.module.bdecode, bad)
def test_int(self):
self._check(0, 'i0e')
@@ -78,7 +64,7 @@
self._check('1234567890', '10:1234567890')
def test_large_string(self):
- self.assertRaises(ValueError, self.bencode.bdecode, "2147483639:foo")
+ self.assertRaises(ValueError, self.module.bdecode, "2147483639:foo")
def test_malformed_string(self):
self._run_check_error(ValueError, '10:x')
@@ -133,7 +119,7 @@
self._run_check_error(ValueError, 'd432432432432432432:e')
def test_empty_string(self):
- self.assertRaises(ValueError, self.bencode.bdecode, '')
+ self.assertRaises(ValueError, self.module.bdecode, '')
def test_junk(self):
self._run_check_error(ValueError, 'i6easd')
@@ -142,7 +128,7 @@
self._run_check_error(ValueError, 'leanfdldjfh')
def test_unknown_object(self):
- self.assertRaises(ValueError, self.bencode.bdecode, 'relwjhrlewjh')
+ self.assertRaises(ValueError, self.module.bdecode, 'relwjhrlewjh')
def test_unsupported_type(self):
self._run_check_error(TypeError, float(1.5))
@@ -152,15 +138,15 @@
self._run_check_error(TypeError, u"ie")
def test_decoder_type_error(self):
- self.assertRaises(TypeError, self.bencode.bdecode, 1)
+ self.assertRaises(TypeError, self.module.bdecode, 1)
class TestBencodeEncode(tests.TestCase):
- bencode = None
+ module = None
def _check(self, expected, source):
- self.assertEquals(expected, self.bencode.bencode(source))
+ self.assertEquals(expected, self.module.bencode(source))
def test_int(self):
self._check('i4e', 4)
@@ -192,7 +178,7 @@
for i in range(10000):
l.append([])
l = l[0]
- self.assertRaises(RuntimeError, self.bencode.bencode,
+ self.assertRaises(RuntimeError, self.module.bencode,
top)
def test_dict(self):
@@ -207,14 +193,14 @@
for i in range(10000):
d[''] = {}
d = d['']
- self.assertRaises(RuntimeError, self.bencode.bencode,
+ self.assertRaises(RuntimeError, self.module.bencode,
top)
def test_bencached(self):
- self._check('i3e', self.bencode.Bencached(self.bencode.bencode(3)))
+ self._check('i3e', self.module.Bencached(self.module.bencode(3)))
def test_invalid_dict(self):
- self.assertRaises(TypeError, self.bencode.bencode, {1:"foo"})
+ self.assertRaises(TypeError, self.module.bencode, {1:"foo"})
def test_bool(self):
self._check('i1e', True)
=== modified file 'bzrlib/tests/test__chk_map.py'
--- a/bzrlib/tests/test__chk_map.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__chk_map.py 2009-12-22 16:28:47 +0000
@@ -25,25 +25,11 @@
def load_tests(standard_tests, module, loader):
- # parameterize all tests in this module
- suite = loader.suiteClass()
- import bzrlib._chk_map_py as py_module
- scenarios = [('python', {'module': py_module})]
- if compiled_chkmap_feature.available():
- scenarios.append(('C', {'module': compiled_chkmap_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_chkmap_feature)
- suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
- tests.multiply_tests(standard_tests, scenarios, suite)
+ suite, _ = tests.permute_tests_for_extension(standard_tests, loader,
+ 'bzrlib._chk_map_py', 'bzrlib._chk_map_pyx')
return suite
-compiled_chkmap_feature = tests.ModuleAvailableFeature('bzrlib._chk_map_pyx')
-
-
class TestSearchKeys(tests.TestCase):
module = None # Filled in by test parameterization
=== modified file 'bzrlib/tests/test__chunks_to_lines.py'
--- a/bzrlib/tests/test__chunks_to_lines.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__chunks_to_lines.py 2009-12-22 17:14:45 +0000
@@ -21,21 +21,14 @@
def load_tests(standard_tests, module, loader):
- # parameterize all tests in this module
- import bzrlib._chunks_to_lines_py as py_module
- scenarios = [('python', {'module': py_module})]
- if compiled_chunkstolines_feature.available():
- scenarios.append(('C', {'module':
- compiled_chunkstolines_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_chunkstolines_feature)
- standard_tests.addTest(FailWithoutFeature("test_fail"))
- return tests.multiply_tests(standard_tests, scenarios, loader.suiteClass())
-
-
+ suite, _ = tests.permute_tests_for_extension(
+ standard_tests, loader, 'bzrlib._chunks_to_lines_py',
+ 'bzrlib._chunks_to_lines_pyx')
+ return suite
+
+# test_osutils depends on this feature being around. We can't just use the one
+# generated by load_tests, because if we only load osutils but not this module,
+# then that code never gets run
compiled_chunkstolines_feature = tests.ModuleAvailableFeature(
'bzrlib._chunks_to_lines_pyx')
=== modified file 'bzrlib/tests/test__rio.py'
--- a/bzrlib/tests/test__rio.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__rio.py 2009-12-22 16:28:47 +0000
@@ -23,25 +23,11 @@
def load_tests(standard_tests, module, loader):
- # parameterize all tests in this module
- suite = loader.suiteClass()
- import bzrlib._rio_py as py_module
- scenarios = [('python', {'module': py_module})]
- if compiled_rio_feature.available():
- scenarios.append(('C', {'module': compiled_rio_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_rio_feature)
- suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
- tests.multiply_tests(standard_tests, scenarios, suite)
+ suite, _ = tests.permute_tests_for_extension(standard_tests, loader,
+ 'bzrlib._rio_py', 'bzrlib._rio_pyx')
return suite
-compiled_rio_feature = tests.ModuleAvailableFeature('bzrlib._rio_pyx')
-
-
class TestValidTag(tests.TestCase):
module = None # Filled in by test parameterization
=== modified file 'bzrlib/tests/test__static_tuple.py'
--- a/bzrlib/tests/test__static_tuple.py 2009-12-22 15:50:40 +0000
+++ b/bzrlib/tests/test__static_tuple.py 2009-12-22 16:28:47 +0000
@@ -32,25 +32,11 @@
def load_tests(standard_tests, module, loader):
"""Parameterize tests for all versions of groupcompress."""
- scenarios = [
- ('python', {'module': _static_tuple_py}),
- ]
- suite = loader.suiteClass()
- if compiled_static_tuple_feature.available():
- scenarios.append(('C', {'module':
- compiled_static_tuple_feature.module}))
- else:
- # the compiled module isn't available, so we add a failing test
- class FailWithoutFeature(tests.TestCase):
- def test_fail(self):
- self.requireFeature(compiled_static_tuple_feature)
- suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
- result = tests.multiply_tests(standard_tests, scenarios, suite)
- return result
-
-
-compiled_static_tuple_feature = tests.ModuleAvailableFeature(
- 'bzrlib._static_tuple_c')
+ global compiled_static_tuple_feature
+ suite, compiled_static_tuple_feature = tests.permute_tests_for_extension(
+ standard_tests, loader, 'bzrlib._static_tuple_py',
+ 'bzrlib._static_tuple_c')
+ return suite
class _Meliae(tests.Feature):
=== modified file 'doc/developers/testing.txt'
--- a/doc/developers/testing.txt 2009-12-22 06:07:26 +0000
+++ b/doc/developers/testing.txt 2009-12-23 05:04:12 +0000
@@ -173,15 +173,21 @@
Per-implementation tests are tests that are defined once and then run
against multiple implementations of an interface. For example,
-``test_transport_implementations.py`` defines tests that all Transport
-implementations (local filesystem, HTTP, and so on) must pass.
-
-They are found in ``bzrlib/tests/*_implementations/test_*.py``,
-``bzrlib/tests/per_*/*.py``, and
-``bzrlib/tests/test_*_implementations.py``.
+``per_transport.py`` defines tests that all Transport implementations
+(local filesystem, HTTP, and so on) must pass. They are found in
+``bzrlib/tests/per_*/*.py``, and ``bzrlib/tests/per_*.py``.
These are really a sub-category of unit tests, but an important one.
+Along the same lines are tests for extension modules. We generally have
+both a pure-python and a compiled implementation for each module. As such,
+we want to run the same tests against both implementations. These can
+generally be found in ``bzrlib/tests/*__*.py`` since extension modules are
+usually prefixed with an underscore. Since there are only two
+implementations, we have a helper function
+``bzrlib.tests.permute_for_extension``, which can simplify the
+``load_tests`` implementation.
+
Doctests
~~~~~~~~
More information about the bazaar-commits
mailing list