/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/selftest/TestUtil.py

  • Committer: Robert Collins
  • Date: 2005-10-19 10:11:57 UTC
  • mfrom: (1185.16.78)
  • mto: This revision was merged to the branch mainline in revision 1470.
  • Revision ID: robertc@robertcollins.net-20051019101157-17438d311e746b4f
mergeĀ fromĀ upstream

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
    """Custome TestLoader to set the right TestSuite class."""
134
73
    suiteClass = TestSuite
135
 
    # Memoize test names by test class dict
136
 
    test_func_names = {}
137
 
 
138
 
    def loadTestsFromModuleNames(self, names):
139
 
        """use a custom means to load tests from modules.
140
 
 
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.
144
 
        """
145
 
        result = self.suiteClass()
146
 
        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()
186
 
 
187
74
 
188
75
class TestVisitor(object):
189
76
    """A visitor for Tests"""
190
 
 
191
77
    def visitSuite(self, aTestSuite):
192
78
        pass
193
 
 
194
79
    def visitCase(self, aTestCase):
195
80
        pass