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 .. import pyutils
26
# Mark this python module as being part of the implementation
27
# of unittest: this gives us better tracebacks where the last
28
# shown frame is the test code, not our assertXYZ.
24
32
class LogCollector(logging.Handler):
25
34
def __init__(self):
26
35
logging.Handler.__init__(self)
28
38
def emit(self, record):
29
39
self.records.append(record.getMessage())
53
63
visitor.visitSuite(test)
54
64
visitTests(test, visitor)
56
print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
66
print("unvisitable non-unittest.TestCase element %r (%r)" % (
67
test, test.__class__))
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)
59
88
class TestSuite(unittest.TestSuite):
60
89
"""I am an extended TestSuite with a visitor interface.
67
96
visitor.visitSuite(self)
68
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 breezy.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)
71
132
class TestLoader(unittest.TestLoader):
72
"""Custome TestLoader to set the right TestSuite class."""
133
"""Custom TestLoader to extend the stock python one."""
73
135
suiteClass = TestSuite
136
# Memoize test names by test class dict
139
def loadTestsFromModuleNames(self, names):
140
"""use a custom means to load tests from modules.
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
144
requested name is resolvable, if its not raising the original error.
146
result = self.suiteClass()
148
result.addTests(self.loadTestsFromModuleName(name))
151
def loadTestsFromModuleName(self, name):
152
result = self.suiteClass()
153
module = pyutils.get_named_object(name)
155
result.addTests(self.loadTestsFromModule(module))
158
def getTestCaseNames(self, test_case_class):
159
test_fn_names = self.test_func_names.get(test_case_class, None)
160
if test_fn_names is not None:
161
# We already know them
164
test_fn_names = unittest.TestLoader.getTestCaseNames(self,
166
self.test_func_names[test_case_class] = test_fn_names
170
class FilteredByModuleTestLoader(TestLoader):
171
"""A test loader that import only the needed modules."""
173
def __init__(self, needs_module):
176
:param needs_module: a callable taking a module name as a
177
parameter returing True if the module should be loaded.
179
TestLoader.__init__(self)
180
self.needs_module = needs_module
182
def loadTestsFromModuleName(self, name):
183
if self.needs_module(name):
184
return TestLoader.loadTestsFromModuleName(self, name)
186
return self.suiteClass()
75
189
class TestVisitor(object):
76
190
"""A visitor for Tests"""
77
192
def visitSuite(self, aTestSuite):
79
195
def visitCase(self, aTestCase):