comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/unittest/suite.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
comparison
equal deleted inserted replaced
67:0e9998148a16 68:5028fdace37b
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 _cleanup = True
20
21 def __init__(self, tests=()):
22 self._tests = []
23 self._removed_tests = 0
24 self.addTests(tests)
25
26 def __repr__(self):
27 return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
28
29 def __eq__(self, other):
30 if not isinstance(other, self.__class__):
31 return NotImplemented
32 return list(self) == list(other)
33
34 def __iter__(self):
35 return iter(self._tests)
36
37 def countTestCases(self):
38 cases = self._removed_tests
39 for test in self:
40 if test:
41 cases += test.countTestCases()
42 return cases
43
44 def addTest(self, test):
45 # sanity checks
46 if not callable(test):
47 raise TypeError("{} is not callable".format(repr(test)))
48 if isinstance(test, type) and issubclass(test,
49 (case.TestCase, TestSuite)):
50 raise TypeError("TestCases and TestSuites must be instantiated "
51 "before passing them to addTest()")
52 self._tests.append(test)
53
54 def addTests(self, tests):
55 if isinstance(tests, str):
56 raise TypeError("tests must be an iterable of tests, not a string")
57 for test in tests:
58 self.addTest(test)
59
60 def run(self, result):
61 for index, test in enumerate(self):
62 if result.shouldStop:
63 break
64 test(result)
65 if self._cleanup:
66 self._removeTestAtIndex(index)
67 return result
68
69 def _removeTestAtIndex(self, index):
70 """Stop holding a reference to the TestCase at index."""
71 try:
72 test = self._tests[index]
73 except TypeError:
74 # support for suite implementations that have overridden self._tests
75 pass
76 else:
77 # Some unittest tests add non TestCase/TestSuite objects to
78 # the suite.
79 if hasattr(test, 'countTestCases'):
80 self._removed_tests += test.countTestCases()
81 self._tests[index] = None
82
83 def __call__(self, *args, **kwds):
84 return self.run(*args, **kwds)
85
86 def debug(self):
87 """Run the tests without collecting errors in a TestResult"""
88 for test in self:
89 test.debug()
90
91
92 class TestSuite(BaseTestSuite):
93 """A test suite is a composite test consisting of a number of TestCases.
94
95 For use, create an instance of TestSuite, then add test case instances.
96 When all tests have been added, the suite can be passed to a test
97 runner, such as TextTestRunner. It will run the individual test cases
98 in the order in which they were added, aggregating the results. When
99 subclassing, do not forget to call the base class constructor.
100 """
101
102 def run(self, result, debug=False):
103 topLevel = False
104 if getattr(result, '_testRunEntered', False) is False:
105 result._testRunEntered = topLevel = True
106
107 for index, test in enumerate(self):
108 if result.shouldStop:
109 break
110
111 if _isnotsuite(test):
112 self._tearDownPreviousClass(test, result)
113 self._handleModuleFixture(test, result)
114 self._handleClassSetUp(test, result)
115 result._previousTestClass = test.__class__
116
117 if (getattr(test.__class__, '_classSetupFailed', False) or
118 getattr(result, '_moduleSetUpFailed', False)):
119 continue
120
121 if not debug:
122 test(result)
123 else:
124 test.debug()
125
126 if self._cleanup:
127 self._removeTestAtIndex(index)
128
129 if topLevel:
130 self._tearDownPreviousClass(None, result)
131 self._handleModuleTearDown(result)
132 result._testRunEntered = False
133 return result
134
135 def debug(self):
136 """Run the tests without collecting errors in a TestResult"""
137 debug = _DebugResult()
138 self.run(debug, True)
139
140 ################################
141
142 def _handleClassSetUp(self, test, result):
143 previousClass = getattr(result, '_previousTestClass', None)
144 currentClass = test.__class__
145 if currentClass == previousClass:
146 return
147 if result._moduleSetUpFailed:
148 return
149 if getattr(currentClass, "__unittest_skip__", False):
150 return
151
152 try:
153 currentClass._classSetupFailed = False
154 except TypeError:
155 # test may actually be a function
156 # so its class will be a builtin-type
157 pass
158
159 setUpClass = getattr(currentClass, 'setUpClass', None)
160 if setUpClass is not None:
161 _call_if_exists(result, '_setupStdout')
162 try:
163 setUpClass()
164 except Exception as e:
165 if isinstance(result, _DebugResult):
166 raise
167 currentClass._classSetupFailed = True
168 className = util.strclass(currentClass)
169 self._createClassOrModuleLevelException(result, e,
170 'setUpClass',
171 className)
172 finally:
173 _call_if_exists(result, '_restoreStdout')
174 if currentClass._classSetupFailed is True:
175 currentClass.doClassCleanups()
176 if len(currentClass.tearDown_exceptions) > 0:
177 for exc in currentClass.tearDown_exceptions:
178 self._createClassOrModuleLevelException(
179 result, exc[1], 'setUpClass', className,
180 info=exc)
181
182 def _get_previous_module(self, result):
183 previousModule = None
184 previousClass = getattr(result, '_previousTestClass', None)
185 if previousClass is not None:
186 previousModule = previousClass.__module__
187 return previousModule
188
189
190 def _handleModuleFixture(self, test, result):
191 previousModule = self._get_previous_module(result)
192 currentModule = test.__class__.__module__
193 if currentModule == previousModule:
194 return
195
196 self._handleModuleTearDown(result)
197
198
199 result._moduleSetUpFailed = False
200 try:
201 module = sys.modules[currentModule]
202 except KeyError:
203 return
204 setUpModule = getattr(module, 'setUpModule', None)
205 if setUpModule is not None:
206 _call_if_exists(result, '_setupStdout')
207 try:
208 setUpModule()
209 except Exception as e:
210 try:
211 case.doModuleCleanups()
212 except Exception as exc:
213 self._createClassOrModuleLevelException(result, exc,
214 'setUpModule',
215 currentModule)
216 if isinstance(result, _DebugResult):
217 raise
218 result._moduleSetUpFailed = True
219 self._createClassOrModuleLevelException(result, e,
220 'setUpModule',
221 currentModule)
222 finally:
223 _call_if_exists(result, '_restoreStdout')
224
225 def _createClassOrModuleLevelException(self, result, exc, method_name,
226 parent, info=None):
227 errorName = f'{method_name} ({parent})'
228 self._addClassOrModuleLevelException(result, exc, errorName, info)
229
230 def _addClassOrModuleLevelException(self, result, exception, errorName,
231 info=None):
232 error = _ErrorHolder(errorName)
233 addSkip = getattr(result, 'addSkip', None)
234 if addSkip is not None and isinstance(exception, case.SkipTest):
235 addSkip(error, str(exception))
236 else:
237 if not info:
238 result.addError(error, sys.exc_info())
239 else:
240 result.addError(error, info)
241
242 def _handleModuleTearDown(self, result):
243 previousModule = self._get_previous_module(result)
244 if previousModule is None:
245 return
246 if result._moduleSetUpFailed:
247 return
248
249 try:
250 module = sys.modules[previousModule]
251 except KeyError:
252 return
253
254 tearDownModule = getattr(module, 'tearDownModule', None)
255 if tearDownModule is not None:
256 _call_if_exists(result, '_setupStdout')
257 try:
258 tearDownModule()
259 except Exception as e:
260 if isinstance(result, _DebugResult):
261 raise
262 self._createClassOrModuleLevelException(result, e,
263 'tearDownModule',
264 previousModule)
265 finally:
266 _call_if_exists(result, '_restoreStdout')
267 try:
268 case.doModuleCleanups()
269 except Exception as e:
270 self._createClassOrModuleLevelException(result, e,
271 'tearDownModule',
272 previousModule)
273
274 def _tearDownPreviousClass(self, test, result):
275 previousClass = getattr(result, '_previousTestClass', None)
276 currentClass = test.__class__
277 if currentClass == previousClass:
278 return
279 if getattr(previousClass, '_classSetupFailed', False):
280 return
281 if getattr(result, '_moduleSetUpFailed', False):
282 return
283 if getattr(previousClass, "__unittest_skip__", False):
284 return
285
286 tearDownClass = getattr(previousClass, 'tearDownClass', None)
287 if tearDownClass is not None:
288 _call_if_exists(result, '_setupStdout')
289 try:
290 tearDownClass()
291 except Exception as e:
292 if isinstance(result, _DebugResult):
293 raise
294 className = util.strclass(previousClass)
295 self._createClassOrModuleLevelException(result, e,
296 'tearDownClass',
297 className)
298 finally:
299 _call_if_exists(result, '_restoreStdout')
300 previousClass.doClassCleanups()
301 if len(previousClass.tearDown_exceptions) > 0:
302 for exc in previousClass.tearDown_exceptions:
303 className = util.strclass(previousClass)
304 self._createClassOrModuleLevelException(result, exc[1],
305 'tearDownClass',
306 className,
307 info=exc)
308
309
310 class _ErrorHolder(object):
311 """
312 Placeholder for a TestCase inside a result. As far as a TestResult
313 is concerned, this looks exactly like a unit test. Used to insert
314 arbitrary errors into a test suite run.
315 """
316 # Inspired by the ErrorHolder from Twisted:
317 # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
318
319 # attribute used by TestResult._exc_info_to_string
320 failureException = None
321
322 def __init__(self, description):
323 self.description = description
324
325 def id(self):
326 return self.description
327
328 def shortDescription(self):
329 return None
330
331 def __repr__(self):
332 return "<ErrorHolder description=%r>" % (self.description,)
333
334 def __str__(self):
335 return self.id()
336
337 def run(self, result):
338 # could call result.addError(...) - but this test-like object
339 # shouldn't be run anyway
340 pass
341
342 def __call__(self, result):
343 return self.run(result)
344
345 def countTestCases(self):
346 return 0
347
348 def _isnotsuite(test):
349 "A crude way to tell apart testcases and suites with duck-typing"
350 try:
351 iter(test)
352 except TypeError:
353 return True
354 return False
355
356
357 class _DebugResult(object):
358 "Used by the TestSuite to hold previous class when running in debug."
359 _previousTestClass = None
360 _moduleSetUpFailed = False
361 shouldStop = False