From 9878f75899d40821d65f01777fd103e054f2a108 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 15 Oct 2015 23:19:07 -0400 Subject: [PATCH 1/3] Coverage for 'gcloud._apitools.buffered_stream'. --- gcloud/_apitools/buffered_stream.py | 38 +++++----- gcloud/_apitools/test_buffered_stream.py | 89 ++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 gcloud/_apitools/test_buffered_stream.py diff --git a/gcloud/_apitools/buffered_stream.py b/gcloud/_apitools/buffered_stream.py index 83205d37aedc..a90a7d98b1e0 100644 --- a/gcloud/_apitools/buffered_stream.py +++ b/gcloud/_apitools/buffered_stream.py @@ -13,32 +13,32 @@ class BufferedStream(object): """Buffers a stream, reading ahead to determine if we're at the end.""" def __init__(self, stream, start, size): - self.__stream = stream - self.__start_pos = start - self.__buffer_pos = 0 - self.__buffered_data = self.__stream.read(size) - self.__stream_at_end = len(self.__buffered_data) < size - self.__end_pos = self.__start_pos + len(self.__buffered_data) - - def __str__(self): + self._stream = stream + self._start_pos = start + self._buffer_pos = 0 + self._buffered_data = self._stream.read(size) + self._stream_at_end = len(self._buffered_data) < size + self._end_pos = self._start_pos + len(self._buffered_data) + + def __str__(self): # pragma: NO COVER return ('Buffered stream %s from position %s-%s with %s ' - 'bytes remaining' % (self.__stream, self.__start_pos, - self.__end_pos, self._bytes_remaining)) + 'bytes remaining' % (self._stream, self._start_pos, + self._end_pos, self._bytes_remaining)) def __len__(self): - return len(self.__buffered_data) + return len(self._buffered_data) @property def stream_exhausted(self): - return self.__stream_at_end + return self._stream_at_end @property def stream_end_position(self): - return self.__end_pos + return self._end_pos @property def _bytes_remaining(self): - return len(self.__buffered_data) - self.__buffer_pos + return len(self._buffered_data) - self._buffer_pos def read(self, size=None): # pylint: disable=invalid-name """Reads from the buffer.""" @@ -47,13 +47,13 @@ def read(self, size=None): # pylint: disable=invalid-name 'Illegal read of size %s requested on BufferedStream. ' 'Wrapped stream %s is at position %s-%s, ' '%s bytes remaining.' % - (size, self.__stream, self.__start_pos, self.__end_pos, + (size, self._stream, self._start_pos, self._end_pos, self._bytes_remaining)) - data = '' + data = b'' if self._bytes_remaining: size = min(size, self._bytes_remaining) - data = self.__buffered_data[ - self.__buffer_pos:self.__buffer_pos + size] - self.__buffer_pos += size + data = self._buffered_data[ + self._buffer_pos:self._buffer_pos + size] + self._buffer_pos += size return data diff --git a/gcloud/_apitools/test_buffered_stream.py b/gcloud/_apitools/test_buffered_stream.py new file mode 100644 index 000000000000..52b614cfc951 --- /dev/null +++ b/gcloud/_apitools/test_buffered_stream.py @@ -0,0 +1,89 @@ +# pylint: skip-file +import unittest2 + + +class Test_BufferedStream(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud._apitools.buffered_stream import BufferedStream + return BufferedStream + + def _makeOne(self, *args, **kw): + return self._getTargetClass()(*args, **kw) + + def test_ctor_start_zero_longer_than_buffer(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = 0 + BUFSIZE = 4 + stream = BytesIO(CONTENT) + bufstream = self._makeOne(stream, START, BUFSIZE) + self.assertTrue(bufstream._stream is stream) + self.assertEqual(bufstream._start_pos, START) + self.assertEqual(bufstream._buffer_pos, 0) + self.assertEqual(bufstream._buffered_data, CONTENT[:BUFSIZE]) + self.assertEqual(len(bufstream), BUFSIZE) + self.assertFalse(bufstream.stream_exhausted) + self.assertEqual(bufstream.stream_end_position, BUFSIZE) + self.assertEqual(bufstream._bytes_remaining, BUFSIZE) + + def test_ctor_start_nonzero_shorter_than_buffer(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = 8 + BUFSIZE = 10 + stream = BytesIO(CONTENT) + stream.read(START) # already consumed + bufstream = self._makeOne(stream, START, BUFSIZE) + self.assertTrue(bufstream._stream is stream) + self.assertEqual(bufstream._start_pos, START) + self.assertEqual(bufstream._buffer_pos, 0) + self.assertEqual(bufstream._buffered_data, CONTENT[START:]) + self.assertEqual(len(bufstream), len(CONTENT) - START) + self.assertTrue(bufstream.stream_exhausted) + self.assertEqual(bufstream.stream_end_position, len(CONTENT)) + self.assertEqual(bufstream._bytes_remaining, len(CONTENT) - START) + + def test_read_w_none(self): + from io import BytesIO + from gcloud._apitools.exceptions import NotYetImplementedError + CONTENT = b'CONTENT GOES HERE' + START = 0 + BUFSIZE = 4 + stream = BytesIO(CONTENT) + bufstream = self._makeOne(stream, START, BUFSIZE) + with self.assertRaises(NotYetImplementedError): + bufstream.read(None) + + def test_read_w_negative_size(self): + from io import BytesIO + from gcloud._apitools.exceptions import NotYetImplementedError + CONTENT = b'CONTENT GOES HERE' + START = 0 + BUFSIZE = 4 + stream = BytesIO(CONTENT) + bufstream = self._makeOne(stream, START, BUFSIZE) + with self.assertRaises(NotYetImplementedError): + bufstream.read(-2) + + def test_read_from_start(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = 0 + BUFSIZE = 4 + stream = BytesIO(CONTENT) + bufstream = self._makeOne(stream, START, BUFSIZE) + self.assertEqual(bufstream.read(4), CONTENT[:4]) + + def test_read_exhausted(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = len(CONTENT) + BUFSIZE = 10 + stream = BytesIO(CONTENT) + stream.read(START) # already consumed + bufstream = self._makeOne(stream, START, BUFSIZE) + self.assertTrue(bufstream.stream_exhausted) + self.assertEqual(bufstream.stream_end_position, len(CONTENT)) + self.assertEqual(bufstream._bytes_remaining, 0) + self.assertEqual(bufstream.read(10), b'') From 56ce42661d7bb91621ff6024f83ef40d86674f18 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 26 Oct 2015 10:41:00 -0400 Subject: [PATCH 2/3] Rename 'BufferedStream.__str__' -> '__repr__'. Addresses: https://github.com/GoogleCloudPlatform/gcloud-python/pull/1192#discussion_r42947845 --- gcloud/_apitools/buffered_stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcloud/_apitools/buffered_stream.py b/gcloud/_apitools/buffered_stream.py index a90a7d98b1e0..7daf5d2b0e6a 100644 --- a/gcloud/_apitools/buffered_stream.py +++ b/gcloud/_apitools/buffered_stream.py @@ -20,7 +20,7 @@ def __init__(self, stream, start, size): self._stream_at_end = len(self._buffered_data) < size self._end_pos = self._start_pos + len(self._buffered_data) - def __str__(self): # pragma: NO COVER + def __repr__(self): return ('Buffered stream %s from position %s-%s with %s ' 'bytes remaining' % (self._stream, self._start_pos, self._end_pos, self._bytes_remaining)) From d7b4ffb5fdcd8a91ca42f177302c863d6ea3b08e Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 26 Oct 2015 10:46:14 -0400 Subject: [PATCH 3/3] Add explicitly-named test for 'BufferedStream._bytes_remaining'. Addresses: https://github.com/GoogleCloudPlatform/gcloud-python/pull/1192#discussion_r42950038 --- gcloud/_apitools/test_buffered_stream.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gcloud/_apitools/test_buffered_stream.py b/gcloud/_apitools/test_buffered_stream.py index 52b614cfc951..f0bcd8793e49 100644 --- a/gcloud/_apitools/test_buffered_stream.py +++ b/gcloud/_apitools/test_buffered_stream.py @@ -25,7 +25,6 @@ def test_ctor_start_zero_longer_than_buffer(self): self.assertEqual(len(bufstream), BUFSIZE) self.assertFalse(bufstream.stream_exhausted) self.assertEqual(bufstream.stream_end_position, BUFSIZE) - self.assertEqual(bufstream._bytes_remaining, BUFSIZE) def test_ctor_start_nonzero_shorter_than_buffer(self): from io import BytesIO @@ -42,6 +41,24 @@ def test_ctor_start_nonzero_shorter_than_buffer(self): self.assertEqual(len(bufstream), len(CONTENT) - START) self.assertTrue(bufstream.stream_exhausted) self.assertEqual(bufstream.stream_end_position, len(CONTENT)) + + def test__bytes_remaining_start_zero_longer_than_buffer(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = 0 + BUFSIZE = 4 + stream = BytesIO(CONTENT) + bufstream = self._makeOne(stream, START, BUFSIZE) + self.assertEqual(bufstream._bytes_remaining, BUFSIZE) + + def test__bytes_remaining_start_zero_shorter_than_buffer(self): + from io import BytesIO + CONTENT = b'CONTENT GOES HERE' + START = 8 + BUFSIZE = 10 + stream = BytesIO(CONTENT) + stream.read(START) # already consumed + bufstream = self._makeOne(stream, START, BUFSIZE) self.assertEqual(bufstream._bytes_remaining, len(CONTENT) - START) def test_read_w_none(self):