Properly test raw writes in Python 3

Previously we were trying to test writing bytes in Python 3 using only
native (unicode) string objects. That doesn't test what we thought we
were testing.

Change-Id: I10a0a38143d7f7d850ab9a7005ad87f5d314c375
This commit is contained in:
Tim Burke 2015-05-17 23:51:37 -07:00
parent 92b8277752
commit cf0b6c03df
2 changed files with 22 additions and 30 deletions

@ -12,7 +12,6 @@
# implied. # implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import sys import sys
import testtools import testtools
import threading import threading
@ -206,10 +205,12 @@ class TestOutputManager(testtools.TestCase):
u'some raw bytes: \u062A\u062A'.encode('utf-8')) u'some raw bytes: \u062A\u062A'.encode('utf-8'))
thread_manager.print_items([ thread_manager.print_items([
('key', u'value'), ('key', 'value'),
('object', 'O\xcc\x88bject') ('object', u'O\u0308bject'),
]) ])
thread_manager.print_raw(b'\xffugly\xffraw')
# Now we have a thread for error printing and a thread for # Now we have a thread for error printing and a thread for
# normal print messages # normal print messages
self.assertEqual(starting_thread_count + 2, self.assertEqual(starting_thread_count + 2,
@ -220,31 +221,23 @@ class TestOutputManager(testtools.TestCase):
if six.PY3: if six.PY3:
over_the = "over the '\u062a\u062a'\n" over_the = "over the '\u062a\u062a'\n"
# The CaptureStreamBuffer just encodes all bytes written to it by
# mapping chr over the byte string to produce a str.
raw_bytes = ''.join(
map(chr, u'some raw bytes: \u062A\u062A'.encode('utf-8'))
)
else: else:
over_the = "over the u'\\u062a\\u062a'\n" over_the = "over the u'\\u062a\\u062a'\n"
# We write to the CaptureStream so no decoding is performed # We write to the CaptureStream so no decoding is performed
raw_bytes = 'some raw bytes: \xd8\xaa\xd8\xaa'
self.assertEqual(''.join([ self.assertEqual(''.join([
'one-argument\n', 'one-argument\n',
'one fish, 88 fish\n', 'one fish, 88 fish\n',
'some\n', 'where\n', 'some\n', 'where\n',
over_the, raw_bytes, over_the,
u'some raw bytes: \u062a\u062a',
' key: value\n', ' key: value\n',
' object: O\xcc\x88bject\n' u' object: O\u0308bject\n'
]), out_stream.getvalue()) ]).encode('utf8') + b'\xffugly\xffraw', out_stream.getvalue())
first_item = u'I have 99 problems, but a \u062A\u062A is not one\n'
if six.PY2:
first_item = first_item.encode('utf8')
self.assertEqual(''.join([ self.assertEqual(''.join([
first_item, u'I have 99 problems, but a \u062A\u062A is not one\n',
'one-error-argument\n', 'one-error-argument\n',
'Sometimes\n', '3.1% just\n', 'does not\n', 'work!\n' 'Sometimes\n', '3.1% just\n', 'does not\n', 'work!\n'
]), err_stream.getvalue()) ]), err_stream.getvalue().decode('utf8'))
self.assertEqual(3, thread_manager.error_count) self.assertEqual(3, thread_manager.error_count)

@ -381,28 +381,27 @@ class MockHttpTest(testtools.TestCase):
reload_module(c) reload_module(c)
class CaptureStreamBuffer(object): class CaptureStreamPrinter(object):
""" """
CaptureStreamBuffer is used for testing raw byte writing for PY3. Anything CaptureStreamPrinter is used for testing unicode writing for PY3. Anything
written here is decoded as utf-8 and written to the parent CaptureStream written here is encoded as utf-8 and written to the parent CaptureStream
""" """
def __init__(self, captured_stream): def __init__(self, captured_stream):
self._captured_stream = captured_stream self._captured_stream = captured_stream
def write(self, bytes_data): def write(self, data):
# No encoding, just convert the raw bytes into a str for testing # No encoding, just convert the raw bytes into a str for testing
# The below call also validates that we have a byte string. # The below call also validates that we have a byte string.
self._captured_stream.write( self._captured_stream.write(
''.join(map(chr, bytes_data)) data if isinstance(data, six.binary_type) else data.encode('utf8'))
)
class CaptureStream(object): class CaptureStream(object):
def __init__(self, stream): def __init__(self, stream):
self.stream = stream self.stream = stream
self._capture = six.StringIO() self._buffer = six.BytesIO()
self._buffer = CaptureStreamBuffer(self) self._capture = CaptureStreamPrinter(self._buffer)
self.streams = [self._capture] self.streams = [self._capture]
@property @property
@ -425,11 +424,11 @@ class CaptureStream(object):
stream.writelines(*args, **kwargs) stream.writelines(*args, **kwargs)
def getvalue(self): def getvalue(self):
return self._capture.getvalue() return self._buffer.getvalue()
def clear(self): def clear(self):
self._capture.truncate(0) self._buffer.truncate(0)
self._capture.seek(0) self._buffer.seek(0)
class CaptureOutput(object): class CaptureOutput(object):
@ -467,11 +466,11 @@ class CaptureOutput(object):
@property @property
def out(self): def out(self):
return self._out.getvalue() return self._out.getvalue().decode('utf8')
@property @property
def err(self): def err(self):
return self._err.getvalue() return self._err.getvalue().decode('utf8')
def clear(self): def clear(self):
self._out.clear() self._out.clear()