Home | History | Annotate | Download | only in internal
      1 #! /usr/bin/env python
      2 #
      3 # Protocol Buffers - Google's data interchange format
      4 # Copyright 2008 Google Inc.  All rights reserved.
      5 # https://developers.google.com/protocol-buffers/
      6 #
      7 # Redistribution and use in source and binary forms, with or without
      8 # modification, are permitted provided that the following conditions are
      9 # met:
     10 #
     11 #     * Redistributions of source code must retain the above copyright
     12 # notice, this list of conditions and the following disclaimer.
     13 #     * Redistributions in binary form must reproduce the above
     14 # copyright notice, this list of conditions and the following disclaimer
     15 # in the documentation and/or other materials provided with the
     16 # distribution.
     17 #     * Neither the name of Google Inc. nor the names of its
     18 # contributors may be used to endorse or promote products derived from
     19 # this software without specific prior written permission.
     20 #
     21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32 
     33 """Test for google.protobuf.internal.well_known_types."""
     34 
     35 __author__ = 'jieluo (at] google.com (Jie Luo)'
     36 
     37 from datetime import datetime
     38 
     39 try:
     40   import unittest2 as unittest  #PY26
     41 except ImportError:
     42   import unittest
     43 
     44 from google.protobuf import any_pb2
     45 from google.protobuf import duration_pb2
     46 from google.protobuf import field_mask_pb2
     47 from google.protobuf import struct_pb2
     48 from google.protobuf import timestamp_pb2
     49 from google.protobuf import unittest_pb2
     50 from google.protobuf.internal import any_test_pb2
     51 from google.protobuf.internal import test_util
     52 from google.protobuf.internal import well_known_types
     53 from google.protobuf import descriptor
     54 from google.protobuf import text_format
     55 
     56 
     57 class TimeUtilTestBase(unittest.TestCase):
     58 
     59   def CheckTimestampConversion(self, message, text):
     60     self.assertEqual(text, message.ToJsonString())
     61     parsed_message = timestamp_pb2.Timestamp()
     62     parsed_message.FromJsonString(text)
     63     self.assertEqual(message, parsed_message)
     64 
     65   def CheckDurationConversion(self, message, text):
     66     self.assertEqual(text, message.ToJsonString())
     67     parsed_message = duration_pb2.Duration()
     68     parsed_message.FromJsonString(text)
     69     self.assertEqual(message, parsed_message)
     70 
     71 
     72 class TimeUtilTest(TimeUtilTestBase):
     73 
     74   def testTimestampSerializeAndParse(self):
     75     message = timestamp_pb2.Timestamp()
     76     # Generated output should contain 3, 6, or 9 fractional digits.
     77     message.seconds = 0
     78     message.nanos = 0
     79     self.CheckTimestampConversion(message, '1970-01-01T00:00:00Z')
     80     message.nanos = 10000000
     81     self.CheckTimestampConversion(message, '1970-01-01T00:00:00.010Z')
     82     message.nanos = 10000
     83     self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000010Z')
     84     message.nanos = 10
     85     self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000000010Z')
     86     # Test min timestamps.
     87     message.seconds = -62135596800
     88     message.nanos = 0
     89     self.CheckTimestampConversion(message, '0001-01-01T00:00:00Z')
     90     # Test max timestamps.
     91     message.seconds = 253402300799
     92     message.nanos = 999999999
     93     self.CheckTimestampConversion(message, '9999-12-31T23:59:59.999999999Z')
     94     # Test negative timestamps.
     95     message.seconds = -1
     96     self.CheckTimestampConversion(message, '1969-12-31T23:59:59.999999999Z')
     97 
     98     # Parsing accepts an fractional digits as long as they fit into nano
     99     # precision.
    100     message.FromJsonString('1970-01-01T00:00:00.1Z')
    101     self.assertEqual(0, message.seconds)
    102     self.assertEqual(100000000, message.nanos)
    103     # Parsing accpets offsets.
    104     message.FromJsonString('1970-01-01T00:00:00-08:00')
    105     self.assertEqual(8 * 3600, message.seconds)
    106     self.assertEqual(0, message.nanos)
    107 
    108   def testDurationSerializeAndParse(self):
    109     message = duration_pb2.Duration()
    110     # Generated output should contain 3, 6, or 9 fractional digits.
    111     message.seconds = 0
    112     message.nanos = 0
    113     self.CheckDurationConversion(message, '0s')
    114     message.nanos = 10000000
    115     self.CheckDurationConversion(message, '0.010s')
    116     message.nanos = 10000
    117     self.CheckDurationConversion(message, '0.000010s')
    118     message.nanos = 10
    119     self.CheckDurationConversion(message, '0.000000010s')
    120 
    121     # Test min and max
    122     message.seconds = 315576000000
    123     message.nanos = 999999999
    124     self.CheckDurationConversion(message, '315576000000.999999999s')
    125     message.seconds = -315576000000
    126     message.nanos = -999999999
    127     self.CheckDurationConversion(message, '-315576000000.999999999s')
    128 
    129     # Parsing accepts an fractional digits as long as they fit into nano
    130     # precision.
    131     message.FromJsonString('0.1s')
    132     self.assertEqual(100000000, message.nanos)
    133     message.FromJsonString('0.0000001s')
    134     self.assertEqual(100, message.nanos)
    135 
    136   def testTimestampIntegerConversion(self):
    137     message = timestamp_pb2.Timestamp()
    138     message.FromNanoseconds(1)
    139     self.assertEqual('1970-01-01T00:00:00.000000001Z',
    140                      message.ToJsonString())
    141     self.assertEqual(1, message.ToNanoseconds())
    142 
    143     message.FromNanoseconds(-1)
    144     self.assertEqual('1969-12-31T23:59:59.999999999Z',
    145                      message.ToJsonString())
    146     self.assertEqual(-1, message.ToNanoseconds())
    147 
    148     message.FromMicroseconds(1)
    149     self.assertEqual('1970-01-01T00:00:00.000001Z',
    150                      message.ToJsonString())
    151     self.assertEqual(1, message.ToMicroseconds())
    152 
    153     message.FromMicroseconds(-1)
    154     self.assertEqual('1969-12-31T23:59:59.999999Z',
    155                      message.ToJsonString())
    156     self.assertEqual(-1, message.ToMicroseconds())
    157 
    158     message.FromMilliseconds(1)
    159     self.assertEqual('1970-01-01T00:00:00.001Z',
    160                      message.ToJsonString())
    161     self.assertEqual(1, message.ToMilliseconds())
    162 
    163     message.FromMilliseconds(-1)
    164     self.assertEqual('1969-12-31T23:59:59.999Z',
    165                      message.ToJsonString())
    166     self.assertEqual(-1, message.ToMilliseconds())
    167 
    168     message.FromSeconds(1)
    169     self.assertEqual('1970-01-01T00:00:01Z',
    170                      message.ToJsonString())
    171     self.assertEqual(1, message.ToSeconds())
    172 
    173     message.FromSeconds(-1)
    174     self.assertEqual('1969-12-31T23:59:59Z',
    175                      message.ToJsonString())
    176     self.assertEqual(-1, message.ToSeconds())
    177 
    178     message.FromNanoseconds(1999)
    179     self.assertEqual(1, message.ToMicroseconds())
    180     # For negative values, Timestamp will be rounded down.
    181     # For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds
    182     # will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than
    183     # "1970-01-01T00:00:00Z" (i.e., 0s).
    184     message.FromNanoseconds(-1999)
    185     self.assertEqual(-2, message.ToMicroseconds())
    186 
    187   def testDurationIntegerConversion(self):
    188     message = duration_pb2.Duration()
    189     message.FromNanoseconds(1)
    190     self.assertEqual('0.000000001s',
    191                      message.ToJsonString())
    192     self.assertEqual(1, message.ToNanoseconds())
    193 
    194     message.FromNanoseconds(-1)
    195     self.assertEqual('-0.000000001s',
    196                      message.ToJsonString())
    197     self.assertEqual(-1, message.ToNanoseconds())
    198 
    199     message.FromMicroseconds(1)
    200     self.assertEqual('0.000001s',
    201                      message.ToJsonString())
    202     self.assertEqual(1, message.ToMicroseconds())
    203 
    204     message.FromMicroseconds(-1)
    205     self.assertEqual('-0.000001s',
    206                      message.ToJsonString())
    207     self.assertEqual(-1, message.ToMicroseconds())
    208 
    209     message.FromMilliseconds(1)
    210     self.assertEqual('0.001s',
    211                      message.ToJsonString())
    212     self.assertEqual(1, message.ToMilliseconds())
    213 
    214     message.FromMilliseconds(-1)
    215     self.assertEqual('-0.001s',
    216                      message.ToJsonString())
    217     self.assertEqual(-1, message.ToMilliseconds())
    218 
    219     message.FromSeconds(1)
    220     self.assertEqual('1s', message.ToJsonString())
    221     self.assertEqual(1, message.ToSeconds())
    222 
    223     message.FromSeconds(-1)
    224     self.assertEqual('-1s',
    225                      message.ToJsonString())
    226     self.assertEqual(-1, message.ToSeconds())
    227 
    228     # Test truncation behavior.
    229     message.FromNanoseconds(1999)
    230     self.assertEqual(1, message.ToMicroseconds())
    231 
    232     # For negative values, Duration will be rounded towards 0.
    233     message.FromNanoseconds(-1999)
    234     self.assertEqual(-1, message.ToMicroseconds())
    235 
    236   def testDatetimeConverison(self):
    237     message = timestamp_pb2.Timestamp()
    238     dt = datetime(1970, 1, 1)
    239     message.FromDatetime(dt)
    240     self.assertEqual(dt, message.ToDatetime())
    241 
    242     message.FromMilliseconds(1999)
    243     self.assertEqual(datetime(1970, 1, 1, 0, 0, 1, 999000),
    244                      message.ToDatetime())
    245 
    246   def testTimedeltaConversion(self):
    247     message = duration_pb2.Duration()
    248     message.FromNanoseconds(1999999999)
    249     td = message.ToTimedelta()
    250     self.assertEqual(1, td.seconds)
    251     self.assertEqual(999999, td.microseconds)
    252 
    253     message.FromNanoseconds(-1999999999)
    254     td = message.ToTimedelta()
    255     self.assertEqual(-1, td.days)
    256     self.assertEqual(86398, td.seconds)
    257     self.assertEqual(1, td.microseconds)
    258 
    259     message.FromMicroseconds(-1)
    260     td = message.ToTimedelta()
    261     self.assertEqual(-1, td.days)
    262     self.assertEqual(86399, td.seconds)
    263     self.assertEqual(999999, td.microseconds)
    264     converted_message = duration_pb2.Duration()
    265     converted_message.FromTimedelta(td)
    266     self.assertEqual(message, converted_message)
    267 
    268   def testInvalidTimestamp(self):
    269     message = timestamp_pb2.Timestamp()
    270     self.assertRaisesRegexp(
    271         ValueError,
    272         'time data \'10000-01-01T00:00:00\' does not match'
    273         ' format \'%Y-%m-%dT%H:%M:%S\'',
    274         message.FromJsonString, '10000-01-01T00:00:00.00Z')
    275     self.assertRaisesRegexp(
    276         well_known_types.ParseError,
    277         'nanos 0123456789012 more than 9 fractional digits.',
    278         message.FromJsonString,
    279         '1970-01-01T00:00:00.0123456789012Z')
    280     self.assertRaisesRegexp(
    281         well_known_types.ParseError,
    282         (r'Invalid timezone offset value: \+08.'),
    283         message.FromJsonString,
    284         '1972-01-01T01:00:00.01+08',)
    285     self.assertRaisesRegexp(
    286         ValueError,
    287         'year is out of range',
    288         message.FromJsonString,
    289         '0000-01-01T00:00:00Z')
    290     message.seconds = 253402300800
    291     self.assertRaisesRegexp(
    292         OverflowError,
    293         'date value out of range',
    294         message.ToJsonString)
    295 
    296   def testInvalidDuration(self):
    297     message = duration_pb2.Duration()
    298     self.assertRaisesRegexp(
    299         well_known_types.ParseError,
    300         'Duration must end with letter "s": 1.',
    301         message.FromJsonString, '1')
    302     self.assertRaisesRegexp(
    303         well_known_types.ParseError,
    304         'Couldn\'t parse duration: 1...2s.',
    305         message.FromJsonString, '1...2s')
    306 
    307 
    308 class FieldMaskTest(unittest.TestCase):
    309 
    310   def testStringFormat(self):
    311     mask = field_mask_pb2.FieldMask()
    312     self.assertEqual('', mask.ToJsonString())
    313     mask.paths.append('foo')
    314     self.assertEqual('foo', mask.ToJsonString())
    315     mask.paths.append('bar')
    316     self.assertEqual('foo,bar', mask.ToJsonString())
    317 
    318     mask.FromJsonString('')
    319     self.assertEqual('', mask.ToJsonString())
    320     mask.FromJsonString('foo')
    321     self.assertEqual(['foo'], mask.paths)
    322     mask.FromJsonString('foo,bar')
    323     self.assertEqual(['foo', 'bar'], mask.paths)
    324 
    325   def testDescriptorToFieldMask(self):
    326     mask = field_mask_pb2.FieldMask()
    327     msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
    328     mask.AllFieldsFromDescriptor(msg_descriptor)
    329     self.assertEqual(75, len(mask.paths))
    330     self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
    331     for field in msg_descriptor.fields:
    332       self.assertTrue(field.name in mask.paths)
    333     mask.paths.append('optional_nested_message.bb')
    334     self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
    335     mask.paths.append('repeated_nested_message.bb')
    336     self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
    337 
    338   def testCanonicalFrom(self):
    339     mask = field_mask_pb2.FieldMask()
    340     out_mask = field_mask_pb2.FieldMask()
    341     # Paths will be sorted.
    342     mask.FromJsonString('baz.quz,bar,foo')
    343     out_mask.CanonicalFormFromMask(mask)
    344     self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString())
    345     # Duplicated paths will be removed.
    346     mask.FromJsonString('foo,bar,foo')
    347     out_mask.CanonicalFormFromMask(mask)
    348     self.assertEqual('bar,foo', out_mask.ToJsonString())
    349     # Sub-paths of other paths will be removed.
    350     mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar')
    351     out_mask.CanonicalFormFromMask(mask)
    352     self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString())
    353 
    354     # Test more deeply nested cases.
    355     mask.FromJsonString(
    356         'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2')
    357     out_mask.CanonicalFormFromMask(mask)
    358     self.assertEqual('foo.bar.baz1,foo.bar.baz2',
    359                      out_mask.ToJsonString())
    360     mask.FromJsonString(
    361         'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz')
    362     out_mask.CanonicalFormFromMask(mask)
    363     self.assertEqual('foo.bar.baz1,foo.bar.baz2',
    364                      out_mask.ToJsonString())
    365     mask.FromJsonString(
    366         'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar')
    367     out_mask.CanonicalFormFromMask(mask)
    368     self.assertEqual('foo.bar', out_mask.ToJsonString())
    369     mask.FromJsonString(
    370         'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo')
    371     out_mask.CanonicalFormFromMask(mask)
    372     self.assertEqual('foo', out_mask.ToJsonString())
    373 
    374   def testUnion(self):
    375     mask1 = field_mask_pb2.FieldMask()
    376     mask2 = field_mask_pb2.FieldMask()
    377     out_mask = field_mask_pb2.FieldMask()
    378     mask1.FromJsonString('foo,baz')
    379     mask2.FromJsonString('bar,quz')
    380     out_mask.Union(mask1, mask2)
    381     self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString())
    382     # Overlap with duplicated paths.
    383     mask1.FromJsonString('foo,baz.bb')
    384     mask2.FromJsonString('baz.bb,quz')
    385     out_mask.Union(mask1, mask2)
    386     self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString())
    387     # Overlap with paths covering some other paths.
    388     mask1.FromJsonString('foo.bar.baz,quz')
    389     mask2.FromJsonString('foo.bar,bar')
    390     out_mask.Union(mask1, mask2)
    391     self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString())
    392 
    393   def testIntersect(self):
    394     mask1 = field_mask_pb2.FieldMask()
    395     mask2 = field_mask_pb2.FieldMask()
    396     out_mask = field_mask_pb2.FieldMask()
    397     # Test cases without overlapping.
    398     mask1.FromJsonString('foo,baz')
    399     mask2.FromJsonString('bar,quz')
    400     out_mask.Intersect(mask1, mask2)
    401     self.assertEqual('', out_mask.ToJsonString())
    402     # Overlap with duplicated paths.
    403     mask1.FromJsonString('foo,baz.bb')
    404     mask2.FromJsonString('baz.bb,quz')
    405     out_mask.Intersect(mask1, mask2)
    406     self.assertEqual('baz.bb', out_mask.ToJsonString())
    407     # Overlap with paths covering some other paths.
    408     mask1.FromJsonString('foo.bar.baz,quz')
    409     mask2.FromJsonString('foo.bar,bar')
    410     out_mask.Intersect(mask1, mask2)
    411     self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
    412     mask1.FromJsonString('foo.bar,bar')
    413     mask2.FromJsonString('foo.bar.baz,quz')
    414     out_mask.Intersect(mask1, mask2)
    415     self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
    416 
    417   def testMergeMessage(self):
    418     # Test merge one field.
    419     src = unittest_pb2.TestAllTypes()
    420     test_util.SetAllFields(src)
    421     for field in src.DESCRIPTOR.fields:
    422       if field.containing_oneof:
    423         continue
    424       field_name = field.name
    425       dst = unittest_pb2.TestAllTypes()
    426       # Only set one path to mask.
    427       mask = field_mask_pb2.FieldMask()
    428       mask.paths.append(field_name)
    429       mask.MergeMessage(src, dst)
    430       # The expected result message.
    431       msg = unittest_pb2.TestAllTypes()
    432       if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
    433         repeated_src = getattr(src, field_name)
    434         repeated_msg = getattr(msg, field_name)
    435         if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
    436           for item in repeated_src:
    437             repeated_msg.add().CopyFrom(item)
    438         else:
    439           repeated_msg.extend(repeated_src)
    440       elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
    441         getattr(msg, field_name).CopyFrom(getattr(src, field_name))
    442       else:
    443         setattr(msg, field_name, getattr(src, field_name))
    444       # Only field specified in mask is merged.
    445       self.assertEqual(msg, dst)
    446 
    447     # Test merge nested fields.
    448     nested_src = unittest_pb2.NestedTestAllTypes()
    449     nested_dst = unittest_pb2.NestedTestAllTypes()
    450     nested_src.child.payload.optional_int32 = 1234
    451     nested_src.child.child.payload.optional_int32 = 5678
    452     mask = field_mask_pb2.FieldMask()
    453     mask.FromJsonString('child.payload')
    454     mask.MergeMessage(nested_src, nested_dst)
    455     self.assertEqual(1234, nested_dst.child.payload.optional_int32)
    456     self.assertEqual(0, nested_dst.child.child.payload.optional_int32)
    457 
    458     mask.FromJsonString('child.child.payload')
    459     mask.MergeMessage(nested_src, nested_dst)
    460     self.assertEqual(1234, nested_dst.child.payload.optional_int32)
    461     self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
    462 
    463     nested_dst.Clear()
    464     mask.FromJsonString('child.child.payload')
    465     mask.MergeMessage(nested_src, nested_dst)
    466     self.assertEqual(0, nested_dst.child.payload.optional_int32)
    467     self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
    468 
    469     nested_dst.Clear()
    470     mask.FromJsonString('child')
    471     mask.MergeMessage(nested_src, nested_dst)
    472     self.assertEqual(1234, nested_dst.child.payload.optional_int32)
    473     self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
    474 
    475     # Test MergeOptions.
    476     nested_dst.Clear()
    477     nested_dst.child.payload.optional_int64 = 4321
    478     # Message fields will be merged by default.
    479     mask.FromJsonString('child.payload')
    480     mask.MergeMessage(nested_src, nested_dst)
    481     self.assertEqual(1234, nested_dst.child.payload.optional_int32)
    482     self.assertEqual(4321, nested_dst.child.payload.optional_int64)
    483     # Change the behavior to replace message fields.
    484     mask.FromJsonString('child.payload')
    485     mask.MergeMessage(nested_src, nested_dst, True, False)
    486     self.assertEqual(1234, nested_dst.child.payload.optional_int32)
    487     self.assertEqual(0, nested_dst.child.payload.optional_int64)
    488 
    489     # By default, fields missing in source are not cleared in destination.
    490     nested_dst.payload.optional_int32 = 1234
    491     self.assertTrue(nested_dst.HasField('payload'))
    492     mask.FromJsonString('payload')
    493     mask.MergeMessage(nested_src, nested_dst)
    494     self.assertTrue(nested_dst.HasField('payload'))
    495     # But they are cleared when replacing message fields.
    496     nested_dst.Clear()
    497     nested_dst.payload.optional_int32 = 1234
    498     mask.FromJsonString('payload')
    499     mask.MergeMessage(nested_src, nested_dst, True, False)
    500     self.assertFalse(nested_dst.HasField('payload'))
    501 
    502     nested_src.payload.repeated_int32.append(1234)
    503     nested_dst.payload.repeated_int32.append(5678)
    504     # Repeated fields will be appended by default.
    505     mask.FromJsonString('payload.repeated_int32')
    506     mask.MergeMessage(nested_src, nested_dst)
    507     self.assertEqual(2, len(nested_dst.payload.repeated_int32))
    508     self.assertEqual(5678, nested_dst.payload.repeated_int32[0])
    509     self.assertEqual(1234, nested_dst.payload.repeated_int32[1])
    510     # Change the behavior to replace repeated fields.
    511     mask.FromJsonString('payload.repeated_int32')
    512     mask.MergeMessage(nested_src, nested_dst, False, True)
    513     self.assertEqual(1, len(nested_dst.payload.repeated_int32))
    514     self.assertEqual(1234, nested_dst.payload.repeated_int32[0])
    515 
    516 
    517 class StructTest(unittest.TestCase):
    518 
    519   def testStruct(self):
    520     struct = struct_pb2.Struct()
    521     struct_class = struct.__class__
    522 
    523     struct['key1'] = 5
    524     struct['key2'] = 'abc'
    525     struct['key3'] = True
    526     struct.get_or_create_struct('key4')['subkey'] = 11.0
    527     struct_list = struct.get_or_create_list('key5')
    528     struct_list.extend([6, 'seven', True, False, None])
    529     struct_list.add_struct()['subkey2'] = 9
    530 
    531     self.assertTrue(isinstance(struct, well_known_types.Struct))
    532     self.assertEquals(5, struct['key1'])
    533     self.assertEquals('abc', struct['key2'])
    534     self.assertIs(True, struct['key3'])
    535     self.assertEquals(11, struct['key4']['subkey'])
    536     inner_struct = struct_class()
    537     inner_struct['subkey2'] = 9
    538     self.assertEquals([6, 'seven', True, False, None, inner_struct],
    539                       list(struct['key5'].items()))
    540 
    541     serialized = struct.SerializeToString()
    542 
    543     struct2 = struct_pb2.Struct()
    544     struct2.ParseFromString(serialized)
    545 
    546     self.assertEquals(struct, struct2)
    547 
    548     self.assertTrue(isinstance(struct2, well_known_types.Struct))
    549     self.assertEquals(5, struct2['key1'])
    550     self.assertEquals('abc', struct2['key2'])
    551     self.assertIs(True, struct2['key3'])
    552     self.assertEquals(11, struct2['key4']['subkey'])
    553     self.assertEquals([6, 'seven', True, False, None, inner_struct],
    554                       list(struct2['key5'].items()))
    555 
    556     struct_list = struct2['key5']
    557     self.assertEquals(6, struct_list[0])
    558     self.assertEquals('seven', struct_list[1])
    559     self.assertEquals(True, struct_list[2])
    560     self.assertEquals(False, struct_list[3])
    561     self.assertEquals(None, struct_list[4])
    562     self.assertEquals(inner_struct, struct_list[5])
    563 
    564     struct_list[1] = 7
    565     self.assertEquals(7, struct_list[1])
    566 
    567     struct_list.add_list().extend([1, 'two', True, False, None])
    568     self.assertEquals([1, 'two', True, False, None],
    569                       list(struct_list[6].items()))
    570 
    571     text_serialized = str(struct)
    572     struct3 = struct_pb2.Struct()
    573     text_format.Merge(text_serialized, struct3)
    574     self.assertEquals(struct, struct3)
    575 
    576     struct.get_or_create_struct('key3')['replace'] = 12
    577     self.assertEquals(12, struct['key3']['replace'])
    578 
    579 
    580 class AnyTest(unittest.TestCase):
    581 
    582   def testAnyMessage(self):
    583     # Creates and sets message.
    584     msg = any_test_pb2.TestAny()
    585     msg_descriptor = msg.DESCRIPTOR
    586     all_types = unittest_pb2.TestAllTypes()
    587     all_descriptor = all_types.DESCRIPTOR
    588     all_types.repeated_string.append(u'\u00fc\ua71f')
    589     # Packs to Any.
    590     msg.value.Pack(all_types)
    591     self.assertEqual(msg.value.type_url,
    592                      'type.googleapis.com/%s' % all_descriptor.full_name)
    593     self.assertEqual(msg.value.value,
    594                      all_types.SerializeToString())
    595     # Tests Is() method.
    596     self.assertTrue(msg.value.Is(all_descriptor))
    597     self.assertFalse(msg.value.Is(msg_descriptor))
    598     # Unpacks Any.
    599     unpacked_message = unittest_pb2.TestAllTypes()
    600     self.assertTrue(msg.value.Unpack(unpacked_message))
    601     self.assertEqual(all_types, unpacked_message)
    602     # Unpacks to different type.
    603     self.assertFalse(msg.value.Unpack(msg))
    604     # Only Any messages have Pack method.
    605     try:
    606       msg.Pack(all_types)
    607     except AttributeError:
    608       pass
    609     else:
    610       raise AttributeError('%s should not have Pack method.' %
    611                            msg_descriptor.full_name)
    612 
    613   def testMessageName(self):
    614     # Creates and sets message.
    615     submessage = any_test_pb2.TestAny()
    616     submessage.int_value = 12345
    617     msg = any_pb2.Any()
    618     msg.Pack(submessage)
    619     self.assertEqual(msg.TypeName(), 'google.protobuf.internal.TestAny')
    620 
    621   def testPackWithCustomTypeUrl(self):
    622     submessage = any_test_pb2.TestAny()
    623     submessage.int_value = 12345
    624     msg = any_pb2.Any()
    625     # Pack with a custom type URL prefix.
    626     msg.Pack(submessage, 'type.myservice.com')
    627     self.assertEqual(msg.type_url,
    628                      'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
    629     # Pack with a custom type URL prefix ending with '/'.
    630     msg.Pack(submessage, 'type.myservice.com/')
    631     self.assertEqual(msg.type_url,
    632                      'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
    633     # Pack with an empty type URL prefix.
    634     msg.Pack(submessage, '')
    635     self.assertEqual(msg.type_url,
    636                      '/%s' % submessage.DESCRIPTOR.full_name)
    637     # Test unpacking the type.
    638     unpacked_message = any_test_pb2.TestAny()
    639     self.assertTrue(msg.Unpack(unpacked_message))
    640     self.assertEqual(submessage, unpacked_message)
    641 
    642 
    643 if __name__ == '__main__':
    644   unittest.main()
    645