3 # Protocol Buffers - Google's data interchange format
4 # Copyright 2008 Google Inc. All rights reserved.
5 # https://developers.google.com/protocol-buffers/
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
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
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.
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.
33 """Test for google.protobuf.internal.well_known_types."""
35 __author__ = 'jieluo@google.com (Jie Luo)'
41 import collections.abc as collections_abc
43 # Won't work after python 3.8
44 import collections as collections_abc
47 import unittest2 as unittest #PY26
51 from google.protobuf import any_pb2
52 from google.protobuf import duration_pb2
53 from google.protobuf import field_mask_pb2
54 from google.protobuf import struct_pb2
55 from google.protobuf import timestamp_pb2
56 from google.protobuf import map_unittest_pb2
57 from google.protobuf import unittest_pb2
58 from google.protobuf.internal import any_test_pb2
59 from google.protobuf.internal import test_util
60 from google.protobuf.internal import well_known_types
61 from google.protobuf import descriptor
62 from google.protobuf import text_format
65 class TimeUtilTestBase(unittest.TestCase):
67 def CheckTimestampConversion(self, message, text):
68 self.assertEqual(text, message.ToJsonString())
69 parsed_message = timestamp_pb2.Timestamp()
70 parsed_message.FromJsonString(text)
71 self.assertEqual(message, parsed_message)
73 def CheckDurationConversion(self, message, text):
74 self.assertEqual(text, message.ToJsonString())
75 parsed_message = duration_pb2.Duration()
76 parsed_message.FromJsonString(text)
77 self.assertEqual(message, parsed_message)
80 class TimeUtilTest(TimeUtilTestBase):
82 def testTimestampSerializeAndParse(self):
83 message = timestamp_pb2.Timestamp()
84 # Generated output should contain 3, 6, or 9 fractional digits.
87 self.CheckTimestampConversion(message, '1970-01-01T00:00:00Z')
88 message.nanos = 10000000
89 self.CheckTimestampConversion(message, '1970-01-01T00:00:00.010Z')
91 self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000010Z')
93 self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000000010Z')
94 # Test min timestamps.
95 message.seconds = -62135596800
97 self.CheckTimestampConversion(message, '0001-01-01T00:00:00Z')
98 # Test max timestamps.
99 message.seconds = 253402300799
100 message.nanos = 999999999
101 self.CheckTimestampConversion(message, '9999-12-31T23:59:59.999999999Z')
102 # Test negative timestamps.
104 self.CheckTimestampConversion(message, '1969-12-31T23:59:59.999999999Z')
106 # Parsing accepts an fractional digits as long as they fit into nano
108 message.FromJsonString('1970-01-01T00:00:00.1Z')
109 self.assertEqual(0, message.seconds)
110 self.assertEqual(100000000, message.nanos)
111 # Parsing accepts offsets.
112 message.FromJsonString('1970-01-01T00:00:00-08:00')
113 self.assertEqual(8 * 3600, message.seconds)
114 self.assertEqual(0, message.nanos)
116 # It is not easy to check with current time. For test coverage only.
117 message.GetCurrentTime()
118 self.assertNotEqual(8 * 3600, message.seconds)
120 def testDurationSerializeAndParse(self):
121 message = duration_pb2.Duration()
122 # Generated output should contain 3, 6, or 9 fractional digits.
125 self.CheckDurationConversion(message, '0s')
126 message.nanos = 10000000
127 self.CheckDurationConversion(message, '0.010s')
128 message.nanos = 10000
129 self.CheckDurationConversion(message, '0.000010s')
131 self.CheckDurationConversion(message, '0.000000010s')
134 message.seconds = 315576000000
135 message.nanos = 999999999
136 self.CheckDurationConversion(message, '315576000000.999999999s')
137 message.seconds = -315576000000
138 message.nanos = -999999999
139 self.CheckDurationConversion(message, '-315576000000.999999999s')
141 # Parsing accepts an fractional digits as long as they fit into nano
143 message.FromJsonString('0.1s')
144 self.assertEqual(100000000, message.nanos)
145 message.FromJsonString('0.0000001s')
146 self.assertEqual(100, message.nanos)
148 def testTimestampIntegerConversion(self):
149 message = timestamp_pb2.Timestamp()
150 message.FromNanoseconds(1)
151 self.assertEqual('1970-01-01T00:00:00.000000001Z',
152 message.ToJsonString())
153 self.assertEqual(1, message.ToNanoseconds())
155 message.FromNanoseconds(-1)
156 self.assertEqual('1969-12-31T23:59:59.999999999Z',
157 message.ToJsonString())
158 self.assertEqual(-1, message.ToNanoseconds())
160 message.FromMicroseconds(1)
161 self.assertEqual('1970-01-01T00:00:00.000001Z',
162 message.ToJsonString())
163 self.assertEqual(1, message.ToMicroseconds())
165 message.FromMicroseconds(-1)
166 self.assertEqual('1969-12-31T23:59:59.999999Z',
167 message.ToJsonString())
168 self.assertEqual(-1, message.ToMicroseconds())
170 message.FromMilliseconds(1)
171 self.assertEqual('1970-01-01T00:00:00.001Z',
172 message.ToJsonString())
173 self.assertEqual(1, message.ToMilliseconds())
175 message.FromMilliseconds(-1)
176 self.assertEqual('1969-12-31T23:59:59.999Z',
177 message.ToJsonString())
178 self.assertEqual(-1, message.ToMilliseconds())
180 message.FromSeconds(1)
181 self.assertEqual('1970-01-01T00:00:01Z',
182 message.ToJsonString())
183 self.assertEqual(1, message.ToSeconds())
185 message.FromSeconds(-1)
186 self.assertEqual('1969-12-31T23:59:59Z',
187 message.ToJsonString())
188 self.assertEqual(-1, message.ToSeconds())
190 message.FromNanoseconds(1999)
191 self.assertEqual(1, message.ToMicroseconds())
192 # For negative values, Timestamp will be rounded down.
193 # For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds
194 # will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than
195 # "1970-01-01T00:00:00Z" (i.e., 0s).
196 message.FromNanoseconds(-1999)
197 self.assertEqual(-2, message.ToMicroseconds())
199 def testDurationIntegerConversion(self):
200 message = duration_pb2.Duration()
201 message.FromNanoseconds(1)
202 self.assertEqual('0.000000001s',
203 message.ToJsonString())
204 self.assertEqual(1, message.ToNanoseconds())
206 message.FromNanoseconds(-1)
207 self.assertEqual('-0.000000001s',
208 message.ToJsonString())
209 self.assertEqual(-1, message.ToNanoseconds())
211 message.FromMicroseconds(1)
212 self.assertEqual('0.000001s',
213 message.ToJsonString())
214 self.assertEqual(1, message.ToMicroseconds())
216 message.FromMicroseconds(-1)
217 self.assertEqual('-0.000001s',
218 message.ToJsonString())
219 self.assertEqual(-1, message.ToMicroseconds())
221 message.FromMilliseconds(1)
222 self.assertEqual('0.001s',
223 message.ToJsonString())
224 self.assertEqual(1, message.ToMilliseconds())
226 message.FromMilliseconds(-1)
227 self.assertEqual('-0.001s',
228 message.ToJsonString())
229 self.assertEqual(-1, message.ToMilliseconds())
231 message.FromSeconds(1)
232 self.assertEqual('1s', message.ToJsonString())
233 self.assertEqual(1, message.ToSeconds())
235 message.FromSeconds(-1)
236 self.assertEqual('-1s',
237 message.ToJsonString())
238 self.assertEqual(-1, message.ToSeconds())
240 # Test truncation behavior.
241 message.FromNanoseconds(1999)
242 self.assertEqual(1, message.ToMicroseconds())
244 # For negative values, Duration will be rounded towards 0.
245 message.FromNanoseconds(-1999)
246 self.assertEqual(-1, message.ToMicroseconds())
248 def testDatetimeConverison(self):
249 message = timestamp_pb2.Timestamp()
250 dt = datetime.datetime(1970, 1, 1)
251 message.FromDatetime(dt)
252 self.assertEqual(dt, message.ToDatetime())
254 message.FromMilliseconds(1999)
255 self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0, 1, 999000),
256 message.ToDatetime())
258 dt = datetime.datetime(2555, 2, 22, 1, 2, 3, 456789)
259 message.FromDatetime(dt)
260 self.assertEqual(dt, message.ToDatetime())
262 dt = datetime.datetime.max
263 message.FromDatetime(dt)
264 self.assertEqual(dt, message.ToDatetime())
266 def testDatetimeConversionWithTimezone(self):
267 class TZ(datetime.tzinfo):
269 def utcoffset(self, _):
270 return datetime.timedelta(hours=1)
273 return datetime.timedelta(0)
278 message1 = timestamp_pb2.Timestamp()
279 dt = datetime.datetime(1970, 1, 1, 1, tzinfo=TZ())
280 message1.FromDatetime(dt)
281 message2 = timestamp_pb2.Timestamp()
282 dt = datetime.datetime(1970, 1, 1, 0)
283 message2.FromDatetime(dt)
284 self.assertEqual(message1, message2)
286 def testTimedeltaConversion(self):
287 message = duration_pb2.Duration()
288 message.FromNanoseconds(1999999999)
289 td = message.ToTimedelta()
290 self.assertEqual(1, td.seconds)
291 self.assertEqual(999999, td.microseconds)
293 message.FromNanoseconds(-1999999999)
294 td = message.ToTimedelta()
295 self.assertEqual(-1, td.days)
296 self.assertEqual(86398, td.seconds)
297 self.assertEqual(1, td.microseconds)
299 message.FromMicroseconds(-1)
300 td = message.ToTimedelta()
301 self.assertEqual(-1, td.days)
302 self.assertEqual(86399, td.seconds)
303 self.assertEqual(999999, td.microseconds)
304 converted_message = duration_pb2.Duration()
305 converted_message.FromTimedelta(td)
306 self.assertEqual(message, converted_message)
308 def testInvalidTimestamp(self):
309 message = timestamp_pb2.Timestamp()
310 self.assertRaisesRegexp(
312 'Failed to parse timestamp: missing valid timezone offset.',
313 message.FromJsonString,
315 self.assertRaisesRegexp(
317 'Failed to parse timestamp: invalid trailing data '
318 '1970-01-01T00:00:01Ztrail.',
319 message.FromJsonString,
320 '1970-01-01T00:00:01Ztrail')
321 self.assertRaisesRegexp(
323 'time data \'10000-01-01T00:00:00\' does not match'
324 ' format \'%Y-%m-%dT%H:%M:%S\'',
325 message.FromJsonString, '10000-01-01T00:00:00.00Z')
326 self.assertRaisesRegexp(
328 'nanos 0123456789012 more than 9 fractional digits.',
329 message.FromJsonString,
330 '1970-01-01T00:00:00.0123456789012Z')
331 self.assertRaisesRegexp(
333 (r'Invalid timezone offset value: \+08.'),
334 message.FromJsonString,
335 '1972-01-01T01:00:00.01+08',)
336 self.assertRaisesRegexp(
338 'year (0 )?is out of range',
339 message.FromJsonString,
340 '0000-01-01T00:00:00Z')
341 message.seconds = 253402300800
342 self.assertRaisesRegexp(
344 'date value out of range',
345 message.ToJsonString)
347 def testInvalidDuration(self):
348 message = duration_pb2.Duration()
349 self.assertRaisesRegexp(
351 'Duration must end with letter "s": 1.',
352 message.FromJsonString, '1')
353 self.assertRaisesRegexp(
355 'Couldn\'t parse duration: 1...2s.',
356 message.FromJsonString, '1...2s')
357 text = '-315576000001.000000000s'
358 self.assertRaisesRegexp(
360 r'Duration is not valid\: Seconds -315576000001 must be in range'
361 r' \[-315576000000\, 315576000000\].',
362 message.FromJsonString, text)
363 text = '315576000001.000000000s'
364 self.assertRaisesRegexp(
366 r'Duration is not valid\: Seconds 315576000001 must be in range'
367 r' \[-315576000000\, 315576000000\].',
368 message.FromJsonString, text)
369 message.seconds = -315576000001
371 self.assertRaisesRegexp(
373 r'Duration is not valid\: Seconds -315576000001 must be in range'
374 r' \[-315576000000\, 315576000000\].',
375 message.ToJsonString)
377 message.nanos = 999999999 + 1
378 self.assertRaisesRegexp(
380 r'Duration is not valid\: Nanos 1000000000 must be in range'
381 r' \[-999999999\, 999999999\].',
382 message.ToJsonString)
385 self.assertRaisesRegexp(
387 r'Duration is not valid\: Sign mismatch.',
388 message.ToJsonString)
391 class FieldMaskTest(unittest.TestCase):
393 def testStringFormat(self):
394 mask = field_mask_pb2.FieldMask()
395 self.assertEqual('', mask.ToJsonString())
396 mask.paths.append('foo')
397 self.assertEqual('foo', mask.ToJsonString())
398 mask.paths.append('bar')
399 self.assertEqual('foo,bar', mask.ToJsonString())
401 mask.FromJsonString('')
402 self.assertEqual('', mask.ToJsonString())
403 mask.FromJsonString('foo')
404 self.assertEqual(['foo'], mask.paths)
405 mask.FromJsonString('foo,bar')
406 self.assertEqual(['foo', 'bar'], mask.paths)
410 mask.paths.append('foo_bar')
411 self.assertEqual('fooBar', mask.ToJsonString())
412 mask.paths.append('bar_quz')
413 self.assertEqual('fooBar,barQuz', mask.ToJsonString())
415 mask.FromJsonString('')
416 self.assertEqual('', mask.ToJsonString())
417 self.assertEqual([], mask.paths)
418 mask.FromJsonString('fooBar')
419 self.assertEqual(['foo_bar'], mask.paths)
420 mask.FromJsonString('fooBar,barQuz')
421 self.assertEqual(['foo_bar', 'bar_quz'], mask.paths)
423 def testDescriptorToFieldMask(self):
424 mask = field_mask_pb2.FieldMask()
425 msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
426 mask.AllFieldsFromDescriptor(msg_descriptor)
427 self.assertEqual(75, len(mask.paths))
428 self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
429 for field in msg_descriptor.fields:
430 self.assertTrue(field.name in mask.paths)
432 def testIsValidForDescriptor(self):
433 msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
435 mask = field_mask_pb2.FieldMask()
436 self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
437 # All fields from descriptor
438 mask.AllFieldsFromDescriptor(msg_descriptor)
439 self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
440 # Child under optional message
441 mask.paths.append('optional_nested_message.bb')
442 self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
443 # Repeated field is only allowed in the last position of path
444 mask.paths.append('repeated_nested_message.bb')
445 self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
446 # Invalid top level field
447 mask = field_mask_pb2.FieldMask()
448 mask.paths.append('xxx')
449 self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
450 # Invalid field in root
451 mask = field_mask_pb2.FieldMask()
452 mask.paths.append('xxx.zzz')
453 self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
454 # Invalid field in internal node
455 mask = field_mask_pb2.FieldMask()
456 mask.paths.append('optional_nested_message.xxx.zzz')
457 self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
458 # Invalid field in leaf
459 mask = field_mask_pb2.FieldMask()
460 mask.paths.append('optional_nested_message.xxx')
461 self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
463 def testCanonicalFrom(self):
464 mask = field_mask_pb2.FieldMask()
465 out_mask = field_mask_pb2.FieldMask()
466 # Paths will be sorted.
467 mask.FromJsonString('baz.quz,bar,foo')
468 out_mask.CanonicalFormFromMask(mask)
469 self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString())
470 # Duplicated paths will be removed.
471 mask.FromJsonString('foo,bar,foo')
472 out_mask.CanonicalFormFromMask(mask)
473 self.assertEqual('bar,foo', out_mask.ToJsonString())
474 # Sub-paths of other paths will be removed.
475 mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar')
476 out_mask.CanonicalFormFromMask(mask)
477 self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString())
479 # Test more deeply nested cases.
481 'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2')
482 out_mask.CanonicalFormFromMask(mask)
483 self.assertEqual('foo.bar.baz1,foo.bar.baz2',
484 out_mask.ToJsonString())
486 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz')
487 out_mask.CanonicalFormFromMask(mask)
488 self.assertEqual('foo.bar.baz1,foo.bar.baz2',
489 out_mask.ToJsonString())
491 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar')
492 out_mask.CanonicalFormFromMask(mask)
493 self.assertEqual('foo.bar', out_mask.ToJsonString())
495 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo')
496 out_mask.CanonicalFormFromMask(mask)
497 self.assertEqual('foo', out_mask.ToJsonString())
500 mask1 = field_mask_pb2.FieldMask()
501 mask2 = field_mask_pb2.FieldMask()
502 out_mask = field_mask_pb2.FieldMask()
503 mask1.FromJsonString('foo,baz')
504 mask2.FromJsonString('bar,quz')
505 out_mask.Union(mask1, mask2)
506 self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString())
507 # Overlap with duplicated paths.
508 mask1.FromJsonString('foo,baz.bb')
509 mask2.FromJsonString('baz.bb,quz')
510 out_mask.Union(mask1, mask2)
511 self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString())
512 # Overlap with paths covering some other paths.
513 mask1.FromJsonString('foo.bar.baz,quz')
514 mask2.FromJsonString('foo.bar,bar')
515 out_mask.Union(mask1, mask2)
516 self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString())
517 src = unittest_pb2.TestAllTypes()
518 with self.assertRaises(ValueError):
519 out_mask.Union(src, mask2)
521 def testIntersect(self):
522 mask1 = field_mask_pb2.FieldMask()
523 mask2 = field_mask_pb2.FieldMask()
524 out_mask = field_mask_pb2.FieldMask()
525 # Test cases without overlapping.
526 mask1.FromJsonString('foo,baz')
527 mask2.FromJsonString('bar,quz')
528 out_mask.Intersect(mask1, mask2)
529 self.assertEqual('', out_mask.ToJsonString())
530 self.assertEqual(len(out_mask.paths), 0)
531 self.assertEqual(out_mask.paths, [])
532 # Overlap with duplicated paths.
533 mask1.FromJsonString('foo,baz.bb')
534 mask2.FromJsonString('baz.bb,quz')
535 out_mask.Intersect(mask1, mask2)
536 self.assertEqual('baz.bb', out_mask.ToJsonString())
537 # Overlap with paths covering some other paths.
538 mask1.FromJsonString('foo.bar.baz,quz')
539 mask2.FromJsonString('foo.bar,bar')
540 out_mask.Intersect(mask1, mask2)
541 self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
542 mask1.FromJsonString('foo.bar,bar')
543 mask2.FromJsonString('foo.bar.baz,quz')
544 out_mask.Intersect(mask1, mask2)
545 self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
546 # Intersect '' with ''
549 mask1.paths.append('')
550 mask2.paths.append('')
551 self.assertEqual(mask1.paths, [''])
552 self.assertEqual('', mask1.ToJsonString())
553 out_mask.Intersect(mask1, mask2)
554 self.assertEqual(out_mask.paths, [])
556 def testMergeMessageWithoutMapFields(self):
557 # Test merge one field.
558 src = unittest_pb2.TestAllTypes()
559 test_util.SetAllFields(src)
560 for field in src.DESCRIPTOR.fields:
561 if field.containing_oneof:
563 field_name = field.name
564 dst = unittest_pb2.TestAllTypes()
565 # Only set one path to mask.
566 mask = field_mask_pb2.FieldMask()
567 mask.paths.append(field_name)
568 mask.MergeMessage(src, dst)
569 # The expected result message.
570 msg = unittest_pb2.TestAllTypes()
571 if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
572 repeated_src = getattr(src, field_name)
573 repeated_msg = getattr(msg, field_name)
574 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
575 for item in repeated_src:
576 repeated_msg.add().CopyFrom(item)
578 repeated_msg.extend(repeated_src)
579 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
580 getattr(msg, field_name).CopyFrom(getattr(src, field_name))
582 setattr(msg, field_name, getattr(src, field_name))
583 # Only field specified in mask is merged.
584 self.assertEqual(msg, dst)
586 # Test merge nested fields.
587 nested_src = unittest_pb2.NestedTestAllTypes()
588 nested_dst = unittest_pb2.NestedTestAllTypes()
589 nested_src.child.payload.optional_int32 = 1234
590 nested_src.child.child.payload.optional_int32 = 5678
591 mask = field_mask_pb2.FieldMask()
592 mask.FromJsonString('child.payload')
593 mask.MergeMessage(nested_src, nested_dst)
594 self.assertEqual(1234, nested_dst.child.payload.optional_int32)
595 self.assertEqual(0, nested_dst.child.child.payload.optional_int32)
597 mask.FromJsonString('child.child.payload')
598 mask.MergeMessage(nested_src, nested_dst)
599 self.assertEqual(1234, nested_dst.child.payload.optional_int32)
600 self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
603 mask.FromJsonString('child.child.payload')
604 mask.MergeMessage(nested_src, nested_dst)
605 self.assertEqual(0, nested_dst.child.payload.optional_int32)
606 self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
609 mask.FromJsonString('child')
610 mask.MergeMessage(nested_src, nested_dst)
611 self.assertEqual(1234, nested_dst.child.payload.optional_int32)
612 self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
616 nested_dst.child.payload.optional_int64 = 4321
617 # Message fields will be merged by default.
618 mask.FromJsonString('child.payload')
619 mask.MergeMessage(nested_src, nested_dst)
620 self.assertEqual(1234, nested_dst.child.payload.optional_int32)
621 self.assertEqual(4321, nested_dst.child.payload.optional_int64)
622 # Change the behavior to replace message fields.
623 mask.FromJsonString('child.payload')
624 mask.MergeMessage(nested_src, nested_dst, True, False)
625 self.assertEqual(1234, nested_dst.child.payload.optional_int32)
626 self.assertEqual(0, nested_dst.child.payload.optional_int64)
628 # By default, fields missing in source are not cleared in destination.
629 nested_dst.payload.optional_int32 = 1234
630 self.assertTrue(nested_dst.HasField('payload'))
631 mask.FromJsonString('payload')
632 mask.MergeMessage(nested_src, nested_dst)
633 self.assertTrue(nested_dst.HasField('payload'))
634 # But they are cleared when replacing message fields.
636 nested_dst.payload.optional_int32 = 1234
637 mask.FromJsonString('payload')
638 mask.MergeMessage(nested_src, nested_dst, True, False)
639 self.assertFalse(nested_dst.HasField('payload'))
641 nested_src.payload.repeated_int32.append(1234)
642 nested_dst.payload.repeated_int32.append(5678)
643 # Repeated fields will be appended by default.
644 mask.FromJsonString('payload.repeatedInt32')
645 mask.MergeMessage(nested_src, nested_dst)
646 self.assertEqual(2, len(nested_dst.payload.repeated_int32))
647 self.assertEqual(5678, nested_dst.payload.repeated_int32[0])
648 self.assertEqual(1234, nested_dst.payload.repeated_int32[1])
649 # Change the behavior to replace repeated fields.
650 mask.FromJsonString('payload.repeatedInt32')
651 mask.MergeMessage(nested_src, nested_dst, False, True)
652 self.assertEqual(1, len(nested_dst.payload.repeated_int32))
653 self.assertEqual(1234, nested_dst.payload.repeated_int32[0])
655 # Test Merge oneof field.
656 new_msg = unittest_pb2.TestOneof2()
657 dst = unittest_pb2.TestOneof2()
658 dst.foo_message.qux_int = 1
659 mask = field_mask_pb2.FieldMask()
660 mask.FromJsonString('fooMessage,fooLazyMessage.quxInt')
661 mask.MergeMessage(new_msg, dst)
662 self.assertTrue(dst.HasField('foo_message'))
663 self.assertFalse(dst.HasField('foo_lazy_message'))
665 def testMergeMessageWithMapField(self):
666 empty_map = map_unittest_pb2.TestRecursiveMapMessage()
667 src_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
668 src_level_2.a['src level 2'].CopyFrom(empty_map)
669 src = map_unittest_pb2.TestRecursiveMapMessage()
670 src.a['common key'].CopyFrom(src_level_2)
671 src.a['src level 1'].CopyFrom(src_level_2)
673 dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
674 dst_level_2.a['dst level 2'].CopyFrom(empty_map)
675 dst = map_unittest_pb2.TestRecursiveMapMessage()
676 dst.a['common key'].CopyFrom(dst_level_2)
677 dst.a['dst level 1'].CopyFrom(empty_map)
679 mask = field_mask_pb2.FieldMask()
680 mask.FromJsonString('a')
681 mask.MergeMessage(src, dst)
683 # map from dst is replaced with map from src.
684 self.assertEqual(dst.a['common key'], src_level_2)
685 self.assertEqual(dst.a['src level 1'], src_level_2)
686 self.assertEqual(dst.a['dst level 1'], empty_map)
688 def testMergeErrors(self):
689 src = unittest_pb2.TestAllTypes()
690 dst = unittest_pb2.TestAllTypes()
691 mask = field_mask_pb2.FieldMask()
692 test_util.SetAllFields(src)
693 mask.FromJsonString('optionalInt32.field')
694 with self.assertRaises(ValueError) as e:
695 mask.MergeMessage(src, dst)
696 self.assertEqual('Error: Field optional_int32 in message '
697 'protobuf_unittest.TestAllTypes is not a singular '
698 'message field and cannot have sub-fields.',
701 def testSnakeCaseToCamelCase(self):
702 self.assertEqual('fooBar',
703 well_known_types._SnakeCaseToCamelCase('foo_bar'))
704 self.assertEqual('FooBar',
705 well_known_types._SnakeCaseToCamelCase('_foo_bar'))
706 self.assertEqual('foo3Bar',
707 well_known_types._SnakeCaseToCamelCase('foo3_bar'))
709 # No uppercase letter is allowed.
710 self.assertRaisesRegexp(
712 'Fail to print FieldMask to Json string: Path name Foo must '
713 'not contain uppercase letters.',
714 well_known_types._SnakeCaseToCamelCase,
716 # Any character after a "_" must be a lowercase letter.
717 # 1. "_" cannot be followed by another "_".
718 # 2. "_" cannot be followed by a digit.
719 # 3. "_" cannot appear as the last character.
720 self.assertRaisesRegexp(
722 'Fail to print FieldMask to Json string: The character after a '
723 '"_" must be a lowercase letter in path name foo__bar.',
724 well_known_types._SnakeCaseToCamelCase,
726 self.assertRaisesRegexp(
728 'Fail to print FieldMask to Json string: The character after a '
729 '"_" must be a lowercase letter in path name foo_3bar.',
730 well_known_types._SnakeCaseToCamelCase,
732 self.assertRaisesRegexp(
734 'Fail to print FieldMask to Json string: Trailing "_" in path '
736 well_known_types._SnakeCaseToCamelCase,
739 def testCamelCaseToSnakeCase(self):
740 self.assertEqual('foo_bar',
741 well_known_types._CamelCaseToSnakeCase('fooBar'))
742 self.assertEqual('_foo_bar',
743 well_known_types._CamelCaseToSnakeCase('FooBar'))
744 self.assertEqual('foo3_bar',
745 well_known_types._CamelCaseToSnakeCase('foo3Bar'))
746 self.assertRaisesRegexp(
748 'Fail to parse FieldMask: Path name foo_bar must not contain "_"s.',
749 well_known_types._CamelCaseToSnakeCase,
753 class StructTest(unittest.TestCase):
755 def testStruct(self):
756 struct = struct_pb2.Struct()
757 self.assertIsInstance(struct, collections_abc.Mapping)
758 self.assertEqual(0, len(struct))
759 struct_class = struct.__class__
762 struct['key2'] = 'abc'
763 struct['key3'] = True
764 struct.get_or_create_struct('key4')['subkey'] = 11.0
765 struct_list = struct.get_or_create_list('key5')
766 self.assertIsInstance(struct_list, collections_abc.Sequence)
767 struct_list.extend([6, 'seven', True, False, None])
768 struct_list.add_struct()['subkey2'] = 9
769 struct['key6'] = {'subkey': {}}
770 struct['key7'] = [2, False]
772 self.assertEqual(7, len(struct))
773 self.assertTrue(isinstance(struct, well_known_types.Struct))
774 self.assertEqual(5, struct['key1'])
775 self.assertEqual('abc', struct['key2'])
776 self.assertIs(True, struct['key3'])
777 self.assertEqual(11, struct['key4']['subkey'])
778 inner_struct = struct_class()
779 inner_struct['subkey2'] = 9
780 self.assertEqual([6, 'seven', True, False, None, inner_struct],
781 list(struct['key5'].items()))
782 self.assertEqual({}, dict(struct['key6']['subkey'].fields))
783 self.assertEqual([2, False], list(struct['key7'].items()))
785 serialized = struct.SerializeToString()
786 struct2 = struct_pb2.Struct()
787 struct2.ParseFromString(serialized)
789 self.assertEqual(struct, struct2)
790 for key, value in struct.items():
791 self.assertIn(key, struct)
792 self.assertIn(key, struct2)
793 self.assertEqual(value, struct2[key])
795 self.assertEqual(7, len(struct.keys()))
796 self.assertEqual(7, len(struct.values()))
797 for key in struct.keys():
798 self.assertIn(key, struct)
799 self.assertIn(key, struct2)
800 self.assertEqual(struct[key], struct2[key])
802 item = (next(iter(struct.keys())), next(iter(struct.values())))
803 self.assertEqual(item, next(iter(struct.items())))
805 self.assertTrue(isinstance(struct2, well_known_types.Struct))
806 self.assertEqual(5, struct2['key1'])
807 self.assertEqual('abc', struct2['key2'])
808 self.assertIs(True, struct2['key3'])
809 self.assertEqual(11, struct2['key4']['subkey'])
810 self.assertEqual([6, 'seven', True, False, None, inner_struct],
811 list(struct2['key5'].items()))
813 struct_list = struct2['key5']
814 self.assertEqual(6, struct_list[0])
815 self.assertEqual('seven', struct_list[1])
816 self.assertEqual(True, struct_list[2])
817 self.assertEqual(False, struct_list[3])
818 self.assertEqual(None, struct_list[4])
819 self.assertEqual(inner_struct, struct_list[5])
822 self.assertEqual(7, struct_list[1])
824 struct_list.add_list().extend([1, 'two', True, False, None])
825 self.assertEqual([1, 'two', True, False, None],
826 list(struct_list[6].items()))
827 struct_list.extend([{'nested_struct': 30}, ['nested_list', 99], {}, []])
828 self.assertEqual(11, len(struct_list.values))
829 self.assertEqual(30, struct_list[7]['nested_struct'])
830 self.assertEqual('nested_list', struct_list[8][0])
831 self.assertEqual(99, struct_list[8][1])
832 self.assertEqual({}, dict(struct_list[9].fields))
833 self.assertEqual([], list(struct_list[10].items()))
834 struct_list[0] = {'replace': 'set'}
835 struct_list[1] = ['replace', 'set']
836 self.assertEqual('set', struct_list[0]['replace'])
837 self.assertEqual(['replace', 'set'], list(struct_list[1].items()))
839 text_serialized = str(struct)
840 struct3 = struct_pb2.Struct()
841 text_format.Merge(text_serialized, struct3)
842 self.assertEqual(struct, struct3)
844 struct.get_or_create_struct('key3')['replace'] = 12
845 self.assertEqual(12, struct['key3']['replace'])
848 struct.get_or_create_list('empty_list')
849 empty_list = struct['empty_list']
850 self.assertEqual([], list(empty_list.items()))
851 list2 = struct_pb2.ListValue()
853 empty_list = list2[0]
854 self.assertEqual([], list(empty_list.items()))
856 # Tests empty struct.
857 struct.get_or_create_struct('empty_struct')
858 empty_struct = struct['empty_struct']
859 self.assertEqual({}, dict(empty_struct.fields))
861 empty_struct = list2[1]
862 self.assertEqual({}, dict(empty_struct.fields))
864 self.assertEqual(9, len(struct))
867 self.assertEqual(7, len(struct))
868 self.assertEqual(6, len(struct['key5']))
869 del struct['key5'][1]
870 self.assertEqual(5, len(struct['key5']))
871 self.assertEqual([6, True, False, None, inner_struct],
872 list(struct['key5'].items()))
874 def testMergeFrom(self):
875 struct = struct_pb2.Struct()
876 struct_class = struct.__class__
882 'key4': {'subkey': 11.0},
883 'key5': [6, 'seven', True, False, None, {'subkey2': 9}],
884 'key6': [['nested_list', True]],
888 struct.update(dictionary)
889 self.assertEqual(5, struct['key1'])
890 self.assertEqual('abc', struct['key2'])
891 self.assertIs(True, struct['key3'])
892 self.assertEqual(11, struct['key4']['subkey'])
893 inner_struct = struct_class()
894 inner_struct['subkey2'] = 9
895 self.assertEqual([6, 'seven', True, False, None, inner_struct],
896 list(struct['key5'].items()))
897 self.assertEqual(2, len(struct['key6'][0].values))
898 self.assertEqual('nested_list', struct['key6'][0][0])
899 self.assertEqual(True, struct['key6'][0][1])
900 empty_list = struct['empty_list']
901 self.assertEqual([], list(empty_list.items()))
902 empty_struct = struct['empty_struct']
903 self.assertEqual({}, dict(empty_struct.fields))
905 # According to documentation: "When parsing from the wire or when merging,
906 # if there are duplicate map keys the last key seen is used".
908 'key4': {'replace': 20},
911 struct.update(duplicate)
912 self.assertEqual(1, len(struct['key4'].fields))
913 self.assertEqual(20, struct['key4']['replace'])
914 self.assertEqual(1, len(struct['key5'].values))
915 self.assertEqual(False, struct['key5'][0][0])
916 self.assertEqual(5, struct['key5'][0][1])
919 class AnyTest(unittest.TestCase):
921 def testAnyMessage(self):
922 # Creates and sets message.
923 msg = any_test_pb2.TestAny()
924 msg_descriptor = msg.DESCRIPTOR
925 all_types = unittest_pb2.TestAllTypes()
926 all_descriptor = all_types.DESCRIPTOR
927 all_types.repeated_string.append(u'\u00fc\ua71f')
929 msg.value.Pack(all_types)
930 self.assertEqual(msg.value.type_url,
931 'type.googleapis.com/%s' % all_descriptor.full_name)
932 self.assertEqual(msg.value.value,
933 all_types.SerializeToString())
935 self.assertTrue(msg.value.Is(all_descriptor))
936 self.assertFalse(msg.value.Is(msg_descriptor))
938 unpacked_message = unittest_pb2.TestAllTypes()
939 self.assertTrue(msg.value.Unpack(unpacked_message))
940 self.assertEqual(all_types, unpacked_message)
941 # Unpacks to different type.
942 self.assertFalse(msg.value.Unpack(msg))
943 # Only Any messages have Pack method.
946 except AttributeError:
949 raise AttributeError('%s should not have Pack method.' %
950 msg_descriptor.full_name)
952 def testUnpackWithNoSlashInTypeUrl(self):
953 msg = any_test_pb2.TestAny()
954 all_types = unittest_pb2.TestAllTypes()
955 all_descriptor = all_types.DESCRIPTOR
956 msg.value.Pack(all_types)
957 # Reset type_url to part of type_url after '/'
958 msg.value.type_url = msg.value.TypeName()
959 self.assertFalse(msg.value.Is(all_descriptor))
960 unpacked_message = unittest_pb2.TestAllTypes()
961 self.assertFalse(msg.value.Unpack(unpacked_message))
963 def testMessageName(self):
964 # Creates and sets message.
965 submessage = any_test_pb2.TestAny()
966 submessage.int_value = 12345
969 self.assertEqual(msg.TypeName(), 'google.protobuf.internal.TestAny')
971 def testPackWithCustomTypeUrl(self):
972 submessage = any_test_pb2.TestAny()
973 submessage.int_value = 12345
975 # Pack with a custom type URL prefix.
976 msg.Pack(submessage, 'type.myservice.com')
977 self.assertEqual(msg.type_url,
978 'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
979 # Pack with a custom type URL prefix ending with '/'.
980 msg.Pack(submessage, 'type.myservice.com/')
981 self.assertEqual(msg.type_url,
982 'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
983 # Pack with an empty type URL prefix.
984 msg.Pack(submessage, '')
985 self.assertEqual(msg.type_url,
986 '/%s' % submessage.DESCRIPTOR.full_name)
987 # Test unpacking the type.
988 unpacked_message = any_test_pb2.TestAny()
989 self.assertTrue(msg.Unpack(unpacked_message))
990 self.assertEqual(submessage, unpacked_message)
992 def testPackDeterministic(self):
993 submessage = any_test_pb2.TestAny()
995 submessage.map_value[str(i)] = i * 2
997 msg.Pack(submessage, deterministic=True)
998 serialized = msg.SerializeToString(deterministic=True)
999 golden = (b'\n4type.googleapis.com/google.protobuf.internal.TestAny\x12F'
1000 b'\x1a\x05\n\x010\x10\x00\x1a\x05\n\x011\x10\x02\x1a\x05\n\x01'
1001 b'2\x10\x04\x1a\x05\n\x013\x10\x06\x1a\x05\n\x014\x10\x08\x1a'
1002 b'\x05\n\x015\x10\n\x1a\x05\n\x016\x10\x0c\x1a\x05\n\x017\x10'
1003 b'\x0e\x1a\x05\n\x018\x10\x10\x1a\x05\n\x019\x10\x12')
1004 self.assertEqual(golden, serialized)
1007 if __name__ == '__main__':