1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
# Author: Robert Collins <robert.collins@canonical.com>
4
4
# This program is free software; you can redistribute it and/or modify
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
from bzrlib import pyutils
23
26
# Mark this python module as being part of the implementation
24
27
# of unittest: this gives us better tracebacks where the last
47
52
def visitTests(suite, visitor):
48
53
"""A foreign method for visiting the tests in a test suite."""
49
54
for test in suite._tests:
50
#Abusing types to avoid monkey patching unittest.TestCase.
55
#Abusing types to avoid monkey patching unittest.TestCase.
51
56
# Maybe that would be better?
53
58
test.visit(visitor)
58
63
visitor.visitSuite(test)
59
64
visitTests(test, visitor)
61
print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
66
print "unvisitable non-unittest.TestCase element %r (%r)" % (
70
class FailedCollectionCase(unittest.TestCase):
71
"""Pseudo-test to run and report failure if given case was uncollected"""
73
def __init__(self, case):
74
super(FailedCollectionCase, self).__init__("fail_uncollected")
75
# GZ 2011-09-16: Maybe catch errors from id() method as cases may be
76
# in a bit of a funny state by now.
77
self._problem_case_id = case.id()
80
if self._problem_case_id[-1:] == ")":
81
return self._problem_case_id[:-1] + ",uncollected)"
82
return self._problem_case_id + "(uncollected)"
84
def fail_uncollected(self):
85
self.fail("Uncollected test case: " + self._problem_case_id)
64
88
class TestSuite(unittest.TestSuite):
65
89
"""I am an extended TestSuite with a visitor interface.
72
96
visitor.visitSuite(self)
73
97
visitTests(self, visitor)
99
def run(self, result):
100
"""Run the tests in the suite, discarding references after running."""
105
count_stored_tests = getattr(result, "_count_stored_tests", int)
106
from bzrlib.tests import selftest_debug_flags
107
notify = "uncollected_cases" in selftest_debug_flags
109
if result.shouldStop:
110
self._tests = reversed(tests)
112
case = _run_and_collect_case(tests.pop(), result)()
113
new_stored_count = count_stored_tests()
114
if case is not None and isinstance(case, unittest.TestCase):
115
if stored_count == new_stored_count and notify:
116
# Testcase didn't fail, but somehow is still alive
117
FailedCollectionCase(case).run(result)
118
# Adding a new failure so need to reupdate the count
119
new_stored_count = count_stored_tests()
120
# GZ 2011-09-16: Previously zombied the case at this point by
121
# clearing the dict as fallback, skip for now.
122
stored_count = new_stored_count
126
def _run_and_collect_case(case, res):
127
"""Run test case against result and use weakref to drop the refcount"""
129
return weakref.ref(case)
76
132
class TestLoader(unittest.TestLoader):
77
133
"""Custom TestLoader to extend the stock python one."""
83
139
def loadTestsFromModuleNames(self, names):
84
140
"""use a custom means to load tests from modules.
86
There is an undesirable glitch in the python TestLoader where a
87
import error is ignore. We think this can be solved by ensuring the
142
There is an undesirable glitch in the python TestLoader where a
143
import error is ignore. We think this can be solved by ensuring the
88
144
requested name is resolvable, if its not raising the original error.
90
146
result = self.suiteClass()
95
151
def loadTestsFromModuleName(self, name):
96
152
result = self.suiteClass()
97
module = _load_module_by_name(name)
153
module = pyutils.get_named_object(name)
99
155
result.addTests(self.loadTestsFromModule(module))
107
163
regular python loadTestsFromModule.
109
165
If a load_tests attribute is found, it is called and the result is
112
168
load_tests should be defined like so:
113
169
>>> def load_tests(standard_tests, module, loader):
123
179
>>> result.addTests([test, test])
124
180
>>> return result
126
basic_tests = super(TestLoader, self).loadTestsFromModule(module)
182
if sys.version_info < (2, 7):
183
basic_tests = super(TestLoader, self).loadTestsFromModule(module)
185
# GZ 2010-07-19: Python 2.7 unittest also uses load_tests but with
186
# a different and incompatible signature
187
basic_tests = super(TestLoader, self).loadTestsFromModule(module,
188
use_load_tests=False)
127
189
load_tests = getattr(module, "load_tests", None)
128
190
if load_tests is not None:
129
191
return load_tests(basic_tests, module, self)
161
223
return self.suiteClass()
164
def _load_module_by_name(mod_name):
165
parts = mod_name.split('.')
166
module = __import__(mod_name)
168
# for historical reasons python returns the top-level module even though
169
# it loads the submodule; we need to walk down to get the one we want.
171
module = getattr(module, parts.pop(0))
175
226
class TestVisitor(object):
176
227
"""A visitor for Tests"""
177
229
def visitSuite(self, aTestSuite):
179
232
def visitCase(self, aTestCase):