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.json_format."""
35 __author__ = 'jieluo@google.com (Jie Luo)'
42 import unittest2 as unittest #PY26
46 from google.protobuf import any_pb2
47 from google.protobuf import duration_pb2
48 from google.protobuf import field_mask_pb2
49 from google.protobuf import struct_pb2
50 from google.protobuf import timestamp_pb2
51 from google.protobuf import wrappers_pb2
52 from google.protobuf import any_test_pb2
53 from google.protobuf import unittest_mset_pb2
54 from google.protobuf import unittest_pb2
55 from google.protobuf import descriptor_pool
56 from google.protobuf import json_format
57 from google.protobuf.util import json_format_proto3_pb2
60 class JsonFormatBase(unittest.TestCase):
62 def FillAllFields(self, message):
63 message.int32_value = 20
64 message.int64_value = -20
65 message.uint32_value = 3120987654
66 message.uint64_value = 12345678900
67 message.float_value = float('-inf')
68 message.double_value = 3.1415
69 message.bool_value = True
70 message.string_value = 'foo'
71 message.bytes_value = b'bar'
72 message.message_value.value = 10
73 message.enum_value = json_format_proto3_pb2.BAR
75 message.repeated_int32_value.append(0x7FFFFFFF)
76 message.repeated_int32_value.append(-2147483648)
77 message.repeated_int64_value.append(9007199254740992)
78 message.repeated_int64_value.append(-9007199254740992)
79 message.repeated_uint32_value.append(0xFFFFFFF)
80 message.repeated_uint32_value.append(0x7FFFFFF)
81 message.repeated_uint64_value.append(9007199254740992)
82 message.repeated_uint64_value.append(9007199254740991)
83 message.repeated_float_value.append(0)
85 message.repeated_double_value.append(1E-15)
86 message.repeated_double_value.append(float('inf'))
87 message.repeated_bool_value.append(True)
88 message.repeated_bool_value.append(False)
89 message.repeated_string_value.append('Few symbols!#$,;')
90 message.repeated_string_value.append('bar')
91 message.repeated_bytes_value.append(b'foo')
92 message.repeated_bytes_value.append(b'bar')
93 message.repeated_message_value.add().value = 10
94 message.repeated_message_value.add().value = 11
95 message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
96 message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
97 self.message = message
99 def CheckParseBack(self, message, parsed_message):
100 json_format.Parse(json_format.MessageToJson(message),
102 self.assertEqual(message, parsed_message)
104 def CheckError(self, text, error_message):
105 message = json_format_proto3_pb2.TestMessage()
106 self.assertRaisesRegexp(
107 json_format.ParseError,
109 json_format.Parse, text, message)
112 class JsonFormatTest(JsonFormatBase):
114 def testEmptyMessageToJson(self):
115 message = json_format_proto3_pb2.TestMessage()
116 self.assertEqual(json_format.MessageToJson(message),
118 parsed_message = json_format_proto3_pb2.TestMessage()
119 self.CheckParseBack(message, parsed_message)
121 def testPartialMessageToJson(self):
122 message = json_format_proto3_pb2.TestMessage(
124 repeated_int32_value=[89, 4])
125 self.assertEqual(json.loads(json_format.MessageToJson(message)),
126 json.loads('{"stringValue": "test", '
127 '"repeatedInt32Value": [89, 4]}'))
128 parsed_message = json_format_proto3_pb2.TestMessage()
129 self.CheckParseBack(message, parsed_message)
131 def testAllFieldsToJson(self):
132 message = json_format_proto3_pb2.TestMessage()
133 text = ('{"int32Value": 20, '
134 '"int64Value": "-20", '
135 '"uint32Value": 3120987654,'
136 '"uint64Value": "12345678900",'
137 '"floatValue": "-Infinity",'
138 '"doubleValue": 3.1415,'
140 '"stringValue": "foo",'
141 '"bytesValue": "YmFy",'
142 '"messageValue": {"value": 10},'
143 '"enumValue": "BAR",'
144 '"repeatedInt32Value": [2147483647, -2147483648],'
145 '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
146 '"repeatedUint32Value": [268435455, 134217727],'
147 '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
148 '"repeatedFloatValue": [0],'
149 '"repeatedDoubleValue": [1e-15, "Infinity"],'
150 '"repeatedBoolValue": [true, false],'
151 '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
152 '"repeatedBytesValue": ["Zm9v", "YmFy"],'
153 '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
154 '"repeatedEnumValue": ["FOO", "BAR"]'
156 self.FillAllFields(message)
158 json.loads(json_format.MessageToJson(message)),
160 parsed_message = json_format_proto3_pb2.TestMessage()
161 json_format.Parse(text, parsed_message)
162 self.assertEqual(message, parsed_message)
164 def testUnknownEnumToJsonAndBack(self):
165 text = '{\n "enumValue": 999\n}'
166 message = json_format_proto3_pb2.TestMessage()
167 message.enum_value = 999
168 self.assertEqual(json_format.MessageToJson(message),
170 parsed_message = json_format_proto3_pb2.TestMessage()
171 json_format.Parse(text, parsed_message)
172 self.assertEqual(message, parsed_message)
174 def testExtensionToJsonAndBack(self):
175 message = unittest_mset_pb2.TestMessageSetContainer()
176 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
177 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
178 message.message_set.Extensions[ext1].i = 23
179 message.message_set.Extensions[ext2].str = 'foo'
180 message_text = json_format.MessageToJson(
183 parsed_message = unittest_mset_pb2.TestMessageSetContainer()
184 json_format.Parse(message_text, parsed_message)
185 self.assertEqual(message, parsed_message)
187 def testExtensionErrors(self):
188 self.CheckError('{"[extensionField]": {}}',
189 'Message type proto3.TestMessage does not have extensions')
191 def testExtensionToDictAndBack(self):
192 message = unittest_mset_pb2.TestMessageSetContainer()
193 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
194 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
195 message.message_set.Extensions[ext1].i = 23
196 message.message_set.Extensions[ext2].str = 'foo'
197 message_dict = json_format.MessageToDict(
200 parsed_message = unittest_mset_pb2.TestMessageSetContainer()
201 json_format.ParseDict(message_dict, parsed_message)
202 self.assertEqual(message, parsed_message)
204 def testExtensionToDictAndBackWithScalar(self):
205 message = unittest_pb2.TestAllExtensions()
206 ext1 = unittest_pb2.TestNestedExtension.test
207 message.Extensions[ext1] = 'data'
208 message_dict = json_format.MessageToDict(
211 parsed_message = unittest_pb2.TestAllExtensions()
212 json_format.ParseDict(message_dict, parsed_message)
213 self.assertEqual(message, parsed_message)
215 def testJsonParseDictToAnyDoesNotAlterInput(self):
218 '@type': 'type.googleapis.com/proto3.TestMessage'
220 copied_dict = json.loads(json.dumps(orig_dict))
221 parsed_message = any_pb2.Any()
222 json_format.ParseDict(copied_dict, parsed_message)
223 self.assertEqual(copied_dict, orig_dict)
225 def testExtensionSerializationDictMatchesProto3Spec(self):
226 """See go/proto3-json-spec for spec.
228 message = unittest_mset_pb2.TestMessageSetContainer()
229 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
230 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
231 message.message_set.Extensions[ext1].i = 23
232 message.message_set.Extensions[ext2].str = 'foo'
233 message_dict = json_format.MessageToDict(
238 '[protobuf_unittest.'
239 'TestMessageSetExtension1.messageSetExtension]': {
242 '[protobuf_unittest.'
243 'TestMessageSetExtension2.messageSetExtension]': {
248 self.assertEqual(golden_dict, message_dict)
251 def testExtensionSerializationJsonMatchesProto3Spec(self):
252 """See go/proto3-json-spec for spec.
254 message = unittest_mset_pb2.TestMessageSetContainer()
255 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
256 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
257 message.message_set.Extensions[ext1].i = 23
258 message.message_set.Extensions[ext2].str = 'foo'
259 message_text = json_format.MessageToJson(
262 ext1_text = ('protobuf_unittest.TestMessageSetExtension1.'
263 'messageSetExtension')
264 ext2_text = ('protobuf_unittest.TestMessageSetExtension2.'
265 'messageSetExtension')
266 golden_text = ('{"messageSet": {'
273 '}}') % (ext1_text, ext2_text)
274 self.assertEqual(json.loads(golden_text), json.loads(message_text))
277 def testJsonEscapeString(self):
278 message = json_format_proto3_pb2.TestMessage()
279 if sys.version_info[0] < 3:
280 message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
282 message.string_value = '&\n<\"\r>\b\t\f\\\001/'
283 message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
285 json_format.MessageToJson(message),
286 '{\n "stringValue": '
287 '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
288 parsed_message = json_format_proto3_pb2.TestMessage()
289 self.CheckParseBack(message, parsed_message)
290 text = u'{"int32Value": "\u0031"}'
291 json_format.Parse(text, message)
292 self.assertEqual(message.int32_value, 1)
294 def testAlwaysSeriliaze(self):
295 message = json_format_proto3_pb2.TestMessage(
298 json.loads(json_format.MessageToJson(message, True)),
300 '"repeatedStringValue": [],'
301 '"stringValue": "foo",'
302 '"repeatedBoolValue": [],'
303 '"repeatedUint32Value": [],'
304 '"repeatedInt32Value": [],'
305 '"enumValue": "FOO",'
310 '"repeatedBytesValue": [],'
311 '"repeatedUint64Value": [],'
312 '"repeatedDoubleValue": [],'
314 '"boolValue": false,'
315 '"repeatedEnumValue": [],'
316 '"uint64Value": "0",'
318 '"repeatedFloatValue": [],'
319 '"repeatedInt64Value": [],'
320 '"repeatedMessageValue": []}'))
321 parsed_message = json_format_proto3_pb2.TestMessage()
322 self.CheckParseBack(message, parsed_message)
324 def testIntegersRepresentedAsFloat(self):
325 message = json_format_proto3_pb2.TestMessage()
326 json_format.Parse('{"int32Value": -2.147483648e9}', message)
327 self.assertEqual(message.int32_value, -2147483648)
328 json_format.Parse('{"int32Value": 1e5}', message)
329 self.assertEqual(message.int32_value, 100000)
330 json_format.Parse('{"int32Value": 1.0}', message)
331 self.assertEqual(message.int32_value, 1)
333 def testMapFields(self):
334 message = json_format_proto3_pb2.TestNestedMap()
336 json.loads(json_format.MessageToJson(message, True)),
346 message.bool_map[True] = 1
347 message.bool_map[False] = 2
348 message.int32_map[1] = 2
349 message.int32_map[2] = 3
350 message.int64_map[1] = 2
351 message.int64_map[2] = 3
352 message.uint32_map[1] = 2
353 message.uint32_map[2] = 3
354 message.uint64_map[1] = 2
355 message.uint64_map[2] = 3
356 message.string_map['1'] = 2
357 message.string_map['null'] = 3
358 message.map_map['1'].bool_map[True] = 3
360 json.loads(json_format.MessageToJson(message, False)),
362 '"boolMap": {"false": 2, "true": 1},'
363 '"int32Map": {"1": 2, "2": 3},'
364 '"int64Map": {"1": 2, "2": 3},'
365 '"uint32Map": {"1": 2, "2": 3},'
366 '"uint64Map": {"1": 2, "2": 3},'
367 '"stringMap": {"1": 2, "null": 3},'
368 '"mapMap": {"1": {"boolMap": {"true": 3}}}'
370 parsed_message = json_format_proto3_pb2.TestNestedMap()
371 self.CheckParseBack(message, parsed_message)
373 def testOneofFields(self):
374 message = json_format_proto3_pb2.TestOneof()
375 # Always print does not affect oneof fields.
377 json_format.MessageToJson(message, True),
379 message.oneof_int32_value = 0
381 json_format.MessageToJson(message, True),
383 ' "oneofInt32Value": 0\n'
385 parsed_message = json_format_proto3_pb2.TestOneof()
386 self.CheckParseBack(message, parsed_message)
388 def testSurrogates(self):
389 # Test correct surrogate handling.
390 message = json_format_proto3_pb2.TestMessage()
391 json_format.Parse('{"stringValue": "\\uD83D\\uDE01"}', message)
392 self.assertEqual(message.string_value,
393 b'\xF0\x9F\x98\x81'.decode('utf-8', 'strict'))
395 # Error case: unpaired high surrogate.
397 '{"stringValue": "\\uD83D"}',
398 r'Invalid \\uXXXX escape|Unpaired.*surrogate')
400 # Unpaired low surrogate.
402 '{"stringValue": "\\uDE01"}',
403 r'Invalid \\uXXXX escape|Unpaired.*surrogate')
405 def testTimestampMessage(self):
406 message = json_format_proto3_pb2.TestTimestamp()
407 message.value.seconds = 0
408 message.value.nanos = 0
409 message.repeated_value.add().seconds = 20
410 message.repeated_value[0].nanos = 1
411 message.repeated_value.add().seconds = 0
412 message.repeated_value[1].nanos = 10000
413 message.repeated_value.add().seconds = 100000000
414 message.repeated_value[2].nanos = 0
416 message.repeated_value.add().seconds = 253402300799
417 message.repeated_value[3].nanos = 999999999
419 message.repeated_value.add().seconds = -62135596800
420 message.repeated_value[4].nanos = 0
422 json.loads(json_format.MessageToJson(message, True)),
424 '"value": "1970-01-01T00:00:00Z",'
426 ' "1970-01-01T00:00:20.000000001Z",'
427 ' "1970-01-01T00:00:00.000010Z",'
428 ' "1973-03-03T09:46:40Z",'
429 ' "9999-12-31T23:59:59.999999999Z",'
430 ' "0001-01-01T00:00:00Z"'
433 parsed_message = json_format_proto3_pb2.TestTimestamp()
434 self.CheckParseBack(message, parsed_message)
435 text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
437 r' "1970-01-01T00:00:00.01+08:30",'
438 r' "1970-01-01T00:00:00.01-01:23"]}')
439 json_format.Parse(text, parsed_message)
440 self.assertEqual(parsed_message.value.seconds, -8 * 3600)
441 self.assertEqual(parsed_message.value.nanos, 10000000)
442 self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
443 self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
445 def testDurationMessage(self):
446 message = json_format_proto3_pb2.TestDuration()
447 message.value.seconds = 1
448 message.repeated_value.add().seconds = 0
449 message.repeated_value[0].nanos = 10
450 message.repeated_value.add().seconds = -1
451 message.repeated_value[1].nanos = -1000
452 message.repeated_value.add().seconds = 10
453 message.repeated_value[2].nanos = 11000000
454 message.repeated_value.add().seconds = -315576000000
455 message.repeated_value.add().seconds = 315576000000
457 json.loads(json_format.MessageToJson(message, True)),
468 parsed_message = json_format_proto3_pb2.TestDuration()
469 self.CheckParseBack(message, parsed_message)
471 def testFieldMaskMessage(self):
472 message = json_format_proto3_pb2.TestFieldMask()
473 message.value.paths.append('foo.bar')
474 message.value.paths.append('bar')
476 json_format.MessageToJson(message, True),
478 ' "value": "foo.bar,bar"\n'
480 parsed_message = json_format_proto3_pb2.TestFieldMask()
481 self.CheckParseBack(message, parsed_message)
483 message.value.Clear()
485 json_format.MessageToJson(message, True),
489 self.CheckParseBack(message, parsed_message)
491 def testWrapperMessage(self):
492 message = json_format_proto3_pb2.TestWrapper()
493 message.bool_value.value = False
494 message.int32_value.value = 0
495 message.string_value.value = ''
496 message.bytes_value.value = b''
497 message.repeated_bool_value.add().value = True
498 message.repeated_bool_value.add().value = False
499 message.repeated_int32_value.add()
501 json.loads(json_format.MessageToJson(message, True)),
504 ' "boolValue": false,'
505 ' "stringValue": "",'
507 ' "repeatedBoolValue": [true, false],'
508 ' "repeatedInt32Value": [0],'
509 ' "repeatedUint32Value": [],'
510 ' "repeatedFloatValue": [],'
511 ' "repeatedDoubleValue": [],'
512 ' "repeatedBytesValue": [],'
513 ' "repeatedInt64Value": [],'
514 ' "repeatedUint64Value": [],'
515 ' "repeatedStringValue": []'
517 parsed_message = json_format_proto3_pb2.TestWrapper()
518 self.CheckParseBack(message, parsed_message)
520 def testStructMessage(self):
521 message = json_format_proto3_pb2.TestStruct()
522 message.value['name'] = 'Jim'
523 message.value['age'] = 10
524 message.value['attend'] = True
525 message.value['email'] = None
526 message.value.get_or_create_struct('address')['city'] = 'SFO'
527 message.value['address']['house_number'] = 1024
528 message.value.get_or_create_struct('empty_struct')
529 message.value.get_or_create_list('empty_list')
530 struct_list = message.value.get_or_create_list('list')
531 struct_list.extend([6, 'seven', True, False, None])
532 struct_list.add_struct()['subkey2'] = 9
533 message.repeated_value.add()['age'] = 11
534 message.repeated_value.add()
536 json.loads(json_format.MessageToJson(message, False)),
542 ' "house_number": 1024'
544 ' "empty_struct": {}, '
545 ' "empty_list": [], '
550 ' "list": [6, "seven", true, false, null, {"subkey2": 9}]'
552 ' "repeatedValue": [{"age": 11}, {}]'
554 parsed_message = json_format_proto3_pb2.TestStruct()
555 self.CheckParseBack(message, parsed_message)
556 # check for regression; this used to raise
557 parsed_message.value['empty_struct']
558 parsed_message.value['empty_list']
560 def testValueMessage(self):
561 message = json_format_proto3_pb2.TestValue()
562 message.value.string_value = 'hello'
563 message.repeated_value.add().number_value = 11.1
564 message.repeated_value.add().bool_value = False
565 message.repeated_value.add().null_value = 0
567 json.loads(json_format.MessageToJson(message, False)),
571 ' "repeatedValue": [11.1, false, null]'
573 parsed_message = json_format_proto3_pb2.TestValue()
574 self.CheckParseBack(message, parsed_message)
575 # Can't parse back if the Value message is not set.
576 message.repeated_value.add()
578 json.loads(json_format.MessageToJson(message, False)),
582 ' "repeatedValue": [11.1, false, null, null]'
585 json_format.Parse('{"value": null}', message)
586 self.assertEqual(message.value.WhichOneof('kind'), 'null_value')
588 def testListValueMessage(self):
589 message = json_format_proto3_pb2.TestListValue()
590 message.value.values.add().number_value = 11.1
591 message.value.values.add().null_value = 0
592 message.value.values.add().bool_value = True
593 message.value.values.add().string_value = 'hello'
594 message.value.values.add().struct_value['name'] = 'Jim'
595 message.repeated_value.add().values.add().number_value = 1
596 message.repeated_value.add()
598 json.loads(json_format.MessageToJson(message, False)),
600 '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
601 '"repeatedValue": [[1], []]}'))
602 parsed_message = json_format_proto3_pb2.TestListValue()
603 self.CheckParseBack(message, parsed_message)
605 def testAnyMessage(self):
606 message = json_format_proto3_pb2.TestAny()
607 value1 = json_format_proto3_pb2.MessageType()
608 value2 = json_format_proto3_pb2.MessageType()
611 message.value.Pack(value1)
612 message.repeated_value.add().Pack(value1)
613 message.repeated_value.add().Pack(value2)
614 message.repeated_value.add()
616 json.loads(json_format.MessageToJson(message, True)),
619 ' "repeatedValue": [ {\n'
620 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
623 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
628 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
632 parsed_message = json_format_proto3_pb2.TestAny()
633 self.CheckParseBack(message, parsed_message)
634 # Must print @type first
635 test_message = json_format_proto3_pb2.TestMessage(
644 message.value.Pack(test_message)
646 json_format.MessageToJson(message, False)[0:68],
649 ' "@type": "type.googleapis.com/proto3.TestMessage"')
651 def testAnyMessageDescriptorPoolMissingType(self):
652 packed_message = unittest_pb2.OneString()
653 packed_message.data = 'string'
654 message = any_test_pb2.TestAny()
655 message.any_value.Pack(packed_message)
656 empty_pool = descriptor_pool.DescriptorPool()
657 with self.assertRaises(TypeError) as cm:
658 json_format.MessageToJson(message, True, descriptor_pool=empty_pool)
660 'Can not find message descriptor by type_url:'
661 ' type.googleapis.com/protobuf_unittest.OneString.',
664 def testWellKnownInAnyMessage(self):
665 message = any_pb2.Any()
666 int32_value = wrappers_pb2.Int32Value()
667 int32_value.value = 1234
668 message.Pack(int32_value)
670 json.loads(json_format.MessageToJson(message, True)),
673 ' "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
676 parsed_message = any_pb2.Any()
677 self.CheckParseBack(message, parsed_message)
679 timestamp = timestamp_pb2.Timestamp()
680 message.Pack(timestamp)
682 json.loads(json_format.MessageToJson(message, True)),
685 ' "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
686 ' "value": "1970-01-01T00:00:00Z"\n'
688 self.CheckParseBack(message, parsed_message)
690 duration = duration_pb2.Duration()
692 message.Pack(duration)
694 json.loads(json_format.MessageToJson(message, True)),
697 ' "@type": "type.googleapis.com/google.protobuf.Duration",\n'
700 self.CheckParseBack(message, parsed_message)
702 field_mask = field_mask_pb2.FieldMask()
703 field_mask.paths.append('foo.bar')
704 field_mask.paths.append('bar')
705 message.Pack(field_mask)
707 json.loads(json_format.MessageToJson(message, True)),
710 ' "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
711 ' "value": "foo.bar,bar"\n'
713 self.CheckParseBack(message, parsed_message)
715 struct_message = struct_pb2.Struct()
716 struct_message['name'] = 'Jim'
717 message.Pack(struct_message)
719 json.loads(json_format.MessageToJson(message, True)),
722 ' "@type": "type.googleapis.com/google.protobuf.Struct",\n'
723 ' "value": {"name": "Jim"}\n'
725 self.CheckParseBack(message, parsed_message)
727 nested_any = any_pb2.Any()
728 int32_value.value = 5678
729 nested_any.Pack(int32_value)
730 message.Pack(nested_any)
732 json.loads(json_format.MessageToJson(message, True)),
735 ' "@type": "type.googleapis.com/google.protobuf.Any",\n'
737 ' "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
741 self.CheckParseBack(message, parsed_message)
743 def testParseNull(self):
744 message = json_format_proto3_pb2.TestMessage()
745 parsed_message = json_format_proto3_pb2.TestMessage()
746 self.FillAllFields(parsed_message)
747 json_format.Parse('{"int32Value": null, '
748 '"int64Value": null, '
749 '"uint32Value": null,'
750 '"uint64Value": null,'
751 '"floatValue": null,'
752 '"doubleValue": null,'
754 '"stringValue": null,'
755 '"bytesValue": null,'
756 '"messageValue": null,'
758 '"repeatedInt32Value": null,'
759 '"repeatedInt64Value": null,'
760 '"repeatedUint32Value": null,'
761 '"repeatedUint64Value": null,'
762 '"repeatedFloatValue": null,'
763 '"repeatedDoubleValue": null,'
764 '"repeatedBoolValue": null,'
765 '"repeatedStringValue": null,'
766 '"repeatedBytesValue": null,'
767 '"repeatedMessageValue": null,'
768 '"repeatedEnumValue": null'
771 self.assertEqual(message, parsed_message)
772 # Null and {} should have different behavior for sub message.
773 self.assertFalse(parsed_message.HasField('message_value'))
774 json_format.Parse('{"messageValue": {}}', parsed_message)
775 self.assertTrue(parsed_message.HasField('message_value'))
776 # Null is not allowed to be used as an element in repeated field.
777 self.assertRaisesRegexp(
778 json_format.ParseError,
779 'Failed to parse repeatedInt32Value field: '
780 'null is not allowed to be used as an element in a repeated field.',
782 '{"repeatedInt32Value":[1, null]}',
784 self.CheckError('{"repeatedMessageValue":[null]}',
785 'Failed to parse repeatedMessageValue field: null is not'
786 ' allowed to be used as an element in a repeated field.')
788 def testNanFloat(self):
789 message = json_format_proto3_pb2.TestMessage()
790 message.float_value = float('nan')
791 text = '{\n "floatValue": "NaN"\n}'
792 self.assertEqual(json_format.MessageToJson(message), text)
793 parsed_message = json_format_proto3_pb2.TestMessage()
794 json_format.Parse(text, parsed_message)
795 self.assertTrue(math.isnan(parsed_message.float_value))
797 def testParseDoubleToFloat(self):
798 message = json_format_proto3_pb2.TestMessage()
799 text = ('{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}')
800 json_format.Parse(text, message)
801 self.assertEqual(message.repeated_float_value[0], float('inf'))
802 self.assertAlmostEqual(message.repeated_float_value[1], 1.4028235e-39)
804 def testParseEmptyText(self):
806 r'Failed to load JSON: (Expecting value)|(No JSON).')
808 def testParseEnumValue(self):
809 message = json_format_proto3_pb2.TestMessage()
810 text = '{"enumValue": 0}'
811 json_format.Parse(text, message)
812 text = '{"enumValue": 1}'
813 json_format.Parse(text, message)
815 '{"enumValue": "baz"}',
816 'Failed to parse enumValue field: Invalid enum value baz '
817 'for enum type proto3.EnumType.')
818 # Proto3 accepts numeric unknown enums.
819 text = '{"enumValue": 12345}'
820 json_format.Parse(text, message)
821 # Proto2 does not accept unknown enums.
822 message = unittest_pb2.TestAllTypes()
823 self.assertRaisesRegexp(
824 json_format.ParseError,
825 'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
826 'for enum type protobuf_unittest.TestAllTypes.NestedEnum.',
827 json_format.Parse, '{"optionalNestedEnum": 12345}', message)
829 def testParseBadIdentifer(self):
830 self.CheckError('{int32Value: 1}',
831 (r'Failed to load JSON: Expecting property name'
832 r'( enclosed in double quotes)?: line 1'))
833 self.CheckError('{"unknownName": 1}',
834 'Message type "proto3.TestMessage" has no field named '
837 def testIgnoreUnknownField(self):
838 text = '{"unknownName": 1}'
839 parsed_message = json_format_proto3_pb2.TestMessage()
840 json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
842 ' "repeatedValue": [ {\n'
843 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
844 ' "unknownName": 1\n'
847 parsed_message = json_format_proto3_pb2.TestAny()
848 json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
850 def testDuplicateField(self):
851 self.CheckError('{"int32Value": 1,\n"int32Value":2}',
852 'Failed to load JSON: duplicate key int32Value.')
854 def testInvalidBoolValue(self):
855 self.CheckError('{"boolValue": 1}',
856 'Failed to parse boolValue field: '
857 'Expected true or false without quotes.')
858 self.CheckError('{"boolValue": "true"}',
859 'Failed to parse boolValue field: '
860 'Expected true or false without quotes.')
862 def testInvalidIntegerValue(self):
863 message = json_format_proto3_pb2.TestMessage()
864 text = '{"int32Value": 0x12345}'
865 self.assertRaises(json_format.ParseError,
866 json_format.Parse, text, message)
867 self.CheckError('{"int32Value": 1.5}',
868 'Failed to parse int32Value field: '
869 'Couldn\'t parse integer: 1.5.')
870 self.CheckError('{"int32Value": 012345}',
871 (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
873 self.CheckError('{"int32Value": " 1 "}',
874 'Failed to parse int32Value field: '
875 'Couldn\'t parse integer: " 1 ".')
876 self.CheckError('{"int32Value": "1 "}',
877 'Failed to parse int32Value field: '
878 'Couldn\'t parse integer: "1 ".')
879 self.CheckError('{"int32Value": 12345678901234567890}',
880 'Failed to parse int32Value field: Value out of range: '
881 '12345678901234567890.')
882 self.CheckError('{"uint32Value": -1}',
883 'Failed to parse uint32Value field: '
884 'Value out of range: -1.')
886 def testInvalidFloatValue(self):
887 self.CheckError('{"floatValue": "nan"}',
888 'Failed to parse floatValue field: Couldn\'t '
889 'parse float "nan", use "NaN" instead.')
891 def testInvalidBytesValue(self):
892 self.CheckError('{"bytesValue": "AQI"}',
893 'Failed to parse bytesValue field: Incorrect padding.')
894 self.CheckError('{"bytesValue": "AQI*"}',
895 'Failed to parse bytesValue field: Incorrect padding.')
897 def testInvalidRepeated(self):
898 self.CheckError('{"repeatedInt32Value": 12345}',
899 (r'Failed to parse repeatedInt32Value field: repeated field'
900 r' repeatedInt32Value must be in \[\] which is 12345.'))
902 def testInvalidMap(self):
903 message = json_format_proto3_pb2.TestMap()
904 text = '{"int32Map": {"null": 2, "2": 3}}'
905 self.assertRaisesRegexp(
906 json_format.ParseError,
907 'Failed to parse int32Map field: invalid literal',
908 json_format.Parse, text, message)
909 text = '{"int32Map": {1: 2, "2": 3}}'
910 self.assertRaisesRegexp(
911 json_format.ParseError,
912 (r'Failed to load JSON: Expecting property name'
913 r'( enclosed in double quotes)?: line 1'),
914 json_format.Parse, text, message)
915 text = '{"boolMap": {"null": 1}}'
916 self.assertRaisesRegexp(
917 json_format.ParseError,
918 'Failed to parse boolMap field: Expected "true" or "false", not null.',
919 json_format.Parse, text, message)
920 if sys.version_info < (2, 7):
922 text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
923 self.assertRaisesRegexp(
924 json_format.ParseError,
925 'Failed to load JSON: duplicate key a',
926 json_format.Parse, text, message)
927 text = r'{"stringMap": 0}'
928 self.assertRaisesRegexp(
929 json_format.ParseError,
930 'Failed to parse stringMap field: Map field string_map must be '
931 'in a dict which is 0.',
932 json_format.Parse, text, message)
934 def testInvalidTimestamp(self):
935 message = json_format_proto3_pb2.TestTimestamp()
936 text = '{"value": "10000-01-01T00:00:00.00Z"}'
937 self.assertRaisesRegexp(
938 json_format.ParseError,
939 'Failed to parse value field: '
940 'time data \'10000-01-01T00:00:00\' does not match'
941 ' format \'%Y-%m-%dT%H:%M:%S\'.',
942 json_format.Parse, text, message)
943 text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
944 self.assertRaisesRegexp(
945 json_format.ParseError,
946 'nanos 0123456789012 more than 9 fractional digits.',
947 json_format.Parse, text, message)
948 text = '{"value": "1972-01-01T01:00:00.01+08"}'
949 self.assertRaisesRegexp(
950 json_format.ParseError,
951 (r'Invalid timezone offset value: \+08.'),
952 json_format.Parse, text, message)
953 # Time smaller than minimum time.
954 text = '{"value": "0000-01-01T00:00:00Z"}'
955 self.assertRaisesRegexp(
956 json_format.ParseError,
957 'Failed to parse value field: year (0 )?is out of range.',
958 json_format.Parse, text, message)
959 # Time bigger than maxinum time.
960 message.value.seconds = 253402300800
961 self.assertRaisesRegexp(
963 'date value out of range',
964 json_format.MessageToJson, message)
966 def testInvalidOneof(self):
967 message = json_format_proto3_pb2.TestOneof()
968 text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
969 self.assertRaisesRegexp(
970 json_format.ParseError,
971 'Message type "proto3.TestOneof"'
972 ' should not have multiple "oneof_value" oneof fields.',
973 json_format.Parse, text, message)
975 def testInvalidListValue(self):
976 message = json_format_proto3_pb2.TestListValue()
977 text = '{"value": 1234}'
978 self.assertRaisesRegexp(
979 json_format.ParseError,
980 r'Failed to parse value field: ListValue must be in \[\] which is 1234',
981 json_format.Parse, text, message)
983 def testInvalidStruct(self):
984 message = json_format_proto3_pb2.TestStruct()
985 text = '{"value": 1234}'
986 self.assertRaisesRegexp(
987 json_format.ParseError,
988 'Failed to parse value field: Struct must be in a dict which is 1234',
989 json_format.Parse, text, message)
991 def testInvalidAny(self):
992 message = any_pb2.Any()
993 text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
994 self.assertRaisesRegexp(
997 json_format.Parse, text, message)
998 text = '{"value": 1234}'
999 self.assertRaisesRegexp(
1000 json_format.ParseError,
1001 '@type is missing when parsing any message.',
1002 json_format.Parse, text, message)
1003 text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
1004 self.assertRaisesRegexp(
1006 'Can not find message descriptor by type_url: '
1007 'type.googleapis.com/MessageNotExist.',
1008 json_format.Parse, text, message)
1009 # Only last part is to be used: b/25630112
1010 text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
1012 json_format.Parse(text, message)
1014 def testPreservingProtoFieldNames(self):
1015 message = json_format_proto3_pb2.TestMessage()
1016 message.int32_value = 12345
1017 self.assertEqual('{\n "int32Value": 12345\n}',
1018 json_format.MessageToJson(message))
1019 self.assertEqual('{\n "int32_value": 12345\n}',
1020 json_format.MessageToJson(message, False, True))
1021 # When including_default_value_fields is True.
1022 message = json_format_proto3_pb2.TestTimestamp()
1023 self.assertEqual('{\n "repeatedValue": []\n}',
1024 json_format.MessageToJson(message, True, False))
1025 self.assertEqual('{\n "repeated_value": []\n}',
1026 json_format.MessageToJson(message, True, True))
1028 # Parsers accept both original proto field names and lowerCamelCase names.
1029 message = json_format_proto3_pb2.TestMessage()
1030 json_format.Parse('{"int32Value": 54321}', message)
1031 self.assertEqual(54321, message.int32_value)
1032 json_format.Parse('{"int32_value": 12345}', message)
1033 self.assertEqual(12345, message.int32_value)
1035 def testIndent(self):
1036 message = json_format_proto3_pb2.TestMessage()
1037 message.int32_value = 12345
1038 self.assertEqual('{\n"int32Value": 12345\n}',
1039 json_format.MessageToJson(message, indent=0))
1041 def testFormatEnumsAsInts(self):
1042 message = json_format_proto3_pb2.TestMessage()
1043 message.enum_value = json_format_proto3_pb2.BAR
1044 message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
1045 message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
1046 self.assertEqual(json.loads('{\n'
1047 ' "enumValue": 1,\n'
1048 ' "repeatedEnumValue": [0, 1]\n'
1050 json.loads(json_format.MessageToJson(
1051 message, use_integers_for_enums=True)))
1053 def testParseDict(self):
1055 js_dict = {'int32Value': expected}
1056 message = json_format_proto3_pb2.TestMessage()
1057 json_format.ParseDict(js_dict, message)
1058 self.assertEqual(expected, message.int32_value)
1060 def testParseDictAnyDescriptorPoolMissingType(self):
1061 # Confirm that ParseDict does not raise ParseError with default pool
1064 '@type': 'type.googleapis.com/proto3.MessageType',
1068 json_format.ParseDict(js_dict, any_test_pb2.TestAny())
1069 # Check ParseDict raises ParseError with empty pool
1072 '@type': 'type.googleapis.com/proto3.MessageType',
1076 with self.assertRaises(json_format.ParseError) as cm:
1077 empty_pool = descriptor_pool.DescriptorPool()
1078 json_format.ParseDict(js_dict,
1079 any_test_pb2.TestAny(),
1080 descriptor_pool=empty_pool)
1083 'Failed to parse any_value field: Can not find message descriptor by'
1084 ' type_url: type.googleapis.com/proto3.MessageType..')
1086 def testMessageToDict(self):
1087 message = json_format_proto3_pb2.TestMessage()
1088 message.int32_value = 12345
1089 expected = {'int32Value': 12345}
1090 self.assertEqual(expected,
1091 json_format.MessageToDict(message))
1093 def testJsonName(self):
1094 message = json_format_proto3_pb2.TestCustomJsonName()
1095 message.value = 12345
1096 self.assertEqual('{\n "@value": 12345\n}',
1097 json_format.MessageToJson(message))
1098 parsed_message = json_format_proto3_pb2.TestCustomJsonName()
1099 self.CheckParseBack(message, parsed_message)
1101 def testSortKeys(self):
1102 # Testing sort_keys is not perfectly working, as by random luck we could
1103 # get the output sorted. We just use a selection of names.
1104 message = json_format_proto3_pb2.TestMessage(bool_value=True,
1110 json_format.MessageToJson(message, sort_keys=True),
1111 # We use json.dumps() instead of a hardcoded string due to differences
1112 # between Python 2 and Python 3.
1113 json.dumps({'boolValue': True, 'int32Value': 1, 'int64Value': '3',
1114 'uint32Value': 4, 'stringValue': 'bla'},
1115 indent=2, sort_keys=True))
1118 if __name__ == '__main__':