# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.python.failure import Failure from twisted.trial import unittest from twisted.internet.defer import Deferred, fail class ResultOfCoroutineAssertionsTests(unittest.SynchronousTestCase): """ Tests for L{SynchronousTestCase.successResultOf}, L{SynchronousTestCase.failureResultOf}, and L{SynchronousTestCase.assertNoResult} when given a coroutine. """ result = object() exception = Exception("Bad times") failure = Failure(exception) async def successResult(self): return self.result async def noCurrentResult(self): await Deferred() async def raisesException(self): raise self.exception def test_withoutResult(self): """ L{SynchronousTestCase.successResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine with no current result. """ self.assertRaises( self.failureException, self.successResultOf, self.noCurrentResult() ) def test_successResultOfWithException(self): """ L{SynchronousTestCase.successResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception. """ self.assertRaises( self.failureException, self.successResultOf, self.raisesException() ) def test_successResultOfWithFailureHasTraceback(self): """ L{SynchronousTestCase.successResultOf} raises a L{SynchronousTestCase.failureException} that has the original failure traceback when called with a coroutine with a failure result. """ try: self.successResultOf(self.raisesException()) except self.failureException as e: self.assertIn(self.failure.getTraceback(), str(e)) test_successResultOfWithFailureHasTraceback.todo = ( "Tracebacks aren't preserved by exceptions later wrapped in Failures" ) def test_failureResultOfWithoutResult(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine with no current result. """ self.assertRaises( self.failureException, self.failureResultOf, self.noCurrentResult() ) def test_failureResultOfWithSuccess(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine with a success result. """ self.assertRaises( self.failureException, self.failureResultOf, self.successResult() ) def test_failureResultOfWithWrongFailure(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception that was not expected. """ self.assertRaises( self.failureException, self.failureResultOf, self.raisesException(), KeyError ) def test_failureResultOfWithWrongExceptionOneExpectedException(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception with a failure type that was not expected, and the L{SynchronousTestCase.failureException} message contains the expected exception type. """ try: self.failureResultOf(self.raisesException(), KeyError) except self.failureException as e: self.assertIn( "Failure of type ({0}.{1}) expected on".format( KeyError.__module__, KeyError.__name__ ), str(e) ) def test_failureResultOfWithWrongExceptionOneExpectedExceptionHasTB(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception with a failure type that was not expected, and the L{SynchronousTestCase.failureException} message contains the original exception traceback. """ try: self.failureResultOf(self.raisesException(), KeyError) except self.failureException as e: self.assertIn(self.failure.getTraceback(), str(e)) test_failureResultOfWithWrongExceptionOneExpectedExceptionHasTB.todo = ( "Tracebacks aren't preserved by exceptions later wrapped in Failures" ) def test_failureResultOfWithWrongExceptionMultiExpectedExceptions(self): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception of a type that was not expected, and the L{SynchronousTestCase.failureException} message contains expected exception types in the error message. """ try: self.failureResultOf(self.raisesException(), KeyError, IOError) except self.failureException as e: self.assertIn( "Failure of type ({0}.{1} or {2}.{3}) expected on".format( KeyError.__module__, KeyError.__name__, IOError.__module__, IOError.__name__, ), str(e) ) def test_failureResultOfWithWrongExceptionMultiExpectedExceptionsHasTB( self ): """ L{SynchronousTestCase.failureResultOf} raises L{SynchronousTestCase.failureException} when called with a coroutine that raises an exception of a type that was not expected, and the L{SynchronousTestCase.failureException} message contains the original exception traceback in the error message. """ try: self.failureResultOf(self.raisesException(), KeyError, IOError) except self.failureException as e: self.assertIn(self.failure.getTraceback(), str(e)) test_failureResultOfWithWrongExceptionMultiExpectedExceptionsHasTB.todo = ( "Tracebacks aren't preserved by exceptions later wrapped in Failures" ) def test_successResultOfWithSuccessResult(self): """ When passed a coroutine which currently has a result (ie, if converted into a L{Deferred}, L{Deferred.addCallback} would cause the added callback to be called before C{addCallback} returns), L{SynchronousTestCase.successResultOf} returns that result. """ self.assertIdentical( self.result, self.successResultOf(self.successResult()) ) def test_failureResultOfWithExpectedException(self): """ When passed a coroutine which currently has an exception result (ie, if converted into a L{Deferred}, L{Deferred.addErrback} would cause the added errback to be called before C{addErrback} returns), L{SynchronousTestCase.failureResultOf} returns a L{Failure} containing that exception, if the exception type is expected. """ self.assertEqual( self.failure.value, self.failureResultOf( self.raisesException(), self.failure.type, KeyError ).value ) def test_failureResultOfWithException(self): """ When passed a coroutine which currently has an exception result (ie, if converted into a L{Deferred}, L{Deferred.addErrback} would cause the added errback to be called before C{addErrback} returns), L{SynchronousTestCase.failureResultOf} returns returns a L{Failure} containing that exception. """ self.assertEqual( self.failure.value, self.failureResultOf(self.raisesException()).value ) def test_assertNoResultSuccess(self): """ When passed a coroutine which currently has a success result (see L{test_withSuccessResult}), L{SynchronousTestCase.assertNoResult} raises L{SynchronousTestCase.failureException}. """ self.assertRaises( self.failureException, self.assertNoResult, self.successResult() ) def test_assertNoResultFailure(self): """ When passed a coroutine which currently has an exception result (see L{test_withFailureResult}), L{SynchronousTestCase.assertNoResult} raises L{SynchronousTestCase.failureException}. """ self.assertRaises( self.failureException, self.assertNoResult, self.raisesException() ) def test_assertNoResult(self): """ When passed a coroutine with no current result, L{SynchronousTestCase.assertNoResult} does not raise an exception. """ self.assertNoResult(self.noCurrentResult()) def test_assertNoResultPropagatesSuccess(self): """ When passed a coroutine awaiting a L{Deferred} with no current result, which is then fired with a success result, L{SynchronousTestCase.assertNoResult} doesn't modify the result of the L{Deferred}. """ d = Deferred() async def noCurrentResult(): return await d c = noCurrentResult() self.assertNoResult(d) d.callback(self.result) self.assertEqual(self.result, self.successResultOf(c)) def test_assertNoResultPropagatesLaterFailure(self): """ When passed a coroutine awaiting a L{Deferred} with no current result, which is then fired with a L{Failure} result, L{SynchronousTestCase.assertNoResult} doesn't modify the result of the L{Deferred}. """ f = Failure(self.exception) d = Deferred() async def noCurrentResult(): return await d c = noCurrentResult() self.assertNoResult(d) d.errback(f) self.assertEqual(f.value, self.failureResultOf(c).value) def test_assertNoResultSwallowsImmediateFailure(self): """ When passed a L{Deferred} which currently has a L{Failure} result, L{SynchronousTestCase.assertNoResult} changes the result of the L{Deferred} to a success. """ d = fail(self.failure) async def raisesException(): return await d c = raisesException() try: self.assertNoResult(d) except self.failureException: pass self.assertEqual(None, self.successResultOf(c))