~jfb-tempo-consulting/unifield-wm/sync-env-py3

« back to all changes in this revision

Viewing changes to unittest27/suite.py

  • Committer: Samus CTO
  • Date: 2012-09-05 10:40:27 UTC
  • Revision ID: cto@openerp.com-20120905104027-geoynct7122bnoig
[IMPORT] imported unittest from Python 2.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""TestSuite"""
 
2
 
 
3
import sys
 
4
 
 
5
from . import case
 
6
from . import util
 
7
 
 
8
__unittest = True
 
9
 
 
10
 
 
11
def _call_if_exists(parent, attr):
 
12
    func = getattr(parent, attr, lambda: None)
 
13
    func()
 
14
 
 
15
 
 
16
class BaseTestSuite(object):
 
17
    """A simple test suite that doesn't provide class or module shared fixtures.
 
18
    """
 
19
    def __init__(self, tests=()):
 
20
        self._tests = []
 
21
        self.addTests(tests)
 
22
 
 
23
    def __repr__(self):
 
24
        return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
 
25
 
 
26
    def __eq__(self, other):
 
27
        if not isinstance(other, self.__class__):
 
28
            return NotImplemented
 
29
        return list(self) == list(other)
 
30
 
 
31
    def __ne__(self, other):
 
32
        return not self == other
 
33
 
 
34
    # Can't guarantee hash invariant, so flag as unhashable
 
35
    __hash__ = None
 
36
 
 
37
    def __iter__(self):
 
38
        return iter(self._tests)
 
39
 
 
40
    def countTestCases(self):
 
41
        cases = 0
 
42
        for test in self:
 
43
            cases += test.countTestCases()
 
44
        return cases
 
45
 
 
46
    def addTest(self, test):
 
47
        # sanity checks
 
48
        if not hasattr(test, '__call__'):
 
49
            raise TypeError("{} is not callable".format(repr(test)))
 
50
        if isinstance(test, type) and issubclass(test,
 
51
                                                 (case.TestCase, TestSuite)):
 
52
            raise TypeError("TestCases and TestSuites must be instantiated "
 
53
                            "before passing them to addTest()")
 
54
        self._tests.append(test)
 
55
 
 
56
    def addTests(self, tests):
 
57
        if isinstance(tests, basestring):
 
58
            raise TypeError("tests must be an iterable of tests, not a string")
 
59
        for test in tests:
 
60
            self.addTest(test)
 
61
 
 
62
    def run(self, result):
 
63
        for test in self:
 
64
            if result.shouldStop:
 
65
                break
 
66
            test(result)
 
67
        return result
 
68
 
 
69
    def __call__(self, *args, **kwds):
 
70
        return self.run(*args, **kwds)
 
71
 
 
72
    def debug(self):
 
73
        """Run the tests without collecting errors in a TestResult"""
 
74
        for test in self:
 
75
            test.debug()
 
76
 
 
77
 
 
78
class TestSuite(BaseTestSuite):
 
79
    """A test suite is a composite test consisting of a number of TestCases.
 
80
 
 
81
    For use, create an instance of TestSuite, then add test case instances.
 
82
    When all tests have been added, the suite can be passed to a test
 
83
    runner, such as TextTestRunner. It will run the individual test cases
 
84
    in the order in which they were added, aggregating the results. When
 
85
    subclassing, do not forget to call the base class constructor.
 
86
    """
 
87
 
 
88
    def run(self, result, debug=False):
 
89
        topLevel = False
 
90
        if getattr(result, '_testRunEntered', False) is False:
 
91
            result._testRunEntered = topLevel = True
 
92
 
 
93
        for test in self:
 
94
            if result.shouldStop:
 
95
                break
 
96
 
 
97
            if _isnotsuite(test):
 
98
                self._tearDownPreviousClass(test, result)
 
99
                self._handleModuleFixture(test, result)
 
100
                self._handleClassSetUp(test, result)
 
101
                result._previousTestClass = test.__class__
 
102
 
 
103
                if (getattr(test.__class__, '_classSetupFailed', False) or
 
104
                    getattr(result, '_moduleSetUpFailed', False)):
 
105
                    continue
 
106
 
 
107
            if not debug:
 
108
                test(result)
 
109
            else:
 
110
                test.debug()
 
111
 
 
112
        if topLevel:
 
113
            self._tearDownPreviousClass(None, result)
 
114
            self._handleModuleTearDown(result)
 
115
            result._testRunEntered = False
 
116
        return result
 
117
 
 
118
    def debug(self):
 
119
        """Run the tests without collecting errors in a TestResult"""
 
120
        debug = _DebugResult()
 
121
        self.run(debug, True)
 
122
 
 
123
    ################################
 
124
 
 
125
    def _handleClassSetUp(self, test, result):
 
126
        previousClass = getattr(result, '_previousTestClass', None)
 
127
        currentClass = test.__class__
 
128
        if currentClass == previousClass:
 
129
            return
 
130
        if result._moduleSetUpFailed:
 
131
            return
 
132
        if getattr(currentClass, "__unittest_skip__", False):
 
133
            return
 
134
 
 
135
        try:
 
136
            currentClass._classSetupFailed = False
 
137
        except TypeError:
 
138
            # test may actually be a function
 
139
            # so its class will be a builtin-type
 
140
            pass
 
141
 
 
142
        setUpClass = getattr(currentClass, 'setUpClass', None)
 
143
        if setUpClass is not None:
 
144
            _call_if_exists(result, '_setupStdout')
 
145
            try:
 
146
                setUpClass()
 
147
            except Exception as e:
 
148
                if isinstance(result, _DebugResult):
 
149
                    raise
 
150
                currentClass._classSetupFailed = True
 
151
                className = util.strclass(currentClass)
 
152
                errorName = 'setUpClass (%s)' % className
 
153
                self._addClassOrModuleLevelException(result, e, errorName)
 
154
            finally:
 
155
                _call_if_exists(result, '_restoreStdout')
 
156
 
 
157
    def _get_previous_module(self, result):
 
158
        previousModule = None
 
159
        previousClass = getattr(result, '_previousTestClass', None)
 
160
        if previousClass is not None:
 
161
            previousModule = previousClass.__module__
 
162
        return previousModule
 
163
 
 
164
 
 
165
    def _handleModuleFixture(self, test, result):
 
166
        previousModule = self._get_previous_module(result)
 
167
        currentModule = test.__class__.__module__
 
168
        if currentModule == previousModule:
 
169
            return
 
170
 
 
171
        self._handleModuleTearDown(result)
 
172
 
 
173
        result._moduleSetUpFailed = False
 
174
        try:
 
175
            module = sys.modules[currentModule]
 
176
        except KeyError:
 
177
            return
 
178
        setUpModule = getattr(module, 'setUpModule', None)
 
179
        if setUpModule is not None:
 
180
            _call_if_exists(result, '_setupStdout')
 
181
            try:
 
182
                setUpModule()
 
183
            except Exception, e:
 
184
                if isinstance(result, _DebugResult):
 
185
                    raise
 
186
                result._moduleSetUpFailed = True
 
187
                errorName = 'setUpModule (%s)' % currentModule
 
188
                self._addClassOrModuleLevelException(result, e, errorName)
 
189
            finally:
 
190
                _call_if_exists(result, '_restoreStdout')
 
191
 
 
192
    def _addClassOrModuleLevelException(self, result, exception, errorName):
 
193
        error = _ErrorHolder(errorName)
 
194
        addSkip = getattr(result, 'addSkip', None)
 
195
        if addSkip is not None and isinstance(exception, case.SkipTest):
 
196
            addSkip(error, str(exception))
 
197
        else:
 
198
            result.addError(error, sys.exc_info())
 
199
 
 
200
    def _handleModuleTearDown(self, result):
 
201
        previousModule = self._get_previous_module(result)
 
202
        if previousModule is None:
 
203
            return
 
204
        if result._moduleSetUpFailed:
 
205
            return
 
206
 
 
207
        try:
 
208
            module = sys.modules[previousModule]
 
209
        except KeyError:
 
210
            return
 
211
 
 
212
        tearDownModule = getattr(module, 'tearDownModule', None)
 
213
        if tearDownModule is not None:
 
214
            _call_if_exists(result, '_setupStdout')
 
215
            try:
 
216
                tearDownModule()
 
217
            except Exception as e:
 
218
                if isinstance(result, _DebugResult):
 
219
                    raise
 
220
                errorName = 'tearDownModule (%s)' % previousModule
 
221
                self._addClassOrModuleLevelException(result, e, errorName)
 
222
            finally:
 
223
                _call_if_exists(result, '_restoreStdout')
 
224
 
 
225
    def _tearDownPreviousClass(self, test, result):
 
226
        previousClass = getattr(result, '_previousTestClass', None)
 
227
        currentClass = test.__class__
 
228
        if currentClass == previousClass:
 
229
            return
 
230
        if getattr(previousClass, '_classSetupFailed', False):
 
231
            return
 
232
        if getattr(result, '_moduleSetUpFailed', False):
 
233
            return
 
234
        if getattr(previousClass, "__unittest_skip__", False):
 
235
            return
 
236
 
 
237
        tearDownClass = getattr(previousClass, 'tearDownClass', None)
 
238
        if tearDownClass is not None:
 
239
            _call_if_exists(result, '_setupStdout')
 
240
            try:
 
241
                tearDownClass()
 
242
            except Exception, e:
 
243
                if isinstance(result, _DebugResult):
 
244
                    raise
 
245
                className = util.strclass(previousClass)
 
246
                errorName = 'tearDownClass (%s)' % className
 
247
                self._addClassOrModuleLevelException(result, e, errorName)
 
248
            finally:
 
249
                _call_if_exists(result, '_restoreStdout')
 
250
 
 
251
 
 
252
class _ErrorHolder(object):
 
253
    """
 
254
    Placeholder for a TestCase inside a result. As far as a TestResult
 
255
    is concerned, this looks exactly like a unit test. Used to insert
 
256
    arbitrary errors into a test suite run.
 
257
    """
 
258
    # Inspired by the ErrorHolder from Twisted:
 
259
    # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
 
260
 
 
261
    # attribute used by TestResult._exc_info_to_string
 
262
    failureException = None
 
263
 
 
264
    def __init__(self, description):
 
265
        self.description = description
 
266
 
 
267
    def id(self):
 
268
        return self.description
 
269
 
 
270
    def shortDescription(self):
 
271
        return None
 
272
 
 
273
    def __repr__(self):
 
274
        return "<ErrorHolder description=%r>" % (self.description,)
 
275
 
 
276
    def __str__(self):
 
277
        return self.id()
 
278
 
 
279
    def run(self, result):
 
280
        # could call result.addError(...) - but this test-like object
 
281
        # shouldn't be run anyway
 
282
        pass
 
283
 
 
284
    def __call__(self, result):
 
285
        return self.run(result)
 
286
 
 
287
    def countTestCases(self):
 
288
        return 0
 
289
 
 
290
def _isnotsuite(test):
 
291
    "A crude way to tell apart testcases and suites with duck-typing"
 
292
    try:
 
293
        iter(test)
 
294
    except TypeError:
 
295
        return True
 
296
    return False
 
297
 
 
298
 
 
299
class _DebugResult(object):
 
300
    "Used by the TestSuite to hold previous class when running in debug."
 
301
    _previousTestClass = None
 
302
    _moduleSetUpFailed = False
 
303
    shouldStop = False