summaryrefslogtreecommitdiff
path: root/lib/testtools/testtools/testresult/real.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/testtools/testtools/testresult/real.py')
-rw-r--r--lib/testtools/testtools/testresult/real.py57
1 files changed, 41 insertions, 16 deletions
diff --git a/lib/testtools/testtools/testresult/real.py b/lib/testtools/testtools/testresult/real.py
index aec6edb032..a627f0900e 100644
--- a/lib/testtools/testtools/testresult/real.py
+++ b/lib/testtools/testtools/testresult/real.py
@@ -12,6 +12,7 @@ __all__ = [
import datetime
import sys
+import traceback
import unittest
from testtools.compat import all, _format_exc_info, str_is_unicode, _u
@@ -35,6 +36,9 @@ class UTC(datetime.tzinfo):
utc = UTC()
+STDOUT_LINE = '\nStdout:\n%s'
+STDERR_LINE = '\nStderr:\n%s'
+
class TestResult(unittest.TestResult):
"""Subclass of unittest.TestResult extending the protocol for flexability.
@@ -137,22 +141,43 @@ class TestResult(unittest.TestResult):
"""
return not (self.errors or self.failures or self.unexpectedSuccesses)
- if str_is_unicode:
- # Python 3 and IronPython strings are unicode, use parent class method
- _exc_info_to_unicode = unittest.TestResult._exc_info_to_string
- else:
- # For Python 2, need to decode components of traceback according to
- # their source, so can't use traceback.format_exception
- # Here follows a little deep magic to copy the existing method and
- # replace the formatter with one that returns unicode instead
- from types import FunctionType as __F, ModuleType as __M
- __f = unittest.TestResult._exc_info_to_string.im_func
- __g = dict(__f.func_globals)
- __m = __M("__fake_traceback")
- __m.format_exception = _format_exc_info
- __g["traceback"] = __m
- _exc_info_to_unicode = __F(__f.func_code, __g, "_exc_info_to_unicode")
- del __F, __M, __f, __g, __m
+ def _exc_info_to_unicode(self, err, test):
+ """Converts a sys.exc_info()-style tuple of values into a string.
+
+ Copied from Python 2.7's unittest.TestResult._exc_info_to_string.
+ """
+ exctype, value, tb = err
+ # Skip test runner traceback levels
+ while tb and self._is_relevant_tb_level(tb):
+ tb = tb.tb_next
+
+ # testtools customization. When str is unicode (e.g. IronPython,
+ # Python 3), traceback.format_exception returns unicode. For Python 2,
+ # it returns bytes. We need to guarantee unicode.
+ if str_is_unicode:
+ format_exception = traceback.format_exception
+ else:
+ format_exception = _format_exc_info
+
+ if test.failureException and isinstance(value, test.failureException):
+ # Skip assert*() traceback levels
+ length = self._count_relevant_tb_levels(tb)
+ msgLines = format_exception(exctype, value, tb, length)
+ else:
+ msgLines = format_exception(exctype, value, tb)
+
+ if getattr(self, 'buffer', None):
+ output = sys.stdout.getvalue()
+ error = sys.stderr.getvalue()
+ if output:
+ if not output.endswith('\n'):
+ output += '\n'
+ msgLines.append(STDOUT_LINE % output)
+ if error:
+ if not error.endswith('\n'):
+ error += '\n'
+ msgLines.append(STDERR_LINE % error)
+ return ''.join(msgLines)
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."""