diff options
Diffstat (limited to 'python/google/protobuf/internal/unknown_fields_test.py')
-rwxr-xr-x | python/google/protobuf/internal/unknown_fields_test.py | 107 |
1 files changed, 62 insertions, 45 deletions
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 84073f1c..d614eaa8 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -47,16 +47,20 @@ from google.protobuf.internal import encoder from google.protobuf.internal import message_set_extensions_pb2 from google.protobuf.internal import missing_enum_values_pb2 from google.protobuf.internal import test_util +from google.protobuf.internal import testing_refleaks from google.protobuf.internal import type_checkers +BaseTestCase = testing_refleaks.BaseTestCase + + def SkipIfCppImplementation(func): return unittest.skipIf( api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, 'C++ implementation does not expose unknown fields to Python')(func) -class UnknownFieldsTest(unittest.TestCase): +class UnknownFieldsTest(BaseTestCase): def setUp(self): self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR @@ -140,7 +144,7 @@ class UnknownFieldsTest(unittest.TestCase): b'', message.repeated_nested_message[0].SerializeToString()) -class UnknownFieldsAccessorsTest(unittest.TestCase): +class UnknownFieldsAccessorsTest(BaseTestCase): def setUp(self): self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR @@ -149,21 +153,18 @@ class UnknownFieldsAccessorsTest(unittest.TestCase): self.all_fields_data = self.all_fields.SerializeToString() self.empty_message = unittest_pb2.TestEmptyMessage() self.empty_message.ParseFromString(self.all_fields_data) - if api_implementation.Type() != 'cpp': - # _unknown_fields is an implementation detail. - self.unknown_fields = self.empty_message._unknown_fields - # All the tests that use GetField() check an implementation detail of the - # Python implementation, which stores unknown fields as serialized strings. - # These tests are skipped by the C++ implementation: it's enough to check that - # the message is correctly serialized. + # GetUnknownField() checks a detail of the Python implementation, which stores + # unknown fields as serialized strings. It cannot be used by the C++ + # implementation: it's enough to check that the message is correctly + # serialized. - def GetField(self, name): + def GetUnknownField(self, name): field_descriptor = self.descriptor.fields_by_name[name] wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type] field_tag = encoder.TagBytes(field_descriptor.number, wire_type) result_dict = {} - for tag_bytes, value in self.unknown_fields: + for tag_bytes, value in self.empty_message._unknown_fields: if tag_bytes == field_tag: decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0] decoder(value, 0, len(value), self.all_fields, result_dict) @@ -171,37 +172,37 @@ class UnknownFieldsAccessorsTest(unittest.TestCase): @SkipIfCppImplementation def testEnum(self): - value = self.GetField('optional_nested_enum') + value = self.GetUnknownField('optional_nested_enum') self.assertEqual(self.all_fields.optional_nested_enum, value) @SkipIfCppImplementation def testRepeatedEnum(self): - value = self.GetField('repeated_nested_enum') + value = self.GetUnknownField('repeated_nested_enum') self.assertEqual(self.all_fields.repeated_nested_enum, value) @SkipIfCppImplementation def testVarint(self): - value = self.GetField('optional_int32') + value = self.GetUnknownField('optional_int32') self.assertEqual(self.all_fields.optional_int32, value) @SkipIfCppImplementation def testFixed32(self): - value = self.GetField('optional_fixed32') + value = self.GetUnknownField('optional_fixed32') self.assertEqual(self.all_fields.optional_fixed32, value) @SkipIfCppImplementation def testFixed64(self): - value = self.GetField('optional_fixed64') + value = self.GetUnknownField('optional_fixed64') self.assertEqual(self.all_fields.optional_fixed64, value) @SkipIfCppImplementation def testLengthDelimited(self): - value = self.GetField('optional_string') + value = self.GetUnknownField('optional_string') self.assertEqual(self.all_fields.optional_string, value) @SkipIfCppImplementation def testGroup(self): - value = self.GetField('optionalgroup') + value = self.GetUnknownField('optionalgroup') self.assertEqual(self.all_fields.optionalgroup, value) def testCopyFrom(self): @@ -241,43 +242,41 @@ class UnknownFieldsAccessorsTest(unittest.TestCase): self.assertEqual(message.SerializeToString(), self.all_fields_data) -class UnknownEnumValuesTest(unittest.TestCase): +class UnknownEnumValuesTest(BaseTestCase): def setUp(self): self.descriptor = missing_enum_values_pb2.TestEnumValues.DESCRIPTOR self.message = missing_enum_values_pb2.TestEnumValues() + # TestEnumValues.ZERO = 0, but does not exist in the other NestedEnum. self.message.optional_nested_enum = ( - missing_enum_values_pb2.TestEnumValues.ZERO) + missing_enum_values_pb2.TestEnumValues.ZERO) self.message.repeated_nested_enum.extend([ - missing_enum_values_pb2.TestEnumValues.ZERO, - missing_enum_values_pb2.TestEnumValues.ONE, - ]) + missing_enum_values_pb2.TestEnumValues.ZERO, + missing_enum_values_pb2.TestEnumValues.ONE, + ]) self.message.packed_nested_enum.extend([ - missing_enum_values_pb2.TestEnumValues.ZERO, - missing_enum_values_pb2.TestEnumValues.ONE, - ]) + missing_enum_values_pb2.TestEnumValues.ZERO, + missing_enum_values_pb2.TestEnumValues.ONE, + ]) self.message_data = self.message.SerializeToString() self.missing_message = missing_enum_values_pb2.TestMissingEnumValues() self.missing_message.ParseFromString(self.message_data) - if api_implementation.Type() != 'cpp': - # _unknown_fields is an implementation detail. - self.unknown_fields = self.missing_message._unknown_fields - # All the tests that use GetField() check an implementation detail of the - # Python implementation, which stores unknown fields as serialized strings. - # These tests are skipped by the C++ implementation: it's enough to check that - # the message is correctly serialized. + # GetUnknownField() checks a detail of the Python implementation, which stores + # unknown fields as serialized strings. It cannot be used by the C++ + # implementation: it's enough to check that the message is correctly + # serialized. - def GetField(self, name): + def GetUnknownField(self, name): field_descriptor = self.descriptor.fields_by_name[name] wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type] field_tag = encoder.TagBytes(field_descriptor.number, wire_type) result_dict = {} - for tag_bytes, value in self.unknown_fields: + for tag_bytes, value in self.missing_message._unknown_fields: if tag_bytes == field_tag: decoder = missing_enum_values_pb2.TestEnumValues._decoders_by_tag[ - tag_bytes][0] + tag_bytes][0] decoder(value, 0, len(value), self.message, result_dict) return result_dict[field_descriptor] @@ -294,21 +293,39 @@ class UnknownEnumValuesTest(unittest.TestCase): # default value. self.assertEqual(missing.optional_nested_enum, 0) - @SkipIfCppImplementation def testUnknownEnumValue(self): + if api_implementation.Type() == 'cpp': + # The CPP implementation of protos (wrongly) allows unknown enum values + # for proto2. + self.assertTrue(self.missing_message.HasField('optional_nested_enum')) + self.assertEqual(self.message.optional_nested_enum, + self.missing_message.optional_nested_enum) + else: + # On the other hand, the Python implementation considers unknown values + # as unknown fields. This is the correct behavior. + self.assertFalse(self.missing_message.HasField('optional_nested_enum')) + value = self.GetUnknownField('optional_nested_enum') + self.assertEqual(self.message.optional_nested_enum, value) + self.missing_message.ClearField('optional_nested_enum') self.assertFalse(self.missing_message.HasField('optional_nested_enum')) - value = self.GetField('optional_nested_enum') - self.assertEqual(self.message.optional_nested_enum, value) - @SkipIfCppImplementation def testUnknownRepeatedEnumValue(self): - value = self.GetField('repeated_nested_enum') - self.assertEqual(self.message.repeated_nested_enum, value) + if api_implementation.Type() == 'cpp': + # For repeated enums, both implementations agree. + self.assertEqual([], self.missing_message.repeated_nested_enum) + else: + self.assertEqual([], self.missing_message.repeated_nested_enum) + value = self.GetUnknownField('repeated_nested_enum') + self.assertEqual(self.message.repeated_nested_enum, value) - @SkipIfCppImplementation def testUnknownPackedEnumValue(self): - value = self.GetField('packed_nested_enum') - self.assertEqual(self.message.packed_nested_enum, value) + if api_implementation.Type() == 'cpp': + # For repeated enums, both implementations agree. + self.assertEqual([], self.missing_message.packed_nested_enum) + else: + self.assertEqual([], self.missing_message.packed_nested_enum) + value = self.GetUnknownField('packed_nested_enum') + self.assertEqual(self.message.packed_nested_enum, value) def testRoundTrip(self): new_message = missing_enum_values_pb2.TestEnumValues() |