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.py67
1 files changed, 49 insertions, 18 deletions
diff --git a/lib/testtools/testtools/testresult/real.py b/lib/testtools/testtools/testresult/real.py
index 8c8a3edd6e..95f6e8f04c 100644
--- a/lib/testtools/testtools/testresult/real.py
+++ b/lib/testtools/testtools/testresult/real.py
@@ -13,6 +13,8 @@ __all__ = [
import datetime
import unittest
+from testtools.compat import _format_exc_info, str_is_unicode, _u
+
class TestResult(unittest.TestResult):
"""Subclass of unittest.TestResult extending the protocol for flexability.
@@ -105,10 +107,27 @@ class TestResult(unittest.TestResult):
"""Called when a test was expected to fail, but succeed."""
self.unexpectedSuccesses.append(test)
+ 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 _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 self._exc_info_to_string(err, test)
+ return self._exc_info_to_unicode(err, test)
return _details_to_str(details)
def _now(self):
@@ -165,41 +184,43 @@ class MultiTestResult(TestResult):
self._results = map(ExtendedToOriginalDecorator, results)
def _dispatch(self, message, *args, **kwargs):
- for result in self._results:
+ return tuple(
getattr(result, message)(*args, **kwargs)
+ for result in self._results)
def startTest(self, test):
- self._dispatch('startTest', test)
+ return self._dispatch('startTest', test)
def stopTest(self, test):
- self._dispatch('stopTest', test)
+ return self._dispatch('stopTest', test)
def addError(self, test, error=None, details=None):
- self._dispatch('addError', test, error, details=details)
+ return self._dispatch('addError', test, error, details=details)
def addExpectedFailure(self, test, err=None, details=None):
- self._dispatch('addExpectedFailure', test, err, details=details)
+ return self._dispatch(
+ 'addExpectedFailure', test, err, details=details)
def addFailure(self, test, err=None, details=None):
- self._dispatch('addFailure', test, err, details=details)
+ return self._dispatch('addFailure', test, err, details=details)
def addSkip(self, test, reason=None, details=None):
- self._dispatch('addSkip', test, reason, details=details)
+ return self._dispatch('addSkip', test, reason, details=details)
def addSuccess(self, test, details=None):
- self._dispatch('addSuccess', test, details=details)
+ return self._dispatch('addSuccess', test, details=details)
def addUnexpectedSuccess(self, test, details=None):
- self._dispatch('addUnexpectedSuccess', test, details=details)
+ return self._dispatch('addUnexpectedSuccess', test, details=details)
def startTestRun(self):
- self._dispatch('startTestRun')
+ return self._dispatch('startTestRun')
def stopTestRun(self):
- self._dispatch('stopTestRun')
+ return self._dispatch('stopTestRun')
def done(self):
- self._dispatch('done')
+ return self._dispatch('done')
class TextTestResult(TestResult):
@@ -508,13 +529,23 @@ class ExtendedToOriginalDecorator(object):
class _StringException(Exception):
"""An exception made from an arbitrary string."""
+ if not str_is_unicode:
+ def __init__(self, string):
+ if type(string) is not unicode:
+ raise TypeError("_StringException expects unicode, got %r" %
+ (string,))
+ Exception.__init__(self, string)
+
+ def __str__(self):
+ return self.args[0].encode("utf-8")
+
+ def __unicode__(self):
+ return self.args[0]
+ # For 3.0 and above the default __str__ is fine, so we don't define one.
+
def __hash__(self):
return id(self)
- def __str__(self):
- """Stringify better than 2.x's default behaviour of ascii encoding."""
- return self.args[0]
-
def __eq__(self, other):
try:
return self.args == other.args
@@ -537,4 +568,4 @@ def _details_to_str(details):
if not chars[-1].endswith('\n'):
chars.append('\n')
chars.append('------------\n')
- return ''.join(chars)
+ return _u('').join(chars)