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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
from .. import pyutils
25
# Mark this python module as being part of the implementation
26
# of unittest: this gives us better tracebacks where the last
27
# shown frame is the test code, not our assertXYZ.
31
24
class LogCollector(logging.Handler):
33
25
def __init__(self):
34
26
logging.Handler.__init__(self)
37
28
def emit(self, record):
38
29
self.records.append(record.getMessage())
62
53
visitor.visitSuite(test)
63
54
visitTests(test, visitor)
65
print("unvisitable non-unittest.TestCase element %r (%r)" % (
66
test, test.__class__))
69
class FailedCollectionCase(unittest.TestCase):
70
"""Pseudo-test to run and report failure if given case was uncollected"""
72
def __init__(self, case):
73
super(FailedCollectionCase, self).__init__("fail_uncollected")
74
# GZ 2011-09-16: Maybe catch errors from id() method as cases may be
75
# in a bit of a funny state by now.
76
self._problem_case_id = case.id()
79
if self._problem_case_id[-1:] == ")":
80
return self._problem_case_id[:-1] + ",uncollected)"
81
return self._problem_case_id + "(uncollected)"
83
def fail_uncollected(self):
84
self.fail("Uncollected test case: " + self._problem_case_id)
56
print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
87
59
class TestSuite(unittest.TestSuite):
88
60
"""I am an extended TestSuite with a visitor interface.
95
67
visitor.visitSuite(self)
96
68
visitTests(self, visitor)
98
def run(self, result):
99
"""Run the tests in the suite, discarding references after running."""
104
count_stored_tests = getattr(result, "_count_stored_tests", int)
105
from breezy.tests import selftest_debug_flags
106
notify = "uncollected_cases" in selftest_debug_flags
108
if result.shouldStop:
109
self._tests = reversed(tests)
111
case = _run_and_collect_case(tests.pop(), result)()
112
new_stored_count = count_stored_tests()
113
if case is not None and isinstance(case, unittest.TestCase):
114
if stored_count == new_stored_count and notify:
115
# Testcase didn't fail, but somehow is still alive
116
FailedCollectionCase(case).run(result)
117
# Adding a new failure so need to reupdate the count
118
new_stored_count = count_stored_tests()
119
# GZ 2011-09-16: Previously zombied the case at this point by
120
# clearing the dict as fallback, skip for now.
121
stored_count = new_stored_count
125
def _run_and_collect_case(case, res):
126
"""Run test case against result and use weakref to drop the refcount"""
128
return weakref.ref(case)
131
71
class TestLoader(unittest.TestLoader):
132
"""Custom TestLoader to extend the stock python one."""
72
"""Custome TestLoader to set the right TestSuite class."""
134
73
suiteClass = TestSuite
135
# Memoize test names by test class dict
138
def loadTestsFromModuleNames(self, names):
139
"""use a custom means to load tests from modules.
141
There is an undesirable glitch in the python TestLoader where a
142
import error is ignore. We think this can be solved by ensuring the
143
requested name is resolvable, if its not raising the original error.
145
result = self.suiteClass()
147
result.addTests(self.loadTestsFromModuleName(name))
150
def loadTestsFromModuleName(self, name):
151
result = self.suiteClass()
152
module = pyutils.get_named_object(name)
154
result.addTests(self.loadTestsFromModule(module))
157
def getTestCaseNames(self, test_case_class):
158
test_fn_names = self.test_func_names.get(test_case_class, None)
159
if test_fn_names is not None:
160
# We already know them
163
test_fn_names = unittest.TestLoader.getTestCaseNames(self,
165
self.test_func_names[test_case_class] = test_fn_names
169
class FilteredByModuleTestLoader(TestLoader):
170
"""A test loader that import only the needed modules."""
172
def __init__(self, needs_module):
175
:param needs_module: a callable taking a module name as a
176
parameter returing True if the module should be loaded.
178
TestLoader.__init__(self)
179
self.needs_module = needs_module
181
def loadTestsFromModuleName(self, name):
182
if self.needs_module(name):
183
return TestLoader.loadTestsFromModuleName(self, name)
185
return self.suiteClass()
188
75
class TestVisitor(object):
189
76
"""A visitor for Tests"""
191
77
def visitSuite(self, aTestSuite):
194
79
def visitCase(self, aTestCase):