/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/TestUtil.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#       Author: Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
19
19
import sys
20
20
import logging
21
21
import unittest
22
 
import weakref
23
 
 
24
 
from .. import pyutils
25
22
 
26
23
# Mark this python module as being part of the implementation
27
24
# of unittest: this gives us better tracebacks where the last
30
27
 
31
28
 
32
29
class LogCollector(logging.Handler):
33
 
 
34
30
    def __init__(self):
35
31
        logging.Handler.__init__(self)
36
32
        self.records=[]
37
 
 
38
33
    def emit(self, record):
39
34
        self.records.append(record.getMessage())
40
35
 
63
58
                visitor.visitSuite(test)
64
59
                visitTests(test, visitor)
65
60
            else:
66
 
                print("unvisitable non-unittest.TestCase element %r (%r)" % (
67
 
                    test, test.__class__))
68
 
 
69
 
 
70
 
class FailedCollectionCase(unittest.TestCase):
71
 
    """Pseudo-test to run and report failure if given case was uncollected"""
72
 
 
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()
78
 
 
79
 
    def id(self):
80
 
        if self._problem_case_id[-1:] == ")":
81
 
            return self._problem_case_id[:-1] + ",uncollected)"
82
 
        return self._problem_case_id + "(uncollected)"
83
 
 
84
 
    def fail_uncollected(self):
85
 
        self.fail("Uncollected test case: " + self._problem_case_id)
 
61
                print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
86
62
 
87
63
 
88
64
class TestSuite(unittest.TestSuite):
101
77
        tests = list(self)
102
78
        tests.reverse()
103
79
        self._tests = []
104
 
        stored_count = 0
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
108
80
        while tests:
109
81
            if result.shouldStop:
110
82
                self._tests = reversed(tests)
111
83
                break
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
 
84
            tests.pop().run(result)
123
85
        return result
124
86
 
125
87
 
126
 
def _run_and_collect_case(case, res):
127
 
    """Run test case against result and use weakref to drop the refcount"""
128
 
    case.run(res)
129
 
    return weakref.ref(case)
130
 
 
131
 
 
132
88
class TestLoader(unittest.TestLoader):
133
89
    """Custom TestLoader to extend the stock python one."""
134
90
 
150
106
 
151
107
    def loadTestsFromModuleName(self, name):
152
108
        result = self.suiteClass()
153
 
        module = pyutils.get_named_object(name)
 
109
        module = _load_module_by_name(name)
154
110
 
155
111
        result.addTests(self.loadTestsFromModule(module))
156
112
        return result
157
113
 
 
114
    def loadTestsFromModule(self, module):
 
115
        """Load tests from a module object.
 
116
 
 
117
        This extension of the python test loader looks for an attribute
 
118
        load_tests in the module object, and if not found falls back to the
 
119
        regular python loadTestsFromModule.
 
120
 
 
121
        If a load_tests attribute is found, it is called and the result is
 
122
        returned.
 
123
 
 
124
        load_tests should be defined like so:
 
125
        >>> def load_tests(standard_tests, module, loader):
 
126
        >>>    pass
 
127
 
 
128
        standard_tests is the tests found by the stock TestLoader in the
 
129
        module, module and loader are the module and loader instances.
 
130
 
 
131
        For instance, to run every test twice, you might do:
 
132
        >>> def load_tests(standard_tests, module, loader):
 
133
        >>>     result = loader.suiteClass()
 
134
        >>>     for test in iter_suite_tests(standard_tests):
 
135
        >>>         result.addTests([test, test])
 
136
        >>>     return result
 
137
        """
 
138
        basic_tests = super(TestLoader, self).loadTestsFromModule(module)
 
139
        load_tests = getattr(module, "load_tests", None)
 
140
        if load_tests is not None:
 
141
            return load_tests(basic_tests, module, self)
 
142
        else:
 
143
            return basic_tests
 
144
 
158
145
    def getTestCaseNames(self, test_case_class):
159
146
        test_fn_names = self.test_func_names.get(test_case_class, None)
160
147
        if test_fn_names is not None:
186
173
            return self.suiteClass()
187
174
 
188
175
 
 
176
def _load_module_by_name(mod_name):
 
177
    parts = mod_name.split('.')
 
178
    module = __import__(mod_name)
 
179
    del parts[0]
 
180
    # for historical reasons python returns the top-level module even though
 
181
    # it loads the submodule; we need to walk down to get the one we want.
 
182
    while parts:
 
183
        module = getattr(module, parts.pop(0))
 
184
    return module
 
185
 
 
186
 
189
187
class TestVisitor(object):
190
188
    """A visitor for Tests"""
191
 
 
192
189
    def visitSuite(self, aTestSuite):
193
190
        pass
194
 
 
195
191
    def visitCase(self, aTestCase):
196
192
        pass