blob: 2cc17d71c853541cfc491cf8b60181e587d92fee [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Test result object"""
2
Michael Foord5637f042010-04-02 21:42:47 +00003import os
4import sys
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00005import traceback
6
Michael Foordf6ff26c2010-04-07 23:04:22 +00007from StringIO import StringIO
Michael Foord5637f042010-04-02 21:42:47 +00008
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00009from . import util
Michael Foord1b9e9532010-03-22 01:01:34 +000010from functools import wraps
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000011
Michael Foordb1aa30f2010-03-22 00:06:30 +000012__unittest = True
13
Michael Foord1b9e9532010-03-22 01:01:34 +000014def failfast(method):
15 @wraps(method)
16 def inner(self, *args, **kw):
17 if getattr(self, 'failfast', False):
18 self.stop()
19 return method(self, *args, **kw)
20 return inner
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000021
Michael Foord9b4ee122010-04-03 02:21:39 +000022STDOUT_LINE = '\nStdout:\n%s'
23STDERR_LINE = '\nStderr:\n%s'
Michael Foord5637f042010-04-02 21:42:47 +000024
25
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000026class TestResult(object):
27 """Holder for test result information.
28
29 Test results are automatically managed by the TestCase and TestSuite
30 classes, and do not need to be explicitly manipulated by writers of tests.
31
32 Each instance holds the total number of tests run, and collections of
33 failures and errors that occurred among those test runs. The collections
34 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
35 formatted traceback of the error that occurred.
36 """
Michael Foord5ffa3252010-03-07 22:04:55 +000037 _previousTestClass = None
Michael Foorde5dc24e2010-11-01 22:11:53 +000038 _testRunEntered = False
Michael Foord5ffa3252010-03-07 22:04:55 +000039 _moduleSetUpFailed = False
Michael Foordd99ef9a2010-02-23 17:00:53 +000040 def __init__(self, stream=None, descriptions=None, verbosity=None):
Michael Foord1b9e9532010-03-22 01:01:34 +000041 self.failfast = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000042 self.failures = []
43 self.errors = []
44 self.testsRun = 0
45 self.skipped = []
46 self.expectedFailures = []
47 self.unexpectedSuccesses = []
48 self.shouldStop = False
Michael Foord5637f042010-04-02 21:42:47 +000049 self.buffer = False
Michael Foordf6ff26c2010-04-07 23:04:22 +000050 self._stdout_buffer = None
51 self._stderr_buffer = None
Michael Foord58c1e782010-04-02 22:08:29 +000052 self._original_stdout = sys.stdout
53 self._original_stderr = sys.stderr
Michael Foord5637f042010-04-02 21:42:47 +000054 self._mirrorOutput = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000055
Michael Foordd99ef9a2010-02-23 17:00:53 +000056 def printErrors(self):
57 "Called by TestRunner after test run"
58
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000059 def startTest(self, test):
60 "Called when the given test is about to be run"
Michael Foorddb43b5a2010-02-10 14:25:12 +000061 self.testsRun += 1
Michael Foord5637f042010-04-02 21:42:47 +000062 self._mirrorOutput = False
Michael Foord8faa2072011-03-17 12:48:56 -040063 self._setupStdout()
64
65 def _setupStdout(self):
Michael Foord5637f042010-04-02 21:42:47 +000066 if self.buffer:
Michael Foordf6ff26c2010-04-07 23:04:22 +000067 if self._stderr_buffer is None:
68 self._stderr_buffer = StringIO()
69 self._stdout_buffer = StringIO()
Michael Foord5637f042010-04-02 21:42:47 +000070 sys.stdout = self._stdout_buffer
71 sys.stderr = self._stderr_buffer
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000072
73 def startTestRun(self):
74 """Called once before any tests are executed.
75
76 See startTest for a method called before each test.
77 """
78
79 def stopTest(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000080 """Called when the given test has been run"""
Michael Foord8faa2072011-03-17 12:48:56 -040081 self._restoreStdout()
82 self._mirrorOutput = False
83
84 def _restoreStdout(self):
Michael Foord5637f042010-04-02 21:42:47 +000085 if self.buffer:
86 if self._mirrorOutput:
87 output = sys.stdout.getvalue()
88 error = sys.stderr.getvalue()
89 if output:
Michael Foord9b4ee122010-04-03 02:21:39 +000090 if not output.endswith('\n'):
91 output += '\n'
Michael Foord58c1e782010-04-02 22:08:29 +000092 self._original_stdout.write(STDOUT_LINE % output)
Michael Foord5637f042010-04-02 21:42:47 +000093 if error:
Michael Foord9b4ee122010-04-03 02:21:39 +000094 if not error.endswith('\n'):
95 error += '\n'
Michael Foord58c1e782010-04-02 22:08:29 +000096 self._original_stderr.write(STDERR_LINE % error)
Michael Foord5637f042010-04-02 21:42:47 +000097
Michael Foord25d79762010-04-02 22:30:56 +000098 sys.stdout = self._original_stdout
99 sys.stderr = self._original_stderr
Michael Foord5637f042010-04-02 21:42:47 +0000100 self._stdout_buffer.seek(0)
101 self._stdout_buffer.truncate()
102 self._stderr_buffer.seek(0)
103 self._stderr_buffer.truncate()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000104
105 def stopTestRun(self):
106 """Called once after all tests are executed.
107
108 See stopTest for a method called after each test.
109 """
110
Michael Foord1b9e9532010-03-22 01:01:34 +0000111 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000112 def addError(self, test, err):
113 """Called when an error has occurred. 'err' is a tuple of values as
114 returned by sys.exc_info().
115 """
116 self.errors.append((test, self._exc_info_to_string(err, test)))
Michael Foord5637f042010-04-02 21:42:47 +0000117 self._mirrorOutput = True
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000118
Michael Foord1b9e9532010-03-22 01:01:34 +0000119 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000120 def addFailure(self, test, err):
121 """Called when an error has occurred. 'err' is a tuple of values as
122 returned by sys.exc_info()."""
123 self.failures.append((test, self._exc_info_to_string(err, test)))
Michael Foord5637f042010-04-02 21:42:47 +0000124 self._mirrorOutput = True
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000125
126 def addSuccess(self, test):
127 "Called when a test has completed successfully"
128 pass
129
130 def addSkip(self, test, reason):
131 """Called when a test is skipped."""
132 self.skipped.append((test, reason))
133
134 def addExpectedFailure(self, test, err):
135 """Called when an expected failure/error occured."""
136 self.expectedFailures.append(
137 (test, self._exc_info_to_string(err, test)))
138
Michael Foord1b9e9532010-03-22 01:01:34 +0000139 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000140 def addUnexpectedSuccess(self, test):
141 """Called when a test was expected to fail, but succeed."""
142 self.unexpectedSuccesses.append(test)
143
144 def wasSuccessful(self):
145 "Tells whether or not this result was a success"
146 return len(self.failures) == len(self.errors) == 0
147
148 def stop(self):
149 "Indicates that the tests should be aborted"
150 self.shouldStop = True
151
152 def _exc_info_to_string(self, err, test):
153 """Converts a sys.exc_info()-style tuple of values into a string."""
154 exctype, value, tb = err
155 # Skip test runner traceback levels
156 while tb and self._is_relevant_tb_level(tb):
157 tb = tb.tb_next
Michael Foord5637f042010-04-02 21:42:47 +0000158
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000159 if exctype is test.failureException:
160 # Skip assert*() traceback levels
161 length = self._count_relevant_tb_levels(tb)
Michael Foord5637f042010-04-02 21:42:47 +0000162 msgLines = traceback.format_exception(exctype, value, tb, length)
163 else:
164 msgLines = traceback.format_exception(exctype, value, tb)
165
166 if self.buffer:
167 output = sys.stdout.getvalue()
168 error = sys.stderr.getvalue()
169 if output:
Michael Foord9b4ee122010-04-03 02:21:39 +0000170 if not output.endswith('\n'):
171 output += '\n'
Michael Foord5637f042010-04-02 21:42:47 +0000172 msgLines.append(STDOUT_LINE % output)
173 if error:
Michael Foord9b4ee122010-04-03 02:21:39 +0000174 if not error.endswith('\n'):
175 error += '\n'
Michael Foord5637f042010-04-02 21:42:47 +0000176 msgLines.append(STDERR_LINE % error)
177 return ''.join(msgLines)
178
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000179
180 def _is_relevant_tb_level(self, tb):
Michael Foordb1aa30f2010-03-22 00:06:30 +0000181 return '__unittest' in tb.tb_frame.f_globals
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000182
183 def _count_relevant_tb_levels(self, tb):
184 length = 0
185 while tb and not self._is_relevant_tb_level(tb):
186 length += 1
187 tb = tb.tb_next
188 return length
189
190 def __repr__(self):
Michael Foordae3db0a2010-02-22 23:28:32 +0000191 return ("<%s run=%i errors=%i failures=%i>" %
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000192 (util.strclass(self.__class__), self.testsRun, len(self.errors),
Michael Foordae3db0a2010-02-22 23:28:32 +0000193 len(self.failures)))