]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """Test result object"""\r |
2 | \r | |
3 | import os\r | |
4 | import sys\r | |
5 | import traceback\r | |
6 | \r | |
7 | from StringIO import StringIO\r | |
8 | \r | |
9 | from . import util\r | |
10 | from functools import wraps\r | |
11 | \r | |
12 | __unittest = True\r | |
13 | \r | |
14 | def failfast(method):\r | |
15 | @wraps(method)\r | |
16 | def inner(self, *args, **kw):\r | |
17 | if getattr(self, 'failfast', False):\r | |
18 | self.stop()\r | |
19 | return method(self, *args, **kw)\r | |
20 | return inner\r | |
21 | \r | |
22 | STDOUT_LINE = '\nStdout:\n%s'\r | |
23 | STDERR_LINE = '\nStderr:\n%s'\r | |
24 | \r | |
25 | \r | |
26 | class TestResult(object):\r | |
27 | """Holder for test result information.\r | |
28 | \r | |
29 | Test results are automatically managed by the TestCase and TestSuite\r | |
30 | classes, and do not need to be explicitly manipulated by writers of tests.\r | |
31 | \r | |
32 | Each instance holds the total number of tests run, and collections of\r | |
33 | failures and errors that occurred among those test runs. The collections\r | |
34 | contain tuples of (testcase, exceptioninfo), where exceptioninfo is the\r | |
35 | formatted traceback of the error that occurred.\r | |
36 | """\r | |
37 | _previousTestClass = None\r | |
38 | _testRunEntered = False\r | |
39 | _moduleSetUpFailed = False\r | |
40 | def __init__(self, stream=None, descriptions=None, verbosity=None):\r | |
41 | self.failfast = False\r | |
42 | self.failures = []\r | |
43 | self.errors = []\r | |
44 | self.testsRun = 0\r | |
45 | self.skipped = []\r | |
46 | self.expectedFailures = []\r | |
47 | self.unexpectedSuccesses = []\r | |
48 | self.shouldStop = False\r | |
49 | self.buffer = False\r | |
50 | self._stdout_buffer = None\r | |
51 | self._stderr_buffer = None\r | |
52 | self._original_stdout = sys.stdout\r | |
53 | self._original_stderr = sys.stderr\r | |
54 | self._mirrorOutput = False\r | |
55 | \r | |
56 | def printErrors(self):\r | |
57 | "Called by TestRunner after test run"\r | |
58 | \r | |
59 | def startTest(self, test):\r | |
60 | "Called when the given test is about to be run"\r | |
61 | self.testsRun += 1\r | |
62 | self._mirrorOutput = False\r | |
63 | self._setupStdout()\r | |
64 | \r | |
65 | def _setupStdout(self):\r | |
66 | if self.buffer:\r | |
67 | if self._stderr_buffer is None:\r | |
68 | self._stderr_buffer = StringIO()\r | |
69 | self._stdout_buffer = StringIO()\r | |
70 | sys.stdout = self._stdout_buffer\r | |
71 | sys.stderr = self._stderr_buffer\r | |
72 | \r | |
73 | def startTestRun(self):\r | |
74 | """Called once before any tests are executed.\r | |
75 | \r | |
76 | See startTest for a method called before each test.\r | |
77 | """\r | |
78 | \r | |
79 | def stopTest(self, test):\r | |
80 | """Called when the given test has been run"""\r | |
81 | self._restoreStdout()\r | |
82 | self._mirrorOutput = False\r | |
83 | \r | |
84 | def _restoreStdout(self):\r | |
85 | if self.buffer:\r | |
86 | if self._mirrorOutput:\r | |
87 | output = sys.stdout.getvalue()\r | |
88 | error = sys.stderr.getvalue()\r | |
89 | if output:\r | |
90 | if not output.endswith('\n'):\r | |
91 | output += '\n'\r | |
92 | self._original_stdout.write(STDOUT_LINE % output)\r | |
93 | if error:\r | |
94 | if not error.endswith('\n'):\r | |
95 | error += '\n'\r | |
96 | self._original_stderr.write(STDERR_LINE % error)\r | |
97 | \r | |
98 | sys.stdout = self._original_stdout\r | |
99 | sys.stderr = self._original_stderr\r | |
100 | self._stdout_buffer.seek(0)\r | |
101 | self._stdout_buffer.truncate()\r | |
102 | self._stderr_buffer.seek(0)\r | |
103 | self._stderr_buffer.truncate()\r | |
104 | \r | |
105 | def stopTestRun(self):\r | |
106 | """Called once after all tests are executed.\r | |
107 | \r | |
108 | See stopTest for a method called after each test.\r | |
109 | """\r | |
110 | \r | |
111 | @failfast\r | |
112 | def addError(self, test, err):\r | |
113 | """Called when an error has occurred. 'err' is a tuple of values as\r | |
114 | returned by sys.exc_info().\r | |
115 | """\r | |
116 | self.errors.append((test, self._exc_info_to_string(err, test)))\r | |
117 | self._mirrorOutput = True\r | |
118 | \r | |
119 | @failfast\r | |
120 | def addFailure(self, test, err):\r | |
121 | """Called when an error has occurred. 'err' is a tuple of values as\r | |
122 | returned by sys.exc_info()."""\r | |
123 | self.failures.append((test, self._exc_info_to_string(err, test)))\r | |
124 | self._mirrorOutput = True\r | |
125 | \r | |
126 | def addSuccess(self, test):\r | |
127 | "Called when a test has completed successfully"\r | |
128 | pass\r | |
129 | \r | |
130 | def addSkip(self, test, reason):\r | |
131 | """Called when a test is skipped."""\r | |
132 | self.skipped.append((test, reason))\r | |
133 | \r | |
134 | def addExpectedFailure(self, test, err):\r | |
135 | """Called when an expected failure/error occured."""\r | |
136 | self.expectedFailures.append(\r | |
137 | (test, self._exc_info_to_string(err, test)))\r | |
138 | \r | |
139 | @failfast\r | |
140 | def addUnexpectedSuccess(self, test):\r | |
141 | """Called when a test was expected to fail, but succeed."""\r | |
142 | self.unexpectedSuccesses.append(test)\r | |
143 | \r | |
144 | def wasSuccessful(self):\r | |
145 | "Tells whether or not this result was a success"\r | |
146 | return len(self.failures) == len(self.errors) == 0\r | |
147 | \r | |
148 | def stop(self):\r | |
149 | "Indicates that the tests should be aborted"\r | |
150 | self.shouldStop = True\r | |
151 | \r | |
152 | def _exc_info_to_string(self, err, test):\r | |
153 | """Converts a sys.exc_info()-style tuple of values into a string."""\r | |
154 | exctype, value, tb = err\r | |
155 | # Skip test runner traceback levels\r | |
156 | while tb and self._is_relevant_tb_level(tb):\r | |
157 | tb = tb.tb_next\r | |
158 | \r | |
159 | if exctype is test.failureException:\r | |
160 | # Skip assert*() traceback levels\r | |
161 | length = self._count_relevant_tb_levels(tb)\r | |
162 | msgLines = traceback.format_exception(exctype, value, tb, length)\r | |
163 | else:\r | |
164 | msgLines = traceback.format_exception(exctype, value, tb)\r | |
165 | \r | |
166 | if self.buffer:\r | |
167 | output = sys.stdout.getvalue()\r | |
168 | error = sys.stderr.getvalue()\r | |
169 | if output:\r | |
170 | if not output.endswith('\n'):\r | |
171 | output += '\n'\r | |
172 | msgLines.append(STDOUT_LINE % output)\r | |
173 | if error:\r | |
174 | if not error.endswith('\n'):\r | |
175 | error += '\n'\r | |
176 | msgLines.append(STDERR_LINE % error)\r | |
177 | return ''.join(msgLines)\r | |
178 | \r | |
179 | \r | |
180 | def _is_relevant_tb_level(self, tb):\r | |
181 | return '__unittest' in tb.tb_frame.f_globals\r | |
182 | \r | |
183 | def _count_relevant_tb_levels(self, tb):\r | |
184 | length = 0\r | |
185 | while tb and not self._is_relevant_tb_level(tb):\r | |
186 | length += 1\r | |
187 | tb = tb.tb_next\r | |
188 | return length\r | |
189 | \r | |
190 | def __repr__(self):\r | |
191 | return ("<%s run=%i errors=%i failures=%i>" %\r | |
192 | (util.strclass(self.__class__), self.testsRun, len(self.errors),\r | |
193 | len(self.failures)))\r |