/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: Marius Kruger
  • Date: 2010-07-10 21:28:56 UTC
  • mto: (5384.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5385.
  • Revision ID: marius.kruger@enerweb.co.za-20100710212856-uq4ji3go0u5se7hx
* Update documentation
* add NEWS

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
16
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
22
 
25
23
# Mark this python module as being part of the implementation
26
24
# of unittest: this gives us better tracebacks where the last
29
27
 
30
28
 
31
29
class LogCollector(logging.Handler):
32
 
 
33
30
    def __init__(self):
34
31
        logging.Handler.__init__(self)
35
 
        self.records = []
36
 
 
 
32
        self.records=[]
37
33
    def emit(self, record):
38
34
        self.records.append(record.getMessage())
39
35
 
41
37
def makeCollectingLogger():
42
38
    """I make a logger instance that collects its logs for programmatic analysis
43
39
    -> (logger, collector)"""
44
 
    logger = logging.Logger("collector")
45
 
    handler = LogCollector()
 
40
    logger=logging.Logger("collector")
 
41
    handler=LogCollector()
46
42
    handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
47
43
    logger.addHandler(handler)
48
44
    return logger, handler
51
47
def visitTests(suite, visitor):
52
48
    """A foreign method for visiting the tests in a test suite."""
53
49
    for test in suite._tests:
54
 
        # Abusing types to avoid monkey patching unittest.TestCase.
 
50
        #Abusing types to avoid monkey patching unittest.TestCase.
55
51
        # Maybe that would be better?
56
52
        try:
57
53
            test.visit(visitor)
62
58
                visitor.visitSuite(test)
63
59
                visitTests(test, visitor)
64
60
            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)
 
61
                print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
85
62
 
86
63
 
87
64
class TestSuite(unittest.TestSuite):
100
77
        tests = list(self)
101
78
        tests.reverse()
102
79
        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
80
        while tests:
108
81
            if result.shouldStop:
109
82
                self._tests = reversed(tests)
110
83
                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
 
84
            tests.pop().run(result)
122
85
        return result
123
86
 
124
87
 
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
 
 
131
88
class TestLoader(unittest.TestLoader):
132
89
    """Custom TestLoader to extend the stock python one."""
133
90
 
149
106
 
150
107
    def loadTestsFromModuleName(self, name):
151
108
        result = self.suiteClass()
152
 
        module = pyutils.get_named_object(name)
 
109
        module = _load_module_by_name(name)
153
110
 
154
111
        result.addTests(self.loadTestsFromModule(module))
155
112
        return result
156
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
 
157
145
    def getTestCaseNames(self, test_case_class):
158
146
        test_fn_names = self.test_func_names.get(test_case_class, None)
159
147
        if test_fn_names is not None:
185
173
            return self.suiteClass()
186
174
 
187
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
 
188
187
class TestVisitor(object):
189
188
    """A visitor for Tests"""
190
 
 
191
189
    def visitSuite(self, aTestSuite):
192
190
        pass
193
 
 
194
191
    def visitCase(self, aTestCase):
195
192
        pass