From 93d8ed3ffed812c37cf54b4ccc22a25026f940ae Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 10 Mar 2011 17:37:19 -0500 Subject: Work around Python3 syntax errors. Notions borrowed from the 'six' portability library. --- python/subunit/__init__.py | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 9dc849a..aadd228 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -118,12 +118,11 @@ Utility modules import os import re -from StringIO import StringIO import subprocess import sys import unittest -import iso8601 +import subunit.iso8601 from testtools import content, content_type, ExtendedToOriginalDecorator try: from testtools.testresult.real import _StringException @@ -142,6 +141,22 @@ PROGRESS_CUR = 1 PROGRESS_PUSH = 2 PROGRESS_POP = 3 +if sys.version_info >= (3, 0): + def b(s): + return s.encode("latin-1") + def u(s): + return s + import io + StringIO = io.StringIO + BytesIO = io.BytesIO +else: + def b(s): + return s + def u(s): + return unicode(s) + import StringIO + StringIO = BytesIO = StringIO.StringIO + def test_suite(): import subunit.tests @@ -241,7 +256,7 @@ class _ParserState(object): def lostConnection(self): """Connection lost.""" - self.parser._lostConnectionInTest(u'unknown state of ') + self.parser._lostConnectionInTest(u('unknown state of ')) def startTest(self, offset, line): """A test start command received.""" @@ -321,7 +336,7 @@ class _InTest(_ParserState): def lostConnection(self): """Connection lost.""" - self.parser._lostConnectionInTest(u'') + self.parser._lostConnectionInTest(u('')) class _OutSideTest(_ParserState): @@ -356,8 +371,8 @@ class _ReadingDetails(_ParserState): def lostConnection(self): """Connection lost.""" - self.parser._lostConnectionInTest(u'%s report of ' % - self._outcome_label()) + self.parser._lostConnectionInTest(u('%s report of ' % + self._outcome_label())) def _outcome_label(self): """The label to describe this outcome.""" @@ -488,9 +503,10 @@ class TestProtocolServer(object): def _handleTime(self, offset, line): # Accept it, but do not do anything with it yet. try: - event_time = iso8601.parse_date(line[offset:-1]) - except TypeError, e: - raise TypeError("Failed to parse %r, got %r" % (line, e)) + event_time = subunit.iso8601.parse_date(line[offset:-1]) + except TypeError: + raise TypeError("Failed to parse %r, got %r" + % (line, sys.exec_info[1])) self.client.time(event_time) def lineReceived(self, line): @@ -498,8 +514,8 @@ class TestProtocolServer(object): self._state.lineReceived(line) def _lostConnectionInTest(self, state_string): - error_string = u"lost connection during %stest '%s'" % ( - state_string, self.current_test_description) + error_string = u("lost connection during %stest '%s'" % ( + state_string, self.current_test_description)) self.client.addError(self._current_test, RemoteError(error_string)) self.client.stopTest(self._current_test) @@ -680,7 +696,7 @@ class TestProtocolClient(testresult.TestResult): ":param datetime: A datetime.datetime object. """ - time = a_datetime.astimezone(iso8601.Utc()) + time = a_datetime.astimezone(subunit.iso8601.Utc()) self._stream.write("time: %04d-%02d-%02d %02d:%02d:%02d.%06dZ\n" % ( time.year, time.month, time.day, time.hour, time.minute, time.second, time.microsecond)) @@ -710,7 +726,7 @@ class TestProtocolClient(testresult.TestResult): """Obey the testtools result.done() interface.""" -def RemoteError(description=u""): +def RemoteError(description=u("")): return (_StringException, _StringException(description), None) @@ -760,7 +776,7 @@ class RemotedTestCase(unittest.TestCase): def run(self, result=None): if result is None: result = self.defaultTestResult() result.startTest(self) - result.addError(self, RemoteError(u"Cannot run RemotedTestCases.\n")) + result.addError(self, RemoteError(u("Cannot run RemotedTestCases.\n"))) result.stopTest(self) def _strclass(self): -- cgit v1.2.1 From 049a3c5342faac9aa46afc9a882ab37950331fb5 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 09:29:56 +1200 Subject: Get pydoc3.1 subunit working. --- python/subunit/details.py | 2 +- python/subunit/test_results.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/subunit/details.py b/python/subunit/details.py index aedba9d..36c9974 100644 --- a/python/subunit/details.py +++ b/python/subunit/details.py @@ -19,7 +19,7 @@ from testtools import content, content_type from testtools.compat import StringIO -import chunked +from subunit import chunked class DetailsParser(object): diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py index e7f9171..63ef0b9 100644 --- a/python/subunit/test_results.py +++ b/python/subunit/test_results.py @@ -18,9 +18,10 @@ import datetime -import iso8601 import testtools +from subunit import iso8601 + # NOT a TestResult, because we are implementing the interface, not inheriting # it. -- cgit v1.2.1 From aaa87b0d6f110bd52fe659c0fca873d820ad31f2 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 09:40:52 +1200 Subject: Make test suite importable in py3. --- python/subunit/tests/TestUtil.py | 2 +- python/subunit/tests/test_chunked.py | 3 ++- python/subunit/tests/test_details.py | 3 ++- python/subunit/tests/test_subunit_filter.py | 2 +- python/subunit/tests/test_subunit_stats.py | 3 ++- python/subunit/tests/test_subunit_tags.py | 3 ++- python/subunit/tests/test_tap2subunit.py | 4 +++- python/subunit/tests/test_test_protocol.py | 30 ++++++++++++++--------------- 8 files changed, 28 insertions(+), 22 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/TestUtil.py b/python/subunit/tests/TestUtil.py index 1b5ba9c..39d901e 100644 --- a/python/subunit/tests/TestUtil.py +++ b/python/subunit/tests/TestUtil.py @@ -53,7 +53,7 @@ def visitTests(suite, visitor): visitor.visitSuite(test) visitTests(test, visitor) else: - print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__) + print ("unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)) class TestSuite(unittest.TestSuite): diff --git a/python/subunit/tests/test_chunked.py b/python/subunit/tests/test_chunked.py index eee7fe9..6323b02 100644 --- a/python/subunit/tests/test_chunked.py +++ b/python/subunit/tests/test_chunked.py @@ -15,9 +15,10 @@ # limitations under that license. # -from cStringIO import StringIO import unittest +from testtools.compat import StringIO + import subunit.chunked diff --git a/python/subunit/tests/test_details.py b/python/subunit/tests/test_details.py index 41c3212..06eb430 100644 --- a/python/subunit/tests/test_details.py +++ b/python/subunit/tests/test_details.py @@ -14,9 +14,10 @@ # limitations under that license. # -from cStringIO import StringIO import unittest +from testtools.compat import StringIO + import subunit.tests from subunit import content, content_type, details diff --git a/python/subunit/tests/test_subunit_filter.py b/python/subunit/tests/test_subunit_filter.py index cf6c2b6..682f726 100644 --- a/python/subunit/tests/test_subunit_filter.py +++ b/python/subunit/tests/test_subunit_filter.py @@ -19,9 +19,9 @@ from datetime import datetime from subunit import iso8601 import unittest -from StringIO import StringIO from testtools import TestCase +from testtools.compat import StringIO from testtools.testresult.doubles import ExtendedTestResult import subunit diff --git a/python/subunit/tests/test_subunit_stats.py b/python/subunit/tests/test_subunit_stats.py index a7f8fca..778bb7f 100644 --- a/python/subunit/tests/test_subunit_stats.py +++ b/python/subunit/tests/test_subunit_stats.py @@ -17,7 +17,8 @@ """Tests for subunit.TestResultStats.""" import unittest -from StringIO import StringIO + +from testtools.compat import StringIO import subunit diff --git a/python/subunit/tests/test_subunit_tags.py b/python/subunit/tests/test_subunit_tags.py index 227e2b7..c98506a 100644 --- a/python/subunit/tests/test_subunit_tags.py +++ b/python/subunit/tests/test_subunit_tags.py @@ -17,7 +17,8 @@ """Tests for subunit.tag_stream.""" import unittest -from StringIO import StringIO + +from testtools.compat import StringIO import subunit import subunit.test_results diff --git a/python/subunit/tests/test_tap2subunit.py b/python/subunit/tests/test_tap2subunit.py index c4ca4cd..11bc191 100644 --- a/python/subunit/tests/test_tap2subunit.py +++ b/python/subunit/tests/test_tap2subunit.py @@ -17,7 +17,9 @@ """Tests for TAP2SubUnit.""" import unittest -from StringIO import StringIO + +from testtools.compat import StringIO + import subunit diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index f7bab5c..8171696 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -16,9 +16,9 @@ import datetime import unittest -from StringIO import StringIO import os +from testtools.compat import _u, StringIO from testtools.content import Content, TracebackContent from testtools.content_type import ContentType from testtools.tests.helpers import ( @@ -286,7 +286,7 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.protocol.lineReceived("test old mcdonald\n") self.protocol.lostConnection() failure = subunit.RemoteError( - u"lost connection during test 'old mcdonald'") + _u("lost connection during test 'old mcdonald'")) self.assertEqual([ ('startTest', self.test), ('addError', self.test, failure), @@ -299,7 +299,7 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.protocol.lostConnection() self.assertEqual([ ('startTest', self.test), - ('addError', self.test, subunit.RemoteError(u"")), + ('addError', self.test, subunit.RemoteError(_u(""))), ('stopTest', self.test), ], self.client._events) @@ -308,7 +308,7 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.protocol.lineReceived("%s old mcdonald %s" % (outcome, opening)) self.protocol.lostConnection() failure = subunit.RemoteError( - u"lost connection during %s report of test 'old mcdonald'" % + _u("lost connection during %s report of test 'old mcdonald'") % outcome) self.assertEqual([ ('startTest', self.test), @@ -328,7 +328,7 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.protocol.lostConnection() self.assertEqual([ ('startTest', self.test), - ('addFailure', self.test, subunit.RemoteError(u"")), + ('addFailure', self.test, subunit.RemoteError(_u(""))), ('stopTest', self.test), ], self.client._events) @@ -542,8 +542,8 @@ class TestTestProtocolServerAddxFail(unittest.TestCase): value = details else: if error_message is not None: - value = subunit.RemoteError(u'Text attachment: traceback\n' - '------------\n' + error_message + '------------\n') + value = subunit.RemoteError(_u("Text attachment: traceback\n" + "------------\n") + error_message + _u("------------\n")) else: value = subunit.RemoteError() self.assertEqual([ @@ -841,15 +841,15 @@ class TestRemotedTestCase(unittest.TestCase): class TestRemoteError(unittest.TestCase): def test_eq(self): - error = subunit.RemoteError(u"Something went wrong") - another_error = subunit.RemoteError(u"Something went wrong") - different_error = subunit.RemoteError(u"boo!") + error = subunit.RemoteError(_u("Something went wrong")) + another_error = subunit.RemoteError(_u("Something went wrong")) + different_error = subunit.RemoteError(_u("boo!")) self.assertEqual(error, another_error) self.assertNotEqual(error, different_error) self.assertNotEqual(different_error, another_error) def test_empty_constructor(self): - self.assertEqual(subunit.RemoteError(), subunit.RemoteError(u"")) + self.assertEqual(subunit.RemoteError(), subunit.RemoteError(_u(""))) class TestExecTestCase(unittest.TestCase): @@ -1000,7 +1000,7 @@ class TestTestProtocolClient(unittest.TestCase): 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) + subunit.RemoteError(_u("boo qux")), self.test) def test_start_test(self): """Test startTest on a TestProtocolClient.""" @@ -1030,7 +1030,7 @@ class TestTestProtocolClient(unittest.TestCase): def test_add_failure(self): """Test addFailure on a TestProtocolClient.""" self.protocol.addFailure( - self.test, subunit.RemoteError(u"boo qux")) + self.test, subunit.RemoteError(_u("boo qux"))) self.assertEqual( self.io.getvalue(), ('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n') @@ -1054,7 +1054,7 @@ class TestTestProtocolClient(unittest.TestCase): def test_add_error(self): """Test stopTest on a TestProtocolClient.""" self.protocol.addError( - self.test, subunit.RemoteError(u"phwoar crikey")) + self.test, subunit.RemoteError(_u("phwoar crikey"))) self.assertEqual( self.io.getvalue(), ('error: %s [\n' + @@ -1079,7 +1079,7 @@ class TestTestProtocolClient(unittest.TestCase): def test_add_expected_failure(self): """Test addExpectedFailure on a TestProtocolClient.""" self.protocol.addExpectedFailure( - self.test, subunit.RemoteError(u"phwoar crikey")) + self.test, subunit.RemoteError(_u("phwoar crikey"))) self.assertEqual( self.io.getvalue(), ('xfail: %s [\n' + -- cgit v1.2.1 From b21965301c3ab72e5e19848d1019ca2d8e83da50 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 10:36:45 +1200 Subject: More progress. --- python/subunit/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index ba7f63e..281c3dd 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -123,7 +123,7 @@ import sys import unittest from testtools import content, content_type, ExtendedToOriginalDecorator -from testtools.compat import _b, _u, StringIO +from testtools.compat import _b, _u, BytesIO, StringIO try: from testtools.testresult.real import _StringException RemoteException = _StringException @@ -212,7 +212,7 @@ class _ParserState(object): if len(parts) == 2 and line.startswith(parts[0]): cmd, rest = parts offset = len(cmd) + 1 - cmd = cmd.rstrip(':') + cmd = cmd.rstrip(_b(':')) if cmd in ('test', 'testing'): self.startTest(offset, line) elif cmd == 'error': @@ -439,7 +439,7 @@ class TestProtocolServer(object): :param stream: The stream that lines received which are not part of the subunit protocol should be written to. This allows custom handling of mixed protocols. By default, sys.stdout will be used for - convenience. + convenience. It should accept bytes to its write() method. :param forward_stream: A stream to forward subunit lines to. This allows a filter to forward the entire stream while still parsing and acting on it. By default forward_stream is set to @@ -447,7 +447,10 @@ class TestProtocolServer(object): """ self.client = ExtendedToOriginalDecorator(client) if stream is None: - stream = sys.stdout + if sys.version_info > (3, 0): + stream = sys.stdout.buffer + else: + stream = sys.stdout self._stream = stream self._forward_stream = forward_stream or DiscardStream() # state objects we can switch too @@ -796,7 +799,7 @@ class ExecTestCase(unittest.TestCase): protocol = TestProtocolServer(result) output = subprocess.Popen(self.script, shell=True, stdout=subprocess.PIPE).communicate()[0] - protocol.readFrom(StringIO(output)) + protocol.readFrom(BytesIO(output)) class IsolatedTestCase(unittest.TestCase): -- cgit v1.2.1 From 86cff2f184f6bbd34fd330bae739a29a34a78d2a Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 11:09:54 +1200 Subject: Progress. --- python/subunit/__init__.py | 9 ++++++--- python/subunit/details.py | 11 +++++++---- python/subunit/tests/test_details.py | 28 ++++++++++++++-------------- python/subunit/tests/test_test_protocol.py | 14 +++++++------- 4 files changed, 34 insertions(+), 28 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 281c3dd..6a46a40 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -185,6 +185,7 @@ class _ParserState(object): def __init__(self, parser): self.parser = parser + self._test_sym = (_b('test'), _b('testing')) def addError(self, offset, line): """An 'error:' directive has been read.""" @@ -213,7 +214,7 @@ class _ParserState(object): cmd, rest = parts offset = len(cmd) + 1 cmd = cmd.rstrip(_b(':')) - if cmd in ('test', 'testing'): + if cmd in self._test_sym: self.startTest(offset, line) elif cmd == 'error': self.addError(offset, line) @@ -332,8 +333,9 @@ class _OutSideTest(_ParserState): def startTest(self, offset, line): """A test start command received.""" self.parser._state = self.parser._in_test - self.parser._current_test = RemotedTestCase(line[offset:-1]) - self.parser.current_test_description = line[offset:-1] + test_name = line[offset:-1].decode('utf8') + self.parser._current_test = RemotedTestCase(test_name) + self.parser.current_test_description = test_name self.parser.client.startTest(self.parser._current_test) self.parser.subunitLineReceived(line) @@ -1138,6 +1140,7 @@ def get_default_formatter(): def _make_stream_binary(stream): """Ensure that a stream will be binary safe. See _make_binary_on_windows.""" if getattr(stream, 'fileno', None) is not None: + print (stream, type(stream)) _make_binary_on_windows(stream.fileno()) def _make_binary_on_windows(fileno): diff --git a/python/subunit/details.py b/python/subunit/details.py index 36c9974..9790543 100644 --- a/python/subunit/details.py +++ b/python/subunit/details.py @@ -17,10 +17,13 @@ """Handlers for outcome details.""" from testtools import content, content_type -from testtools.compat import StringIO +from testtools.compat import _b, StringIO from subunit import chunked +end_marker = _b("]\n") +quoted_marker = _b(" ]") + class DetailsParser(object): """Base class/API reference for details parsing.""" @@ -30,14 +33,14 @@ class SimpleDetailsParser(DetailsParser): """Parser for single-part [] delimited details.""" def __init__(self, state): - self._message = "" + self._message = _b("") self._state = state def lineReceived(self, line): - if line == "]\n": + if line == end_marker: self._state.endDetails() return - if line[0:2] == " ]": + if line[0:2] == quoted_marker: # quoted ] start self._message += line[1:] else: diff --git a/python/subunit/tests/test_details.py b/python/subunit/tests/test_details.py index 06eb430..49010d2 100644 --- a/python/subunit/tests/test_details.py +++ b/python/subunit/tests/test_details.py @@ -16,7 +16,7 @@ import unittest -from testtools.compat import StringIO +from testtools.compat import _b, StringIO import subunit.tests from subunit import content, content_type, details @@ -32,20 +32,20 @@ class TestSimpleDetails(unittest.TestCase): def test_lineReceived(self): parser = details.SimpleDetailsParser(None) - parser.lineReceived("foo\n") - parser.lineReceived("bar\n") - self.assertEqual("foo\nbar\n", parser._message) + parser.lineReceived(_b("foo\n")) + parser.lineReceived(_b("bar\n")) + self.assertEqual(_b("foo\nbar\n"), parser._message) def test_lineReceived_escaped_bracket(self): parser = details.SimpleDetailsParser(None) - parser.lineReceived("foo\n") - parser.lineReceived(" ]are\n") - parser.lineReceived("bar\n") - self.assertEqual("foo\n]are\nbar\n", parser._message) + parser.lineReceived(_b("foo\n")) + parser.lineReceived(_b(" ]are\n")) + parser.lineReceived(_b("bar\n")) + self.assertEqual(_b("foo\n]are\nbar\n"), parser._message) def test_get_message(self): parser = details.SimpleDetailsParser(None) - self.assertEqual("", parser.get_message()) + self.assertEqual(_b(""), parser.get_message()) def test_get_details(self): parser = details.SimpleDetailsParser(None) @@ -54,13 +54,13 @@ class TestSimpleDetails(unittest.TestCase): expected['traceback'] = content.Content( content_type.ContentType("text", "x-traceback", {'charset': 'utf8'}), - lambda:[""]) + lambda:[_b("")]) found = parser.get_details() self.assertEqual(expected.keys(), found.keys()) self.assertEqual(expected['traceback'].content_type, found['traceback'].content_type) - self.assertEqual(''.join(expected['traceback'].iter_bytes()), - ''.join(found['traceback'].iter_bytes())) + self.assertEqual(_b('').join(expected['traceback'].iter_bytes()), + _b('').join(found['traceback'].iter_bytes())) def test_get_details_skip(self): parser = details.SimpleDetailsParser(None) @@ -68,7 +68,7 @@ class TestSimpleDetails(unittest.TestCase): expected = {} expected['reason'] = content.Content( content_type.ContentType("text", "plain"), - lambda:[""]) + lambda:[_b("")]) found = parser.get_details("skip") self.assertEqual(expected, found) @@ -78,7 +78,7 @@ class TestSimpleDetails(unittest.TestCase): expected = {} expected['message'] = content.Content( content_type.ContentType("text", "plain"), - lambda:[""]) + lambda:[_b("")]) found = parser.get_details("success") self.assertEqual(expected, found) diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index 8171696..5541653 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -18,7 +18,7 @@ import datetime import unittest import os -from testtools.compat import _u, StringIO +from testtools.compat import _b, _u, StringIO from testtools.content import Content, TracebackContent from testtools.content_type import ContentType from testtools.tests.helpers import ( @@ -372,8 +372,8 @@ class TestInTestMultipart(unittest.TestCase): def setUp(self): self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") - self.test = subunit.RemotedTestCase("mcdonalds farm") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) + self.test = subunit.RemotedTestCase(_u("mcdonalds farm")) def test__outcome_sets_details_parser(self): self.protocol._reading_success_details.details_parser = None @@ -770,13 +770,13 @@ class TestTestProtocolServerStreamTags(unittest.TestCase): ], self.client._events) def test_tags_do_not_get_set_on_test(self): - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) test = self.client._events[0][-1] self.assertEqual(None, getattr(test, 'tags', None)) def test_tags_do_not_get_set_on_global_tags(self): - self.protocol.lineReceived("tags: foo bar\n") - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("tags: foo bar\n")) + self.protocol.lineReceived(_b("test mcdonalds farm\n")) test = self.client._events[-1][-1] self.assertEqual(None, getattr(test, 'tags', None)) @@ -884,7 +884,7 @@ class TestExecTestCase(unittest.TestCase): bing = subunit.RemotedTestCase("bing crosby") bing_details = {} bing_details['traceback'] = Content(ContentType("text", "x-traceback", - {'charset': 'utf8'}), lambda:["foo.c:53:ERROR invalid state\n"]) + {'charset': 'utf8'}), lambda:[_b("foo.c:53:ERROR invalid state\n")]) an_error = subunit.RemotedTestCase("an error") error_details = {} self.assertEqual([ -- cgit v1.2.1 From 970fe166268ac41a20aa6dc78e4c491ae5449173 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 11:19:53 +1200 Subject: More small stuff. --- python/subunit/__init__.py | 4 ++-- python/subunit/tests/test_test_protocol.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 6a46a40..5387cae 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -696,14 +696,14 @@ class TestProtocolClient(testresult.TestResult): :param details: An extended details dict for a test outcome. """ self._stream.write(" [ multipart\n") - for name, content in sorted(details.iteritems()): + for name, content in sorted(details.items()): self._stream.write("Content-Type: %s/%s" % (content.content_type.type, content.content_type.subtype)) parameters = content.content_type.parameters if parameters: self._stream.write(";") param_strs = [] - for param, value in parameters.iteritems(): + for param, value in parameters.items(): param_strs.append("%s=%s" % (param, value)) self._stream.write(",".join(param_strs)) self._stream.write("\n%s\n" % name) diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index 5541653..9152cce 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -18,7 +18,7 @@ import datetime import unittest import os -from testtools.compat import _b, _u, StringIO +from testtools.compat import _b, _u, BytesIO, StringIO from testtools.content import Content, TracebackContent from testtools.content_type import ContentType from testtools.tests.helpers import ( @@ -55,23 +55,23 @@ class TestProtocolServerForward(unittest.TestCase): def test_story(self): client = unittest.TestResult() - out = StringIO() + out = BytesIO() protocol = subunit.TestProtocolServer(client, forward_stream=out) - pipe = StringIO("test old mcdonald\n" - "success old mcdonald\n") + pipe = BytesIO(_b("test old mcdonald\n" + "success old mcdonald\n")) protocol.readFrom(pipe) self.assertEqual(client.testsRun, 1) self.assertEqual(pipe.getvalue(), out.getvalue()) def test_not_command(self): client = unittest.TestResult() - out = StringIO() + out = BytesIO() protocol = subunit.TestProtocolServer(client, stream=subunit.DiscardStream(), forward_stream=out) - pipe = StringIO("success old mcdonald\n") + pipe = BytesIO(_b("success old mcdonald\n")) protocol.readFrom(pipe) self.assertEqual(client.testsRun, 0) - self.assertEqual("", out.getvalue()) + self.assertEqual(_b(""), out.getvalue()) class TestTestProtocolServerPipe(unittest.TestCase): -- cgit v1.2.1 From 83ee9fc3528955994c55ba46c1784cbf6d3c3ae8 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 25 Apr 2011 00:37:52 +0100 Subject: Use try/except rather than getattr to test for fileno _make_stream_binary --- python/subunit/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 5387cae..146d2c1 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -1139,9 +1139,11 @@ def get_default_formatter(): def _make_stream_binary(stream): """Ensure that a stream will be binary safe. See _make_binary_on_windows.""" - if getattr(stream, 'fileno', None) is not None: - print (stream, type(stream)) - _make_binary_on_windows(stream.fileno()) + try: + fileno = stream.fileno() + except AttributeError: + return + _make_binary_on_windows(fileno) def _make_binary_on_windows(fileno): """Win32 mangles \r\n to \n and that breaks streams. See bug lp:505078.""" -- cgit v1.2.1 From 4953d515c61733237dc78842f0785ddd3e9d69c5 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 25 Apr 2011 00:38:27 +0100 Subject: Vary fileno attempt exception type to support Python 3 --- python/subunit/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 146d2c1..7e2f141 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -1137,11 +1137,16 @@ def get_default_formatter(): return sys.stdout +if sys.version_info > (3, 0): + from io import UnsupportedOperation as _NoFilenoError +else: + _NoFilenoError = AttributeError + def _make_stream_binary(stream): """Ensure that a stream will be binary safe. See _make_binary_on_windows.""" try: fileno = stream.fileno() - except AttributeError: + except _NoFilenoError: return _make_binary_on_windows(fileno) -- cgit v1.2.1 From 264161d485bfb5e2e952b329eb53d0a60555bced Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 25 Apr 2011 00:39:31 +0100 Subject: Remove presumably erroneous _make_stream_binary call --- python/subunit/__init__.py | 1 - 1 file changed, 1 deletion(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 7e2f141..a49641c 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -1058,7 +1058,6 @@ class ProtocolTestCase(object): _make_stream_binary(stream) self._passthrough = passthrough self._forward = forward - _make_stream_binary(forward) def __call__(self, result=None): return self.run(result) -- cgit v1.2.1 From d8df52062fbcee4da77b6e1cdb701defa2e8a2da Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 12:40:59 +1200 Subject: More fixups. --- python/subunit/__init__.py | 49 ++++-- python/subunit/tests/test_test_protocol.py | 269 +++++++++++++++-------------- 2 files changed, 168 insertions(+), 150 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 5387cae..14fb94d 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -186,6 +186,17 @@ class _ParserState(object): def __init__(self, parser): self.parser = parser self._test_sym = (_b('test'), _b('testing')) + self._colon_sym = _b(':') + self._error_sym = (_b('error'),) + self._failure_sym = (_b('failure'),) + self._progress_sym = (_b('progress'),) + self._skip_sym = _b('skip') + self._success_sym = (_b('success'), _b('successful')) + self._tags_sym = (_b('tags'),) + self._time_sym = (_b('time'),) + self._xfail_sym = (_b('xfail'),) + self._start_simple = _u(" [") + self._start_multipart = _u(" [ multipart") def addError(self, offset, line): """An 'error:' directive has been read.""" @@ -213,26 +224,26 @@ class _ParserState(object): if len(parts) == 2 and line.startswith(parts[0]): cmd, rest = parts offset = len(cmd) + 1 - cmd = cmd.rstrip(_b(':')) + cmd = cmd.rstrip(self._colon_sym) if cmd in self._test_sym: self.startTest(offset, line) - elif cmd == 'error': + elif cmd in self._error_sym: self.addError(offset, line) - elif cmd == 'failure': + elif cmd in self._failure_sym: self.addFailure(offset, line) - elif cmd == 'progress': + elif cmd in self._progress_sym: self.parser._handleProgress(offset, line) - elif cmd == 'skip': + elif cmd in self._skip_sym: self.addSkip(offset, line) - elif cmd in ('success', 'successful'): + elif cmd in self._success_sym: self.addSuccess(offset, line) - elif cmd in ('tags',): + elif cmd in self._tags_sym: self.parser._handleTags(offset, line) self.parser.subunitLineReceived(line) - elif cmd in ('time',): + elif cmd in self._time_sym: self.parser._handleTime(offset, line) self.parser.subunitLineReceived(line) - elif cmd == 'xfail': + elif cmd in self._xfail_sym: self.addExpectedFail(offset, line) else: self.parser.stdOutLineReceived(line) @@ -258,19 +269,21 @@ class _InTest(_ParserState): :param details_state: The state to switch to for details processing of this outcome. """ - if self.parser.current_test_description == line[offset:-1]: + test_name = line[offset:-1].decode('utf8') + if self.parser.current_test_description == test_name: self.parser._state = self.parser._outside_test self.parser.current_test_description = None no_details() self.parser.client.stopTest(self.parser._current_test) self.parser._current_test = None self.parser.subunitLineReceived(line) - elif self.parser.current_test_description + " [" == line[offset:-1]: + elif self.parser.current_test_description + self._start_simple == \ + test_name: self.parser._state = details_state details_state.set_simple() self.parser.subunitLineReceived(line) - elif self.parser.current_test_description + " [ multipart" == \ - line[offset:-1]: + elif self.parser.current_test_description + self._start_multipart == \ + test_name: self.parser._state = details_state details_state.set_multipart() self.parser.subunitLineReceived(line) @@ -465,17 +478,21 @@ class TestProtocolServer(object): self._reading_xfail_details = _ReadingExpectedFailureDetails(self) # start with outside test. self._state = self._outside_test + # Avoid casts on every call + self._plusminus = _b('+-') + self._push_sym = _b('push') + self._pop_sym = _b('pop') def _handleProgress(self, offset, line): """Process a progress directive.""" line = line[offset:].strip() - if line[0] in '+-': + if line[0] in self._plusminus: whence = PROGRESS_CUR delta = int(line) - elif line == "push": + elif line == self._push_sym: whence = PROGRESS_PUSH delta = None - elif line == "pop": + elif line == self._pop_sym: whence = PROGRESS_POP delta = None else: diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index 9152cce..7778fcc 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -79,14 +79,14 @@ class TestTestProtocolServerPipe(unittest.TestCase): def test_story(self): client = unittest.TestResult() protocol = subunit.TestProtocolServer(client) - pipe = StringIO("test old mcdonald\n" + pipe = BytesIO(_b("test old mcdonald\n" "success old mcdonald\n" "test bing crosby\n" "failure bing crosby [\n" "foo.c:53:ERROR invalid state\n" "]\n" "test an error\n" - "error an error\n") + "error an error\n")) protocol.readFrom(pipe) bing = subunit.RemotedTestCase("bing crosby") an_error = subunit.RemotedTestCase("an error") @@ -110,26 +110,26 @@ class TestTestProtocolServerStartTest(unittest.TestCase): self.protocol = subunit.TestProtocolServer(self.client) def test_start_test(self): - self.protocol.lineReceived("test old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) self.assertEqual(self.client._events, [('startTest', subunit.RemotedTestCase("old mcdonald"))]) def test_start_testing(self): - self.protocol.lineReceived("testing old mcdonald\n") + self.protocol.lineReceived(_b("testing old mcdonald\n")) self.assertEqual(self.client._events, [('startTest', subunit.RemotedTestCase("old mcdonald"))]) def test_start_test_colon(self): - self.protocol.lineReceived("test: old mcdonald\n") + self.protocol.lineReceived(_b("test: old mcdonald\n")) self.assertEqual(self.client._events, [('startTest', subunit.RemotedTestCase("old mcdonald"))]) def test_indented_test_colon_ignored(self): - self.protocol.lineReceived(" test: old mcdonald\n") + self.protocol.lineReceived(_b(" test: old mcdonald\n")) self.assertEqual([], self.client._events) def test_start_testing_colon(self): - self.protocol.lineReceived("testing: old mcdonald\n") + self.protocol.lineReceived(_b("testing: old mcdonald\n")) self.assertEqual(self.client._events, [('startTest', subunit.RemotedTestCase("old mcdonald"))]) @@ -137,22 +137,22 @@ class TestTestProtocolServerStartTest(unittest.TestCase): class TestTestProtocolServerPassThrough(unittest.TestCase): def setUp(self): - self.stdout = StringIO() + self.stdout = BytesIO() self.test = subunit.RemotedTestCase("old mcdonald") self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client, self.stdout) def keywords_before_test(self): - self.protocol.lineReceived("failure a\n") - self.protocol.lineReceived("failure: a\n") - self.protocol.lineReceived("error a\n") - self.protocol.lineReceived("error: a\n") - self.protocol.lineReceived("success a\n") - self.protocol.lineReceived("success: a\n") - self.protocol.lineReceived("successful a\n") - self.protocol.lineReceived("successful: a\n") - self.protocol.lineReceived("]\n") - self.assertEqual(self.stdout.getvalue(), "failure a\n" + self.protocol.lineReceived(_b("failure a\n")) + self.protocol.lineReceived(_b("failure: a\n")) + self.protocol.lineReceived(_b("error a\n")) + self.protocol.lineReceived(_b("error: a\n")) + self.protocol.lineReceived(_b("success a\n")) + self.protocol.lineReceived(_b("success: a\n")) + self.protocol.lineReceived(_b("successful a\n")) + self.protocol.lineReceived(_b("successful: a\n")) + self.protocol.lineReceived(_b("]\n")) + self.assertEqual(self.stdout.getvalue(), _b("failure a\n" "failure: a\n" "error a\n" "error: a\n" @@ -160,15 +160,15 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): "success: a\n" "successful a\n" "successful: a\n" - "]\n") + "]\n")) def test_keywords_before_test(self): self.keywords_before_test() self.assertEqual(self.client._events, []) def test_keywords_after_error(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("error old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("error old mcdonald\n")) self.keywords_before_test() self.assertEqual([ ('startTest', self.test), @@ -177,8 +177,8 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): ], self.client._events) def test_keywords_after_failure(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("failure old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("failure old mcdonald\n")) self.keywords_before_test() self.assertEqual(self.client._events, [ ('startTest', self.test), @@ -187,8 +187,8 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): ]) def test_keywords_after_success(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("success old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("success old mcdonald\n")) self.keywords_before_test() self.assertEqual([ ('startTest', self.test), @@ -197,19 +197,19 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): ], self.client._events) def test_keywords_after_test(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("failure a\n") - self.protocol.lineReceived("failure: a\n") - self.protocol.lineReceived("error a\n") - self.protocol.lineReceived("error: a\n") - self.protocol.lineReceived("success a\n") - self.protocol.lineReceived("success: a\n") - self.protocol.lineReceived("successful a\n") - self.protocol.lineReceived("successful: a\n") - self.protocol.lineReceived("]\n") - self.protocol.lineReceived("failure old mcdonald\n") - self.assertEqual(self.stdout.getvalue(), "test old mcdonald\n" + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("failure a\n")) + self.protocol.lineReceived(_b("failure: a\n")) + self.protocol.lineReceived(_b("error a\n")) + self.protocol.lineReceived(_b("error: a\n")) + self.protocol.lineReceived(_b("success a\n")) + self.protocol.lineReceived(_b("success: a\n")) + self.protocol.lineReceived(_b("successful a\n")) + self.protocol.lineReceived(_b("successful: a\n")) + self.protocol.lineReceived(_b("]\n")) + self.protocol.lineReceived(_b("failure old mcdonald\n")) + self.assertEqual(self.stdout.getvalue(), _b("test old mcdonald\n" "failure a\n" "failure: a\n" "error a\n" @@ -218,7 +218,7 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): "success: a\n" "successful a\n" "successful: a\n" - "]\n") + "]\n")) self.assertEqual(self.client._events, [ ('startTest', self.test), ('addFailure', self.test, {}), @@ -228,24 +228,24 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): def test_keywords_during_failure(self): # A smoke test to make sure that the details parsers have control # appropriately. - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("failure: old mcdonald [\n") - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("failure a\n") - self.protocol.lineReceived("failure: a\n") - self.protocol.lineReceived("error a\n") - self.protocol.lineReceived("error: a\n") - self.protocol.lineReceived("success a\n") - self.protocol.lineReceived("success: a\n") - self.protocol.lineReceived("successful a\n") - self.protocol.lineReceived("successful: a\n") - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") - self.assertEqual(self.stdout.getvalue(), "") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("failure: old mcdonald [\n")) + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("failure a\n")) + self.protocol.lineReceived(_b("failure: a\n")) + self.protocol.lineReceived(_b("error a\n")) + self.protocol.lineReceived(_b("error: a\n")) + self.protocol.lineReceived(_b("success a\n")) + self.protocol.lineReceived(_b("success: a\n")) + self.protocol.lineReceived(_b("successful a\n")) + self.protocol.lineReceived(_b("successful: a\n")) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) + self.assertEqual(self.stdout.getvalue(), _b("")) details = {} details['traceback'] = Content(ContentType("text", "x-traceback", {'charset': 'utf8'}), - lambda:[ + lambda:[_b( "test old mcdonald\n" "failure a\n" "failure: a\n" @@ -255,7 +255,7 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): "success: a\n" "successful a\n" "successful: a\n" - "]\n"]) + "]\n")]) self.assertEqual(self.client._events, [ ('startTest', self.test), ('addFailure', self.test, details), @@ -266,7 +266,7 @@ class TestTestProtocolServerPassThrough(unittest.TestCase): """Lines received which cannot be interpreted as any protocol action should be passed through to sys.stdout. """ - bytes = "randombytes\n" + bytes = _b("randombytes\n") self.protocol.lineReceived(bytes) self.assertEqual(self.stdout.getvalue(), bytes) @@ -283,7 +283,7 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.assertEqual([], self.client._events) def test_lost_connection_after_start(self): - self.protocol.lineReceived("test old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) self.protocol.lostConnection() failure = subunit.RemoteError( _u("lost connection during test 'old mcdonald'")) @@ -294,8 +294,8 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): ], self.client._events) def test_lost_connected_after_error(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("error old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("error old mcdonald\n")) self.protocol.lostConnection() self.assertEqual([ ('startTest', self.test), @@ -304,8 +304,8 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): ], self.client._events) def do_connection_lost(self, outcome, opening): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("%s old mcdonald %s" % (outcome, opening)) + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("%s old mcdonald %s" % (outcome, opening))) self.protocol.lostConnection() failure = subunit.RemoteError( _u("lost connection during %s report of test 'old mcdonald'") % @@ -323,8 +323,8 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.do_connection_lost("error", "[ multipart\n") def test_lost_connected_after_failure(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("failure old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("failure old mcdonald\n")) self.protocol.lostConnection() self.assertEqual([ ('startTest', self.test), @@ -339,8 +339,8 @@ class TestTestProtocolServerLostConnection(unittest.TestCase): self.do_connection_lost("failure", "[ multipart\n") def test_lost_connection_after_success(self): - self.protocol.lineReceived("test old mcdonald\n") - self.protocol.lineReceived("success old mcdonald\n") + self.protocol.lineReceived(_b("test old mcdonald\n")) + self.protocol.lineReceived(_b("success old mcdonald\n")) self.protocol.lostConnection() self.assertEqual([ ('startTest', self.test), @@ -377,7 +377,7 @@ class TestInTestMultipart(unittest.TestCase): def test__outcome_sets_details_parser(self): self.protocol._reading_success_details.details_parser = None - self.protocol._state._outcome(0, "mcdonalds farm [ multipart\n", + self.protocol._state._outcome(0, _b("mcdonalds farm [ multipart\n"), None, self.protocol._reading_success_details) parser = self.protocol._reading_success_details.details_parser self.assertNotEqual(None, parser) @@ -390,11 +390,11 @@ class TestTestProtocolServerAddError(unittest.TestCase): def setUp(self): self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) self.test = subunit.RemotedTestCase("mcdonalds farm") def simple_error_keyword(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm\n" % keyword) + self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword)) details = {} self.assertEqual([ ('startTest', self.test), @@ -409,11 +409,11 @@ class TestTestProtocolServerAddError(unittest.TestCase): self.simple_error_keyword("error:") def test_error_empty_message(self): - self.protocol.lineReceived("error mcdonalds farm [\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("error mcdonalds farm [\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['traceback'] = Content(ContentType("text", "x-traceback", - {'charset': 'utf8'}), lambda:[""]) + {'charset': 'utf8'}), lambda:[_b("")]) self.assertEqual([ ('startTest', self.test), ('addError', self.test, details), @@ -421,12 +421,12 @@ class TestTestProtocolServerAddError(unittest.TestCase): ], self.client._events) def error_quoted_bracket(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword) - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword)) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['traceback'] = Content(ContentType("text", "x-traceback", - {'charset': 'utf8'}), lambda:["]\n"]) + {'charset': 'utf8'}), lambda:[_b("]\n")]) self.assertEqual([ ('startTest', self.test), ('addError', self.test, details), @@ -445,7 +445,7 @@ class TestTestProtocolServerAddFailure(unittest.TestCase): def setUp(self): self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) self.test = subunit.RemotedTestCase("mcdonalds farm") def assertFailure(self, details): @@ -456,7 +456,7 @@ class TestTestProtocolServerAddFailure(unittest.TestCase): ], self.client._events) def simple_failure_keyword(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm\n" % keyword) + self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword)) details = {} self.assertFailure(details) @@ -467,20 +467,20 @@ class TestTestProtocolServerAddFailure(unittest.TestCase): self.simple_failure_keyword("failure:") def test_failure_empty_message(self): - self.protocol.lineReceived("failure mcdonalds farm [\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("failure mcdonalds farm [\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['traceback'] = Content(ContentType("text", "x-traceback", - {'charset': 'utf8'}), lambda:[""]) + {'charset': 'utf8'}), lambda:[_b("")]) self.assertFailure(details) def failure_quoted_bracket(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword) - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword)) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['traceback'] = Content(ContentType("text", "x-traceback", - {'charset': 'utf8'}), lambda:["]\n"]) + {'charset': 'utf8'}), lambda:[_b("]\n")]) self.assertFailure(details) def test_failure_quoted_bracket(self): @@ -518,11 +518,11 @@ class TestTestProtocolServerAddxFail(unittest.TestCase): def setup_protocol(self): """Setup the protocol based on self.client.""" self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) self.test = self.client._events[-1][-1] def simple_xfail_keyword(self, keyword, as_success): - self.protocol.lineReceived("%s mcdonalds farm\n" % keyword) + self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword)) self.check_success_or_xfail(as_success) def check_success_or_xfail(self, as_success, error_message=None): @@ -537,13 +537,14 @@ class TestTestProtocolServerAddxFail(unittest.TestCase): if error_message is not None: details['traceback'] = Content( ContentType("text", "x-traceback", {'charset': 'utf8'}), - lambda:[error_message]) + lambda:[_b(error_message)]) if isinstance(self.client, ExtendedTestResult): value = details else: if error_message is not None: value = subunit.RemoteError(_u("Text attachment: traceback\n" - "------------\n") + error_message + _u("------------\n")) + "------------\n") + _u(error_message) + + _u("------------\n")) else: value = subunit.RemoteError() self.assertEqual([ @@ -577,16 +578,16 @@ class TestTestProtocolServerAddxFail(unittest.TestCase): self.empty_message(False, error_message="") def empty_message(self, as_success, error_message="\n"): - self.protocol.lineReceived("xfail mcdonalds farm [\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("xfail mcdonalds farm [\n")) + self.protocol.lineReceived(_b("]\n")) self.check_success_or_xfail(as_success, error_message) def xfail_quoted_bracket(self, keyword, as_success): # This tests it is accepted, but cannot test it is used today, because # of not having a way to expose it in Python so far. - self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword) - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword)) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) self.check_success_or_xfail(as_success, "]\n") def test_xfail_quoted_bracket(self): @@ -617,7 +618,7 @@ class TestTestProtocolServerAddSkip(unittest.TestCase): """Setup a test object ready to be skipped.""" self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) self.test = self.client._events[-1][-1] def assertSkip(self, reason): @@ -632,7 +633,7 @@ class TestTestProtocolServerAddSkip(unittest.TestCase): ], self.client._events) def simple_skip_keyword(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm\n" % keyword) + self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword)) self.assertSkip(None) def test_simple_skip(self): @@ -642,17 +643,17 @@ class TestTestProtocolServerAddSkip(unittest.TestCase): self.simple_skip_keyword("skip:") def test_skip_empty_message(self): - self.protocol.lineReceived("skip mcdonalds farm [\n") - self.protocol.lineReceived("]\n") - self.assertSkip("") + self.protocol.lineReceived(_b("skip mcdonalds farm [\n")) + self.protocol.lineReceived(_b("]\n")) + self.assertSkip(_b("")) def skip_quoted_bracket(self, keyword): # This tests it is accepted, but cannot test it is used today, because # of not having a way to expose it in Python so far. - self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword) - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") - self.assertSkip("]\n") + self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword)) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) + self.assertSkip(_b("]\n")) def test_skip_quoted_bracket(self): self.skip_quoted_bracket("skip") @@ -666,11 +667,11 @@ class TestTestProtocolServerAddSuccess(unittest.TestCase): def setUp(self): self.client = ExtendedTestResult() self.protocol = subunit.TestProtocolServer(self.client) - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) self.test = subunit.RemotedTestCase("mcdonalds farm") def simple_success_keyword(self, keyword): - self.protocol.lineReceived("%s mcdonalds farm\n" % keyword) + self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword)) self.assertEqual([ ('startTest', self.test), ('addSuccess', self.test), @@ -691,22 +692,22 @@ class TestTestProtocolServerAddSuccess(unittest.TestCase): ], self.client._events) def test_success_empty_message(self): - self.protocol.lineReceived("success mcdonalds farm [\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("success mcdonalds farm [\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['message'] = Content(ContentType("text", "plain"), - lambda:[""]) + lambda:[_b("")]) self.assertSuccess(details) def success_quoted_bracket(self, keyword): # This tests it is accepted, but cannot test it is used today, because # of not having a way to expose it in Python so far. - self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword) - self.protocol.lineReceived(" ]\n") - self.protocol.lineReceived("]\n") + self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword)) + self.protocol.lineReceived(_b(" ]\n")) + self.protocol.lineReceived(_b("]\n")) details = {} details['message'] = Content(ContentType("text", "plain"), - lambda:["]\n"]) + lambda:[_b("]\n")]) self.assertSuccess(details) def test_success_quoted_bracket(self): @@ -721,26 +722,26 @@ class TestTestProtocolServerProgress(unittest.TestCase): def test_progress_accepted_stdlib(self): self.result = Python26TestResult() - self.stream = StringIO() + self.stream = BytesIO() self.protocol = subunit.TestProtocolServer(self.result, stream=self.stream) - self.protocol.lineReceived("progress: 23") - self.protocol.lineReceived("progress: -2") - self.protocol.lineReceived("progress: +4") - self.assertEqual("", self.stream.getvalue()) + self.protocol.lineReceived(_b("progress: 23")) + self.protocol.lineReceived(_b("progress: -2")) + self.protocol.lineReceived(_b("progress: +4")) + self.assertEqual(_b(""), self.stream.getvalue()) def test_progress_accepted_extended(self): # With a progress capable TestResult, progress events are emitted. self.result = ExtendedTestResult() - self.stream = StringIO() + self.stream = BytesIO() self.protocol = subunit.TestProtocolServer(self.result, stream=self.stream) - self.protocol.lineReceived("progress: 23") - self.protocol.lineReceived("progress: push") - self.protocol.lineReceived("progress: -2") - self.protocol.lineReceived("progress: pop") - self.protocol.lineReceived("progress: +4") - self.assertEqual("", self.stream.getvalue()) + self.protocol.lineReceived(_b("progress: 23")) + self.protocol.lineReceived(_b("progress: push")) + self.protocol.lineReceived(_b("progress: -2")) + self.protocol.lineReceived(_b("progress: pop")) + self.protocol.lineReceived(_b("progress: +4")) + self.assertEqual(_b(""), self.stream.getvalue()) self.assertEqual([ ('progress', 23, subunit.PROGRESS_SET), ('progress', None, subunit.PROGRESS_PUSH), @@ -758,13 +759,13 @@ class TestTestProtocolServerStreamTags(unittest.TestCase): self.protocol = subunit.TestProtocolServer(self.client) def test_initial_tags(self): - self.protocol.lineReceived("tags: foo bar:baz quux\n") + self.protocol.lineReceived(_b("tags: foo bar:baz quux\n")) self.assertEqual([ ('tags', set(["foo", "bar:baz", "quux"]), set()), ], self.client._events) def test_minus_removes_tags(self): - self.protocol.lineReceived("tags: -bar quux\n") + self.protocol.lineReceived(_b("tags: -bar quux\n")) self.assertEqual([ ('tags', set(["quux"]), set(["bar"])), ], self.client._events) @@ -781,10 +782,10 @@ class TestTestProtocolServerStreamTags(unittest.TestCase): self.assertEqual(None, getattr(test, 'tags', None)) def test_tags_get_set_on_test_tags(self): - self.protocol.lineReceived("test mcdonalds farm\n") + self.protocol.lineReceived(_b("test mcdonalds farm\n")) test = self.client._events[-1][-1] - self.protocol.lineReceived("tags: foo bar\n") - self.protocol.lineReceived("success mcdonalds farm\n") + self.protocol.lineReceived(_b("tags: foo bar\n")) + self.protocol.lineReceived(_b("success mcdonalds farm\n")) self.assertEqual(None, getattr(test, 'tags', None)) @@ -793,19 +794,19 @@ class TestTestProtocolServerStreamTime(unittest.TestCase): def test_time_accepted_stdlib(self): self.result = Python26TestResult() - self.stream = StringIO() + self.stream = BytesIO() self.protocol = subunit.TestProtocolServer(self.result, stream=self.stream) - self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n") - self.assertEqual("", self.stream.getvalue()) + self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n")) + self.assertEqual(_b(""), self.stream.getvalue()) def test_time_accepted_extended(self): self.result = ExtendedTestResult() - self.stream = StringIO() + self.stream = BytesIO() self.protocol = subunit.TestProtocolServer(self.result, stream=self.stream) - self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n") - self.assertEqual("", self.stream.getvalue()) + self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n")) + self.assertEqual(_b(""), self.stream.getvalue()) self.assertEqual([ ('time', datetime.datetime(2001, 12, 12, 12, 59, 59, 0, iso8601.Utc())) -- cgit v1.2.1 From b05ec2c069cdbc19dffa1061323aaf2f6c3b8568 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 13:10:06 +1200 Subject: Tags in the API are strings. And python3 exception names. --- python/subunit/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index c997296..6e1668e 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -127,7 +127,11 @@ from testtools.compat import _b, _u, BytesIO, StringIO try: from testtools.testresult.real import _StringException RemoteException = _StringException - _remote_exception_str = '_StringException' # For testing. + # For testing: different pythons have different str() implementations. + if sys.version_info > (3, 0): + _remote_exception_str = 'testtools.testresult.real._StringException' + else: + _remote_exception_str = '_StringException' except ImportError: raise ImportError ("testtools.testresult.real does not contain " "_StringException, check your version.") @@ -502,7 +506,7 @@ class TestProtocolServer(object): def _handleTags(self, offset, line): """Process a tags command.""" - tags = line[offset:].split() + tags = line[offset:].decode('utf8').split() new_tags, gone_tags = tags_to_new_gone(tags) self.client.tags(new_tags, gone_tags) -- cgit v1.2.1 From abc703874bcbabc890ffb8d23264a4d2095d72a6 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 13:29:31 +1200 Subject: Update stats tests. --- python/subunit/tests/test_subunit_stats.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'python') diff --git a/python/subunit/tests/test_subunit_stats.py b/python/subunit/tests/test_subunit_stats.py index 778bb7f..6fd3301 100644 --- a/python/subunit/tests/test_subunit_stats.py +++ b/python/subunit/tests/test_subunit_stats.py @@ -18,7 +18,7 @@ import unittest -from testtools.compat import StringIO +from testtools.compat import _b, BytesIO, StringIO import subunit @@ -29,7 +29,7 @@ class TestTestResultStats(unittest.TestCase): def setUp(self): self.output = StringIO() self.result = subunit.TestResultStats(self.output) - self.input_stream = StringIO() + self.input_stream = BytesIO() self.test = subunit.ProtocolTestCase(self.input_stream) def test_stats_empty(self): @@ -40,7 +40,7 @@ class TestTestResultStats(unittest.TestCase): self.assertEqual(set(), self.result.seen_tags) def setUpUsedStream(self): - self.input_stream.write("""tags: global + self.input_stream.write(_b("""tags: global test passed success passed test failed @@ -52,7 +52,7 @@ test skipped skip skipped test todo xfail todo -""") +""")) self.input_stream.seek(0) self.test.run(self.result) -- cgit v1.2.1 From 86b85e3f83f4030a63026386ffc3d3488ab34d13 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 16:25:24 +1200 Subject: Nearly done. --- python/subunit/__init__.py | 72 ++++++++++++--------- python/subunit/chunked.py | 41 +++++++----- python/subunit/details.py | 13 ++-- python/subunit/iso8601.py | 22 +++++-- python/subunit/tests/test_chunked.py | 98 ++++++++++++++--------------- python/subunit/tests/test_details.py | 16 ++--- python/subunit/tests/test_subunit_filter.py | 12 ++-- python/subunit/tests/test_test_protocol.py | 79 +++++++++++------------ 8 files changed, 192 insertions(+), 161 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 6e1668e..8fb3ab7 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -129,9 +129,11 @@ try: RemoteException = _StringException # For testing: different pythons have different str() implementations. if sys.version_info > (3, 0): - _remote_exception_str = 'testtools.testresult.real._StringException' + _remote_exception_str = "testtools.testresult.real._StringException" + _remote_exception_str_chunked = "34\r\n" + _remote_exception_str else: - _remote_exception_str = '_StringException' + _remote_exception_str = "_StringException" + _remote_exception_str_chunked = "1A\r\n" + _remote_exception_str except ImportError: raise ImportError ("testtools.testresult.real does not contain " "_StringException, check your version.") @@ -559,7 +561,8 @@ class TestProtocolClient(testresult.TestResult): # Get a TestSuite or TestCase to run suite = make_suite() - # Create a stream (any object with a 'write' method) + # Create a stream (any object with a 'write' method). This should accept + # bytes not strings: subunit is a byte orientated protocol. stream = file('tests.log', 'wb') # Create a subunit result object which will output to the stream result = subunit.TestProtocolClient(stream) @@ -576,6 +579,14 @@ class TestProtocolClient(testresult.TestResult): testresult.TestResult.__init__(self) self._stream = stream _make_stream_binary(stream) + self._progress_fmt = _b("progress: ") + self._bytes_eol = _b("\n") + self._progress_plus = _b("+") + self._progress_push = _b("push") + self._progress_pop = _b("pop") + self._empty_bytes = _b("") + self._start_simple = _b(" [\n") + self._end_simple = _b("]\n") def addError(self, test, error=None, details=None): """Report an error in test test. @@ -637,42 +648,42 @@ class TestProtocolClient(testresult.TestResult): :param details: New Testing-in-python drafted API; a dict from string to subunit.Content objects. """ - self._stream.write("%s: %s" % (outcome, test.id())) + self._stream.write(_b("%s: %s" % (outcome, test.id()))) if error is None and details is None: raise ValueError if error is not None: - self._stream.write(" [\n") + self._stream.write(self._start_simple) # XXX: this needs to be made much stricter, along the lines of # Martin[gz]'s work in testtools. Perhaps subunit can use that? for line in self._exc_info_to_unicode(error, test).splitlines(): self._stream.write(("%s\n" % line).encode('utf8')) else: self._write_details(details) - self._stream.write("]\n") + self._stream.write(self._end_simple) def addSkip(self, test, reason=None, details=None): """Report a skipped test.""" if reason is None: self._addOutcome("skip", test, error=None, details=details) else: - self._stream.write("skip: %s [\n" % test.id()) - self._stream.write("%s\n" % reason) - self._stream.write("]\n") + self._stream.write(_b("skip: %s [\n" % test.id())) + self._stream.write(_b("%s\n" % reason)) + self._stream.write(self._end_simple) def addSuccess(self, test, details=None): """Report a success in a test.""" - self._stream.write("successful: %s" % test.id()) + self._stream.write(_b("successful: %s" % test.id())) if not details: - self._stream.write("\n") + self._stream.write(_b("\n")) else: self._write_details(details) - self._stream.write("]\n") + self._stream.write(self._end_simple) addUnexpectedSuccess = addSuccess def startTest(self, test): """Mark a test as starting its test run.""" super(TestProtocolClient, self).startTest(test) - self._stream.write("test: %s\n" % test.id()) + self._stream.write(_b("test: %s\n" % test.id())) self._stream.flush() def stopTest(self, test): @@ -690,16 +701,19 @@ class TestProtocolClient(testresult.TestResult): PROGRESS_POP. """ if whence == PROGRESS_CUR and offset > -1: - prefix = "+" + prefix = self._progress_plus + offset = _b(str(offset)) elif whence == PROGRESS_PUSH: - prefix = "" - offset = "push" + prefix = self._empty_bytes + offset = self._progress_push elif whence == PROGRESS_POP: - prefix = "" - offset = "pop" + prefix = self._empty_bytes + offset = self._progress_pop else: - prefix = "" - self._stream.write("progress: %s%s\n" % (prefix, offset)) + prefix = self._empty_bytes + offset = _b(str(offset)) + self._stream.write(self._progress_fmt + prefix + offset + + self._bytes_eol) def time(self, a_datetime): """Inform the client of the time. @@ -707,29 +721,29 @@ class TestProtocolClient(testresult.TestResult): ":param datetime: A datetime.datetime object. """ time = a_datetime.astimezone(iso8601.Utc()) - self._stream.write("time: %04d-%02d-%02d %02d:%02d:%02d.%06dZ\n" % ( + self._stream.write(_b("time: %04d-%02d-%02d %02d:%02d:%02d.%06dZ\n" % ( time.year, time.month, time.day, time.hour, time.minute, - time.second, time.microsecond)) + time.second, time.microsecond))) def _write_details(self, details): """Output details to the stream. :param details: An extended details dict for a test outcome. """ - self._stream.write(" [ multipart\n") + self._stream.write(_b(" [ multipart\n")) for name, content in sorted(details.items()): - self._stream.write("Content-Type: %s/%s" % - (content.content_type.type, content.content_type.subtype)) + self._stream.write(_b("Content-Type: %s/%s" % + (content.content_type.type, content.content_type.subtype))) parameters = content.content_type.parameters if parameters: - self._stream.write(";") + self._stream.write(_b(";")) param_strs = [] for param, value in parameters.items(): param_strs.append("%s=%s" % (param, value)) - self._stream.write(",".join(param_strs)) - self._stream.write("\n%s\n" % name) + self._stream.write(_b(",".join(param_strs))) + self._stream.write(_b("\n%s\n" % name)) encoder = chunked.Encoder(self._stream) - map(encoder.write, content.iter_bytes()) + list(map(encoder.write, content.iter_bytes())) encoder.close() def done(self): diff --git a/python/subunit/chunked.py b/python/subunit/chunked.py index 5f8c6f1..b992129 100644 --- a/python/subunit/chunked.py +++ b/python/subunit/chunked.py @@ -17,6 +17,10 @@ """Encoder/decoder for http style chunked encoding.""" +from testtools.compat import _b + +empty = _b('') + class Decoder(object): """Decode chunked content to a byte stream.""" @@ -25,11 +29,11 @@ class Decoder(object): :param output: A file-like object. Bytes written to the Decoder are decoded to strip off the chunking and written to the output. - Up to a full write worth of data or a single control line may be + Up to a full write worth of data or a single control line may be buffered (whichever is larger). The close method should be called when no more data is available, to detect short streams; the write method will return none-None when the end of a stream is - detected. + detected. The output object must accept bytes objects. :param strict: If True (the default), the decoder will not knowingly accept input that is not conformant to the HTTP specification. @@ -42,6 +46,11 @@ class Decoder(object): self.state = self._read_length self.body_length = 0 self.strict = strict + self._match_chars = _b("0123456789abcdefABCDEF\r\n") + self._slash_n = _b('\n') + self._slash_r = _b('\r') + self._slash_rn = _b('\r\n') + self._slash_nr = _b('\n\r') def close(self): """Close the decoder. @@ -56,7 +65,7 @@ class Decoder(object): if self.buffered_bytes: buffered_bytes = self.buffered_bytes self.buffered_bytes = [] - return ''.join(buffered_bytes) + return empty.join(buffered_bytes) else: raise ValueError("stream is finished") @@ -80,26 +89,26 @@ class Decoder(object): def _read_length(self): """Try to decode a length from the bytes.""" - match_chars = "0123456789abcdefABCDEF\r\n" count_chars = [] for bytes in self.buffered_bytes: - for byte in bytes: - if byte not in match_chars: + for pos in range(len(bytes)): + byte = bytes[pos:pos+1] + if byte not in self._match_chars: break count_chars.append(byte) - if byte == '\n': + if byte == self._slash_n: break if not count_chars: return - if count_chars[-1][-1] != '\n': + if count_chars[-1] != self._slash_n: return - count_str = ''.join(count_chars) + count_str = empty.join(count_chars) if self.strict: - if count_str[-2:] != '\r\n': + if count_str[-2:] != self._slash_rn: raise ValueError("chunk header invalid: %r" % count_str) - if '\r' in count_str[:-2]: + if self._slash_r in count_str[:-2]: raise ValueError("too many CRs in chunk header %r" % count_str) - self.body_length = int(count_str.rstrip('\n\r'), 16) + self.body_length = int(count_str.rstrip(self._slash_nr), 16) excess_bytes = len(count_str) while excess_bytes: if excess_bytes >= len(self.buffered_bytes[0]): @@ -112,7 +121,7 @@ class Decoder(object): self.state = self._finished if not self.buffered_bytes: # May not call into self._finished with no buffered data. - return '' + return empty else: self.state = self._read_body return self.state() @@ -155,9 +164,9 @@ class Encoder(object): buffer_size = self.buffer_size self.buffered_bytes = [] self.buffer_size = 0 - self.output.write("%X\r\n" % (buffer_size + extra_len)) + self.output.write(_b("%X\r\n" % (buffer_size + extra_len))) if buffer_size: - self.output.write(''.join(buffered_bytes)) + self.output.write(empty.join(buffered_bytes)) return True def write(self, bytes): @@ -173,4 +182,4 @@ class Encoder(object): def close(self): """Finish the stream. This does not close the output stream.""" self.flush() - self.output.write("0\r\n") + self.output.write(_b("0\r\n")) diff --git a/python/subunit/details.py b/python/subunit/details.py index 9790543..35bc88e 100644 --- a/python/subunit/details.py +++ b/python/subunit/details.py @@ -17,12 +17,13 @@ """Handlers for outcome details.""" from testtools import content, content_type -from testtools.compat import _b, StringIO +from testtools.compat import _b, BytesIO from subunit import chunked end_marker = _b("]\n") quoted_marker = _b(" ]") +empty = _b('') class DetailsParser(object): @@ -79,18 +80,18 @@ class MultipartDetailsParser(DetailsParser): self._parse_state = self._look_for_content def _look_for_content(self, line): - if line == "]\n": + if line == end_marker: self._state.endDetails() return # TODO error handling - field, value = line[:-1].split(' ', 1) + field, value = line[:-1].decode('utf8').split(' ', 1) main, sub = value.split('/') self._content_type = content_type.ContentType(main, sub) self._parse_state = self._get_name def _get_name(self, line): - self._name = line[:-1] - self._body = StringIO() + self._name = line[:-1].decode('utf8') + self._body = BytesIO() self._chunk_parser = chunked.Decoder(self._body) self._parse_state = self._feed_chunks @@ -98,7 +99,7 @@ class MultipartDetailsParser(DetailsParser): residue = self._chunk_parser.write(line) if residue is not None: # Line based use always ends on no residue. - assert residue == '', 'residue: %r' % (residue,) + assert residue == empty, 'residue: %r' % (residue,) body = self._body self._details[self._name] = content.Content( self._content_type, lambda:[body.getvalue()]) diff --git a/python/subunit/iso8601.py b/python/subunit/iso8601.py index 93c92fb..cbe9a3b 100644 --- a/python/subunit/iso8601.py +++ b/python/subunit/iso8601.py @@ -31,15 +31,25 @@ datetime.datetime(2007, 1, 25, 12, 0, tzinfo=) from datetime import datetime, timedelta, tzinfo import re +import sys __all__ = ["parse_date", "ParseError"] # Adapted from http://delete.me.uk/2005/03/iso8601.html -ISO8601_REGEX = re.compile(r"(?P[0-9]{4})(-(?P[0-9]{1,2})(-(?P[0-9]{1,2})" +ISO8601_REGEX_PATTERN = (r"(?P[0-9]{4})(-(?P[0-9]{1,2})(-(?P[0-9]{1,2})" r"((?P.)(?P[0-9]{2}):(?P[0-9]{2})(:(?P[0-9]{2})(\.(?P[0-9]+))?)?" r"(?PZ|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?" ) -TIMEZONE_REGEX = re.compile("(?P[+-])(?P[0-9]{2}).(?P[0-9]{2})") +TIMEZONE_REGEX_PATTERN = "(?P[+-])(?P[0-9]{2}).(?P[0-9]{2})" +ISO8601_REGEX = re.compile(ISO8601_REGEX_PATTERN.encode('utf8')) +TIMEZONE_REGEX = re.compile(TIMEZONE_REGEX_PATTERN.encode('utf8')) + +zulu = "Z".encode('latin-1') +minus = "-".encode('latin-1') + +if sys.version_info < (3, 0): + bytes = str + class ParseError(Exception): """Raised when there is a problem parsing a date string""" @@ -84,7 +94,7 @@ def parse_timezone(tzstring, default_timezone=UTC): """Parses ISO 8601 time zone specs into tzinfo offsets """ - if tzstring == "Z": + if tzstring == zulu: return default_timezone # This isn't strictly correct, but it's common to encounter dates without # timezones so I'll assume the default (which defaults to UTC). @@ -94,7 +104,7 @@ def parse_timezone(tzstring, default_timezone=UTC): m = TIMEZONE_REGEX.match(tzstring) prefix, hours, minutes = m.groups() hours, minutes = int(hours), int(minutes) - if prefix == "-": + if prefix == minus: hours = -hours minutes = -minutes return FixedOffset(hours, minutes, tzstring) @@ -107,8 +117,8 @@ def parse_date(datestring, default_timezone=UTC): default timezone specified in default_timezone is used. This is UTC by default. """ - if not isinstance(datestring, basestring): - raise ParseError("Expecting a string %r" % datestring) + if not isinstance(datestring, bytes): + raise ParseError("Expecting bytes %r" % datestring) m = ISO8601_REGEX.match(datestring) if not m: raise ParseError("Unable to parse date string %r" % datestring) diff --git a/python/subunit/tests/test_chunked.py b/python/subunit/tests/test_chunked.py index 6323b02..e0742f1 100644 --- a/python/subunit/tests/test_chunked.py +++ b/python/subunit/tests/test_chunked.py @@ -17,7 +17,7 @@ import unittest -from testtools.compat import StringIO +from testtools.compat import _b, BytesIO import subunit.chunked @@ -32,121 +32,121 @@ class TestDecode(unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) - self.output = StringIO() + self.output = BytesIO() self.decoder = subunit.chunked.Decoder(self.output) def test_close_read_length_short_errors(self): self.assertRaises(ValueError, self.decoder.close) def test_close_body_short_errors(self): - self.assertEqual(None, self.decoder.write('2\r\na')) + self.assertEqual(None, self.decoder.write(_b('2\r\na'))) self.assertRaises(ValueError, self.decoder.close) def test_close_body_buffered_data_errors(self): - self.assertEqual(None, self.decoder.write('2\r')) + self.assertEqual(None, self.decoder.write(_b('2\r'))) self.assertRaises(ValueError, self.decoder.close) def test_close_after_finished_stream_safe(self): - self.assertEqual(None, self.decoder.write('2\r\nab')) - self.assertEqual('', self.decoder.write('0\r\n')) + self.assertEqual(None, self.decoder.write(_b('2\r\nab'))) + self.assertEqual(_b(''), self.decoder.write(_b('0\r\n'))) self.decoder.close() def test_decode_nothing(self): - self.assertEqual('', self.decoder.write('0\r\n')) - self.assertEqual('', self.output.getvalue()) + self.assertEqual(_b(''), self.decoder.write(_b('0\r\n'))) + self.assertEqual(_b(''), self.output.getvalue()) def test_decode_serialised_form(self): - self.assertEqual(None, self.decoder.write("F\r\n")) - self.assertEqual(None, self.decoder.write("serialised\n")) - self.assertEqual('', self.decoder.write("form0\r\n")) + self.assertEqual(None, self.decoder.write(_b("F\r\n"))) + self.assertEqual(None, self.decoder.write(_b("serialised\n"))) + self.assertEqual(_b(''), self.decoder.write(_b("form0\r\n"))) def test_decode_short(self): - self.assertEqual('', self.decoder.write('3\r\nabc0\r\n')) - self.assertEqual('abc', self.output.getvalue()) + self.assertEqual(_b(''), self.decoder.write(_b('3\r\nabc0\r\n'))) + self.assertEqual(_b('abc'), self.output.getvalue()) def test_decode_combines_short(self): - self.assertEqual('', self.decoder.write('6\r\nabcdef0\r\n')) - self.assertEqual('abcdef', self.output.getvalue()) + self.assertEqual(_b(''), self.decoder.write(_b('6\r\nabcdef0\r\n'))) + self.assertEqual(_b('abcdef'), self.output.getvalue()) def test_decode_excess_bytes_from_write(self): - self.assertEqual('1234', self.decoder.write('3\r\nabc0\r\n1234')) - self.assertEqual('abc', self.output.getvalue()) + self.assertEqual(_b('1234'), self.decoder.write(_b('3\r\nabc0\r\n1234'))) + self.assertEqual(_b('abc'), self.output.getvalue()) def test_decode_write_after_finished_errors(self): - self.assertEqual('1234', self.decoder.write('3\r\nabc0\r\n1234')) - self.assertRaises(ValueError, self.decoder.write, '') + self.assertEqual(_b('1234'), self.decoder.write(_b('3\r\nabc0\r\n1234'))) + self.assertRaises(ValueError, self.decoder.write, _b('')) def test_decode_hex(self): - self.assertEqual('', self.decoder.write('A\r\n12345678900\r\n')) - self.assertEqual('1234567890', self.output.getvalue()) + self.assertEqual(_b(''), self.decoder.write(_b('A\r\n12345678900\r\n'))) + self.assertEqual(_b('1234567890'), self.output.getvalue()) def test_decode_long_ranges(self): - self.assertEqual(None, self.decoder.write('10000\r\n')) - self.assertEqual(None, self.decoder.write('1' * 65536)) - self.assertEqual(None, self.decoder.write('10000\r\n')) - self.assertEqual(None, self.decoder.write('2' * 65536)) - self.assertEqual('', self.decoder.write('0\r\n')) - self.assertEqual('1' * 65536 + '2' * 65536, self.output.getvalue()) + self.assertEqual(None, self.decoder.write(_b('10000\r\n'))) + self.assertEqual(None, self.decoder.write(_b('1' * 65536))) + self.assertEqual(None, self.decoder.write(_b('10000\r\n'))) + self.assertEqual(None, self.decoder.write(_b('2' * 65536))) + self.assertEqual(_b(''), self.decoder.write(_b('0\r\n'))) + self.assertEqual(_b('1' * 65536 + '2' * 65536), self.output.getvalue()) def test_decode_newline_nonstrict(self): """Tolerate chunk markers with no CR character.""" # From self.decoder = subunit.chunked.Decoder(self.output, strict=False) - self.assertEqual(None, self.decoder.write('a\n')) - self.assertEqual(None, self.decoder.write('abcdeabcde')) - self.assertEqual('', self.decoder.write('0\n')) - self.assertEqual('abcdeabcde', self.output.getvalue()) + self.assertEqual(None, self.decoder.write(_b('a\n'))) + self.assertEqual(None, self.decoder.write(_b('abcdeabcde'))) + self.assertEqual(_b(''), self.decoder.write(_b('0\n'))) + self.assertEqual(_b('abcdeabcde'), self.output.getvalue()) def test_decode_strict_newline_only(self): """Reject chunk markers with no CR character in strict mode.""" # From self.assertRaises(ValueError, - self.decoder.write, 'a\n') + self.decoder.write, _b('a\n')) def test_decode_strict_multiple_crs(self): self.assertRaises(ValueError, - self.decoder.write, 'a\r\r\n') + self.decoder.write, _b('a\r\r\n')) def test_decode_short_header(self): self.assertRaises(ValueError, - self.decoder.write, '\n') + self.decoder.write, _b('\n')) class TestEncode(unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) - self.output = StringIO() + self.output = BytesIO() self.encoder = subunit.chunked.Encoder(self.output) def test_encode_nothing(self): self.encoder.close() - self.assertEqual('0\r\n', self.output.getvalue()) + self.assertEqual(_b('0\r\n'), self.output.getvalue()) def test_encode_empty(self): - self.encoder.write('') + self.encoder.write(_b('')) self.encoder.close() - self.assertEqual('0\r\n', self.output.getvalue()) + self.assertEqual(_b('0\r\n'), self.output.getvalue()) def test_encode_short(self): - self.encoder.write('abc') + self.encoder.write(_b('abc')) self.encoder.close() - self.assertEqual('3\r\nabc0\r\n', self.output.getvalue()) + self.assertEqual(_b('3\r\nabc0\r\n'), self.output.getvalue()) def test_encode_combines_short(self): - self.encoder.write('abc') - self.encoder.write('def') + self.encoder.write(_b('abc')) + self.encoder.write(_b('def')) self.encoder.close() - self.assertEqual('6\r\nabcdef0\r\n', self.output.getvalue()) + self.assertEqual(_b('6\r\nabcdef0\r\n'), self.output.getvalue()) def test_encode_over_9_is_in_hex(self): - self.encoder.write('1234567890') + self.encoder.write(_b('1234567890')) self.encoder.close() - self.assertEqual('A\r\n12345678900\r\n', self.output.getvalue()) + self.assertEqual(_b('A\r\n12345678900\r\n'), self.output.getvalue()) def test_encode_long_ranges_not_combined(self): - self.encoder.write('1' * 65536) - self.encoder.write('2' * 65536) + self.encoder.write(_b('1' * 65536)) + self.encoder.write(_b('2' * 65536)) self.encoder.close() - self.assertEqual('10000\r\n' + '1' * 65536 + '10000\r\n' + - '2' * 65536 + '0\r\n', self.output.getvalue()) + self.assertEqual(_b('10000\r\n' + '1' * 65536 + '10000\r\n' + + '2' * 65536 + '0\r\n'), self.output.getvalue()) diff --git a/python/subunit/tests/test_details.py b/python/subunit/tests/test_details.py index 49010d2..746aa04 100644 --- a/python/subunit/tests/test_details.py +++ b/python/subunit/tests/test_details.py @@ -95,18 +95,18 @@ class TestMultipartDetails(unittest.TestCase): def test_parts(self): parser = details.MultipartDetailsParser(None) - parser.lineReceived("Content-Type: text/plain\n") - parser.lineReceived("something\n") - parser.lineReceived("F\r\n") - parser.lineReceived("serialised\n") - parser.lineReceived("form0\r\n") + parser.lineReceived(_b("Content-Type: text/plain\n")) + parser.lineReceived(_b("something\n")) + parser.lineReceived(_b("F\r\n")) + parser.lineReceived(_b("serialised\n")) + parser.lineReceived(_b("form0\r\n")) expected = {} expected['something'] = content.Content( content_type.ContentType("text", "plain"), - lambda:["serialised\nform"]) + lambda:[_b("serialised\nform")]) found = parser.get_details() self.assertEqual(expected.keys(), found.keys()) self.assertEqual(expected['something'].content_type, found['something'].content_type) - self.assertEqual(''.join(expected['something'].iter_bytes()), - ''.join(found['something'].iter_bytes())) + self.assertEqual(_b('').join(expected['something'].iter_bytes()), + _b('').join(found['something'].iter_bytes())) diff --git a/python/subunit/tests/test_subunit_filter.py b/python/subunit/tests/test_subunit_filter.py index 682f726..fb6ffcd 100644 --- a/python/subunit/tests/test_subunit_filter.py +++ b/python/subunit/tests/test_subunit_filter.py @@ -21,7 +21,7 @@ from subunit import iso8601 import unittest from testtools import TestCase -from testtools.compat import StringIO +from testtools.compat import _b, BytesIO, StringIO from testtools.testresult.doubles import ExtendedTestResult import subunit @@ -35,7 +35,7 @@ class TestTestResultFilter(TestCase): # is an easy pithy way of getting a series of test objects to call into # the TestResult, and as TestResultFilter is intended for use with subunit # also has the benefit of detecting any interface skew issues. - example_subunit_stream = """\ + example_subunit_stream = _b("""\ tags: global test passed success passed @@ -50,7 +50,7 @@ test skipped skip skipped test todo xfail todo -""" +""") def run_tests(self, result_filter, input_stream=None): """Run tests through the given filter. @@ -61,7 +61,7 @@ xfail todo """ if input_stream is None: input_stream = self.example_subunit_stream - test = subunit.ProtocolTestCase(StringIO(input_stream)) + test = subunit.ProtocolTestCase(BytesIO(input_stream)) test.run(result_filter) def test_default(self): @@ -139,13 +139,13 @@ xfail todo date_a = datetime(year=2000, month=1, day=1, tzinfo=iso8601.UTC) date_b = datetime(year=2000, month=1, day=2, tzinfo=iso8601.UTC) date_c = datetime(year=2000, month=1, day=3, tzinfo=iso8601.UTC) - subunit_stream = '\n'.join([ + subunit_stream = _b('\n'.join([ "time: %s", "test: foo", "time: %s", "error: foo", "time: %s", - ""]) % (date_a, date_b, date_c) + ""]) % (date_a, date_b, date_c)) result = ExtendedTestResult() result_filter = TestResultFilter(result) self.run_tests(result_filter, subunit_stream) diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py index 7778fcc..7ec7758 100644 --- a/python/subunit/tests/test_test_protocol.py +++ b/python/subunit/tests/test_test_protocol.py @@ -28,7 +28,7 @@ from testtools.tests.helpers import ( ) import subunit -from subunit import _remote_exception_str +from subunit import _remote_exception_str, _remote_exception_str_chunked import subunit.iso8601 as iso8601 @@ -994,11 +994,11 @@ class TestIsolatedTestSuite(unittest.TestCase): class TestTestProtocolClient(unittest.TestCase): def setUp(self): - self.io = StringIO() + self.io = BytesIO() self.protocol = subunit.TestProtocolClient(self.io) self.test = TestTestProtocolClient("test_start_test") self.sample_details = {'something':Content( - ContentType('text', 'plain'), lambda:['serialised\nform'])} + ContentType('text', 'plain'), lambda:[_b('serialised\nform')])} self.sample_tb_details = dict(self.sample_details) self.sample_tb_details['traceback'] = TracebackContent( subunit.RemoteError(_u("boo qux")), self.test) @@ -1006,27 +1006,27 @@ class TestTestProtocolClient(unittest.TestCase): def test_start_test(self): """Test startTest on a TestProtocolClient.""" self.protocol.startTest(self.test) - self.assertEqual(self.io.getvalue(), "test: %s\n" % self.test.id()) + self.assertEqual(self.io.getvalue(), _b("test: %s\n" % self.test.id())) def test_stop_test(self): # stopTest doesn't output anything. self.protocol.stopTest(self.test) - self.assertEqual(self.io.getvalue(), "") + self.assertEqual(self.io.getvalue(), _b("")) def test_add_success(self): """Test addSuccess on a TestProtocolClient.""" self.protocol.addSuccess(self.test) self.assertEqual( - self.io.getvalue(), "successful: %s\n" % self.test.id()) + self.io.getvalue(), _b("successful: %s\n" % self.test.id())) def test_add_success_details(self): """Test addSuccess on a TestProtocolClient with details.""" self.protocol.addSuccess(self.test, details=self.sample_details) self.assertEqual( - self.io.getvalue(), "successful: %s [ multipart\n" + self.io.getvalue(), _b("successful: %s [ multipart\n" "Content-Type: text/plain\n" "something\n" - "F\r\nserialised\nform0\r\n]\n" % self.test.id()) + "F\r\nserialised\nform0\r\n]\n" % self.test.id())) def test_add_failure(self): """Test addFailure on a TestProtocolClient.""" @@ -1034,8 +1034,8 @@ class TestTestProtocolClient(unittest.TestCase): self.test, subunit.RemoteError(_u("boo qux"))) self.assertEqual( self.io.getvalue(), - ('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n') - % self.test.id()) + _b(('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n') + % self.test.id())) def test_add_failure_details(self): """Test addFailure on a TestProtocolClient with details.""" @@ -1043,14 +1043,13 @@ class TestTestProtocolClient(unittest.TestCase): self.test, details=self.sample_tb_details) self.assertEqual( self.io.getvalue(), - ("failure: %s [ multipart\n" + _b(("failure: %s [ multipart\n" "Content-Type: text/plain\n" "something\n" "F\r\nserialised\nform0\r\n" "Content-Type: text/x-traceback;charset=utf8,language=python\n" - "traceback\n" - "1A\r\n" + _remote_exception_str + ": boo qux\n0\r\n" - "]\n") % self.test.id()) + "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n" + "]\n") % self.test.id())) def test_add_error(self): """Test stopTest on a TestProtocolClient.""" @@ -1058,9 +1057,9 @@ class TestTestProtocolClient(unittest.TestCase): self.test, subunit.RemoteError(_u("phwoar crikey"))) self.assertEqual( self.io.getvalue(), - ('error: %s [\n' + + _b(('error: %s [\n' + _remote_exception_str + ": phwoar crikey\n" - "]\n") % self.test.id()) + "]\n") % self.test.id())) def test_add_error_details(self): """Test stopTest on a TestProtocolClient with details.""" @@ -1068,14 +1067,13 @@ class TestTestProtocolClient(unittest.TestCase): self.test, details=self.sample_tb_details) self.assertEqual( self.io.getvalue(), - ("error: %s [ multipart\n" + _b(("error: %s [ multipart\n" "Content-Type: text/plain\n" "something\n" "F\r\nserialised\nform0\r\n" "Content-Type: text/x-traceback;charset=utf8,language=python\n" - "traceback\n" - "1A\r\n" + _remote_exception_str + ": boo qux\n0\r\n" - "]\n") % self.test.id()) + "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n" + "]\n") % self.test.id())) def test_add_expected_failure(self): """Test addExpectedFailure on a TestProtocolClient.""" @@ -1083,9 +1081,9 @@ class TestTestProtocolClient(unittest.TestCase): self.test, subunit.RemoteError(_u("phwoar crikey"))) self.assertEqual( self.io.getvalue(), - ('xfail: %s [\n' + + _b(('xfail: %s [\n' + _remote_exception_str + ": phwoar crikey\n" - "]\n") % self.test.id()) + "]\n") % self.test.id())) def test_add_expected_failure_details(self): """Test addExpectedFailure on a TestProtocolClient with details.""" @@ -1093,14 +1091,14 @@ class TestTestProtocolClient(unittest.TestCase): self.test, details=self.sample_tb_details) self.assertEqual( self.io.getvalue(), - ("xfail: %s [ multipart\n" + _b(("xfail: %s [ multipart\n" "Content-Type: text/plain\n" "something\n" "F\r\nserialised\nform0\r\n" "Content-Type: text/x-traceback;charset=utf8,language=python\n" - "traceback\n" - "1A\r\n"+ _remote_exception_str + ": boo qux\n0\r\n" - "]\n") % self.test.id()) + "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n" + "]\n") % self.test.id())) + def test_add_skip(self): """Test addSkip on a TestProtocolClient.""" @@ -1108,64 +1106,63 @@ class TestTestProtocolClient(unittest.TestCase): self.test, "Has it really?") self.assertEqual( self.io.getvalue(), - 'skip: %s [\nHas it really?\n]\n' % self.test.id()) + _b('skip: %s [\nHas it really?\n]\n' % self.test.id())) def test_add_skip_details(self): """Test addSkip on a TestProtocolClient with details.""" details = {'reason':Content( - ContentType('text', 'plain'), lambda:['Has it really?'])} - self.protocol.addSkip( - self.test, details=details) + ContentType('text', 'plain'), lambda:[_b('Has it really?')])} + self.protocol.addSkip(self.test, details=details) self.assertEqual( self.io.getvalue(), - "skip: %s [ multipart\n" + _b("skip: %s [ multipart\n" "Content-Type: text/plain\n" "reason\n" "E\r\nHas it really?0\r\n" - "]\n" % self.test.id()) + "]\n" % self.test.id())) def test_progress_set(self): self.protocol.progress(23, subunit.PROGRESS_SET) - self.assertEqual(self.io.getvalue(), 'progress: 23\n') + self.assertEqual(self.io.getvalue(), _b('progress: 23\n')) def test_progress_neg_cur(self): self.protocol.progress(-23, subunit.PROGRESS_CUR) - self.assertEqual(self.io.getvalue(), 'progress: -23\n') + self.assertEqual(self.io.getvalue(), _b('progress: -23\n')) def test_progress_pos_cur(self): self.protocol.progress(23, subunit.PROGRESS_CUR) - self.assertEqual(self.io.getvalue(), 'progress: +23\n') + self.assertEqual(self.io.getvalue(), _b('progress: +23\n')) def test_progress_pop(self): self.protocol.progress(1234, subunit.PROGRESS_POP) - self.assertEqual(self.io.getvalue(), 'progress: pop\n') + self.assertEqual(self.io.getvalue(), _b('progress: pop\n')) def test_progress_push(self): self.protocol.progress(1234, subunit.PROGRESS_PUSH) - self.assertEqual(self.io.getvalue(), 'progress: push\n') + self.assertEqual(self.io.getvalue(), _b('progress: push\n')) def test_time(self): # Calling time() outputs a time signal immediately. self.protocol.time( datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc())) self.assertEqual( - "time: 2009-10-11 12:13:14.000015Z\n", + _b("time: 2009-10-11 12:13:14.000015Z\n"), self.io.getvalue()) def test_add_unexpected_success(self): """Test addUnexpectedSuccess on a TestProtocolClient.""" self.protocol.addUnexpectedSuccess(self.test) self.assertEqual( - self.io.getvalue(), "successful: %s\n" % self.test.id()) + self.io.getvalue(), _b("successful: %s\n" % self.test.id())) def test_add_unexpected_success_details(self): """Test addUnexpectedSuccess on a TestProtocolClient with details.""" self.protocol.addUnexpectedSuccess(self.test, details=self.sample_details) self.assertEqual( - self.io.getvalue(), "successful: %s [ multipart\n" + self.io.getvalue(), _b("successful: %s [ multipart\n" "Content-Type: text/plain\n" "something\n" - "F\r\nserialised\nform0\r\n]\n" % self.test.id()) + "F\r\nserialised\nform0\r\n]\n" % self.test.id())) def test_suite(): -- cgit v1.2.1 From 65ceb1a7645b132fb831344c0d0ddf986e93d6fe Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 25 Apr 2011 17:07:43 +1200 Subject: Test suite passing on 3.1. --- python/subunit/__init__.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'python') diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py index 8fb3ab7..a7048d3 100644 --- a/python/subunit/__init__.py +++ b/python/subunit/__init__.py @@ -468,10 +468,9 @@ class TestProtocolServer(object): """ self.client = ExtendedToOriginalDecorator(client) if stream is None: + stream = sys.stdout if sys.version_info > (3, 0): - stream = sys.stdout.buffer - else: - stream = sys.stdout + stream = stream.buffer self._stream = stream self._forward_stream = forward_stream or DiscardStream() # state objects we can switch too @@ -885,10 +884,10 @@ def run_isolated(klass, self, result): # at this point, sys.stdin is redirected, now we want # to filter it to escape ]'s. ### XXX: test and write that bit. - - result = TestProtocolClient(sys.stdout) + stream = os.fdopen(1, 'wb') + result = TestProtocolClient(stream) klass.run(self, result) - sys.stdout.flush() + stream.flush() sys.stderr.flush() # exit HARD, exit NOW. os._exit(0) @@ -898,7 +897,8 @@ def run_isolated(klass, self, result): os.close(c2pwrite) # hookup a protocol engine protocol = TestProtocolServer(result) - protocol.readFrom(os.fdopen(c2pread, 'rU')) + fileobj = os.fdopen(c2pread, 'rb') + protocol.readFrom(fileobj) os.waitpid(pid, 0) # TODO return code evaluation. return result @@ -1168,7 +1168,10 @@ def get_default_formatter(): if formatter: return os.popen(formatter, "w") else: - return sys.stdout + stream = sys.stdout + if sys.version_info > (3, 0): + stream = stream.buffer + return stream if sys.version_info > (3, 0): -- cgit v1.2.1