/python/google/protobuf/internal/decoder_test.py
Python | 250 lines | 191 code | 10 blank | 49 comment | 6 complexity | a54d0def4949ef28d71242b51231eedf MD5 | raw file
- # Protocol Buffers - Google's data interchange format
- # Copyright 2008 Google Inc. All rights reserved.
- # http://code.google.com/p/protobuf/
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are
- # met:
- #
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # * Redistributions in binary form must reproduce the above
- # copyright notice, this list of conditions and the following disclaimer
- # in the documentation and/or other materials provided with the
- # distribution.
- # * Neither the name of Google Inc. nor the names of its
- # contributors may be used to endorse or promote products derived from
- # this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- """Test for google.protobuf.internal.decoder."""
- __author__ = 'robinson@google.com (Will Robinson)'
- import struct
- import unittest
- from google.protobuf.internal import wire_format
- from google.protobuf.internal import encoder
- from google.protobuf.internal import decoder
- import logging
- from google.protobuf.internal import input_stream
- from google.protobuf import message
- import mox
- class DecoderTest(unittest.TestCase):
- def setUp(self):
- self.mox = mox.Mox()
- self.mock_stream = self.mox.CreateMock(input_stream.InputStream)
- self.mock_message = self.mox.CreateMock(message.Message)
- def testReadFieldNumberAndWireType(self):
- # Test field numbers that will require various varint sizes.
- for expected_field_number in (1, 15, 16, 2047, 2048):
- for expected_wire_type in range(6): # Highest-numbered wiretype is 5.
- e = encoder.Encoder()
- e._AppendTag(expected_field_number, expected_wire_type)
- s = e.ToString()
- d = decoder.Decoder(s)
- field_number, wire_type = d.ReadFieldNumberAndWireType()
- self.assertEqual(expected_field_number, field_number)
- self.assertEqual(expected_wire_type, wire_type)
- def ReadScalarTestHelper(self, test_name, decoder_method, expected_result,
- expected_stream_method_name,
- stream_method_return, *args):
- """Helper for testReadScalars below.
- Calls one of the Decoder.Read*() methods and ensures that the results are
- as expected.
- Args:
- test_name: Name of this test, used for logging only.
- decoder_method: Unbound decoder.Decoder method to call.
- expected_result: Value we expect returned from decoder_method().
- expected_stream_method_name: (string) Name of the InputStream
- method we expect Decoder to call to actually read the value
- on the wire.
- stream_method_return: Value our mocked-out stream method should
- return to the decoder.
- args: Additional arguments that we expect to be passed to the
- stream method.
- """
- logging.info('Testing %s scalar input.\n'
- 'Calling %r(), and expecting that to call the '
- 'stream method %s(%r), which will return %r. Finally, '
- 'expecting the Decoder method to return %r'% (
- test_name, decoder_method,
- expected_stream_method_name, args, stream_method_return,
- expected_result))
- d = decoder.Decoder('')
- d._stream = self.mock_stream
- if decoder_method in (decoder.Decoder.ReadString,
- decoder.Decoder.ReadBytes):
- self.mock_stream.ReadVarUInt32().AndReturn(len(stream_method_return))
- # We have to use names instead of methods to work around some
- # mox weirdness. (ResetAll() is overzealous).
- expected_stream_method = getattr(self.mock_stream,
- expected_stream_method_name)
- expected_stream_method(*args).AndReturn(stream_method_return)
- self.mox.ReplayAll()
- result = decoder_method(d)
- self.assertEqual(expected_result, result)
- self.assert_(isinstance(result, type(expected_result)))
- self.mox.VerifyAll()
- self.mox.ResetAll()
- def testReadScalars(self):
- test_string = 'I can feel myself getting sutpider.'
- scalar_tests = [
- ['int32', decoder.Decoder.ReadInt32, 0, 'ReadVarint32', 0],
- ['int64', decoder.Decoder.ReadInt64, 0, 'ReadVarint64', 0],
- ['uint32', decoder.Decoder.ReadUInt32, 0, 'ReadVarUInt32', 0],
- ['uint64', decoder.Decoder.ReadUInt64, 0, 'ReadVarUInt64', 0],
- ['fixed32', decoder.Decoder.ReadFixed32, 0xffffffff,
- 'ReadLittleEndian32', 0xffffffff],
- ['fixed64', decoder.Decoder.ReadFixed64, 0xffffffffffffffff,
- 'ReadLittleEndian64', 0xffffffffffffffff],
- ['sfixed32', decoder.Decoder.ReadSFixed32, long(-1),
- 'ReadLittleEndian32', 0xffffffff],
- ['sfixed64', decoder.Decoder.ReadSFixed64, long(-1),
- 'ReadLittleEndian64', 0xffffffffffffffff],
- ['float', decoder.Decoder.ReadFloat, 0.0,
- 'ReadBytes', struct.pack('f', 0.0), 4],
- ['double', decoder.Decoder.ReadDouble, 0.0,
- 'ReadBytes', struct.pack('d', 0.0), 8],
- ['bool', decoder.Decoder.ReadBool, True, 'ReadVarUInt32', 1],
- ['enum', decoder.Decoder.ReadEnum, 23, 'ReadVarUInt32', 23],
- ['string', decoder.Decoder.ReadString,
- unicode(test_string, 'utf-8'), 'ReadBytes', test_string,
- len(test_string)],
- ['utf8-string', decoder.Decoder.ReadString,
- unicode(test_string, 'utf-8'), 'ReadBytes', test_string,
- len(test_string)],
- ['bytes', decoder.Decoder.ReadBytes,
- test_string, 'ReadBytes', test_string, len(test_string)],
- # We test zigzag decoding routines more extensively below.
- ['sint32', decoder.Decoder.ReadSInt32, -1, 'ReadVarUInt32', 1],
- ['sint64', decoder.Decoder.ReadSInt64, -1, 'ReadVarUInt64', 1],
- ]
- # Ensure that we're testing different Decoder methods and using
- # different test names in all test cases above.
- self.assertEqual(len(scalar_tests), len(set(t[0] for t in scalar_tests)))
- self.assert_(len(scalar_tests) >= len(set(t[1] for t in scalar_tests)))
- for args in scalar_tests:
- self.ReadScalarTestHelper(*args)
- def testReadMessageInto(self):
- length = 23
- def Test(simulate_error):
- d = decoder.Decoder('')
- d._stream = self.mock_stream
- self.mock_stream.ReadVarUInt32().AndReturn(length)
- sub_buffer = object()
- self.mock_stream.GetSubBuffer(length).AndReturn(sub_buffer)
- if simulate_error:
- self.mock_message.MergeFromString(sub_buffer).AndReturn(length - 1)
- self.mox.ReplayAll()
- self.assertRaises(
- message.DecodeError, d.ReadMessageInto, self.mock_message)
- else:
- self.mock_message.MergeFromString(sub_buffer).AndReturn(length)
- self.mock_stream.SkipBytes(length)
- self.mox.ReplayAll()
- d.ReadMessageInto(self.mock_message)
- self.mox.VerifyAll()
- self.mox.ResetAll()
- Test(simulate_error=False)
- Test(simulate_error=True)
- def testReadGroupInto_Success(self):
- # Test both the empty and nonempty cases.
- for num_bytes in (5, 0):
- field_number = expected_field_number = 10
- d = decoder.Decoder('')
- d._stream = self.mock_stream
- sub_buffer = object()
- self.mock_stream.GetSubBuffer().AndReturn(sub_buffer)
- self.mock_message.MergeFromString(sub_buffer).AndReturn(num_bytes)
- self.mock_stream.SkipBytes(num_bytes)
- self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
- field_number, wire_format.WIRETYPE_END_GROUP))
- self.mox.ReplayAll()
- d.ReadGroupInto(expected_field_number, self.mock_message)
- self.mox.VerifyAll()
- self.mox.ResetAll()
- def ReadGroupInto_FailureTestHelper(self, bytes_read):
- d = decoder.Decoder('')
- d._stream = self.mock_stream
- sub_buffer = object()
- self.mock_stream.GetSubBuffer().AndReturn(sub_buffer)
- self.mock_message.MergeFromString(sub_buffer).AndReturn(bytes_read)
- return d
- def testReadGroupInto_NegativeBytesReported(self):
- expected_field_number = 10
- d = self.ReadGroupInto_FailureTestHelper(bytes_read=-1)
- self.mox.ReplayAll()
- self.assertRaises(message.DecodeError,
- d.ReadGroupInto, expected_field_number,
- self.mock_message)
- self.mox.VerifyAll()
- def testReadGroupInto_NoEndGroupTag(self):
- field_number = expected_field_number = 10
- num_bytes = 5
- d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes)
- self.mock_stream.SkipBytes(num_bytes)
- # Right field number, wrong wire type.
- self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
- field_number, wire_format.WIRETYPE_LENGTH_DELIMITED))
- self.mox.ReplayAll()
- self.assertRaises(message.DecodeError,
- d.ReadGroupInto, expected_field_number,
- self.mock_message)
- self.mox.VerifyAll()
- def testReadGroupInto_WrongFieldNumberInEndGroupTag(self):
- expected_field_number = 10
- field_number = expected_field_number + 1
- num_bytes = 5
- d = self.ReadGroupInto_FailureTestHelper(bytes_read=num_bytes)
- self.mock_stream.SkipBytes(num_bytes)
- # Wrong field number, right wire type.
- self.mock_stream.ReadVarUInt32().AndReturn(wire_format.PackTag(
- field_number, wire_format.WIRETYPE_END_GROUP))
- self.mox.ReplayAll()
- self.assertRaises(message.DecodeError,
- d.ReadGroupInto, expected_field_number,
- self.mock_message)
- self.mox.VerifyAll()
- def testSkipBytes(self):
- d = decoder.Decoder('')
- num_bytes = 1024
- self.mock_stream.SkipBytes(num_bytes)
- d._stream = self.mock_stream
- self.mox.ReplayAll()
- d.SkipBytes(num_bytes)
- self.mox.VerifyAll()
- if __name__ == '__main__':
- unittest.main()