Index: third_party/protobuf/python/google/protobuf/internal/reflection_test.py |
diff --git a/third_party/protobuf/python/google/protobuf/internal/reflection_test.py b/third_party/protobuf/python/google/protobuf/internal/reflection_test.py |
index 54eeebe662c849d11f74576e94fbca98656cae4c..7b9d3398b6efbb7e545ca2d993b983d39a07ddef 100755 |
--- a/third_party/protobuf/python/google/protobuf/internal/reflection_test.py |
+++ b/third_party/protobuf/python/google/protobuf/internal/reflection_test.py |
@@ -41,8 +41,6 @@ import operator |
import struct |
import unittest |
-# TODO(robinson): When we split this test in two, only some of these imports |
-# will be necessary in each test. |
from google.protobuf import unittest_import_pb2 |
from google.protobuf import unittest_mset_pb2 |
from google.protobuf import unittest_pb2 |
@@ -50,6 +48,7 @@ from google.protobuf import descriptor_pb2 |
from google.protobuf import descriptor |
from google.protobuf import message |
from google.protobuf import reflection |
+from google.protobuf.internal import api_implementation |
from google.protobuf.internal import more_extensions_pb2 |
from google.protobuf.internal import more_messages_pb2 |
from google.protobuf.internal import wire_format |
@@ -104,10 +103,10 @@ class _MiniDecoder(object): |
class ReflectionTest(unittest.TestCase): |
- def assertIs(self, values, others): |
+ def assertListsEqual(self, values, others): |
self.assertEqual(len(values), len(others)) |
for i in range(len(values)): |
- self.assertTrue(values[i] is others[i]) |
+ self.assertEqual(values[i], others[i]) |
def testScalarConstructor(self): |
# Constructor with only scalar types should succeed. |
@@ -201,15 +200,24 @@ class ReflectionTest(unittest.TestCase): |
list(proto.repeated_foreign_message)) |
def testConstructorTypeError(self): |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, optional_int32="foo") |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, optional_string=1234) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, optional_nested_message=1234) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_int32=1234) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_int32=["foo"]) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_string=1234) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_string=[1234]) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_nested_message=1234) |
- self.assertRaises(TypeError, unittest_pb2.TestAllTypes, repeated_nested_message=[1234]) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, optional_int32="foo") |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, optional_string=1234) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, optional_nested_message=1234) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_int32=1234) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_int32=["foo"]) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_string=1234) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_string=[1234]) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_nested_message=1234) |
+ self.assertRaises( |
+ TypeError, unittest_pb2.TestAllTypes, repeated_nested_message=[1234]) |
def testConstructorInvalidatesCachedByteSize(self): |
message = unittest_pb2.TestAllTypes(optional_int32 = 12) |
@@ -311,11 +319,14 @@ class ReflectionTest(unittest.TestCase): |
self.assertEqual(0, getattr(composite_field, scalar_field_name)) |
# Finally, ensure that modifications to the old composite field object |
- # don't have any effect on the parent. |
+ # don't have any effect on the parent. Possible only with the pure-python |
+ # implementation of the API. |
# |
# (NOTE that when we clear the composite field in the parent, we actually |
# don't recursively clear down the tree. Instead, we just disconnect the |
# cleared composite from the tree.) |
+ if api_implementation.Type() != 'python': |
+ return |
self.assertTrue(old_composite_field is not composite_field) |
setattr(old_composite_field, scalar_field_name, new_val) |
self.assertTrue(not composite_field.HasField(scalar_field_name)) |
@@ -337,6 +348,8 @@ class ReflectionTest(unittest.TestCase): |
nested.bb = 23 |
def testDisconnectingNestedMessageBeforeSettingField(self): |
+ if api_implementation.Type() != 'python': |
+ return |
proto = unittest_pb2.TestAllTypes() |
nested = proto.optional_nested_message |
proto.ClearField('optional_nested_message') # Should disconnect from parent |
@@ -526,7 +539,6 @@ class ReflectionTest(unittest.TestCase): |
# proto.nonexistent_field = 23 should fail as well. |
self.assertRaises(AttributeError, setattr, proto, 'nonexistent_field', 23) |
- # TODO(robinson): Add type-safety check for enums. |
def testSingleScalarTypeSafety(self): |
proto = unittest_pb2.TestAllTypes() |
self.assertRaises(TypeError, setattr, proto, 'optional_int32', 1.1) |
@@ -538,7 +550,9 @@ class ReflectionTest(unittest.TestCase): |
def TestMinAndMaxIntegers(field_name, expected_min, expected_max): |
pb = unittest_pb2.TestAllTypes() |
setattr(pb, field_name, expected_min) |
+ self.assertEqual(expected_min, getattr(pb, field_name)) |
setattr(pb, field_name, expected_max) |
+ self.assertEqual(expected_max, getattr(pb, field_name)) |
self.assertRaises(ValueError, setattr, pb, field_name, expected_min - 1) |
self.assertRaises(ValueError, setattr, pb, field_name, expected_max + 1) |
@@ -546,7 +560,33 @@ class ReflectionTest(unittest.TestCase): |
TestMinAndMaxIntegers('optional_uint32', 0, 0xffffffff) |
TestMinAndMaxIntegers('optional_int64', -(1 << 63), (1 << 63) - 1) |
TestMinAndMaxIntegers('optional_uint64', 0, 0xffffffffffffffff) |
- TestMinAndMaxIntegers('optional_nested_enum', -(1 << 31), (1 << 31) - 1) |
+ |
+ pb = unittest_pb2.TestAllTypes() |
+ pb.optional_nested_enum = 1 |
+ self.assertEqual(1, pb.optional_nested_enum) |
+ |
+ # Invalid enum values. |
+ pb.optional_nested_enum = 0 |
+ self.assertEqual(0, pb.optional_nested_enum) |
+ |
+ bytes_size_before = pb.ByteSize() |
+ |
+ pb.optional_nested_enum = 4 |
+ self.assertEqual(4, pb.optional_nested_enum) |
+ |
+ pb.optional_nested_enum = 0 |
+ self.assertEqual(0, pb.optional_nested_enum) |
+ |
+ # Make sure that setting the same enum field doesn't just add unknown |
+ # fields (but overwrites them). |
+ self.assertEqual(bytes_size_before, pb.ByteSize()) |
+ |
+ # Is the invalid value preserved after serialization? |
+ serialized = pb.SerializeToString() |
+ pb2 = unittest_pb2.TestAllTypes() |
+ pb2.ParseFromString(serialized) |
+ self.assertEqual(0, pb2.optional_nested_enum) |
+ self.assertEqual(pb, pb2) |
def testRepeatedScalarTypeSafety(self): |
proto = unittest_pb2.TestAllTypes() |
@@ -560,11 +600,19 @@ class ReflectionTest(unittest.TestCase): |
self.assertRaises(IndexError, proto.repeated_int32.__setitem__, 500, 23) |
self.assertRaises(TypeError, proto.repeated_int32.__setitem__, 0, 'abc') |
+ # Repeated enums tests. |
+ #proto.repeated_nested_enum.append(0) |
+ |
def testSingleScalarGettersAndSetters(self): |
proto = unittest_pb2.TestAllTypes() |
self.assertEqual(0, proto.optional_int32) |
proto.optional_int32 = 1 |
self.assertEqual(1, proto.optional_int32) |
+ |
+ proto.optional_uint64 = 0xffffffffffff |
+ self.assertEqual(0xffffffffffff, proto.optional_uint64) |
+ proto.optional_uint64 = 0xffffffffffffffff |
+ self.assertEqual(0xffffffffffffffff, proto.optional_uint64) |
# TODO(robinson): Test all other scalar field types. |
def testSingleScalarClearField(self): |
@@ -645,11 +693,38 @@ class ReflectionTest(unittest.TestCase): |
del proto.repeated_int32[2:] |
self.assertEqual([5, 35], proto.repeated_int32) |
+ # Test extending. |
+ proto.repeated_int32.extend([3, 13]) |
+ self.assertEqual([5, 35, 3, 13], proto.repeated_int32) |
+ |
# Test clearing. |
proto.ClearField('repeated_int32') |
self.assertTrue(not proto.repeated_int32) |
self.assertEqual(0, len(proto.repeated_int32)) |
+ proto.repeated_int32.append(1) |
+ self.assertEqual(1, proto.repeated_int32[-1]) |
+ # Test assignment to a negative index. |
+ proto.repeated_int32[-1] = 2 |
+ self.assertEqual(2, proto.repeated_int32[-1]) |
+ |
+ # Test deletion at negative indices. |
+ proto.repeated_int32[:] = [0, 1, 2, 3] |
+ del proto.repeated_int32[-1] |
+ self.assertEqual([0, 1, 2], proto.repeated_int32) |
+ |
+ del proto.repeated_int32[-2] |
+ self.assertEqual([0, 2], proto.repeated_int32) |
+ |
+ self.assertRaises(IndexError, proto.repeated_int32.__delitem__, -3) |
+ self.assertRaises(IndexError, proto.repeated_int32.__delitem__, 300) |
+ |
+ del proto.repeated_int32[-2:-1] |
+ self.assertEqual([2], proto.repeated_int32) |
+ |
+ del proto.repeated_int32[100:10000] |
+ self.assertEqual([2], proto.repeated_int32) |
+ |
def testRepeatedScalarsRemove(self): |
proto = unittest_pb2.TestAllTypes() |
@@ -687,7 +762,7 @@ class ReflectionTest(unittest.TestCase): |
m1 = proto.repeated_nested_message.add() |
self.assertTrue(proto.repeated_nested_message) |
self.assertEqual(2, len(proto.repeated_nested_message)) |
- self.assertIs([m0, m1], proto.repeated_nested_message) |
+ self.assertListsEqual([m0, m1], proto.repeated_nested_message) |
self.assertTrue(isinstance(m0, unittest_pb2.TestAllTypes.NestedMessage)) |
# Test out-of-bounds indices. |
@@ -706,32 +781,57 @@ class ReflectionTest(unittest.TestCase): |
m2 = proto.repeated_nested_message.add() |
m3 = proto.repeated_nested_message.add() |
m4 = proto.repeated_nested_message.add() |
- self.assertIs([m1, m2, m3], proto.repeated_nested_message[1:4]) |
- self.assertIs([m0, m1, m2, m3, m4], proto.repeated_nested_message[:]) |
+ self.assertListsEqual( |
+ [m1, m2, m3], proto.repeated_nested_message[1:4]) |
+ self.assertListsEqual( |
+ [m0, m1, m2, m3, m4], proto.repeated_nested_message[:]) |
+ self.assertListsEqual( |
+ [m0, m1], proto.repeated_nested_message[:2]) |
+ self.assertListsEqual( |
+ [m2, m3, m4], proto.repeated_nested_message[2:]) |
+ self.assertEqual( |
+ m0, proto.repeated_nested_message[0]) |
+ self.assertListsEqual( |
+ [m0], proto.repeated_nested_message[:1]) |
# Test that we can use the field as an iterator. |
result = [] |
for i in proto.repeated_nested_message: |
result.append(i) |
- self.assertIs([m0, m1, m2, m3, m4], result) |
+ self.assertListsEqual([m0, m1, m2, m3, m4], result) |
# Test single deletion. |
del proto.repeated_nested_message[2] |
- self.assertIs([m0, m1, m3, m4], proto.repeated_nested_message) |
+ self.assertListsEqual([m0, m1, m3, m4], proto.repeated_nested_message) |
# Test slice deletion. |
del proto.repeated_nested_message[2:] |
- self.assertIs([m0, m1], proto.repeated_nested_message) |
+ self.assertListsEqual([m0, m1], proto.repeated_nested_message) |
+ |
+ # Test extending. |
+ n1 = unittest_pb2.TestAllTypes.NestedMessage(bb=1) |
+ n2 = unittest_pb2.TestAllTypes.NestedMessage(bb=2) |
+ proto.repeated_nested_message.extend([n1,n2]) |
+ self.assertEqual(4, len(proto.repeated_nested_message)) |
+ self.assertEqual(n1, proto.repeated_nested_message[2]) |
+ self.assertEqual(n2, proto.repeated_nested_message[3]) |
# Test clearing. |
proto.ClearField('repeated_nested_message') |
self.assertTrue(not proto.repeated_nested_message) |
self.assertEqual(0, len(proto.repeated_nested_message)) |
+ # Test constructing an element while adding it. |
+ proto.repeated_nested_message.add(bb=23) |
+ self.assertEqual(1, len(proto.repeated_nested_message)) |
+ self.assertEqual(23, proto.repeated_nested_message[0].bb) |
+ |
def testHandWrittenReflection(self): |
- # TODO(robinson): We probably need a better way to specify |
- # protocol types by hand. But then again, this isn't something |
- # we expect many people to do. Hmm. |
+ # Hand written extensions are only supported by the pure-Python |
+ # implementation of the API. |
+ if api_implementation.Type() != 'python': |
+ return |
+ |
FieldDescriptor = descriptor.FieldDescriptor |
foo_field_descriptor = FieldDescriptor( |
name='foo_field', full_name='MyProto.foo_field', |
@@ -894,7 +994,7 @@ class ReflectionTest(unittest.TestCase): |
self.assertTrue(not toplevel.HasField('submessage')) |
foreign = toplevel.submessage.Extensions[ |
more_extensions_pb2.repeated_message_extension].add() |
- self.assertTrue(foreign is toplevel.submessage.Extensions[ |
+ self.assertEqual(foreign, toplevel.submessage.Extensions[ |
more_extensions_pb2.repeated_message_extension][0]) |
self.assertTrue(toplevel.HasField('submessage')) |
@@ -997,6 +1097,12 @@ class ReflectionTest(unittest.TestCase): |
self.assertEqual(123, proto2.repeated_nested_message[1].bb) |
self.assertEqual(321, proto2.repeated_nested_message[2].bb) |
+ proto3 = unittest_pb2.TestAllTypes() |
+ proto3.repeated_nested_message.MergeFrom(proto2.repeated_nested_message) |
+ self.assertEqual(999, proto3.repeated_nested_message[0].bb) |
+ self.assertEqual(123, proto3.repeated_nested_message[1].bb) |
+ self.assertEqual(321, proto3.repeated_nested_message[2].bb) |
+ |
def testMergeFromAllFields(self): |
# With all fields set. |
proto1 = unittest_pb2.TestAllTypes() |
@@ -1126,6 +1232,15 @@ class ReflectionTest(unittest.TestCase): |
self.assertEqual(2, proto1.optional_int32) |
self.assertEqual('important-text', proto1.optional_string) |
+ def testCopyFromBadType(self): |
+ # The python implementation doesn't raise an exception in this |
+ # case. In theory it should. |
+ if api_implementation.Type() == 'python': |
+ return |
+ proto1 = unittest_pb2.TestAllTypes() |
+ proto2 = unittest_pb2.TestAllExtensions() |
+ self.assertRaises(TypeError, proto1.CopyFrom, proto2) |
+ |
def testClear(self): |
proto = unittest_pb2.TestAllTypes() |
test_util.SetAllFields(proto) |
@@ -1231,9 +1346,10 @@ class ReflectionTest(unittest.TestCase): |
proto.optional_string = str('Testing') |
self.assertEqual(proto.optional_string, unicode('Testing')) |
- # Values of type 'str' are also accepted as long as they can be encoded in |
- # UTF-8. |
- self.assertEqual(type(proto.optional_string), str) |
+ if api_implementation.Type() == 'python': |
+ # Values of type 'str' are also accepted as long as they can be |
+ # encoded in UTF-8. |
+ self.assertEqual(type(proto.optional_string), str) |
# Try to assign a 'str' value which contains bytes that aren't 7-bit ASCII. |
self.assertRaises(ValueError, |
@@ -1271,7 +1387,7 @@ class ReflectionTest(unittest.TestCase): |
# Check that the type_id is the same as the tag ID in the .proto file. |
self.assertEqual(raw.item[0].type_id, 1547769) |
- # Check the actually bytes on the wire. |
+ # Check the actual bytes on the wire. |
self.assertTrue( |
raw.item[0].message.endswith(test_utf8_bytes)) |
message2.MergeFromString(raw.item[0].message) |
@@ -1279,10 +1395,23 @@ class ReflectionTest(unittest.TestCase): |
self.assertEqual(type(message2.str), unicode) |
self.assertEqual(message2.str, test_utf8) |
- # How about if the bytes on the wire aren't a valid UTF-8 encoded string. |
+ # The pure Python API throws an exception on MergeFromString(), |
+ # if any of the string fields of the message can't be UTF-8 decoded. |
+ # The C++ implementation of the API has no way to check that on |
+ # MergeFromString and thus has no way to throw the exception. |
+ # |
+ # The pure Python API always returns objects of type 'unicode' (UTF-8 |
+ # encoded), or 'str' (in 7 bit ASCII). |
bytes = raw.item[0].message.replace( |
test_utf8_bytes, len(test_utf8_bytes) * '\xff') |
- self.assertRaises(UnicodeDecodeError, message2.MergeFromString, bytes) |
+ |
+ unicode_decode_failed = False |
+ try: |
+ message2.MergeFromString(bytes) |
+ except UnicodeDecodeError, e: |
+ unicode_decode_failed = True |
+ string_field = message2.str |
+ self.assertTrue(unicode_decode_failed or type(string_field) == str) |
def testEmptyNestedMessage(self): |
proto = unittest_pb2.TestAllTypes() |
@@ -1325,6 +1454,9 @@ class TestAllTypesEqualityTest(unittest.TestCase): |
self.first_proto = unittest_pb2.TestAllTypes() |
self.second_proto = unittest_pb2.TestAllTypes() |
+ def testNotHashable(self): |
+ self.assertRaises(TypeError, hash, self.first_proto) |
+ |
def testSelfEquality(self): |
self.assertEqual(self.first_proto, self.first_proto) |
@@ -1342,6 +1474,9 @@ class FullProtosEqualityTest(unittest.TestCase): |
test_util.SetAllFields(self.first_proto) |
test_util.SetAllFields(self.second_proto) |
+ def testNotHashable(self): |
+ self.assertRaises(TypeError, hash, self.first_proto) |
+ |
def testNoneNotEqual(self): |
self.assertNotEqual(self.first_proto, None) |
self.assertNotEqual(None, self.second_proto) |
@@ -1410,9 +1545,6 @@ class FullProtosEqualityTest(unittest.TestCase): |
self.first_proto.ClearField('optional_nested_message') |
self.second_proto.optional_nested_message.ClearField('bb') |
self.assertNotEqual(self.first_proto, self.second_proto) |
- # TODO(robinson): Replace next two lines with method |
- # to set the "has" bit without changing the value, |
- # if/when such a method exists. |
self.first_proto.optional_nested_message.bb = 0 |
self.first_proto.optional_nested_message.ClearField('bb') |
self.assertEqual(self.first_proto, self.second_proto) |
@@ -1477,6 +1609,14 @@ class ByteSizeTest(unittest.TestCase): |
def testEmptyMessage(self): |
self.assertEqual(0, self.proto.ByteSize()) |
+ def testSizedOnKwargs(self): |
+ # Use a separate message to ensure testing right after creation. |
+ proto = unittest_pb2.TestAllTypes() |
+ self.assertEqual(0, proto.ByteSize()) |
+ proto_kwargs = unittest_pb2.TestAllTypes(optional_int64 = 1) |
+ # One byte for the tag, one to encode varint 1. |
+ self.assertEqual(2, proto_kwargs.ByteSize()) |
+ |
def testVarints(self): |
def Test(i, expected_varint_size): |
self.proto.Clear() |
@@ -1668,10 +1808,13 @@ class ByteSizeTest(unittest.TestCase): |
self.assertEqual(3, self.proto.ByteSize()) |
self.proto.ClearField('optional_foreign_message') |
self.assertEqual(0, self.proto.ByteSize()) |
- child = self.proto.optional_foreign_message |
- self.proto.ClearField('optional_foreign_message') |
- child.c = 128 |
- self.assertEqual(0, self.proto.ByteSize()) |
+ |
+ if api_implementation.Type() == 'python': |
+ # This is only possible in pure-Python implementation of the API. |
+ child = self.proto.optional_foreign_message |
+ self.proto.ClearField('optional_foreign_message') |
+ child.c = 128 |
+ self.assertEqual(0, self.proto.ByteSize()) |
# Test within extension. |
extension = more_extensions_pb2.optional_message_extension |
@@ -1737,7 +1880,6 @@ class ByteSizeTest(unittest.TestCase): |
self.assertEqual(19, self.packed_extended_proto.ByteSize()) |
-# TODO(robinson): We need cross-language serialization consistency tests. |
# Issues to be sure to cover include: |
# * Handling of unrecognized tags ("uninterpreted_bytes"). |
# * Handling of MessageSets. |
@@ -1792,6 +1934,10 @@ class SerializationTest(unittest.TestCase): |
self.assertEqual(first_proto, second_proto) |
def testParseTruncated(self): |
+ # This test is only applicable for the Python implementation of the API. |
+ if api_implementation.Type() != 'python': |
+ return |
+ |
first_proto = unittest_pb2.TestAllTypes() |
test_util.SetAllFields(first_proto) |
serialized = first_proto.SerializeToString() |