a0e090d9210946c2a84da58c97ff535e9355f31e
[nivanova/samba-autobuild/.git] / lib / testtools / testtools / tests / test_testresult.py
1 # Copyright (c) 2008 Jonathan M. Lange. See LICENSE for details.
2
3 """Test TestResults and related things."""
4
5 __metaclass__ = type
6
7 import codecs
8 import datetime
9 import doctest
10 import os
11 import shutil
12 import sys
13 import tempfile
14 import threading
15 import warnings
16
17 from testtools import (
18     ExtendedToOriginalDecorator,
19     MultiTestResult,
20     TestCase,
21     TestResult,
22     TextTestResult,
23     ThreadsafeForwardingResult,
24     testresult,
25     try_imports,
26     )
27 from testtools.compat import (
28     _b,
29     _get_exception_encoding,
30     _r,
31     _u,
32     str_is_unicode,
33     )
34 from testtools.content import Content
35 from testtools.content_type import ContentType, UTF8_TEXT
36 from testtools.matchers import (
37     DocTestMatches,
38     MatchesException,
39     Raises,
40     )
41 from testtools.tests.helpers import (
42     LoggingResult,
43     Python26TestResult,
44     Python27TestResult,
45     ExtendedTestResult,
46     an_exc_info
47     )
48
49 StringIO = try_imports(['StringIO.StringIO', 'io.StringIO'])
50
51
52 class Python26Contract(object):
53
54     def test_fresh_result_is_successful(self):
55         # A result is considered successful before any tests are run.
56         result = self.makeResult()
57         self.assertTrue(result.wasSuccessful())
58
59     def test_addError_is_failure(self):
60         # addError fails the test run.
61         result = self.makeResult()
62         result.startTest(self)
63         result.addError(self, an_exc_info)
64         result.stopTest(self)
65         self.assertFalse(result.wasSuccessful())
66
67     def test_addFailure_is_failure(self):
68         # addFailure fails the test run.
69         result = self.makeResult()
70         result.startTest(self)
71         result.addFailure(self, an_exc_info)
72         result.stopTest(self)
73         self.assertFalse(result.wasSuccessful())
74
75     def test_addSuccess_is_success(self):
76         # addSuccess does not fail the test run.
77         result = self.makeResult()
78         result.startTest(self)
79         result.addSuccess(self)
80         result.stopTest(self)
81         self.assertTrue(result.wasSuccessful())
82
83
84 class Python27Contract(Python26Contract):
85
86     def test_addExpectedFailure(self):
87         # Calling addExpectedFailure(test, exc_info) completes ok.
88         result = self.makeResult()
89         result.startTest(self)
90         result.addExpectedFailure(self, an_exc_info)
91
92     def test_addExpectedFailure_is_success(self):
93         # addExpectedFailure does not fail the test run.
94         result = self.makeResult()
95         result.startTest(self)
96         result.addExpectedFailure(self, an_exc_info)
97         result.stopTest(self)
98         self.assertTrue(result.wasSuccessful())
99
100     def test_addSkipped(self):
101         # Calling addSkip(test, reason) completes ok.
102         result = self.makeResult()
103         result.startTest(self)
104         result.addSkip(self, _u("Skipped for some reason"))
105
106     def test_addSkip_is_success(self):
107         # addSkip does not fail the test run.
108         result = self.makeResult()
109         result.startTest(self)
110         result.addSkip(self, _u("Skipped for some reason"))
111         result.stopTest(self)
112         self.assertTrue(result.wasSuccessful())
113
114     def test_addUnexpectedSuccess(self):
115         # Calling addUnexpectedSuccess(test) completes ok.
116         result = self.makeResult()
117         result.startTest(self)
118         result.addUnexpectedSuccess(self)
119
120     def test_addUnexpectedSuccess_was_successful(self):
121         # addUnexpectedSuccess does not fail the test run in Python 2.7.
122         result = self.makeResult()
123         result.startTest(self)
124         result.addUnexpectedSuccess(self)
125         result.stopTest(self)
126         self.assertTrue(result.wasSuccessful())
127
128     def test_startStopTestRun(self):
129         # Calling startTestRun completes ok.
130         result = self.makeResult()
131         result.startTestRun()
132         result.stopTestRun()
133
134
135 class DetailsContract(Python27Contract):
136     """Tests for the contract of TestResults."""
137
138     def test_addExpectedFailure_details(self):
139         # Calling addExpectedFailure(test, details=xxx) completes ok.
140         result = self.makeResult()
141         result.startTest(self)
142         result.addExpectedFailure(self, details={})
143
144     def test_addError_details(self):
145         # Calling addError(test, details=xxx) completes ok.
146         result = self.makeResult()
147         result.startTest(self)
148         result.addError(self, details={})
149
150     def test_addFailure_details(self):
151         # Calling addFailure(test, details=xxx) completes ok.
152         result = self.makeResult()
153         result.startTest(self)
154         result.addFailure(self, details={})
155
156     def test_addSkipped_details(self):
157         # Calling addSkip(test, reason) completes ok.
158         result = self.makeResult()
159         result.startTest(self)
160         result.addSkip(self, details={})
161
162     def test_addUnexpectedSuccess_details(self):
163         # Calling addUnexpectedSuccess(test) completes ok.
164         result = self.makeResult()
165         result.startTest(self)
166         result.addUnexpectedSuccess(self, details={})
167
168     def test_addSuccess_details(self):
169         # Calling addSuccess(test) completes ok.
170         result = self.makeResult()
171         result.startTest(self)
172         result.addSuccess(self, details={})
173
174
175 class FallbackContract(DetailsContract):
176     """When we fallback we take our policy choice to map calls.
177
178     For instance, we map unexpectedSuccess to an error code, not to success.
179     """
180
181     def test_addUnexpectedSuccess_was_successful(self):
182         # addUnexpectedSuccess fails test run in testtools.
183         result = self.makeResult()
184         result.startTest(self)
185         result.addUnexpectedSuccess(self)
186         result.stopTest(self)
187         self.assertFalse(result.wasSuccessful())
188
189
190 class StartTestRunContract(FallbackContract):
191     """Defines the contract for testtools policy choices.
192     
193     That is things which are not simply extensions to unittest but choices we
194     have made differently.
195     """
196
197     def test_startTestRun_resets_unexpected_success(self):
198         result = self.makeResult()
199         result.startTest(self)
200         result.addUnexpectedSuccess(self)
201         result.stopTest(self)
202         result.startTestRun()
203         self.assertTrue(result.wasSuccessful())
204
205     def test_startTestRun_resets_failure(self):
206         result = self.makeResult()
207         result.startTest(self)
208         result.addFailure(self, an_exc_info)
209         result.stopTest(self)
210         result.startTestRun()
211         self.assertTrue(result.wasSuccessful())
212
213     def test_startTestRun_resets_errors(self):
214         result = self.makeResult()
215         result.startTest(self)
216         result.addError(self, an_exc_info)
217         result.stopTest(self)
218         result.startTestRun()
219         self.assertTrue(result.wasSuccessful())
220
221
222 class TestTestResultContract(TestCase, StartTestRunContract):
223
224     def makeResult(self):
225         return TestResult()
226
227
228 class TestMultiTestResultContract(TestCase, StartTestRunContract):
229
230     def makeResult(self):
231         return MultiTestResult(TestResult(), TestResult())
232
233
234 class TestTextTestResultContract(TestCase, StartTestRunContract):
235
236     def makeResult(self):
237         return TextTestResult(StringIO())
238
239
240 class TestThreadSafeForwardingResultContract(TestCase, StartTestRunContract):
241
242     def makeResult(self):
243         result_semaphore = threading.Semaphore(1)
244         target = TestResult()
245         return ThreadsafeForwardingResult(target, result_semaphore)
246
247
248 class TestExtendedTestResultContract(TestCase, StartTestRunContract):
249
250     def makeResult(self):
251         return ExtendedTestResult()
252
253
254 class TestPython26TestResultContract(TestCase, Python26Contract):
255
256     def makeResult(self):
257         return Python26TestResult()
258
259
260 class TestAdaptedPython26TestResultContract(TestCase, FallbackContract):
261
262     def makeResult(self):
263         return ExtendedToOriginalDecorator(Python26TestResult())
264
265
266 class TestPython27TestResultContract(TestCase, Python27Contract):
267
268     def makeResult(self):
269         return Python27TestResult()
270
271
272 class TestAdaptedPython27TestResultContract(TestCase, DetailsContract):
273
274     def makeResult(self):
275         return ExtendedToOriginalDecorator(Python27TestResult())
276
277
278 class TestTestResult(TestCase):
279     """Tests for `TestResult`."""
280
281     def makeResult(self):
282         """Make an arbitrary result for testing."""
283         return TestResult()
284
285     def test_addSkipped(self):
286         # Calling addSkip on a TestResult records the test that was skipped in
287         # its skip_reasons dict.
288         result = self.makeResult()
289         result.addSkip(self, _u("Skipped for some reason"))
290         self.assertEqual({_u("Skipped for some reason"):[self]},
291             result.skip_reasons)
292         result.addSkip(self, _u("Skipped for some reason"))
293         self.assertEqual({_u("Skipped for some reason"):[self, self]},
294             result.skip_reasons)
295         result.addSkip(self, _u("Skipped for another reason"))
296         self.assertEqual({_u("Skipped for some reason"):[self, self],
297             _u("Skipped for another reason"):[self]},
298             result.skip_reasons)
299
300     def test_now_datetime_now(self):
301         result = self.makeResult()
302         olddatetime = testresult.real.datetime
303         def restore():
304             testresult.real.datetime = olddatetime
305         self.addCleanup(restore)
306         class Module:
307             pass
308         now = datetime.datetime.now()
309         stubdatetime = Module()
310         stubdatetime.datetime = Module()
311         stubdatetime.datetime.now = lambda: now
312         testresult.real.datetime = stubdatetime
313         # Calling _now() looks up the time.
314         self.assertEqual(now, result._now())
315         then = now + datetime.timedelta(0, 1)
316         # Set an explicit datetime, which gets returned from then on.
317         result.time(then)
318         self.assertNotEqual(now, result._now())
319         self.assertEqual(then, result._now())
320         # go back to looking it up.
321         result.time(None)
322         self.assertEqual(now, result._now())
323
324     def test_now_datetime_time(self):
325         result = self.makeResult()
326         now = datetime.datetime.now()
327         result.time(now)
328         self.assertEqual(now, result._now())
329
330
331 class TestWithFakeExceptions(TestCase):
332
333     def makeExceptionInfo(self, exceptionFactory, *args, **kwargs):
334         try:
335             raise exceptionFactory(*args, **kwargs)
336         except:
337             return sys.exc_info()
338
339
340 class TestMultiTestResult(TestWithFakeExceptions):
341     """Tests for `MultiTestResult`."""
342
343     def setUp(self):
344         TestWithFakeExceptions.setUp(self)
345         self.result1 = LoggingResult([])
346         self.result2 = LoggingResult([])
347         self.multiResult = MultiTestResult(self.result1, self.result2)
348
349     def assertResultLogsEqual(self, expectedEvents):
350         """Assert that our test results have received the expected events."""
351         self.assertEqual(expectedEvents, self.result1._events)
352         self.assertEqual(expectedEvents, self.result2._events)
353
354     def test_empty(self):
355         # Initializing a `MultiTestResult` doesn't do anything to its
356         # `TestResult`s.
357         self.assertResultLogsEqual([])
358
359     def test_startTest(self):
360         # Calling `startTest` on a `MultiTestResult` calls `startTest` on all
361         # its `TestResult`s.
362         self.multiResult.startTest(self)
363         self.assertResultLogsEqual([('startTest', self)])
364
365     def test_stopTest(self):
366         # Calling `stopTest` on a `MultiTestResult` calls `stopTest` on all
367         # its `TestResult`s.
368         self.multiResult.stopTest(self)
369         self.assertResultLogsEqual([('stopTest', self)])
370
371     def test_addSkipped(self):
372         # Calling `addSkip` on a `MultiTestResult` calls addSkip on its
373         # results.
374         reason = _u("Skipped for some reason")
375         self.multiResult.addSkip(self, reason)
376         self.assertResultLogsEqual([('addSkip', self, reason)])
377
378     def test_addSuccess(self):
379         # Calling `addSuccess` on a `MultiTestResult` calls `addSuccess` on
380         # all its `TestResult`s.
381         self.multiResult.addSuccess(self)
382         self.assertResultLogsEqual([('addSuccess', self)])
383
384     def test_done(self):
385         # Calling `done` on a `MultiTestResult` calls `done` on all its
386         # `TestResult`s.
387         self.multiResult.done()
388         self.assertResultLogsEqual([('done')])
389
390     def test_addFailure(self):
391         # Calling `addFailure` on a `MultiTestResult` calls `addFailure` on
392         # all its `TestResult`s.
393         exc_info = self.makeExceptionInfo(AssertionError, 'failure')
394         self.multiResult.addFailure(self, exc_info)
395         self.assertResultLogsEqual([('addFailure', self, exc_info)])
396
397     def test_addError(self):
398         # Calling `addError` on a `MultiTestResult` calls `addError` on all
399         # its `TestResult`s.
400         exc_info = self.makeExceptionInfo(RuntimeError, 'error')
401         self.multiResult.addError(self, exc_info)
402         self.assertResultLogsEqual([('addError', self, exc_info)])
403
404     def test_startTestRun(self):
405         # Calling `startTestRun` on a `MultiTestResult` forwards to all its
406         # `TestResult`s.
407         self.multiResult.startTestRun()
408         self.assertResultLogsEqual([('startTestRun')])
409
410     def test_stopTestRun(self):
411         # Calling `stopTestRun` on a `MultiTestResult` forwards to all its
412         # `TestResult`s.
413         self.multiResult.stopTestRun()
414         self.assertResultLogsEqual([('stopTestRun')])
415
416     def test_stopTestRun_returns_results(self):
417         # `MultiTestResult.stopTestRun` returns a tuple of all of the return
418         # values the `stopTestRun`s that it forwards to.
419         class Result(LoggingResult):
420             def stopTestRun(self):
421                 super(Result, self).stopTestRun()
422                 return 'foo'
423         multi_result = MultiTestResult(Result([]), Result([]))
424         result = multi_result.stopTestRun()
425         self.assertEqual(('foo', 'foo'), result)
426
427
428 class TestTextTestResult(TestCase):
429     """Tests for `TextTestResult`."""
430
431     def setUp(self):
432         super(TestTextTestResult, self).setUp()
433         self.result = TextTestResult(StringIO())
434
435     def make_erroring_test(self):
436         class Test(TestCase):
437             def error(self):
438                 1/0
439         return Test("error")
440
441     def make_failing_test(self):
442         class Test(TestCase):
443             def failed(self):
444                 self.fail("yo!")
445         return Test("failed")
446
447     def make_unexpectedly_successful_test(self):
448         class Test(TestCase):
449             def succeeded(self):
450                 self.expectFailure("yo!", lambda: None)
451         return Test("succeeded")
452
453     def make_test(self):
454         class Test(TestCase):
455             def test(self):
456                 pass
457         return Test("test")
458
459     def getvalue(self):
460         return self.result.stream.getvalue()
461
462     def test__init_sets_stream(self):
463         result = TextTestResult("fp")
464         self.assertEqual("fp", result.stream)
465
466     def reset_output(self):
467         self.result.stream = StringIO()
468
469     def test_startTestRun(self):
470         self.result.startTestRun()
471         self.assertEqual("Tests running...\n", self.getvalue())
472
473     def test_stopTestRun_count_many(self):
474         test = self.make_test()
475         self.result.startTestRun()
476         self.result.startTest(test)
477         self.result.stopTest(test)
478         self.result.startTest(test)
479         self.result.stopTest(test)
480         self.result.stream = StringIO()
481         self.result.stopTestRun()
482         self.assertThat(self.getvalue(),
483             DocTestMatches("Ran 2 tests in ...s\n...", doctest.ELLIPSIS))
484
485     def test_stopTestRun_count_single(self):
486         test = self.make_test()
487         self.result.startTestRun()
488         self.result.startTest(test)
489         self.result.stopTest(test)
490         self.reset_output()
491         self.result.stopTestRun()
492         self.assertThat(self.getvalue(),
493             DocTestMatches("Ran 1 test in ...s\n\nOK\n", doctest.ELLIPSIS))
494
495     def test_stopTestRun_count_zero(self):
496         self.result.startTestRun()
497         self.reset_output()
498         self.result.stopTestRun()
499         self.assertThat(self.getvalue(),
500             DocTestMatches("Ran 0 tests in ...s\n\nOK\n", doctest.ELLIPSIS))
501
502     def test_stopTestRun_current_time(self):
503         test = self.make_test()
504         now = datetime.datetime.now()
505         self.result.time(now)
506         self.result.startTestRun()
507         self.result.startTest(test)
508         now = now + datetime.timedelta(0, 0, 0, 1)
509         self.result.time(now)
510         self.result.stopTest(test)
511         self.reset_output()
512         self.result.stopTestRun()
513         self.assertThat(self.getvalue(),
514             DocTestMatches("... in 0.001s\n...", doctest.ELLIPSIS))
515
516     def test_stopTestRun_successful(self):
517         self.result.startTestRun()
518         self.result.stopTestRun()
519         self.assertThat(self.getvalue(),
520             DocTestMatches("...\n\nOK\n", doctest.ELLIPSIS))
521
522     def test_stopTestRun_not_successful_failure(self):
523         test = self.make_failing_test()
524         self.result.startTestRun()
525         test.run(self.result)
526         self.result.stopTestRun()
527         self.assertThat(self.getvalue(),
528             DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS))
529
530     def test_stopTestRun_not_successful_error(self):
531         test = self.make_erroring_test()
532         self.result.startTestRun()
533         test.run(self.result)
534         self.result.stopTestRun()
535         self.assertThat(self.getvalue(),
536             DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS))
537
538     def test_stopTestRun_not_successful_unexpected_success(self):
539         test = self.make_unexpectedly_successful_test()
540         self.result.startTestRun()
541         test.run(self.result)
542         self.result.stopTestRun()
543         self.assertThat(self.getvalue(),
544             DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS))
545
546     def test_stopTestRun_shows_details(self):
547         self.result.startTestRun()
548         self.make_erroring_test().run(self.result)
549         self.make_unexpectedly_successful_test().run(self.result)
550         self.make_failing_test().run(self.result)
551         self.reset_output()
552         self.result.stopTestRun()
553         self.assertThat(self.getvalue(),
554             DocTestMatches("""...======================================================================
555 ERROR: testtools.tests.test_testresult.Test.error
556 ----------------------------------------------------------------------
557 Text attachment: traceback
558 ------------
559 Traceback (most recent call last):
560   File "...testtools...runtest.py", line ..., in _run_user...
561     return fn(*args, **kwargs)
562   File "...testtools...testcase.py", line ..., in _run_test_method
563     return self._get_test_method()()
564   File "...testtools...tests...test_testresult.py", line ..., in error
565     1/0
566 ZeroDivisionError:... divi... by zero...
567 ------------
568 ======================================================================
569 FAIL: testtools.tests.test_testresult.Test.failed
570 ----------------------------------------------------------------------
571 Text attachment: traceback
572 ------------
573 Traceback (most recent call last):
574   File "...testtools...runtest.py", line ..., in _run_user...
575     return fn(*args, **kwargs)
576   File "...testtools...testcase.py", line ..., in _run_test_method
577     return self._get_test_method()()
578   File "...testtools...tests...test_testresult.py", line ..., in failed
579     self.fail("yo!")
580 AssertionError: yo!
581 ------------
582 ======================================================================
583 UNEXPECTED SUCCESS: testtools.tests.test_testresult.Test.succeeded
584 ----------------------------------------------------------------------
585 ...""", doctest.ELLIPSIS | doctest.REPORT_NDIFF))
586
587
588 class TestThreadSafeForwardingResult(TestWithFakeExceptions):
589     """Tests for `TestThreadSafeForwardingResult`."""
590
591     def setUp(self):
592         TestWithFakeExceptions.setUp(self)
593         self.result_semaphore = threading.Semaphore(1)
594         self.target = LoggingResult([])
595         self.result1 = ThreadsafeForwardingResult(self.target,
596             self.result_semaphore)
597
598     def test_nonforwarding_methods(self):
599         # startTest and stopTest are not forwarded because they need to be
600         # batched.
601         self.result1.startTest(self)
602         self.result1.stopTest(self)
603         self.assertEqual([], self.target._events)
604
605     def test_startTestRun(self):
606         self.result1.startTestRun()
607         self.result2 = ThreadsafeForwardingResult(self.target,
608             self.result_semaphore)
609         self.result2.startTestRun()
610         self.assertEqual(["startTestRun", "startTestRun"], self.target._events)
611
612     def test_stopTestRun(self):
613         self.result1.stopTestRun()
614         self.result2 = ThreadsafeForwardingResult(self.target,
615             self.result_semaphore)
616         self.result2.stopTestRun()
617         self.assertEqual(["stopTestRun", "stopTestRun"], self.target._events)
618
619     def test_forwarding_methods(self):
620         # error, failure, skip and success are forwarded in batches.
621         exc_info1 = self.makeExceptionInfo(RuntimeError, 'error')
622         starttime1 = datetime.datetime.utcfromtimestamp(1.489)
623         endtime1 = datetime.datetime.utcfromtimestamp(51.476)
624         self.result1.time(starttime1)
625         self.result1.startTest(self)
626         self.result1.time(endtime1)
627         self.result1.addError(self, exc_info1)
628         exc_info2 = self.makeExceptionInfo(AssertionError, 'failure')
629         starttime2 = datetime.datetime.utcfromtimestamp(2.489)
630         endtime2 = datetime.datetime.utcfromtimestamp(3.476)
631         self.result1.time(starttime2)
632         self.result1.startTest(self)
633         self.result1.time(endtime2)
634         self.result1.addFailure(self, exc_info2)
635         reason = _u("Skipped for some reason")
636         starttime3 = datetime.datetime.utcfromtimestamp(4.489)
637         endtime3 = datetime.datetime.utcfromtimestamp(5.476)
638         self.result1.time(starttime3)
639         self.result1.startTest(self)
640         self.result1.time(endtime3)
641         self.result1.addSkip(self, reason)
642         starttime4 = datetime.datetime.utcfromtimestamp(6.489)
643         endtime4 = datetime.datetime.utcfromtimestamp(7.476)
644         self.result1.time(starttime4)
645         self.result1.startTest(self)
646         self.result1.time(endtime4)
647         self.result1.addSuccess(self)
648         self.assertEqual([
649             ('time', starttime1),
650             ('startTest', self),
651             ('time', endtime1),
652             ('addError', self, exc_info1),
653             ('stopTest', self),
654             ('time', starttime2),
655             ('startTest', self),
656             ('time', endtime2),
657             ('addFailure', self, exc_info2),
658             ('stopTest', self),
659             ('time', starttime3),
660             ('startTest', self),
661             ('time', endtime3),
662             ('addSkip', self, reason),
663             ('stopTest', self),
664             ('time', starttime4),
665             ('startTest', self),
666             ('time', endtime4),
667             ('addSuccess', self),
668             ('stopTest', self),
669             ], self.target._events)
670
671
672 class TestExtendedToOriginalResultDecoratorBase(TestCase):
673
674     def make_26_result(self):
675         self.result = Python26TestResult()
676         self.make_converter()
677
678     def make_27_result(self):
679         self.result = Python27TestResult()
680         self.make_converter()
681
682     def make_converter(self):
683         self.converter = ExtendedToOriginalDecorator(self.result)
684
685     def make_extended_result(self):
686         self.result = ExtendedTestResult()
687         self.make_converter()
688
689     def check_outcome_details(self, outcome):
690         """Call an outcome with a details dict to be passed through."""
691         # This dict is /not/ convertible - thats deliberate, as it should
692         # not hit the conversion code path.
693         details = {'foo': 'bar'}
694         getattr(self.converter, outcome)(self, details=details)
695         self.assertEqual([(outcome, self, details)], self.result._events)
696
697     def get_details_and_string(self):
698         """Get a details dict and expected string."""
699         text1 = lambda: [_b("1\n2\n")]
700         text2 = lambda: [_b("3\n4\n")]
701         bin1 = lambda: [_b("5\n")]
702         details = {'text 1': Content(ContentType('text', 'plain'), text1),
703             'text 2': Content(ContentType('text', 'strange'), text2),
704             'bin 1': Content(ContentType('application', 'binary'), bin1)}
705         return (details, "Binary content: bin 1\n"
706             "Text attachment: text 1\n------------\n1\n2\n"
707             "------------\nText attachment: text 2\n------------\n"
708             "3\n4\n------------\n")
709
710     def check_outcome_details_to_exec_info(self, outcome, expected=None):
711         """Call an outcome with a details dict to be made into exc_info."""
712         # The conversion is a done using RemoteError and the string contents
713         # of the text types in the details dict.
714         if not expected:
715             expected = outcome
716         details, err_str = self.get_details_and_string()
717         getattr(self.converter, outcome)(self, details=details)
718         err = self.converter._details_to_exc_info(details)
719         self.assertEqual([(expected, self, err)], self.result._events)
720
721     def check_outcome_details_to_nothing(self, outcome, expected=None):
722         """Call an outcome with a details dict to be swallowed."""
723         if not expected:
724             expected = outcome
725         details = {'foo': 'bar'}
726         getattr(self.converter, outcome)(self, details=details)
727         self.assertEqual([(expected, self)], self.result._events)
728
729     def check_outcome_details_to_string(self, outcome):
730         """Call an outcome with a details dict to be stringified."""
731         details, err_str = self.get_details_and_string()
732         getattr(self.converter, outcome)(self, details=details)
733         self.assertEqual([(outcome, self, err_str)], self.result._events)
734
735     def check_outcome_details_to_arg(self, outcome, arg, extra_detail=None):
736         """Call an outcome with a details dict to have an arg extracted."""
737         details, _ = self.get_details_and_string()
738         if extra_detail:
739             details.update(extra_detail)
740         getattr(self.converter, outcome)(self, details=details)
741         self.assertEqual([(outcome, self, arg)], self.result._events)
742
743     def check_outcome_exc_info(self, outcome, expected=None):
744         """Check that calling a legacy outcome still works."""
745         # calling some outcome with the legacy exc_info style api (no keyword
746         # parameters) gets passed through.
747         if not expected:
748             expected = outcome
749         err = sys.exc_info()
750         getattr(self.converter, outcome)(self, err)
751         self.assertEqual([(expected, self, err)], self.result._events)
752
753     def check_outcome_exc_info_to_nothing(self, outcome, expected=None):
754         """Check that calling a legacy outcome on a fallback works."""
755         # calling some outcome with the legacy exc_info style api (no keyword
756         # parameters) gets passed through.
757         if not expected:
758             expected = outcome
759         err = sys.exc_info()
760         getattr(self.converter, outcome)(self, err)
761         self.assertEqual([(expected, self)], self.result._events)
762
763     def check_outcome_nothing(self, outcome, expected=None):
764         """Check that calling a legacy outcome still works."""
765         if not expected:
766             expected = outcome
767         getattr(self.converter, outcome)(self)
768         self.assertEqual([(expected, self)], self.result._events)
769
770     def check_outcome_string_nothing(self, outcome, expected):
771         """Check that calling outcome with a string calls expected."""
772         getattr(self.converter, outcome)(self, "foo")
773         self.assertEqual([(expected, self)], self.result._events)
774
775     def check_outcome_string(self, outcome):
776         """Check that calling outcome with a string works."""
777         getattr(self.converter, outcome)(self, "foo")
778         self.assertEqual([(outcome, self, "foo")], self.result._events)
779
780
781 class TestExtendedToOriginalResultDecorator(
782     TestExtendedToOriginalResultDecoratorBase):
783
784     def test_progress_py26(self):
785         self.make_26_result()
786         self.converter.progress(1, 2)
787
788     def test_progress_py27(self):
789         self.make_27_result()
790         self.converter.progress(1, 2)
791
792     def test_progress_pyextended(self):
793         self.make_extended_result()
794         self.converter.progress(1, 2)
795         self.assertEqual([('progress', 1, 2)], self.result._events)
796
797     def test_shouldStop(self):
798         self.make_26_result()
799         self.assertEqual(False, self.converter.shouldStop)
800         self.converter.decorated.stop()
801         self.assertEqual(True, self.converter.shouldStop)
802
803     def test_startTest_py26(self):
804         self.make_26_result()
805         self.converter.startTest(self)
806         self.assertEqual([('startTest', self)], self.result._events)
807
808     def test_startTest_py27(self):
809         self.make_27_result()
810         self.converter.startTest(self)
811         self.assertEqual([('startTest', self)], self.result._events)
812
813     def test_startTest_pyextended(self):
814         self.make_extended_result()
815         self.converter.startTest(self)
816         self.assertEqual([('startTest', self)], self.result._events)
817
818     def test_startTestRun_py26(self):
819         self.make_26_result()
820         self.converter.startTestRun()
821         self.assertEqual([], self.result._events)
822
823     def test_startTestRun_py27(self):
824         self.make_27_result()
825         self.converter.startTestRun()
826         self.assertEqual([('startTestRun',)], self.result._events)
827
828     def test_startTestRun_pyextended(self):
829         self.make_extended_result()
830         self.converter.startTestRun()
831         self.assertEqual([('startTestRun',)], self.result._events)
832
833     def test_stopTest_py26(self):
834         self.make_26_result()
835         self.converter.stopTest(self)
836         self.assertEqual([('stopTest', self)], self.result._events)
837
838     def test_stopTest_py27(self):
839         self.make_27_result()
840         self.converter.stopTest(self)
841         self.assertEqual([('stopTest', self)], self.result._events)
842
843     def test_stopTest_pyextended(self):
844         self.make_extended_result()
845         self.converter.stopTest(self)
846         self.assertEqual([('stopTest', self)], self.result._events)
847
848     def test_stopTestRun_py26(self):
849         self.make_26_result()
850         self.converter.stopTestRun()
851         self.assertEqual([], self.result._events)
852
853     def test_stopTestRun_py27(self):
854         self.make_27_result()
855         self.converter.stopTestRun()
856         self.assertEqual([('stopTestRun',)], self.result._events)
857
858     def test_stopTestRun_pyextended(self):
859         self.make_extended_result()
860         self.converter.stopTestRun()
861         self.assertEqual([('stopTestRun',)], self.result._events)
862
863     def test_tags_py26(self):
864         self.make_26_result()
865         self.converter.tags(1, 2)
866
867     def test_tags_py27(self):
868         self.make_27_result()
869         self.converter.tags(1, 2)
870
871     def test_tags_pyextended(self):
872         self.make_extended_result()
873         self.converter.tags(1, 2)
874         self.assertEqual([('tags', 1, 2)], self.result._events)
875
876     def test_time_py26(self):
877         self.make_26_result()
878         self.converter.time(1)
879
880     def test_time_py27(self):
881         self.make_27_result()
882         self.converter.time(1)
883
884     def test_time_pyextended(self):
885         self.make_extended_result()
886         self.converter.time(1)
887         self.assertEqual([('time', 1)], self.result._events)
888
889
890 class TestExtendedToOriginalAddError(TestExtendedToOriginalResultDecoratorBase):
891
892     outcome = 'addError'
893
894     def test_outcome_Original_py26(self):
895         self.make_26_result()
896         self.check_outcome_exc_info(self.outcome)
897
898     def test_outcome_Original_py27(self):
899         self.make_27_result()
900         self.check_outcome_exc_info(self.outcome)
901
902     def test_outcome_Original_pyextended(self):
903         self.make_extended_result()
904         self.check_outcome_exc_info(self.outcome)
905
906     def test_outcome_Extended_py26(self):
907         self.make_26_result()
908         self.check_outcome_details_to_exec_info(self.outcome)
909
910     def test_outcome_Extended_py27(self):
911         self.make_27_result()
912         self.check_outcome_details_to_exec_info(self.outcome)
913
914     def test_outcome_Extended_pyextended(self):
915         self.make_extended_result()
916         self.check_outcome_details(self.outcome)
917
918     def test_outcome__no_details(self):
919         self.make_extended_result()
920         self.assertThat(
921             lambda: getattr(self.converter, self.outcome)(self),
922             Raises(MatchesException(ValueError)))
923
924
925 class TestExtendedToOriginalAddFailure(
926     TestExtendedToOriginalAddError):
927
928     outcome = 'addFailure'
929
930
931 class TestExtendedToOriginalAddExpectedFailure(
932     TestExtendedToOriginalAddError):
933
934     outcome = 'addExpectedFailure'
935
936     def test_outcome_Original_py26(self):
937         self.make_26_result()
938         self.check_outcome_exc_info_to_nothing(self.outcome, 'addSuccess')
939
940     def test_outcome_Extended_py26(self):
941         self.make_26_result()
942         self.check_outcome_details_to_nothing(self.outcome, 'addSuccess')
943
944
945
946 class TestExtendedToOriginalAddSkip(
947     TestExtendedToOriginalResultDecoratorBase):
948
949     outcome = 'addSkip'
950
951     def test_outcome_Original_py26(self):
952         self.make_26_result()
953         self.check_outcome_string_nothing(self.outcome, 'addSuccess')
954
955     def test_outcome_Original_py27(self):
956         self.make_27_result()
957         self.check_outcome_string(self.outcome)
958
959     def test_outcome_Original_pyextended(self):
960         self.make_extended_result()
961         self.check_outcome_string(self.outcome)
962
963     def test_outcome_Extended_py26(self):
964         self.make_26_result()
965         self.check_outcome_string_nothing(self.outcome, 'addSuccess')
966
967     def test_outcome_Extended_py27_no_reason(self):
968         self.make_27_result()
969         self.check_outcome_details_to_string(self.outcome)
970
971     def test_outcome_Extended_py27_reason(self):
972         self.make_27_result()
973         self.check_outcome_details_to_arg(self.outcome, 'foo',
974             {'reason': Content(UTF8_TEXT, lambda:[_b('foo')])})
975
976     def test_outcome_Extended_pyextended(self):
977         self.make_extended_result()
978         self.check_outcome_details(self.outcome)
979
980     def test_outcome__no_details(self):
981         self.make_extended_result()
982         self.assertThat(
983             lambda: getattr(self.converter, self.outcome)(self),
984             Raises(MatchesException(ValueError)))
985
986
987 class TestExtendedToOriginalAddSuccess(
988     TestExtendedToOriginalResultDecoratorBase):
989
990     outcome = 'addSuccess'
991     expected = 'addSuccess'
992
993     def test_outcome_Original_py26(self):
994         self.make_26_result()
995         self.check_outcome_nothing(self.outcome, self.expected)
996
997     def test_outcome_Original_py27(self):
998         self.make_27_result()
999         self.check_outcome_nothing(self.outcome)
1000
1001     def test_outcome_Original_pyextended(self):
1002         self.make_extended_result()
1003         self.check_outcome_nothing(self.outcome)
1004
1005     def test_outcome_Extended_py26(self):
1006         self.make_26_result()
1007         self.check_outcome_details_to_nothing(self.outcome, self.expected)
1008
1009     def test_outcome_Extended_py27(self):
1010         self.make_27_result()
1011         self.check_outcome_details_to_nothing(self.outcome)
1012
1013     def test_outcome_Extended_pyextended(self):
1014         self.make_extended_result()
1015         self.check_outcome_details(self.outcome)
1016
1017
1018 class TestExtendedToOriginalAddUnexpectedSuccess(
1019     TestExtendedToOriginalResultDecoratorBase):
1020
1021     outcome = 'addUnexpectedSuccess'
1022     expected = 'addFailure'
1023
1024     def test_outcome_Original_py26(self):
1025         self.make_26_result()
1026         getattr(self.converter, self.outcome)(self)
1027         [event] = self.result._events
1028         self.assertEqual((self.expected, self), event[:2])
1029
1030     def test_outcome_Original_py27(self):
1031         self.make_27_result()
1032         self.check_outcome_nothing(self.outcome)
1033
1034     def test_outcome_Original_pyextended(self):
1035         self.make_extended_result()
1036         self.check_outcome_nothing(self.outcome)
1037
1038     def test_outcome_Extended_py26(self):
1039         self.make_26_result()
1040         getattr(self.converter, self.outcome)(self)
1041         [event] = self.result._events
1042         self.assertEqual((self.expected, self), event[:2])
1043
1044     def test_outcome_Extended_py27(self):
1045         self.make_27_result()
1046         self.check_outcome_details_to_nothing(self.outcome)
1047
1048     def test_outcome_Extended_pyextended(self):
1049         self.make_extended_result()
1050         self.check_outcome_details(self.outcome)
1051
1052
1053 class TestExtendedToOriginalResultOtherAttributes(
1054     TestExtendedToOriginalResultDecoratorBase):
1055
1056     def test_other_attribute(self):
1057         class OtherExtendedResult:
1058             def foo(self):
1059                 return 2
1060             bar = 1
1061         self.result = OtherExtendedResult()
1062         self.make_converter()
1063         self.assertEqual(1, self.converter.bar)
1064         self.assertEqual(2, self.converter.foo())
1065
1066
1067 class TestNonAsciiResults(TestCase):
1068     """Test all kinds of tracebacks are cleanly interpreted as unicode
1069
1070     Currently only uses weak "contains" assertions, would be good to be much
1071     stricter about the expected output. This would add a few failures for the
1072     current release of IronPython for instance, which gets some traceback
1073     lines muddled.
1074     """
1075
1076     _sample_texts = (
1077         _u("pa\u026a\u03b8\u0259n"), # Unicode encodings only
1078         _u("\u5357\u7121"), # In ISO 2022 encodings
1079         _u("\xa7\xa7\xa7"), # In ISO 8859 encodings
1080         )
1081     # Everything but Jython shows syntax errors on the current character
1082     _error_on_character = os.name != "java"
1083
1084     def _run(self, stream, test):
1085         """Run the test, the same as in testtools.run but not to stdout"""
1086         result = TextTestResult(stream)
1087         result.startTestRun()
1088         try:
1089             return test.run(result)
1090         finally:
1091             result.stopTestRun()
1092
1093     def _write_module(self, name, encoding, contents):
1094         """Create Python module on disk with contents in given encoding"""
1095         try:
1096             # Need to pre-check that the coding is valid or codecs.open drops
1097             # the file without closing it which breaks non-refcounted pythons
1098             codecs.lookup(encoding)
1099         except LookupError:
1100             self.skip("Encoding unsupported by implementation: %r" % encoding)
1101         f = codecs.open(os.path.join(self.dir, name + ".py"), "w", encoding)
1102         try:
1103             f.write(contents)
1104         finally:
1105             f.close()
1106
1107     def _test_external_case(self, testline, coding="ascii", modulelevel="",
1108             suffix=""):
1109         """Create and run a test case in a seperate module"""
1110         self._setup_external_case(testline, coding, modulelevel, suffix)
1111         return self._run_external_case()
1112
1113     def _setup_external_case(self, testline, coding="ascii", modulelevel="",
1114             suffix=""):
1115         """Create a test case in a seperate module"""
1116         _, prefix, self.modname = self.id().rsplit(".", 2)
1117         self.dir = tempfile.mkdtemp(prefix=prefix, suffix=suffix)
1118         self.addCleanup(shutil.rmtree, self.dir)
1119         self._write_module(self.modname, coding,
1120             # Older Python 2 versions don't see a coding declaration in a
1121             # docstring so it has to be in a comment, but then we can't
1122             # workaround bug: <http://ironpython.codeplex.com/workitem/26940>
1123             "# coding: %s\n"
1124             "import testtools\n"
1125             "%s\n"
1126             "class Test(testtools.TestCase):\n"
1127             "    def runTest(self):\n"
1128             "        %s\n" % (coding, modulelevel, testline))
1129
1130     def _run_external_case(self):
1131         """Run the prepared test case in a seperate module"""
1132         sys.path.insert(0, self.dir)
1133         self.addCleanup(sys.path.remove, self.dir)
1134         module = __import__(self.modname)
1135         self.addCleanup(sys.modules.pop, self.modname)
1136         stream = StringIO()
1137         self._run(stream, module.Test())
1138         return stream.getvalue()
1139
1140     def _silence_deprecation_warnings(self):
1141         """Shut up DeprecationWarning for this test only"""
1142         warnings.simplefilter("ignore", DeprecationWarning)
1143         self.addCleanup(warnings.filters.remove, warnings.filters[0])
1144
1145     def _get_sample_text(self, encoding="unicode_internal"):
1146         if encoding is None and str_is_unicode:
1147            encoding = "unicode_internal"
1148         for u in self._sample_texts:
1149             try:
1150                 b = u.encode(encoding)
1151                 if u == b.decode(encoding):
1152                    if str_is_unicode:
1153                        return u, u
1154                    return u, b
1155             except (LookupError, UnicodeError):
1156                 pass
1157         self.skip("Could not find a sample text for encoding: %r" % encoding)
1158
1159     def _as_output(self, text):
1160         return text
1161
1162     def test_non_ascii_failure_string(self):
1163         """Assertion contents can be non-ascii and should get decoded"""
1164         text, raw = self._get_sample_text(_get_exception_encoding())
1165         textoutput = self._test_external_case("self.fail(%s)" % _r(raw))
1166         self.assertIn(self._as_output(text), textoutput)
1167
1168     def test_non_ascii_failure_string_via_exec(self):
1169         """Assertion via exec can be non-ascii and still gets decoded"""
1170         text, raw = self._get_sample_text(_get_exception_encoding())
1171         textoutput = self._test_external_case(
1172             testline='exec ("self.fail(%s)")' % _r(raw))
1173         self.assertIn(self._as_output(text), textoutput)
1174
1175     def test_control_characters_in_failure_string(self):
1176         """Control characters in assertions should be escaped"""
1177         textoutput = self._test_external_case("self.fail('\\a\\a\\a')")
1178         self.expectFailure("Defense against the beeping horror unimplemented",
1179             self.assertNotIn, self._as_output("\a\a\a"), textoutput)
1180         self.assertIn(self._as_output(_u("\uFFFD\uFFFD\uFFFD")), textoutput)
1181
1182     def test_os_error(self):
1183         """Locale error messages from the OS shouldn't break anything"""
1184         textoutput = self._test_external_case(
1185             modulelevel="import os",
1186             testline="os.mkdir('/')")
1187         if os.name != "nt" or sys.version_info < (2, 5):
1188             self.assertIn(self._as_output("OSError: "), textoutput)
1189         else:
1190             self.assertIn(self._as_output("WindowsError: "), textoutput)
1191
1192     def test_assertion_text_shift_jis(self):
1193         """A terminal raw backslash in an encoded string is weird but fine"""
1194         example_text = _u("\u5341")
1195         textoutput = self._test_external_case(
1196             coding="shift_jis",
1197             testline="self.fail('%s')" % example_text)
1198         if str_is_unicode:
1199             output_text = example_text
1200         else:
1201             output_text = example_text.encode("shift_jis").decode(
1202                 _get_exception_encoding(), "replace")
1203         self.assertIn(self._as_output("AssertionError: %s" % output_text),
1204             textoutput)
1205
1206     def test_file_comment_iso2022_jp(self):
1207         """Control character escapes must be preserved if valid encoding"""
1208         example_text, _ = self._get_sample_text("iso2022_jp")
1209         textoutput = self._test_external_case(
1210             coding="iso2022_jp",
1211             testline="self.fail('Simple') # %s" % example_text)
1212         self.assertIn(self._as_output(example_text), textoutput)
1213
1214     def test_unicode_exception(self):
1215         """Exceptions that can be formated losslessly as unicode should be"""
1216         example_text, _ = self._get_sample_text()
1217         exception_class = (
1218             "class FancyError(Exception):\n"
1219             # A __unicode__ method does nothing on py3k but the default works
1220             "    def __unicode__(self):\n"
1221             "        return self.args[0]\n")
1222         textoutput = self._test_external_case(
1223             modulelevel=exception_class,
1224             testline="raise FancyError(%s)" % _r(example_text))
1225         self.assertIn(self._as_output(example_text), textoutput)
1226
1227     def test_unprintable_exception(self):
1228         """A totally useless exception instance still prints something"""
1229         exception_class = (
1230             "class UnprintableError(Exception):\n"
1231             "    def __str__(self):\n"
1232             "        raise RuntimeError\n"
1233             "    def __repr__(self):\n"
1234             "        raise RuntimeError\n")
1235         textoutput = self._test_external_case(
1236             modulelevel=exception_class,
1237             testline="raise UnprintableError")
1238         self.assertIn(self._as_output(
1239             "UnprintableError: <unprintable UnprintableError object>\n"),
1240             textoutput)
1241
1242     def test_string_exception(self):
1243         """Raise a string rather than an exception instance if supported"""
1244         if sys.version_info > (2, 6):
1245             self.skip("No string exceptions in Python 2.6 or later")
1246         elif sys.version_info > (2, 5):
1247             self._silence_deprecation_warnings()
1248         textoutput = self._test_external_case(testline="raise 'plain str'")
1249         self.assertIn(self._as_output("\nplain str\n"), textoutput)
1250
1251     def test_non_ascii_dirname(self):
1252         """Script paths in the traceback can be non-ascii"""
1253         text, raw = self._get_sample_text(sys.getfilesystemencoding())
1254         textoutput = self._test_external_case(
1255             # Avoid bug in Python 3 by giving a unicode source encoding rather
1256             # than just ascii which raises a SyntaxError with no other details
1257             coding="utf-8",
1258             testline="self.fail('Simple')",
1259             suffix=raw)
1260         self.assertIn(self._as_output(text), textoutput)
1261
1262     def test_syntax_error(self):
1263         """Syntax errors should still have fancy special-case formatting"""
1264         textoutput = self._test_external_case("exec ('f(a, b c)')")
1265         self.assertIn(self._as_output(
1266             '  File "<string>", line 1\n'
1267             '    f(a, b c)\n'
1268             + ' ' * self._error_on_character +
1269             '          ^\n'
1270             'SyntaxError: '
1271             ), textoutput)
1272
1273     def test_syntax_error_malformed(self):
1274         """Syntax errors with bogus parameters should break anything"""
1275         textoutput = self._test_external_case("raise SyntaxError(3, 2, 1)")
1276         self.assertIn(self._as_output("\nSyntaxError: "), textoutput)
1277
1278     def test_syntax_error_import_binary(self):
1279         """Importing a binary file shouldn't break SyntaxError formatting"""
1280         if sys.version_info < (2, 5):
1281             # Python 2.4 assumes the file is latin-1 and tells you off
1282             self._silence_deprecation_warnings()
1283         self._setup_external_case("import bad")
1284         f = open(os.path.join(self.dir, "bad.py"), "wb")
1285         try:
1286             f.write(_b("x\x9c\xcb*\xcd\xcb\x06\x00\x04R\x01\xb9"))
1287         finally:
1288             f.close()
1289         textoutput = self._run_external_case()
1290         self.assertIn(self._as_output("\nSyntaxError: "), textoutput)
1291
1292     def test_syntax_error_line_iso_8859_1(self):
1293         """Syntax error on a latin-1 line shows the line decoded"""
1294         text, raw = self._get_sample_text("iso-8859-1")
1295         textoutput = self._setup_external_case("import bad")
1296         self._write_module("bad", "iso-8859-1",
1297             "# coding: iso-8859-1\n! = 0 # %s\n" % text)
1298         textoutput = self._run_external_case()
1299         self.assertIn(self._as_output(_u(
1300             #'bad.py", line 2\n'
1301             '    ! = 0 # %s\n'
1302             '    ^\n'
1303             'SyntaxError: ') %
1304             (text,)), textoutput)
1305
1306     def test_syntax_error_line_iso_8859_5(self):
1307         """Syntax error on a iso-8859-5 line shows the line decoded"""
1308         text, raw = self._get_sample_text("iso-8859-5")
1309         textoutput = self._setup_external_case("import bad")
1310         self._write_module("bad", "iso-8859-5",
1311             "# coding: iso-8859-5\n%% = 0 # %s\n" % text)
1312         textoutput = self._run_external_case()
1313         self.assertIn(self._as_output(_u(
1314             #'bad.py", line 2\n'
1315             '    %% = 0 # %s\n'
1316             + ' ' * self._error_on_character +
1317             '   ^\n'
1318             'SyntaxError: ') %
1319             (text,)), textoutput)
1320
1321     def test_syntax_error_line_euc_jp(self):
1322         """Syntax error on a euc_jp line shows the line decoded"""
1323         text, raw = self._get_sample_text("euc_jp")
1324         textoutput = self._setup_external_case("import bad")
1325         self._write_module("bad", "euc_jp",
1326             "# coding: euc_jp\n$ = 0 # %s\n" % text)
1327         textoutput = self._run_external_case()
1328         self.assertIn(self._as_output(_u(
1329             #'bad.py", line 2\n'
1330             '    $ = 0 # %s\n'
1331             + ' ' * self._error_on_character +
1332             '   ^\n'
1333             'SyntaxError: ') %
1334             (text,)), textoutput)
1335
1336     def test_syntax_error_line_utf_8(self):
1337         """Syntax error on a utf-8 line shows the line decoded"""
1338         text, raw = self._get_sample_text("utf-8")
1339         textoutput = self._setup_external_case("import bad")
1340         self._write_module("bad", "utf-8", _u("\ufeff^ = 0 # %s\n") % text)
1341         textoutput = self._run_external_case()
1342         self.assertIn(self._as_output(_u(
1343             'bad.py", line 1\n'
1344             '    ^ = 0 # %s\n'
1345             + ' ' * self._error_on_character +
1346             '   ^\n'
1347             'SyntaxError: ') %
1348             text), textoutput)
1349
1350
1351 class TestNonAsciiResultsWithUnittest(TestNonAsciiResults):
1352     """Test that running under unittest produces clean ascii strings"""
1353
1354     def _run(self, stream, test):
1355         from unittest import TextTestRunner as _Runner
1356         return _Runner(stream).run(test)
1357
1358     def _as_output(self, text):
1359         if str_is_unicode:
1360             return text
1361         return text.encode("utf-8")
1362
1363
1364 def test_suite():
1365     from unittest import TestLoader
1366     return TestLoader().loadTestsFromName(__name__)