diff options
| author | Martin <gzlist@googlemail.com> | 2010-05-25 22:36:53 +0100 |
|---|---|---|
| committer | Martin <gzlist@googlemail.com> | 2010-05-25 22:36:53 +0100 |
| commit | 55335bc57af8a06ecbf8616bba070bb37ec1df79 (patch) | |
| tree | 6d7f579734b3acd498f55e26445c229fbd890be9 /testtools | |
| parent | c3c962193af8f96c42205a7dc00da1978208b14f (diff) | |
| download | testtools-55335bc57af8a06ecbf8616bba070bb37ec1df79.tar.gz | |
Pull out code for improving rather than just emulating formatting, work on tests some more, and other minor changes
Diffstat (limited to 'testtools')
| -rw-r--r-- | testtools/tests/test_testresult.py | 78 | ||||
| -rw-r--r-- | testtools/utils.py | 27 |
2 files changed, 62 insertions, 43 deletions
diff --git a/testtools/tests/test_testresult.py b/testtools/tests/test_testresult.py index 4daf81c..ae7234a 100644 --- a/testtools/tests/test_testresult.py +++ b/testtools/tests/test_testresult.py @@ -4,6 +4,7 @@ __metaclass__ = type +import codecs import datetime try: from cStringIO import StringIO @@ -14,6 +15,7 @@ import os import sys import tempfile import threading +import warnings from testtools import ( ExtendedToOriginalDecorator, @@ -827,7 +829,8 @@ class TestNonAsciiResults(TestCase): ) def _run(self, stream, test): - result = TextTestResult(unicode_output_stream(stream, "UTF-8")) + """Run the test, the same as in testtools.run but not to stdout""" + result = TextTestResult(codecs.getwriter("UTF-8")(stream)) result.startTestRun() try: return test.run(result) @@ -835,46 +838,50 @@ class TestNonAsciiResults(TestCase): result.stopTestRun() def _run_external_case(self, testline, coding="ascii", modulelevel="", - name=None, prefix="TestNonAscii"): + name=None, prefix="TestNonAscii", additional_setup=None): """Create and run a test case in a seperate module""" if name is None: name = self.id().rsplit(".", 1)[1] - program_as_text = ( - "# coding: %s\n" - "import testtools\n" - "%s\n" - "class Test(testtools.TestCase):\n" - " def runTest(self):\n" - " %s\n") % (coding, modulelevel, testline) + program_as_text = + self.dir = tempfile.mkdtemp(prefix=prefix) + self.addCleanup(self._rmtempdir) + filename = os.path.join(self.dir, name + ".py") try: - program_as_bytes = program_as_text.encode(coding) + f = codecs.open(filename, "w", encoding=coding) except LookupError: - print "S", self.skip("Encoding unsupported by implementation: %r" % coding) - dir = tempfile.mkdtemp(prefix=prefix) - self.addCleanup(self._rmtempdir, dir) - filename = os.path.join(dir, name + ".py") - f = file(filename, "w") try: - # Does Python 3 let you write bytes to a text file like this? - f.write(program_as_bytes) + f.write( + "# coding: %s\n" + "import testtools\n" + "%s\n" + "class Test(testtools.TestCase):\n" + " def runTest(self):\n" + " %s\n") % (coding, modulelevel, testline)) finally: f.close() - sys.path.insert(0, dir) - self.addCleanup(sys.path.remove, dir) + sys.path.insert(0, self.dir) + self.addCleanup(sys.path.remove, self.dir) module = __import__(name) + if additional_setup is not None: + additional_setup() stream = StringIO() self._run(stream, module.Test()) return stream.getvalue() - def _rmtempdir(self, dir): + def _rmtempdir(self): """Like shutil.rmtree but... whatever""" - for root, dirs, files in os.walk(dir, topdown=False): + for root, dirs, files in os.walk(self.dir, topdown=False): for d in dirs: os.rmdir(os.path.join(root, d)) for f in files: os.remove(os.path.join(root, f)) os.rmdir(root) + + def _silence_deprecation_warnings(self): + """Shut up DeprecationWarning for this test only""" + warnings.simplefilter("ignore", DeprecationWarning) + self.addCleanup(warnings.filters.remove, warnings.filters[0]) def _get_sample_text(self, encoding): if sys.version_info > (3, 0) or sys.platform == "cli": @@ -946,7 +953,7 @@ class TestNonAsciiResults(TestCase): self.assertIn(self._as_output("\u1234"), textoutput) def test_unprintable_exception(self): - """Even totally useless exception instances should format somehow""" + """A totally useless exception instance still prints something""" execption_class = ( "class UnprintableError(Exception):\n" " def __str__(self):\n" @@ -960,6 +967,16 @@ class TestNonAsciiResults(TestCase): "\nUnprintableError: <unprintable UnprintableError object>\n"), textoutput) + # GZ 2010-05-25: Seems this breaks testtools internals. + def _disabled_test_string_exception(self): + """Raise a string rather than an exception instance if supported""" + if sys.version_info > (2, 6): + self.skip("No string exceptions in Python 2.6 or later") + elif sys.version_info > (2, 5): + self._silence_deprecation_warnings() + textoutput = self._run_external_case(testline="raise 'plain str'") + self.assertIn(self._as_output("\nplain str\n"), textoutput) + def test_non_ascii_dirname(self): """Script paths in the traceback can be non-ascii""" text, raw = self._get_sample_text(sys.getfilesystemencoding()) @@ -974,10 +991,27 @@ class TestNonAsciiResults(TestCase): self.assertIn(self._as_output( ' File "<string>", line 1\n' ' f(a, b c)\n' + # GZ 2010-05-25: The next line makes this test fail on Jython as + # the caret points at the space not the identifier ' ^\n' 'SyntaxError: ' ), textoutput) + def test_syntax_error_import_binary(self): + """Importing a binary file shouldn't break SyntaxError formatting""" + if sys.version_info < (2, 5): + # Python 2.4 assumes the file is latin-1 and tells you off + self._silence_deprecation_warnings() + def _put_fake_module(): + f = file(os.path.join(self.dir, "bad.py"), "wb") + try: + f.write(_b("x\x9c\xcb*\xcd\xcb\x06\x00\x04R\x01\xb9")) + finally: + f.close() + textoutput = self._run_external_case("import bad", + additional_setup=_put_fake_module) + self.assertIn(self._as_output("\nSyntaxError: "), textoutput) + class TestNonAsciiResultsWithUnittest(TestNonAsciiResults): """Test that running under unittest produces clean ascii strings""" diff --git a/testtools/utils.py b/testtools/utils.py index 4606a6a..2db8767 100644 --- a/testtools/utils.py +++ b/testtools/utils.py @@ -44,7 +44,7 @@ def iterate_tests(test_suite_or_case): for subtest in iterate_tests(test): yield subtest -def unicode_output_stream(stream, default_encoding="ascii"): +def unicode_output_stream(stream): """ Return wrapper for given stream that correctly writes arbitrary unicode @@ -64,7 +64,7 @@ def unicode_output_stream(stream, default_encoding="ascii"): return codecs.getwriter(encoding)(stream, "replace") except LookupError: pass - return codecs.getwriter(default_encoding)(stream, "replace") + return codecs.getwriter("ascii")(stream, "replace") # The default source encoding is actually "iso-8859-1" until Python 2.5 but @@ -97,7 +97,7 @@ def _detect_encoding(lines): try: "".decode(encoding, "replace") except LookupError: - # Some encodings raise something other than LookupError if they don't + # Some codecs raise something other than LookupError if they don't # support the given error handler, but not the text ones that could # actually be used for Python source code return _default_source_encoding @@ -145,12 +145,6 @@ def _exception_to_text(evalue): raise except: pass - try: - return repr(evalue).replace("\\n", "\n").decode("ascii", "replace") - except KeyboardInterrupt: - raise - except: - pass # Okay, out of ideas, let higher level handle it return None @@ -180,8 +174,8 @@ def _format_exc_info(eclass, evalue, tb, limit=None): list = [] if evalue is None: # Is a (deprecated) string exception - list.append("str exception: %r\n" % sclass) - elif isinstance(evalue, SyntaxError): + list.append(sclass.decode("ascii", "replace")) + elif isinstance(evalue, SyntaxError) and len(evalue.args) > 1: # Avoid duplicating the special formatting for SyntaxError here, # instead create a new instance with unicode filename and line # Potentially gives duff spacing, but that's a pre-existing issue @@ -193,16 +187,7 @@ def _format_exc_info(eclass, evalue, tb, limit=None): evalue = eclass(evalue.args[0], (filename, lineno, offset, line)) list.extend(traceback.format_exception_only(eclass, evalue)) else: - smodule = eclass.__module__ - if smodule in ("exceptions", "__main__"): - # Is a builtin exception or in script, module is uninteresting - sclass = eclass.__name__ - elif True: - sclass = eclass.__name__ - # GZ 2010-05-24: Would be nice to do the below instead, but let's - # not change behaviours for the moment - else: - sclass = "%s.%s" % (smodule, eclass.__name__) + sclass = eclass.__name__ svalue = _exception_to_text(evalue) if svalue: list.append("%s: %s\n" % (sclass, svalue)) |
