/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: Alexander Belchenko
  • Date: 2006-06-29 08:41:31 UTC
  • mto: (1860.1.1 win32.installer)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060629084131-3ea4d44e3204e36f
win32 installer for bzr.dev.0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (c) 2004 Canonical Limited
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
13
13
#
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
17
17
#
18
18
 
 
19
import sys
19
20
import logging
20
21
import unittest
21
 
import weakref
22
 
 
23
 
from .. import pyutils
24
 
 
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.
28
 
__unittest = 1
29
22
 
30
23
 
31
24
class LogCollector(logging.Handler):
32
 
 
33
25
    def __init__(self):
34
26
        logging.Handler.__init__(self)
35
 
        self.records = []
36
 
 
 
27
        self.records=[]
37
28
    def emit(self, record):
38
29
        self.records.append(record.getMessage())
39
30
 
41
32
def makeCollectingLogger():
42
33
    """I make a logger instance that collects its logs for programmatic analysis
43
34
    -> (logger, collector)"""
44
 
    logger = logging.Logger("collector")
45
 
    handler = LogCollector()
 
35
    logger=logging.Logger("collector")
 
36
    handler=LogCollector()
46
37
    handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
47
38
    logger.addHandler(handler)
48
39
    return logger, handler
51
42
def visitTests(suite, visitor):
52
43
    """A foreign method for visiting the tests in a test suite."""
53
44
    for test in suite._tests:
54
 
        # Abusing types to avoid monkey patching unittest.TestCase.
 
45
        #Abusing types to avoid monkey patching unittest.TestCase. 
55
46
        # Maybe that would be better?
56
47
        try:
57
48
            test.visit(visitor)
62
53
                visitor.visitSuite(test)
63
54
                visitTests(test, visitor)
64
55
            else:
65
 
                print("unvisitable non-unittest.TestCase element %r (%r)" % (
66
 
                    test, test.__class__))
67
 
 
68
 
 
69
 
class FailedCollectionCase(unittest.TestCase):
70
 
    """Pseudo-test to run and report failure if given case was uncollected"""
71
 
 
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()
77
 
 
78
 
    def id(self):
79
 
        if self._problem_case_id[-1:] == ")":
80
 
            return self._problem_case_id[:-1] + ",uncollected)"
81
 
        return self._problem_case_id + "(uncollected)"
82
 
 
83
 
    def fail_uncollected(self):
84
 
        self.fail("Uncollected test case: " + self._problem_case_id)
85
 
 
 
56
                print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
 
57
    
86
58
 
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)
97
69
 
98
 
    def run(self, result):
99
 
        """Run the tests in the suite, discarding references after running."""
100
 
        tests = list(self)
101
 
        tests.reverse()
102
 
        self._tests = []
103
 
        stored_count = 0
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
107
 
        while tests:
108
 
            if result.shouldStop:
109
 
                self._tests = reversed(tests)
110
 
                break
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
122
 
        return result
123
 
 
124
 
 
125
 
def _run_and_collect_case(case, res):
126
 
    """Run test case against result and use weakref to drop the refcount"""
127
 
    case.run(res)
128
 
    return weakref.ref(case)
129
 
 
130
70
 
131
71
class TestLoader(unittest.TestLoader):
132
 
    """Custom TestLoader to extend the stock python one."""
133
 
 
 
72
    """Custom  TestLoader to address some quirks in the stock python one."""
134
73
    suiteClass = TestSuite
135
 
    # Memoize test names by test class dict
136
 
    test_func_names = {}
137
74
 
138
75
    def loadTestsFromModuleNames(self, names):
139
76
        """use a custom means to load tests from modules.
140
77
 
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
 
78
        There is an undesirable glitch in the python TestLoader where a 
 
79
        import error is ignore. We think this can be solved by ensuring the 
143
80
        requested name is resolvable, if its not raising the original error.
144
81
        """
145
82
        result = self.suiteClass()
146
83
        for name in names:
147
 
            result.addTests(self.loadTestsFromModuleName(name))
148
 
        return result
149
 
 
150
 
    def loadTestsFromModuleName(self, name):
151
 
        result = self.suiteClass()
152
 
        module = pyutils.get_named_object(name)
153
 
 
154
 
        result.addTests(self.loadTestsFromModule(module))
155
 
        return result
156
 
 
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
161
 
            return test_fn_names
162
 
 
163
 
        test_fn_names = unittest.TestLoader.getTestCaseNames(self,
164
 
                                                             test_case_class)
165
 
        self.test_func_names[test_case_class] = test_fn_names
166
 
        return test_fn_names
167
 
 
168
 
 
169
 
class FilteredByModuleTestLoader(TestLoader):
170
 
    """A test loader that import only the needed modules."""
171
 
 
172
 
    def __init__(self, needs_module):
173
 
        """Constructor.
174
 
 
175
 
        :param needs_module: a callable taking a module name as a
176
 
            parameter returing True if the module should be loaded.
177
 
        """
178
 
        TestLoader.__init__(self)
179
 
        self.needs_module = needs_module
180
 
 
181
 
    def loadTestsFromModuleName(self, name):
182
 
        if self.needs_module(name):
183
 
            return TestLoader.loadTestsFromModuleName(self, name)
184
 
        else:
185
 
            return self.suiteClass()
 
84
            _load_module_by_name(name)
 
85
            result.addTests(self.loadTestsFromName(name))
 
86
        return result
 
87
 
 
88
 
 
89
def _load_module_by_name(mod_name):
 
90
    parts = mod_name.split('.')
 
91
    module = __import__(mod_name)
 
92
    del parts[0]
 
93
    # for historical reasons python returns the top-level module even though
 
94
    # it loads the submodule; we need to walk down to get the one we want.
 
95
    while parts:
 
96
        module = getattr(module, parts.pop(0))
 
97
    return module
186
98
 
187
99
 
188
100
class TestVisitor(object):
189
101
    """A visitor for Tests"""
190
 
 
191
102
    def visitSuite(self, aTestSuite):
192
103
        pass
193
 
 
194
104
    def visitCase(self, aTestCase):
195
105
        pass