blob: 46eba0401b929823b02887a71889b11529506a5d [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 Foord5637f042010-04-02 21:42:47 +00007from cStringIO import StringIO
8
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 Foord5637f042010-04-02 21:42:47 +000022
23_std_out = sys.stdout
24_std_err = sys.stderr
25
26NEWLINE = os.linesep
27STDOUT_LINE = '%sStdout:%s%%s' % (NEWLINE, NEWLINE)
28STDERR_LINE = '%sStderr:%s%%s' % (NEWLINE, NEWLINE)
29
30
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000031class TestResult(object):
32 """Holder for test result information.
33
34 Test results are automatically managed by the TestCase and TestSuite
35 classes, and do not need to be explicitly manipulated by writers of tests.
36
37 Each instance holds the total number of tests run, and collections of
38 failures and errors that occurred among those test runs. The collections
39 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
40 formatted traceback of the error that occurred.
41 """
Michael Foord5ffa3252010-03-07 22:04:55 +000042 _previousTestClass = None
43 _moduleSetUpFailed = False
Michael Foordd99ef9a2010-02-23 17:00:53 +000044 def __init__(self, stream=None, descriptions=None, verbosity=None):
Michael Foord1b9e9532010-03-22 01:01:34 +000045 self.failfast = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000046 self.failures = []
47 self.errors = []
48 self.testsRun = 0
49 self.skipped = []
50 self.expectedFailures = []
51 self.unexpectedSuccesses = []
52 self.shouldStop = False
Michael Foord5637f042010-04-02 21:42:47 +000053 self.buffer = False
54 self._stdout_buffer = StringIO()
55 self._stderr_buffer = StringIO()
56 self._mirrorOutput = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000057
Michael Foordd99ef9a2010-02-23 17:00:53 +000058 def printErrors(self):
59 "Called by TestRunner after test run"
60
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000061 def startTest(self, test):
62 "Called when the given test is about to be run"
Michael Foorddb43b5a2010-02-10 14:25:12 +000063 self.testsRun += 1
Michael Foord5637f042010-04-02 21:42:47 +000064 self._mirrorOutput = False
65 if self.buffer:
66 sys.stdout = self._stdout_buffer
67 sys.stderr = self._stderr_buffer
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000068
69 def startTestRun(self):
70 """Called once before any tests are executed.
71
72 See startTest for a method called before each test.
73 """
74
75 def stopTest(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000076 """Called when the given test has been run"""
Michael Foord5637f042010-04-02 21:42:47 +000077 if self.buffer:
78 if self._mirrorOutput:
79 output = sys.stdout.getvalue()
80 error = sys.stderr.getvalue()
81 if output:
82 if not output.endswith(NEWLINE):
83 output += NEWLINE
84 sys.__stdout__.write(STDOUT_LINE % output)
85 if error:
86 if not error.endswith(NEWLINE):
87 error += NEWLINE
88 sys.__stderr__.write(STDERR_LINE % error)
89
90 sys.stdout = _std_out
91 sys.stderr = _std_err
92 self._stdout_buffer.seek(0)
93 self._stdout_buffer.truncate()
94 self._stderr_buffer.seek(0)
95 self._stderr_buffer.truncate()
96 self._mirrorOutput = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000097
98 def stopTestRun(self):
99 """Called once after all tests are executed.
100
101 See stopTest for a method called after each test.
102 """
103
Michael Foord1b9e9532010-03-22 01:01:34 +0000104 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000105 def addError(self, test, err):
106 """Called when an error has occurred. 'err' is a tuple of values as
107 returned by sys.exc_info().
108 """
109 self.errors.append((test, self._exc_info_to_string(err, test)))
Michael Foord5637f042010-04-02 21:42:47 +0000110 self._mirrorOutput = True
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000111
Michael Foord1b9e9532010-03-22 01:01:34 +0000112 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000113 def addFailure(self, test, err):
114 """Called when an error has occurred. 'err' is a tuple of values as
115 returned by sys.exc_info()."""
116 self.failures.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
119 def addSuccess(self, test):
120 "Called when a test has completed successfully"
121 pass
122
123 def addSkip(self, test, reason):
124 """Called when a test is skipped."""
125 self.skipped.append((test, reason))
126
127 def addExpectedFailure(self, test, err):
128 """Called when an expected failure/error occured."""
129 self.expectedFailures.append(
130 (test, self._exc_info_to_string(err, test)))
131
Michael Foord1b9e9532010-03-22 01:01:34 +0000132 @failfast
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000133 def addUnexpectedSuccess(self, test):
134 """Called when a test was expected to fail, but succeed."""
135 self.unexpectedSuccesses.append(test)
136
137 def wasSuccessful(self):
138 "Tells whether or not this result was a success"
139 return len(self.failures) == len(self.errors) == 0
140
141 def stop(self):
142 "Indicates that the tests should be aborted"
143 self.shouldStop = True
144
145 def _exc_info_to_string(self, err, test):
146 """Converts a sys.exc_info()-style tuple of values into a string."""
147 exctype, value, tb = err
148 # Skip test runner traceback levels
149 while tb and self._is_relevant_tb_level(tb):
150 tb = tb.tb_next
Michael Foord5637f042010-04-02 21:42:47 +0000151
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000152 if exctype is test.failureException:
153 # Skip assert*() traceback levels
154 length = self._count_relevant_tb_levels(tb)
Michael Foord5637f042010-04-02 21:42:47 +0000155 msgLines = traceback.format_exception(exctype, value, tb, length)
156 else:
157 msgLines = traceback.format_exception(exctype, value, tb)
158
159 if self.buffer:
160 output = sys.stdout.getvalue()
161 error = sys.stderr.getvalue()
162 if output:
163 if not output.endswith(NEWLINE):
164 output += NEWLINE
165 msgLines.append(STDOUT_LINE % output)
166 if error:
167 if not error.endswith(NEWLINE):
168 error += NEWLINE
169 msgLines.append(STDERR_LINE % error)
170 return ''.join(msgLines)
171
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000172
173 def _is_relevant_tb_level(self, tb):
Michael Foordb1aa30f2010-03-22 00:06:30 +0000174 return '__unittest' in tb.tb_frame.f_globals
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000175
176 def _count_relevant_tb_levels(self, tb):
177 length = 0
178 while tb and not self._is_relevant_tb_level(tb):
179 length += 1
180 tb = tb.tb_next
181 return length
182
183 def __repr__(self):
Michael Foordae3db0a2010-02-22 23:28:32 +0000184 return ("<%s run=%i errors=%i failures=%i>" %
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000185 (util.strclass(self.__class__), self.testsRun, len(self.errors),
Michael Foordae3db0a2010-02-22 23:28:32 +0000186 len(self.failures)))