160 |
160 |
161 # Capture stdout and stderr so we can examine them in tests. |
161 # Capture stdout and stderr so we can examine them in tests. |
162 # nose keeps stdout from littering the screen, so we can safely Tee it, |
162 # nose keeps stdout from littering the screen, so we can safely Tee it, |
163 # but it doesn't capture stderr, so we don't want to Tee stderr to the |
163 # but it doesn't capture stderr, so we don't want to Tee stderr to the |
164 # real stderr, since it will interfere with our nice field of dots. |
164 # real stderr, since it will interfere with our nice field of dots. |
165 self.old_stdout = sys.stdout |
165 old_stdout = sys.stdout |
166 self.captured_stdout = StringIO() |
166 self.captured_stdout = StringIO() |
167 sys.stdout = Tee(sys.stdout, self.captured_stdout) |
167 sys.stdout = Tee(sys.stdout, self.captured_stdout) |
168 |
168 |
169 self.old_stderr = sys.stderr |
169 old_stderr = sys.stderr |
170 self.captured_stderr = StringIO() |
170 self.captured_stderr = StringIO() |
171 sys.stderr = self.captured_stderr |
171 sys.stderr = self.captured_stderr |
172 |
172 |
173 self.addCleanup(self.cleanup_std_streams) |
173 self.addCleanup(self.cleanup_std_streams, old_stdout, old_stderr) |
174 |
174 |
175 def cleanup_std_streams(self): |
175 def cleanup_std_streams(self, old_stdout, old_stderr): |
176 """Restore stdout and stderr.""" |
176 """Restore stdout and stderr.""" |
177 sys.stdout = self.old_stdout |
177 sys.stdout = old_stdout |
178 sys.stderr = self.old_stderr |
178 sys.stderr = old_stderr |
179 |
179 |
180 def stdout(self): |
180 def stdout(self): |
181 """Return the data written to stdout during the test.""" |
181 """Return the data written to stdout during the test.""" |
182 return self.captured_stdout.getvalue() |
182 return self.captured_stdout.getvalue() |
183 |
183 |
184 def stderr(self): |
184 def stderr(self): |
185 """Return the data written to stderr during the test.""" |
185 """Return the data written to stderr during the test.""" |
186 return self.captured_stderr.getvalue() |
186 return self.captured_stderr.getvalue() |
|
187 |
|
188 |
|
189 class DelayedAssertionMixin(TestCase): |
|
190 """A test case mixin that provides a `delayed_assertions` context manager. |
|
191 |
|
192 Use it like this:: |
|
193 |
|
194 with self.delayed_assertions(): |
|
195 self.assertEqual(x, y) |
|
196 self.assertEqual(z, w) |
|
197 |
|
198 All of the assertions will run. The failures will be displayed at the end |
|
199 of the with-statement. |
|
200 |
|
201 NOTE: this only works with some assertions. These are known to work: |
|
202 |
|
203 - `assertEqual(str, str)` |
|
204 |
|
205 - `assertMultilineEqual(str, str)` |
|
206 |
|
207 """ |
|
208 def __init__(self, *args, **kwargs): |
|
209 super(DelayedAssertionMixin, self).__init__(*args, **kwargs) |
|
210 # This mixin only works with assert methods that call `self.fail`. In |
|
211 # Python 2.7, `assertEqual` didn't, but we can do what Python 3 does, |
|
212 # and use `assertMultiLineEqual` for comparing strings. |
|
213 self.addTypeEqualityFunc(str, 'assertMultiLineEqual') |
|
214 self._delayed_assertions = None |
|
215 |
|
216 @contextlib.contextmanager |
|
217 def delayed_assertions(self): |
|
218 """The context manager: assert that we didn't collect any assertions.""" |
|
219 self._delayed_assertions = [] |
|
220 old_fail = self.fail |
|
221 self.fail = self._delayed_fail |
|
222 try: |
|
223 yield |
|
224 finally: |
|
225 self.fail = old_fail |
|
226 if self._delayed_assertions: |
|
227 if len(self._delayed_assertions) == 1: |
|
228 self.fail(self._delayed_assertions[0]) |
|
229 else: |
|
230 self.fail( |
|
231 "{0} failed assertions:\n{1}".format( |
|
232 len(self._delayed_assertions), |
|
233 "\n".join(self._delayed_assertions), |
|
234 ) |
|
235 ) |
|
236 |
|
237 def _delayed_fail(self, msg=None): |
|
238 """The stand-in for TestCase.fail during delayed_assertions.""" |
|
239 self._delayed_assertions.append(msg) |
187 |
240 |
188 |
241 |
189 class TempDirMixin(SysPathAwareMixin, ModuleAwareMixin, TestCase): |
242 class TempDirMixin(SysPathAwareMixin, ModuleAwareMixin, TestCase): |
190 """A test case mixin that creates a temp directory and files in it. |
243 """A test case mixin that creates a temp directory and files in it. |
191 |
244 |