| # -*- coding: utf-8 -*- | |
| # Protocol Buffers - Google's data interchange format | |
| # Copyright 2008 Google Inc. All rights reserved. | |
| # | |
| # Use of this source code is governed by a BSD-style | |
| # license that can be found in the LICENSE file or at | |
| # https://developers.google.com/open-source/licenses/bsd | |
| """Test decoder.""" | |
| import io | |
| import unittest | |
| from google.protobuf import message | |
| from google.protobuf.internal import api_implementation | |
| from google.protobuf.internal import decoder | |
| from google.protobuf.internal import message_set_extensions_pb2 | |
| from google.protobuf.internal import testing_refleaks | |
| from google.protobuf.internal import wire_format | |
| from absl.testing import parameterized | |
| _INPUT_BYTES = b'\x84r\x12' | |
| _EXPECTED = (14596, 18) | |
| @testing_refleaks.TestCase | |
| class DecoderTest(parameterized.TestCase): | |
| def test_decode_varint_bytes(self): | |
| size, pos = decoder._DecodeVarint(_INPUT_BYTES, 0) | |
| self.assertEqual(size, _EXPECTED[0]) | |
| self.assertEqual(pos, 2) | |
| size, pos = decoder._DecodeVarint(_INPUT_BYTES, 2) | |
| self.assertEqual(size, _EXPECTED[1]) | |
| self.assertEqual(pos, 3) | |
| def test_decode_varint_bytes_empty(self): | |
| with self.assertRaises(IndexError) as context: | |
| decoder._DecodeVarint(b'', 0) | |
| self.assertIn('index out of range', str(context.exception)) | |
| def test_decode_varint_bytesio(self): | |
| index = 0 | |
| input_io = io.BytesIO(_INPUT_BYTES) | |
| while True: | |
| size = decoder._DecodeVarint(input_io) | |
| if size is None: | |
| break | |
| self.assertEqual(size, _EXPECTED[index]) | |
| index += 1 | |
| self.assertEqual(index, len(_EXPECTED)) | |
| def test_decode_varint_bytesio_empty(self): | |
| input_io = io.BytesIO(b'') | |
| size = decoder._DecodeVarint(input_io) | |
| self.assertIsNone(size) | |
| def test_decode_unknown_group_field(self): | |
| data = memoryview(b'\013\020\003\014\040\005') | |
| parsed, pos = decoder._DecodeUnknownField( | |
| data, 1, len(data), 1, wire_format.WIRETYPE_START_GROUP | |
| ) | |
| self.assertEqual(pos, 4) | |
| self.assertEqual(len(parsed), 1) | |
| self.assertEqual(parsed[0].field_number, 2) | |
| self.assertEqual(parsed[0].data, 3) | |
| def test_decode_unknown_group_field_nested(self): | |
| data = memoryview(b'\013\023\013\030\004\014\024\014\050\006') | |
| parsed, pos = decoder._DecodeUnknownField( | |
| data, 1, len(data), 1, wire_format.WIRETYPE_START_GROUP | |
| ) | |
| self.assertEqual(pos, 8) | |
| self.assertEqual(len(parsed), 1) | |
| self.assertEqual(parsed[0].field_number, 2) | |
| self.assertEqual(len(parsed[0].data), 1) | |
| self.assertEqual(parsed[0].data[0].field_number, 1) | |
| self.assertEqual(len(parsed[0].data[0].data), 1) | |
| self.assertEqual(parsed[0].data[0].data[0].field_number, 3) | |
| self.assertEqual(parsed[0].data[0].data[0].data, 4) | |
| def test_decode_unknown_group_field_too_many_levels(self): | |
| data = memoryview(b'\023' * 5_000_000) | |
| self.assertRaisesRegex( | |
| message.DecodeError, | |
| 'Error parsing message', | |
| decoder._DecodeUnknownField, | |
| data, | |
| 1, | |
| len(data), | |
| 1, | |
| wire_format.WIRETYPE_START_GROUP, | |
| ) | |
| def test_decode_unknown_mismatched_end_group(self): | |
| self.assertRaisesRegex( | |
| message.DecodeError, | |
| 'Missing group end tag.*', | |
| decoder._DecodeUnknownField, | |
| memoryview(b'\013\024'), | |
| 1, | |
| 2, | |
| 1, | |
| wire_format.WIRETYPE_START_GROUP, | |
| ) | |
| def test_decode_unknown_mismatched_end_group_nested(self): | |
| self.assertRaisesRegex( | |
| message.DecodeError, | |
| 'Missing group end tag.*', | |
| decoder._DecodeUnknownField, | |
| memoryview(b'\013\023\034\024\014'), | |
| 1, | |
| 5, | |
| 1, | |
| wire_format.WIRETYPE_START_GROUP, | |
| ) | |
| def test_decode_message_set_unknown_mismatched_end_group(self): | |
| proto = message_set_extensions_pb2.TestMessageSet() | |
| self.assertRaisesRegex( | |
| message.DecodeError, | |
| 'Unexpected end-group tag.' | |
| if api_implementation.Type() == 'python' | |
| else '.*', | |
| proto.ParseFromString, | |
| b'\013\054\014', | |
| ) | |
| def test_unknown_message_set_decoder_mismatched_end_group(self): | |
| # This behavior isn't actually reachable in practice, but it's good to | |
| # test anyway. | |
| decode = decoder.UnknownMessageSetItemDecoder() | |
| self.assertRaisesRegex( | |
| message.DecodeError, | |
| 'Unexpected end-group tag.', | |
| decode, | |
| memoryview(b'\054\014'), | |
| ) | |
| @parameterized.parameters(int(0), float(0.0), False, '') | |
| def test_default_scalar(self, value): | |
| self.assertTrue(decoder.IsDefaultScalarValue(value)) | |
| @parameterized.parameters(int(1), float(-0.0), float(1.0), True, 'a') | |
| def test_not_default_scalar(self, value): | |
| self.assertFalse(decoder.IsDefaultScalarValue(value)) | |
| if __name__ == '__main__': | |
| unittest.main() |