def _addOutcome(self, outcome, test, error=None, details=None, error_permitted=True): """Report a failure in test test. Only one of error and details should be provided: conceptually there are two separate methods: addOutcome(self, test, error) addOutcome(self, test, details) :param outcome: A string describing the outcome - used as the event name in the subunit stream. :param error: Standard unittest positional argument form - an exc_info tuple. :param details: New Testing-in-python drafted API; a dict from string to subunit.Content objects. :param error_permitted: If True then one and only one of error or details must be supplied. If False then error must not be supplied and details is still optional. """ self._stream.write(_b("%s: " % outcome) + self._test_id(test)) if error_permitted: if error is None and details is None: raise ValueError else: if error is not None: raise ValueError if error is not None: self._stream.write(self._start_simple) tb_content = TracebackContent(error, test) for bytes in tb_content.iter_bytes(): self._stream.write(bytes) elif details is not None: self._write_details(details) else: self._stream.write(_b("\n")) if details is not None or error is not None: self._stream.write(self._end_simple)
def test___init___sets_ivars(self): content = TracebackContent(an_exc_info, self) content_type = ContentType("text", "x-traceback", {"language": "python", "charset": "utf8"}) self.assertEqual(content_type, content.content_type) result = unittest.TestResult() expected = result._exc_info_to_string(an_exc_info, self) self.assertEqual(expected, "".join(list(content.iter_text())))
def test___init___sets_ivars(self): content = TracebackContent(an_exc_info, self) content_type = ContentType("text", "x-traceback", {"language": "python", "charset": "utf8"}) self.assertEqual(content_type, content.content_type) result = unittest.TestResult() expected = result._exc_info_to_string(an_exc_info, self) self.assertEqual(expected, ''.join(list(content.iter_text())))
def setUp(self): self.io = StringIO() self.protocol = subunit.TestProtocolClient(self.io) self.test = TestTestProtocolClient("test_start_test") self.sample_details = {'something':Content( ContentType('text', 'plain'), lambda:['serialised\nform'])} self.sample_tb_details = dict(self.sample_details) self.sample_tb_details['traceback'] = TracebackContent( subunit.RemoteError(u"boo qux"), self.test)
def failure_content(failure): """Create a Content object for a Failure. :param Failure failure: The failure to create content for. :rtype: ``Content`` """ return TracebackContent( (failure.type, failure.value, failure.getTracebackObject()), None, )
def test_add_xfail(self): self.result.startTest(self) try: 1 / 0 except ZeroDivisionError: error = sys.exc_info() self.result.addExpectedFailure(self, error) self.result.stopTest(self) self.assertCalled(status='xfail', details={'traceback': TracebackContent(error, self)})
def test_add_failure(self): self.result.startTest(self) try: self.fail("intentional failure") except self.failureException: failure = sys.exc_info() self.result.addFailure(self, failure) self.result.stopTest(self) self.assertCalled( status='failure', details={'traceback': TracebackContent(failure, self)})
def _addOutcome(self, outcome, test, error=None, details=None, error_permitted=True): """Report a test outcome to the subunit stream The parent class uses this function as a common implementation for various methods that report successes, errors, failures, etc. This version automatically upgrades the error tracebacks to the new 'details' format by wrapping them in a Content object, so that we can include the captured test output in the test result details. Args: outcome: A string describing the outcome - used as the event name in the subunit stream. test: The test case whose outcome is to be reported error: Standard unittest positional argument form - an exc_info tuple. details: New Testing-in-python drafted API; a dict from string to subunit.Content objects. error_permitted: If True then one and only one of error or details must be supplied. If False then error must not be supplied and details is still optional. """ if details is None: details = {} # Parent will raise an exception if error_permitted is False but # error is not None. We want that exception in that case, so # don't touch error when error_permitted is explicitly False. if error_permitted and error is not None: # Parent class prefers error over details details['traceback'] = TracebackContent(error, test) error_permitted = False error = None if self.buffer: stdout = sys.stdout.getvalue() if stdout: details['stdout'] = text_content(stdout) stderr = sys.stderr.getvalue() if stderr: details['stderr'] = text_content(stderr) return super()._addOutcome(outcome, test, error=error, details=details, error_permitted=error_permitted)
def get_error_string(self, e): """Get the string showing how 'e' would be formatted in test output. This is a little bit hacky, since it's designed to give consistent output regardless of Python version. In testtools, TestResult._exc_info_to_unicode is the point of dispatch between various different implementations of methods that format exceptions, so that's what we have to call. However, that method cares about stack traces and formats the exception class. We don't care about either of these, so we take its output and parse it a little. """ error = TracebackContent((e.__class__, e, None), self).as_text() # We aren't at all interested in the traceback. if error.startswith('Traceback (most recent call last):\n'): lines = error.splitlines(True)[1:] for i, line in enumerate(lines): if not line.startswith(' '): break error = ''.join(lines[i:]) # We aren't interested in how the exception type is formatted. exc_class, error = error.split(': ', 1) return error
def match(self, other): if type(other) != tuple: return Mismatch('{!r} is not an exc_info tuple'.format(other)) expected_class = self.expected etype, evalue, etb = other if not issubclass(etype, expected_class): return Mismatch( "{!r} is an instance of {}, expected an instance of {}.".format( evalue, etype, expected_class, ), dict( traceback=TracebackContent(other, None), ), )
def test_failing_fails(self): # A Deferred that has fired with a failure fails to match. deferred = defer.Deferred() fail = make_failure(RuntimeError('arbitrary failure')) deferred.errback(fail) arbitrary_matcher = Is(None) self.assertThat( self.match(arbitrary_matcher, deferred), mismatches( Equals( _u('Success result expected on %r, found failure result ' 'instead: %r' % (deferred, fail))), Equals({'traceback': TracebackContent( (fail.type, fail.value, fail.getTracebackObject()), None, )}), ))
def test___init___None_errors(self): self.assertThat(lambda: TracebackContent(None, None), raises_value_error)
def _err_details_to_string(self, test, err=None, details=None): """Convert an error in exc_info form or a contents dict to a string.""" if err is not None: return TracebackContent(err, test).as_text() return _details_to_str(details, special='traceback')
def _err_to_details(self, test, err, details): if details: return details return {'traceback': TracebackContent(err, test)}
def _exc_info_to_unicode(self, err, test): # Deprecated. Only present because subunit upcalls to it. See # <https://bugs.launchpad.net/testtools/+bug/929063>. return TracebackContent(err, test).as_text()