diff options
Diffstat (limited to 'lib/testtools/testtools/tests/test_testresult.py')
-rw-r--r-- | lib/testtools/testtools/tests/test_testresult.py | 307 |
1 files changed, 220 insertions, 87 deletions
diff --git a/lib/testtools/testtools/tests/test_testresult.py b/lib/testtools/testtools/tests/test_testresult.py index 57c3293c09..a241788bea 100644 --- a/lib/testtools/testtools/tests/test_testresult.py +++ b/lib/testtools/testtools/tests/test_testresult.py @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Jonathan M. Lange. See LICENSE for details. +# Copyright (c) 2008-2011 testtools developers. See LICENSE for details. """Test TestResults and related things.""" @@ -22,7 +22,6 @@ from testtools import ( TextTestResult, ThreadsafeForwardingResult, testresult, - try_imports, ) from testtools.compat import ( _b, @@ -30,24 +29,70 @@ from testtools.compat import ( _r, _u, str_is_unicode, + StringIO, + ) +from testtools.content import ( + Content, + content_from_stream, + text_content, ) -from testtools.content import Content from testtools.content_type import ContentType, UTF8_TEXT from testtools.matchers import ( DocTestMatches, + Equals, MatchesException, Raises, ) from testtools.tests.helpers import ( + an_exc_info, + FullStackRunTest, LoggingResult, + run_with_stack_hidden, + ) +from testtools.testresult.doubles import ( Python26TestResult, Python27TestResult, ExtendedTestResult, - an_exc_info ) -from testtools.testresult.real import utc +from testtools.testresult.real import ( + _details_to_str, + utc, + ) + + +def make_erroring_test(): + class Test(TestCase): + def error(self): + 1/0 + return Test("error") + + +def make_failing_test(): + class Test(TestCase): + def failed(self): + self.fail("yo!") + return Test("failed") + + +def make_unexpectedly_successful_test(): + class Test(TestCase): + def succeeded(self): + self.expectFailure("yo!", lambda: None) + return Test("succeeded") + -StringIO = try_imports(['StringIO.StringIO', 'io.StringIO']) +def make_test(): + class Test(TestCase): + def test(self): + pass + return Test("test") + + +def make_exception_info(exceptionFactory, *args, **kwargs): + try: + raise exceptionFactory(*args, **kwargs) + except: + return sys.exc_info() class Python26Contract(object): @@ -190,7 +235,7 @@ class FallbackContract(DetailsContract): class StartTestRunContract(FallbackContract): """Defines the contract for testtools policy choices. - + That is things which are not simply extensions to unittest but choices we have made differently. """ @@ -222,24 +267,32 @@ class StartTestRunContract(FallbackContract): class TestTestResultContract(TestCase, StartTestRunContract): + run_test_with = FullStackRunTest + def makeResult(self): return TestResult() class TestMultiTestResultContract(TestCase, StartTestRunContract): + run_test_with = FullStackRunTest + def makeResult(self): return MultiTestResult(TestResult(), TestResult()) class TestTextTestResultContract(TestCase, StartTestRunContract): + run_test_with = FullStackRunTest + def makeResult(self): return TextTestResult(StringIO()) class TestThreadSafeForwardingResultContract(TestCase, StartTestRunContract): + run_test_with = FullStackRunTest + def makeResult(self): result_semaphore = threading.Semaphore(1) target = TestResult() @@ -277,7 +330,9 @@ class TestAdaptedPython27TestResultContract(TestCase, DetailsContract): class TestTestResult(TestCase): - """Tests for `TestResult`.""" + """Tests for 'TestResult'.""" + + run_tests_with = FullStackRunTest def makeResult(self): """Make an arbitrary result for testing.""" @@ -328,21 +383,45 @@ class TestTestResult(TestCase): result.time(now) self.assertEqual(now, result._now()) - -class TestWithFakeExceptions(TestCase): - - def makeExceptionInfo(self, exceptionFactory, *args, **kwargs): - try: - raise exceptionFactory(*args, **kwargs) - except: - return sys.exc_info() + def test_traceback_formatting_without_stack_hidden(self): + # During the testtools test run, we show our levels of the stack, + # because we want to be able to use our test suite to debug our own + # code. + result = self.makeResult() + test = make_erroring_test() + test.run(result) + self.assertThat( + result.errors[0][1], + DocTestMatches( + 'Traceback (most recent call last):\n' + ' File "...testtools...runtest.py", line ..., in _run_user\n' + ' return fn(*args, **kwargs)\n' + ' File "...testtools...testcase.py", line ..., in _run_test_method\n' + ' return self._get_test_method()()\n' + ' File "...testtools...tests...test_testresult.py", line ..., in error\n' + ' 1/0\n' + 'ZeroDivisionError: ...\n', + doctest.ELLIPSIS | doctest.REPORT_UDIFF)) + + def test_traceback_formatting_with_stack_hidden(self): + result = self.makeResult() + test = make_erroring_test() + run_with_stack_hidden(True, test.run, result) + self.assertThat( + result.errors[0][1], + DocTestMatches( + 'Traceback (most recent call last):\n' + ' File "...testtools...tests...test_testresult.py", line ..., in error\n' + ' 1/0\n' + 'ZeroDivisionError: ...\n', + doctest.ELLIPSIS)) -class TestMultiTestResult(TestWithFakeExceptions): - """Tests for `MultiTestResult`.""" +class TestMultiTestResult(TestCase): + """Tests for 'MultiTestResult'.""" def setUp(self): - TestWithFakeExceptions.setUp(self) + super(TestMultiTestResult, self).setUp() self.result1 = LoggingResult([]) self.result2 = LoggingResult([]) self.multiResult = MultiTestResult(self.result1, self.result2) @@ -391,14 +470,14 @@ class TestMultiTestResult(TestWithFakeExceptions): def test_addFailure(self): # Calling `addFailure` on a `MultiTestResult` calls `addFailure` on # all its `TestResult`s. - exc_info = self.makeExceptionInfo(AssertionError, 'failure') + exc_info = make_exception_info(AssertionError, 'failure') self.multiResult.addFailure(self, exc_info) self.assertResultLogsEqual([('addFailure', self, exc_info)]) def test_addError(self): # Calling `addError` on a `MultiTestResult` calls `addError` on all # its `TestResult`s. - exc_info = self.makeExceptionInfo(RuntimeError, 'error') + exc_info = make_exception_info(RuntimeError, 'error') self.multiResult.addError(self, exc_info) self.assertResultLogsEqual([('addError', self, exc_info)]) @@ -432,36 +511,12 @@ class TestMultiTestResult(TestWithFakeExceptions): class TestTextTestResult(TestCase): - """Tests for `TextTestResult`.""" + """Tests for 'TextTestResult'.""" def setUp(self): super(TestTextTestResult, self).setUp() self.result = TextTestResult(StringIO()) - def make_erroring_test(self): - class Test(TestCase): - def error(self): - 1/0 - return Test("error") - - def make_failing_test(self): - class Test(TestCase): - def failed(self): - self.fail("yo!") - return Test("failed") - - def make_unexpectedly_successful_test(self): - class Test(TestCase): - def succeeded(self): - self.expectFailure("yo!", lambda: None) - return Test("succeeded") - - def make_test(self): - class Test(TestCase): - def test(self): - pass - return Test("test") - def getvalue(self): return self.result.stream.getvalue() @@ -477,7 +532,7 @@ class TestTextTestResult(TestCase): self.assertEqual("Tests running...\n", self.getvalue()) def test_stopTestRun_count_many(self): - test = self.make_test() + test = make_test() self.result.startTestRun() self.result.startTest(test) self.result.stopTest(test) @@ -486,27 +541,27 @@ class TestTextTestResult(TestCase): self.result.stream = StringIO() self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("Ran 2 tests in ...s\n...", doctest.ELLIPSIS)) + DocTestMatches("\nRan 2 tests in ...s\n...", doctest.ELLIPSIS)) def test_stopTestRun_count_single(self): - test = self.make_test() + test = make_test() self.result.startTestRun() self.result.startTest(test) self.result.stopTest(test) self.reset_output() self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("Ran 1 test in ...s\n\nOK\n", doctest.ELLIPSIS)) + DocTestMatches("\nRan 1 test in ...s\nOK\n", doctest.ELLIPSIS)) def test_stopTestRun_count_zero(self): self.result.startTestRun() self.reset_output() self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("Ran 0 tests in ...s\n\nOK\n", doctest.ELLIPSIS)) + DocTestMatches("\nRan 0 tests in ...s\nOK\n", doctest.ELLIPSIS)) def test_stopTestRun_current_time(self): - test = self.make_test() + test = make_test() now = datetime.datetime.now(utc) self.result.time(now) self.result.startTestRun() @@ -523,79 +578,67 @@ class TestTextTestResult(TestCase): self.result.startTestRun() self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("...\n\nOK\n", doctest.ELLIPSIS)) + DocTestMatches("...\nOK\n", doctest.ELLIPSIS)) def test_stopTestRun_not_successful_failure(self): - test = self.make_failing_test() + test = make_failing_test() self.result.startTestRun() test.run(self.result) self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS)) + DocTestMatches("...\nFAILED (failures=1)\n", doctest.ELLIPSIS)) def test_stopTestRun_not_successful_error(self): - test = self.make_erroring_test() + test = make_erroring_test() self.result.startTestRun() test.run(self.result) self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS)) + DocTestMatches("...\nFAILED (failures=1)\n", doctest.ELLIPSIS)) def test_stopTestRun_not_successful_unexpected_success(self): - test = self.make_unexpectedly_successful_test() + test = make_unexpectedly_successful_test() self.result.startTestRun() test.run(self.result) self.result.stopTestRun() self.assertThat(self.getvalue(), - DocTestMatches("...\n\nFAILED (failures=1)\n", doctest.ELLIPSIS)) + DocTestMatches("...\nFAILED (failures=1)\n", doctest.ELLIPSIS)) def test_stopTestRun_shows_details(self): - self.result.startTestRun() - self.make_erroring_test().run(self.result) - self.make_unexpectedly_successful_test().run(self.result) - self.make_failing_test().run(self.result) - self.reset_output() - self.result.stopTestRun() + def run_tests(): + self.result.startTestRun() + make_erroring_test().run(self.result) + make_unexpectedly_successful_test().run(self.result) + make_failing_test().run(self.result) + self.reset_output() + self.result.stopTestRun() + run_with_stack_hidden(True, run_tests) self.assertThat(self.getvalue(), DocTestMatches("""...====================================================================== ERROR: testtools.tests.test_testresult.Test.error ---------------------------------------------------------------------- -Text attachment: traceback ------------- Traceback (most recent call last): - File "...testtools...runtest.py", line ..., in _run_user... - return fn(*args, **kwargs) - File "...testtools...testcase.py", line ..., in _run_test_method - return self._get_test_method()() File "...testtools...tests...test_testresult.py", line ..., in error 1/0 ZeroDivisionError:... divi... by zero... ------------- ====================================================================== FAIL: testtools.tests.test_testresult.Test.failed ---------------------------------------------------------------------- -Text attachment: traceback ------------- Traceback (most recent call last): - File "...testtools...runtest.py", line ..., in _run_user... - return fn(*args, **kwargs) - File "...testtools...testcase.py", line ..., in _run_test_method - return self._get_test_method()() File "...testtools...tests...test_testresult.py", line ..., in failed self.fail("yo!") AssertionError: yo! ------------- ====================================================================== UNEXPECTED SUCCESS: testtools.tests.test_testresult.Test.succeeded ---------------------------------------------------------------------- ...""", doctest.ELLIPSIS | doctest.REPORT_NDIFF)) -class TestThreadSafeForwardingResult(TestWithFakeExceptions): +class TestThreadSafeForwardingResult(TestCase): """Tests for `TestThreadSafeForwardingResult`.""" def setUp(self): - TestWithFakeExceptions.setUp(self) + super(TestThreadSafeForwardingResult, self).setUp() self.result_semaphore = threading.Semaphore(1) self.target = LoggingResult([]) self.result1 = ThreadsafeForwardingResult(self.target, @@ -624,14 +667,14 @@ class TestThreadSafeForwardingResult(TestWithFakeExceptions): def test_forwarding_methods(self): # error, failure, skip and success are forwarded in batches. - exc_info1 = self.makeExceptionInfo(RuntimeError, 'error') + exc_info1 = make_exception_info(RuntimeError, 'error') starttime1 = datetime.datetime.utcfromtimestamp(1.489) endtime1 = datetime.datetime.utcfromtimestamp(51.476) self.result1.time(starttime1) self.result1.startTest(self) self.result1.time(endtime1) self.result1.addError(self, exc_info1) - exc_info2 = self.makeExceptionInfo(AssertionError, 'failure') + exc_info2 = make_exception_info(AssertionError, 'failure') starttime2 = datetime.datetime.utcfromtimestamp(2.489) endtime2 = datetime.datetime.utcfromtimestamp(3.476) self.result1.time(starttime2) @@ -708,10 +751,19 @@ class TestExtendedToOriginalResultDecoratorBase(TestCase): details = {'text 1': Content(ContentType('text', 'plain'), text1), 'text 2': Content(ContentType('text', 'strange'), text2), 'bin 1': Content(ContentType('application', 'binary'), bin1)} - return (details, "Binary content: bin 1\n" - "Text attachment: text 1\n------------\n1\n2\n" - "------------\nText attachment: text 2\n------------\n" - "3\n4\n------------\n") + return (details, + ("Binary content:\n" + " bin 1 (application/binary)\n" + "\n" + "text 1: {{{\n" + "1\n" + "2\n" + "}}}\n" + "\n" + "text 2: {{{\n" + "3\n" + "4\n" + "}}}\n")) def check_outcome_details_to_exec_info(self, outcome, expected=None): """Call an outcome with a details dict to be made into exc_info.""" @@ -1369,6 +1421,87 @@ class TestNonAsciiResultsWithUnittest(TestNonAsciiResults): return text.encode("utf-8") +class TestDetailsToStr(TestCase): + + def test_no_details(self): + string = _details_to_str({}) + self.assertThat(string, Equals('')) + + def test_binary_content(self): + content = content_from_stream( + StringIO('foo'), content_type=ContentType('image', 'jpeg')) + string = _details_to_str({'attachment': content}) + self.assertThat( + string, Equals("""\ +Binary content: + attachment (image/jpeg) +""")) + + def test_single_line_content(self): + content = text_content('foo') + string = _details_to_str({'attachment': content}) + self.assertThat(string, Equals('attachment: {{{foo}}}\n')) + + def test_multi_line_text_content(self): + content = text_content('foo\nbar\nbaz') + string = _details_to_str({'attachment': content}) + self.assertThat(string, Equals('attachment: {{{\nfoo\nbar\nbaz\n}}}\n')) + + def test_special_text_content(self): + content = text_content('foo') + string = _details_to_str({'attachment': content}, special='attachment') + self.assertThat(string, Equals('foo\n')) + + def test_multiple_text_content(self): + string = _details_to_str( + {'attachment': text_content('foo\nfoo'), + 'attachment-1': text_content('bar\nbar')}) + self.assertThat( + string, Equals('attachment: {{{\n' + 'foo\n' + 'foo\n' + '}}}\n' + '\n' + 'attachment-1: {{{\n' + 'bar\n' + 'bar\n' + '}}}\n')) + + def test_empty_attachment(self): + string = _details_to_str({'attachment': text_content('')}) + self.assertThat( + string, Equals("""\ +Empty attachments: + attachment +""")) + + def test_lots_of_different_attachments(self): + jpg = lambda x: content_from_stream( + StringIO(x), ContentType('image', 'jpeg')) + attachments = { + 'attachment': text_content('foo'), + 'attachment-1': text_content('traceback'), + 'attachment-2': jpg('pic1'), + 'attachment-3': text_content('bar'), + 'attachment-4': text_content(''), + 'attachment-5': jpg('pic2'), + } + string = _details_to_str(attachments, special='attachment-1') + self.assertThat( + string, Equals("""\ +Binary content: + attachment-2 (image/jpeg) + attachment-5 (image/jpeg) +Empty attachments: + attachment-4 + +attachment: {{{foo}}} +attachment-3: {{{bar}}} + +traceback +""")) + + def test_suite(): from unittest import TestLoader return TestLoader().loadTestsFromName(__name__) |