• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc.  All rights reserved.
3#
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file or at
6# https://developers.google.com/open-source/licenses/bsd
7
8"""Test for google.protobuf.json_format."""
9
10__author__ = 'jieluo@google.com (Jie Luo)'
11
12import json
13import math
14import struct
15import unittest
16
17from google.protobuf import descriptor_pool
18from google.protobuf import json_format
19from google.protobuf.internal import more_messages_pb2
20from google.protobuf.internal import test_proto2_pb2
21from google.protobuf.internal import test_proto3_optional_pb2
22
23from google.protobuf import any_pb2
24from google.protobuf import duration_pb2
25from google.protobuf import field_mask_pb2
26from google.protobuf import struct_pb2
27from google.protobuf import timestamp_pb2
28from google.protobuf import wrappers_pb2
29from google.protobuf import any_test_pb2
30from google.protobuf import unittest_mset_pb2
31from google.protobuf import unittest_pb2
32from google.protobuf.util import json_format_pb2
33from google.protobuf.util import json_format_proto3_pb2
34
35
36class JsonFormatBase(unittest.TestCase):
37
38  def FillAllFields(self, message):
39    message.int32_value = 20
40    message.int64_value = -20
41    message.uint32_value = 3120987654
42    message.uint64_value = 12345678900
43    message.float_value = float('-inf')
44    message.double_value = 3.1415
45    message.bool_value = True
46    message.string_value = 'foo'
47    message.bytes_value = b'bar'
48    message.message_value.value = 10
49    message.enum_value = json_format_proto3_pb2.BAR
50    # Repeated
51    message.repeated_int32_value.append(0x7FFFFFFF)
52    message.repeated_int32_value.append(-2147483648)
53    message.repeated_int64_value.append(9007199254740992)
54    message.repeated_int64_value.append(-9007199254740992)
55    message.repeated_uint32_value.append(0xFFFFFFF)
56    message.repeated_uint32_value.append(0x7FFFFFF)
57    message.repeated_uint64_value.append(9007199254740992)
58    message.repeated_uint64_value.append(9007199254740991)
59    message.repeated_float_value.append(0)
60
61    message.repeated_double_value.append(1e-15)
62    message.repeated_double_value.append(float('inf'))
63    message.repeated_bool_value.append(True)
64    message.repeated_bool_value.append(False)
65    message.repeated_string_value.append('Few symbols!#$,;')
66    message.repeated_string_value.append('bar')
67    message.repeated_bytes_value.append(b'foo')
68    message.repeated_bytes_value.append(b'bar')
69    message.repeated_message_value.add().value = 10
70    message.repeated_message_value.add().value = 11
71    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
72    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
73    self.message = message
74
75  def CheckParseBack(self, message, parsed_message):
76    json_format.Parse(json_format.MessageToJson(message), parsed_message)
77    self.assertEqual(message, parsed_message)
78
79  def CheckError(self, text, error_message):
80    message = json_format_proto3_pb2.TestMessage()
81    self.assertRaisesRegex(
82        json_format.ParseError, error_message, json_format.Parse, text, message
83    )
84
85
86class JsonFormatTest(JsonFormatBase):
87
88  def testEmptyMessageToJson(self):
89    message = json_format_proto3_pb2.TestMessage()
90    self.assertEqual(json_format.MessageToJson(message), '{}')
91    parsed_message = json_format_proto3_pb2.TestMessage()
92    self.CheckParseBack(message, parsed_message)
93
94  def testPartialMessageToJson(self):
95    message = json_format_proto3_pb2.TestMessage(
96        string_value='test', repeated_int32_value=[89, 4]
97    )
98    self.assertEqual(
99        json.loads(json_format.MessageToJson(message)),
100        json.loads('{"stringValue": "test", "repeatedInt32Value": [89, 4]}'),
101    )
102    parsed_message = json_format_proto3_pb2.TestMessage()
103    self.CheckParseBack(message, parsed_message)
104
105  def testAllFieldsToJson(self):
106    message = json_format_proto3_pb2.TestMessage()
107    text = (
108        '{"int32Value": 20, '
109        '"int64Value": "-20", '
110        '"uint32Value": 3120987654,'
111        '"uint64Value": "12345678900",'
112        '"floatValue": "-Infinity",'
113        '"doubleValue": 3.1415,'
114        '"boolValue": true,'
115        '"stringValue": "foo",'
116        '"bytesValue": "YmFy",'
117        '"messageValue": {"value": 10},'
118        '"enumValue": "BAR",'
119        '"repeatedInt32Value": [2147483647, -2147483648],'
120        '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
121        '"repeatedUint32Value": [268435455, 134217727],'
122        '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
123        '"repeatedFloatValue": [0],'
124        '"repeatedDoubleValue": [1e-15, "Infinity"],'
125        '"repeatedBoolValue": [true, false],'
126        '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
127        '"repeatedBytesValue": ["Zm9v", "YmFy"],'
128        '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
129        '"repeatedEnumValue": ["FOO", "BAR"]'
130        '}'
131    )
132    self.FillAllFields(message)
133    self.assertEqual(
134        json.loads(json_format.MessageToJson(message)), json.loads(text)
135    )
136    parsed_message = json_format_proto3_pb2.TestMessage()
137    json_format.Parse(text, parsed_message)
138    self.assertEqual(message, parsed_message)
139
140  def testUnknownEnumToJsonAndBack(self):
141    text = '{\n  "enumValue": 999\n}'
142    message = json_format_proto3_pb2.TestMessage()
143    message.enum_value = 999
144    self.assertEqual(json_format.MessageToJson(message), text)
145    parsed_message = json_format_proto3_pb2.TestMessage()
146    json_format.Parse(text, parsed_message)
147    self.assertEqual(message, parsed_message)
148
149  def testExtensionToJsonAndBack(self):
150    message = unittest_mset_pb2.TestMessageSetContainer()
151    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
152    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
153    message.message_set.Extensions[ext1].i = 23
154    message.message_set.Extensions[ext2].str = 'foo'
155    message_text = json_format.MessageToJson(message)
156    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
157    json_format.Parse(message_text, parsed_message)
158    self.assertEqual(message, parsed_message)
159
160  def testExtensionErrors(self):
161    self.CheckError(
162        '{"[extensionField]": {}}',
163        'Message type proto3.TestMessage does not have extensions',
164    )
165
166  def testExtensionToDictAndBack(self):
167    message = unittest_mset_pb2.TestMessageSetContainer()
168    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
169    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
170    message.message_set.Extensions[ext1].i = 23
171    message.message_set.Extensions[ext2].str = 'foo'
172    message_dict = json_format.MessageToDict(message)
173    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
174    json_format.ParseDict(message_dict, parsed_message)
175    self.assertEqual(message, parsed_message)
176
177  def testExtensionToDictAndBackWithScalar(self):
178    message = unittest_pb2.TestAllExtensions()
179    ext1 = unittest_pb2.TestNestedExtension.test
180    message.Extensions[ext1] = 'data'
181    message_dict = json_format.MessageToDict(message)
182    parsed_message = unittest_pb2.TestAllExtensions()
183    json_format.ParseDict(message_dict, parsed_message)
184    self.assertEqual(message, parsed_message)
185
186  def testJsonParseDictToAnyDoesNotAlterInput(self):
187    orig_dict = {
188        'int32Value': 20,
189        '@type': 'type.googleapis.com/proto3.TestMessage',
190    }
191    copied_dict = json.loads(json.dumps(orig_dict))
192    parsed_message = any_pb2.Any()
193    json_format.ParseDict(copied_dict, parsed_message)
194    self.assertEqual(copied_dict, orig_dict)
195
196  def testExtensionSerializationDictMatchesProto3Spec(self):
197    """See go/proto3-json-spec for spec."""
198    message = unittest_mset_pb2.TestMessageSetContainer()
199    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
200    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
201    message.message_set.Extensions[ext1].i = 23
202    message.message_set.Extensions[ext2].str = 'foo'
203    message_dict = json_format.MessageToDict(message)
204    golden_dict = {
205        'messageSet': {
206            '[protobuf_unittest.TestMessageSetExtension1.message_set_extension]': {
207                'i': 23,
208            },
209            '[protobuf_unittest.TestMessageSetExtension2.message_set_extension]': {
210                'str': 'foo',
211            },
212        },
213    }
214    self.assertEqual(golden_dict, message_dict)
215    parsed_msg = unittest_mset_pb2.TestMessageSetContainer()
216    json_format.ParseDict(golden_dict, parsed_msg)
217    self.assertEqual(message, parsed_msg)
218
219  def testExtensionSerializationDictMatchesProto3SpecMore(self):
220    """See go/proto3-json-spec for spec."""
221    message = json_format_pb2.TestMessageWithExtension()
222    ext = json_format_pb2.TestExtension.ext
223    message.Extensions[ext].value = 'stuff'
224    message_dict = json_format.MessageToDict(message)
225    expected_dict = {
226        '[protobuf_unittest.TestExtension.ext]': {
227            'value': 'stuff',
228        },
229    }
230    self.assertEqual(expected_dict, message_dict)
231
232  def testExtensionSerializationJsonMatchesProto3Spec(self):
233    """See go/proto3-json-spec for spec."""
234    message = unittest_mset_pb2.TestMessageSetContainer()
235    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
236    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
237    message.message_set.Extensions[ext1].i = 23
238    message.message_set.Extensions[ext2].str = 'foo'
239    message_text = json_format.MessageToJson(message)
240    ext1_text = 'protobuf_unittest.TestMessageSetExtension1.message_set_extension'
241    ext2_text = 'protobuf_unittest.TestMessageSetExtension2.message_set_extension'
242    golden_text = (
243        '{"messageSet": {'
244        '    "[%s]": {'
245        '        "i": 23'
246        '    },'
247        '    "[%s]": {'
248        '        "str": "foo"'
249        '    }'
250        '}}'
251    ) % (ext1_text, ext2_text)
252    self.assertEqual(json.loads(golden_text), json.loads(message_text))
253
254  def testJsonEscapeString(self):
255    message = json_format_proto3_pb2.TestMessage()
256    message.string_value = '&\n<"\r>\b\t\f\\\001/'
257    message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
258    self.assertEqual(
259        json_format.MessageToJson(message),
260        '{\n  "stringValue": '
261        '"&\\n<\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}',
262    )
263    parsed_message = json_format_proto3_pb2.TestMessage()
264    self.CheckParseBack(message, parsed_message)
265    text = '{"int32Value": "\u0031"}'
266    json_format.Parse(text, message)
267    self.assertEqual(message.int32_value, 1)
268
269  def testProto3Optional_IncludingDefaultValueWithoutPresenceFields(self):
270    message = test_proto3_optional_pb2.TestProto3Optional()
271    self.assertEqual(
272        json.loads(
273            json_format.MessageToJson(
274                message, always_print_fields_with_no_presence=True
275            )
276        ),
277        json.loads('{"repeatedInt32": [], "repeatedNestedMessage": []}'),
278    )
279    message.optional_int32 = 0
280    self.assertEqual(
281        json.loads(
282            json_format.MessageToJson(
283                message, always_print_fields_with_no_presence=True
284            )
285        ),
286        json.loads(
287            '{"optionalInt32": 0,"repeatedInt32": [],'
288            ' "repeatedNestedMessage": []}'
289        ),
290    )
291
292  def testProto2_IncludingDefaultValueWithoutPresenceFields(self):
293    message = test_proto2_pb2.TestProto2()
294    self.assertEqual(
295        json.loads(
296            json_format.MessageToJson(
297                message, always_print_fields_with_no_presence=True
298            )
299        ),
300        json.loads('{"repeatedInt32": [], "repeatedNestedMessage": []}'),
301    )
302    message.optional_int32 = 0
303    self.assertEqual(
304        json.loads(
305            json_format.MessageToJson(
306                message, always_print_fields_with_no_presence=True
307            )
308        ),
309        json.loads(
310            '{"optionalInt32": 0,"repeatedInt32": [],'
311            ' "repeatedNestedMessage": []}'
312        ),
313    )
314
315  def testIntegersRepresentedAsFloat(self):
316    message = json_format_proto3_pb2.TestMessage()
317    json_format.Parse('{"int32Value": -2.147483648e9}', message)
318    self.assertEqual(message.int32_value, -2147483648)
319    json_format.Parse('{"int32Value": 1e5}', message)
320    self.assertEqual(message.int32_value, 100000)
321    json_format.Parse('{"int32Value": 1.0}', message)
322    self.assertEqual(message.int32_value, 1)
323
324  def testMapFields(self):
325    message = json_format_proto3_pb2.TestNestedMap()
326    self.assertEqual(
327        json.loads(
328            json_format.MessageToJson(
329                message, always_print_fields_with_no_presence=True
330            )
331        ),
332        json.loads(
333            '{'
334            '"boolMap": {},'
335            '"int32Map": {},'
336            '"int64Map": {},'
337            '"uint32Map": {},'
338            '"uint64Map": {},'
339            '"stringMap": {},'
340            '"mapMap": {}'
341            '}'
342        ),
343    )
344    message.bool_map[True] = 1
345    message.bool_map[False] = 2
346    message.int32_map[1] = 2
347    message.int32_map[2] = 3
348    message.int64_map[1] = 2
349    message.int64_map[2] = 3
350    message.uint32_map[1] = 2
351    message.uint32_map[2] = 3
352    message.uint64_map[1] = 2
353    message.uint64_map[2] = 3
354    message.string_map['1'] = 2
355    message.string_map['null'] = 3
356    message.map_map['1'].bool_map[True] = 3
357    self.assertEqual(
358        json.loads(
359            json_format.MessageToJson(
360                message, always_print_fields_with_no_presence=False
361            )
362        ),
363        json.loads(
364            '{'
365            '"boolMap": {"false": 2, "true": 1},'
366            '"int32Map": {"1": 2, "2": 3},'
367            '"int64Map": {"1": 2, "2": 3},'
368            '"uint32Map": {"1": 2, "2": 3},'
369            '"uint64Map": {"1": 2, "2": 3},'
370            '"stringMap": {"1": 2, "null": 3},'
371            '"mapMap": {"1": {"boolMap": {"true": 3}}}'
372            '}'
373        ),
374    )
375    parsed_message = json_format_proto3_pb2.TestNestedMap()
376    self.CheckParseBack(message, parsed_message)
377
378  def testOneofFields(self):
379    message = json_format_proto3_pb2.TestOneof()
380    # Always print does not affect oneof fields.
381    self.assertEqual(
382        json_format.MessageToJson(
383            message, always_print_fields_with_no_presence=True
384        ),
385        '{}',
386    )
387    message.oneof_int32_value = 0
388    self.assertEqual(
389        json_format.MessageToJson(
390            message, always_print_fields_with_no_presence=True
391        ),
392        '{\n  "oneofInt32Value": 0\n}',
393    )
394    parsed_message = json_format_proto3_pb2.TestOneof()
395    self.CheckParseBack(message, parsed_message)
396
397  def testSurrogates(self):
398    # Test correct surrogate handling.
399    message = json_format_proto3_pb2.TestMessage()
400    json_format.Parse('{"stringValue": "\\uD83D\\uDE01"}', message)
401    self.assertEqual(
402        message.string_value, b'\xF0\x9F\x98\x81'.decode('utf-8', 'strict')
403    )
404
405    # Error case: unpaired high surrogate.
406    self.CheckError(
407        '{"stringValue": "\\uD83D"}',
408        r'Invalid \\uXXXX escape|Unpaired.*surrogate',
409    )
410
411    # Unpaired low surrogate.
412    self.CheckError(
413        '{"stringValue": "\\uDE01"}',
414        r'Invalid \\uXXXX escape|Unpaired.*surrogate',
415    )
416
417  def testTimestampMessage(self):
418    message = json_format_proto3_pb2.TestTimestamp()
419    message.value.seconds = 0
420    message.value.nanos = 0
421    message.repeated_value.add().seconds = 20
422    message.repeated_value[0].nanos = 1
423    message.repeated_value.add().seconds = 0
424    message.repeated_value[1].nanos = 10000
425    message.repeated_value.add().seconds = 100000000
426    message.repeated_value[2].nanos = 0
427    # Maximum time
428    message.repeated_value.add().seconds = 253402300799
429    message.repeated_value[3].nanos = 999999999
430    # Minimum time
431    message.repeated_value.add().seconds = -62135596800
432    message.repeated_value[4].nanos = 0
433    self.assertEqual(
434        json.loads(
435            json_format.MessageToJson(
436                message, always_print_fields_with_no_presence=True
437            )
438        ),
439        json.loads(
440            '{'
441            '"value": "1970-01-01T00:00:00Z",'
442            '"repeatedValue": ['
443            '  "1970-01-01T00:00:20.000000001Z",'
444            '  "1970-01-01T00:00:00.000010Z",'
445            '  "1973-03-03T09:46:40Z",'
446            '  "9999-12-31T23:59:59.999999999Z",'
447            '  "0001-01-01T00:00:00Z"'
448            ']'
449            '}'
450        ),
451    )
452    parsed_message = json_format_proto3_pb2.TestTimestamp()
453    self.CheckParseBack(message, parsed_message)
454    text = (
455        r'{"value": "1970-01-01T00:00:00.01+08:00",'
456        r'"repeatedValue":['
457        r'  "1970-01-01T00:00:00.01+08:30",'
458        r'  "1970-01-01T00:00:00.01-01:23"]}'
459    )
460    json_format.Parse(text, parsed_message)
461    self.assertEqual(parsed_message.value.seconds, -8 * 3600)
462    self.assertEqual(parsed_message.value.nanos, 10000000)
463    self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
464    self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
465
466  def testDurationMessage(self):
467    message = json_format_proto3_pb2.TestDuration()
468    message.value.seconds = 1
469    message.repeated_value.add().seconds = 0
470    message.repeated_value[0].nanos = 10
471    message.repeated_value.add().seconds = -1
472    message.repeated_value[1].nanos = -1000
473    message.repeated_value.add().seconds = 10
474    message.repeated_value[2].nanos = 11000000
475    message.repeated_value.add().seconds = -315576000000
476    message.repeated_value.add().seconds = 315576000000
477    self.assertEqual(
478        json.loads(
479            json_format.MessageToJson(
480                message, always_print_fields_with_no_presence=True
481            )
482        ),
483        json.loads(
484            '{'
485            '"value": "1s",'
486            '"repeatedValue": ['
487            '  "0.000000010s",'
488            '  "-1.000001s",'
489            '  "10.011s",'
490            '  "-315576000000s",'
491            '  "315576000000s"'
492            ']'
493            '}'
494        ),
495    )
496    parsed_message = json_format_proto3_pb2.TestDuration()
497    self.CheckParseBack(message, parsed_message)
498
499  def testFieldMaskMessage(self):
500    message = json_format_proto3_pb2.TestFieldMask()
501    message.value.paths.append('foo.bar')
502    message.value.paths.append('bar')
503    self.assertEqual(
504        json_format.MessageToJson(
505            message, always_print_fields_with_no_presence=True
506        ),
507        '{\n  "value": "foo.bar,bar"\n}',
508    )
509    parsed_message = json_format_proto3_pb2.TestFieldMask()
510    self.CheckParseBack(message, parsed_message)
511
512    message.value.Clear()
513    self.assertEqual(
514        json_format.MessageToJson(
515            message, always_print_fields_with_no_presence=True
516        ),
517        '{\n  "value": ""\n}',
518    )
519    self.CheckParseBack(message, parsed_message)
520
521  def testWrapperMessage(self):
522    message = json_format_proto3_pb2.TestWrapper()
523    message.bool_value.value = False
524    message.int32_value.value = 0
525    message.string_value.value = ''
526    message.bytes_value.value = b''
527    message.repeated_bool_value.add().value = True
528    message.repeated_bool_value.add().value = False
529    message.repeated_int32_value.add()
530    self.assertEqual(
531        json.loads(
532            json_format.MessageToJson(
533                message, always_print_fields_with_no_presence=True
534            )
535        ),
536        json.loads(
537            '{\n'
538            '  "int32Value": 0,'
539            '  "boolValue": false,'
540            '  "stringValue": "",'
541            '  "bytesValue": "",'
542            '  "repeatedBoolValue": [true, false],'
543            '  "repeatedInt32Value": [0],'
544            '  "repeatedUint32Value": [],'
545            '  "repeatedFloatValue": [],'
546            '  "repeatedDoubleValue": [],'
547            '  "repeatedBytesValue": [],'
548            '  "repeatedInt64Value": [],'
549            '  "repeatedUint64Value": [],'
550            '  "repeatedStringValue": []'
551            '}'
552        ),
553    )
554    parsed_message = json_format_proto3_pb2.TestWrapper()
555    self.CheckParseBack(message, parsed_message)
556
557  def testStructMessage(self):
558    message = json_format_proto3_pb2.TestStruct()
559    message.value['name'] = 'Jim'
560    message.value['age'] = 10
561    message.value['attend'] = True
562    message.value['email'] = None
563    message.value.get_or_create_struct('address')['city'] = 'SFO'
564    message.value['address']['house_number'] = 1024
565    message.value.get_or_create_struct('empty_struct')
566    message.value.get_or_create_list('empty_list')
567    struct_list = message.value.get_or_create_list('list')
568    struct_list.extend([6, 'seven', True, False, None])
569    struct_list.add_struct()['subkey2'] = 9
570    message.repeated_value.add()['age'] = 11
571    message.repeated_value.add()
572    self.assertEqual(
573        json.loads(
574            json_format.MessageToJson(
575                message, always_print_fields_with_no_presence=False
576            )
577        ),
578        json.loads(
579            '{'
580            '  "value": {'
581            '    "address": {'
582            '      "city": "SFO", '
583            '      "house_number": 1024'
584            '    }, '
585            '    "empty_struct": {}, '
586            '    "empty_list": [], '
587            '    "age": 10, '
588            '    "name": "Jim", '
589            '    "attend": true, '
590            '    "email": null, '
591            '    "list": [6, "seven", true, false, null, {"subkey2": 9}]'
592            '  },'
593            '  "repeatedValue": [{"age": 11}, {}]'
594            '}'
595        ),
596    )
597    parsed_message = json_format_proto3_pb2.TestStruct()
598    self.CheckParseBack(message, parsed_message)
599    # check for regression; this used to raise
600    parsed_message.value['empty_struct']
601    parsed_message.value['empty_list']
602
603  def testValueMessage(self):
604    message = json_format_proto3_pb2.TestValue()
605    message.value.string_value = 'hello'
606    message.repeated_value.add().number_value = 11.1
607    message.repeated_value.add().bool_value = False
608    message.repeated_value.add().null_value = 0
609    self.assertEqual(
610        json.loads(
611            json_format.MessageToJson(
612                message, always_print_fields_with_no_presence=False
613            )
614        ),
615        json.loads(
616            '{  "value": "hello",  "repeatedValue": [11.1, false, null]}'
617        ),
618    )
619    parsed_message = json_format_proto3_pb2.TestValue()
620    self.CheckParseBack(message, parsed_message)
621    # Can't parse back if the Value message is not set.
622    message.repeated_value.add()
623    self.assertEqual(
624        json.loads(
625            json_format.MessageToJson(
626                message, always_print_fields_with_no_presence=False
627            )
628        ),
629        json.loads(
630            '{  "value": "hello",  "repeatedValue": [11.1, false, null, null]}'
631        ),
632    )
633    message.Clear()
634    json_format.Parse('{"value": null}', message)
635    self.assertEqual(message.value.WhichOneof('kind'), 'null_value')
636
637  def testValueMessageErrors(self):
638    message = json_format_proto3_pb2.TestValue()
639    message.value.number_value = math.inf
640    with self.assertRaises(json_format.SerializeToJsonError) as cm:
641      json_format.MessageToJson(message)
642    self.assertEqual(
643        'Failed to serialize value field: Fail to serialize Infinity for '
644        'Value.number_value, which would parse as string_value.',
645        str(cm.exception),
646    )
647    message.value.number_value = math.nan
648    with self.assertRaises(json_format.SerializeToJsonError) as cm:
649      json_format.MessageToJson(message)
650    self.assertEqual(
651        'Failed to serialize value field: Fail to serialize NaN for '
652        'Value.number_value, which would parse as string_value.',
653        str(cm.exception),
654    )
655
656  def testListValueMessage(self):
657    message = json_format_proto3_pb2.TestListValue()
658    message.value.values.add().number_value = 11.1
659    message.value.values.add().null_value = 0
660    message.value.values.add().bool_value = True
661    message.value.values.add().string_value = 'hello'
662    message.value.values.add().struct_value['name'] = 'Jim'
663    message.repeated_value.add().values.add().number_value = 1
664    message.repeated_value.add()
665    self.assertEqual(
666        json.loads(
667            json_format.MessageToJson(
668                message, always_print_fields_with_no_presence=False
669            )
670        ),
671        json.loads(
672            '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
673            '"repeatedValue": [[1], []]}'
674        ),
675    )
676    parsed_message = json_format_proto3_pb2.TestListValue()
677    self.CheckParseBack(message, parsed_message)
678
679  def testNullValue(self):
680    message = json_format_proto3_pb2.TestOneof()
681    message.oneof_null_value = 0
682    self.assertEqual(
683        json_format.MessageToJson(message), '{\n  "oneofNullValue": null\n}'
684    )
685    parsed_message = json_format_proto3_pb2.TestOneof()
686    self.CheckParseBack(message, parsed_message)
687    # Check old format is also accepted
688    new_message = json_format_proto3_pb2.TestOneof()
689    json_format.Parse('{\n  "oneofNullValue": "NULL_VALUE"\n}', new_message)
690    self.assertEqual(
691        json_format.MessageToJson(new_message), '{\n  "oneofNullValue": null\n}'
692    )
693
694  def testAnyMessage(self):
695    message = json_format_proto3_pb2.TestAny()
696    value1 = json_format_proto3_pb2.MessageType()
697    value2 = json_format_proto3_pb2.MessageType()
698    value1.value = 1234
699    value2.value = 5678
700    message.value.Pack(value1)
701    message.repeated_value.add().Pack(value1)
702    message.repeated_value.add().Pack(value2)
703    message.repeated_value.add()
704    self.assertEqual(
705        json.loads(
706            json_format.MessageToJson(
707                message, always_print_fields_with_no_presence=True
708            )
709        ),
710        json.loads(
711            '{\n'
712            '  "repeatedValue": [ {\n'
713            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
714            '    "value": 1234\n'
715            '  }, {\n'
716            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
717            '    "value": 5678\n'
718            '  },\n'
719            '  {}],\n'
720            '  "value": {\n'
721            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
722            '    "value": 1234\n'
723            '  }\n'
724            '}\n'
725        ),
726    )
727    parsed_message = json_format_proto3_pb2.TestAny()
728    self.CheckParseBack(message, parsed_message)
729    # Must print @type first
730    test_message = json_format_proto3_pb2.TestMessage(
731        bool_value=True,
732        int32_value=20,
733        int64_value=-20,
734        uint32_value=20,
735        uint64_value=20,
736        double_value=3.14,
737        string_value='foo',
738    )
739    message.Clear()
740    message.value.Pack(test_message)
741    self.assertEqual(
742        json_format.MessageToJson(
743            message, always_print_fields_with_no_presence=False
744        )[0:68],
745        '{\n'
746        '  "value": {\n'
747        '    "@type": "type.googleapis.com/proto3.TestMessage"',
748    )
749
750  def testAnyMessageDescriptorPoolMissingType(self):
751    packed_message = unittest_pb2.OneString()
752    packed_message.data = 'string'
753    message = any_test_pb2.TestAny()
754    message.any_value.Pack(packed_message)
755    empty_pool = descriptor_pool.DescriptorPool()
756    with self.assertRaises(TypeError) as cm:
757      json_format.MessageToJson(
758          message,
759          always_print_fields_with_no_presence=True,
760          descriptor_pool=empty_pool,
761      )
762    self.assertEqual(
763        'Can not find message descriptor by type_url:'
764        ' type.googleapis.com/protobuf_unittest.OneString',
765        str(cm.exception),
766    )
767
768  def testWellKnownInAnyMessage(self):
769    message = any_pb2.Any()
770    int32_value = wrappers_pb2.Int32Value()
771    int32_value.value = 1234
772    message.Pack(int32_value)
773    self.assertEqual(
774        json.loads(
775            json_format.MessageToJson(
776                message, always_print_fields_with_no_presence=True
777            )
778        ),
779        json.loads(
780            '{\n'
781            '  "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
782            '  "value": 1234\n'
783            '}\n'
784        ),
785    )
786    parsed_message = any_pb2.Any()
787    self.CheckParseBack(message, parsed_message)
788
789    timestamp = timestamp_pb2.Timestamp()
790    message.Pack(timestamp)
791    self.assertEqual(
792        json.loads(
793            json_format.MessageToJson(
794                message, always_print_fields_with_no_presence=True
795            )
796        ),
797        json.loads(
798            '{\n'
799            '  "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
800            '  "value": "1970-01-01T00:00:00Z"\n'
801            '}\n'
802        ),
803    )
804    self.CheckParseBack(message, parsed_message)
805
806    duration = duration_pb2.Duration()
807    duration.seconds = 1
808    message.Pack(duration)
809    self.assertEqual(
810        json.loads(
811            json_format.MessageToJson(
812                message, always_print_fields_with_no_presence=True
813            )
814        ),
815        json.loads(
816            '{\n'
817            '  "@type": "type.googleapis.com/google.protobuf.Duration",\n'
818            '  "value": "1s"\n'
819            '}\n'
820        ),
821    )
822    self.CheckParseBack(message, parsed_message)
823
824    field_mask = field_mask_pb2.FieldMask()
825    field_mask.paths.append('foo.bar')
826    field_mask.paths.append('bar')
827    message.Pack(field_mask)
828    self.assertEqual(
829        json.loads(
830            json_format.MessageToJson(
831                message, always_print_fields_with_no_presence=True
832            )
833        ),
834        json.loads(
835            '{\n'
836            '  "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
837            '  "value": "foo.bar,bar"\n'
838            '}\n'
839        ),
840    )
841    self.CheckParseBack(message, parsed_message)
842
843    struct_message = struct_pb2.Struct()
844    struct_message['name'] = 'Jim'
845    message.Pack(struct_message)
846    self.assertEqual(
847        json.loads(
848            json_format.MessageToJson(
849                message, always_print_fields_with_no_presence=True
850            )
851        ),
852        json.loads(
853            '{\n'
854            '  "@type": "type.googleapis.com/google.protobuf.Struct",\n'
855            '  "value": {"name": "Jim"}\n'
856            '}\n'
857        ),
858    )
859    self.CheckParseBack(message, parsed_message)
860
861    nested_any = any_pb2.Any()
862    int32_value.value = 5678
863    nested_any.Pack(int32_value)
864    message.Pack(nested_any)
865    self.assertEqual(
866        json.loads(
867            json_format.MessageToJson(
868                message, always_print_fields_with_no_presence=True
869            )
870        ),
871        json.loads(
872            '{\n'
873            '  "@type": "type.googleapis.com/google.protobuf.Any",\n'
874            '  "value": {\n'
875            '    "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
876            '    "value": 5678\n'
877            '  }\n'
878            '}\n'
879        ),
880    )
881    self.CheckParseBack(message, parsed_message)
882
883  def testParseNull(self):
884    message = json_format_proto3_pb2.TestMessage()
885    parsed_message = json_format_proto3_pb2.TestMessage()
886    self.FillAllFields(parsed_message)
887    json_format.Parse(
888        '{"int32Value": null, '
889        '"int64Value": null, '
890        '"uint32Value": null,'
891        '"uint64Value": null,'
892        '"floatValue": null,'
893        '"doubleValue": null,'
894        '"boolValue": null,'
895        '"stringValue": null,'
896        '"bytesValue": null,'
897        '"messageValue": null,'
898        '"enumValue": null,'
899        '"repeatedInt32Value": null,'
900        '"repeatedInt64Value": null,'
901        '"repeatedUint32Value": null,'
902        '"repeatedUint64Value": null,'
903        '"repeatedFloatValue": null,'
904        '"repeatedDoubleValue": null,'
905        '"repeatedBoolValue": null,'
906        '"repeatedStringValue": null,'
907        '"repeatedBytesValue": null,'
908        '"repeatedMessageValue": null,'
909        '"repeatedEnumValue": null'
910        '}',
911        parsed_message,
912    )
913    self.assertEqual(message, parsed_message)
914    # Null and {} should have different behavior for sub message.
915    self.assertFalse(parsed_message.HasField('message_value'))
916    json_format.Parse('{"messageValue": {}}', parsed_message)
917    self.assertTrue(parsed_message.HasField('message_value'))
918    # Null is not allowed to be used as an element in repeated field.
919    self.assertRaisesRegex(
920        json_format.ParseError,
921        r'Failed to parse repeatedInt32Value field: '
922        r'null is not allowed to be used as an element in a repeated field '
923        r'at TestMessage.repeatedInt32Value\[1\].',
924        json_format.Parse,
925        '{"repeatedInt32Value":[1, null]}',
926        parsed_message,
927    )
928    self.CheckError(
929        '{"repeatedMessageValue":[null]}',
930        r'Failed to parse repeatedMessageValue field: null is not'
931        r' allowed to be used as an element in a repeated field '
932        r'at TestMessage.repeatedMessageValue\[0\].',
933    )
934
935  def testNanFloat(self):
936    message = json_format_proto3_pb2.TestMessage()
937    message.float_value = float('nan')
938    text = '{\n  "floatValue": "NaN"\n}'
939    self.assertEqual(json_format.MessageToJson(message), text)
940    parsed_message = json_format_proto3_pb2.TestMessage()
941    json_format.Parse(text, parsed_message)
942    self.assertTrue(math.isnan(parsed_message.float_value))
943
944  def testParseDoubleToFloat(self):
945    message = json_format_proto3_pb2.TestMessage()
946    text = '{"repeatedDoubleValue": [3.4028235e+39, 1.4028235e-39]\n}'
947    json_format.Parse(text, message)
948    self.assertEqual(message.repeated_double_value[0], 3.4028235e39)
949    self.assertEqual(message.repeated_double_value[1], 1.4028235e-39)
950    text = '{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}'
951    self.CheckError(
952        text,
953        r'Failed to parse repeatedFloatValue field: '
954        r'Float value too large at TestMessage.repeatedFloatValue\[0\].',
955    )
956
957  def testFloatPrecision(self):
958    message = json_format_proto3_pb2.TestMessage()
959    message.float_value = 1.123456789
960    # Set to 8 valid digits.
961    text = '{\n  "floatValue": 1.1234568\n}'
962    self.assertEqual(
963        json_format.MessageToJson(message, float_precision=8), text
964    )
965    # Set to 7 valid digits.
966    text = '{\n  "floatValue": 1.123457\n}'
967    self.assertEqual(
968        json_format.MessageToJson(message, float_precision=7), text
969    )
970
971    # Default float_precision will automatic print shortest float.
972    message.float_value = 1.1000000011
973    text = '{\n  "floatValue": 1.1\n}'
974    self.assertEqual(json_format.MessageToJson(message), text)
975    message.float_value = 1.00000075e-36
976    text = '{\n  "floatValue": 1.00000075e-36\n}'
977    self.assertEqual(json_format.MessageToJson(message), text)
978    message.float_value = 12345678912345e11
979    text = '{\n  "floatValue": 1.234568e+24\n}'
980    self.assertEqual(json_format.MessageToJson(message), text)
981
982    # Test a bunch of data and check json encode/decode do not
983    # lose precision
984    value_list = [0x00, 0xD8, 0x6E, 0x00]
985    msg2 = json_format_proto3_pb2.TestMessage()
986    for a in range(0, 256):
987      value_list[3] = a
988      for b in range(0, 256):
989        value_list[0] = b
990        byte_array = bytearray(value_list)
991        message.float_value = struct.unpack('<f', byte_array)[0]
992        self.CheckParseBack(message, msg2)
993
994  def testParseEmptyText(self):
995    self.CheckError('', r'Failed to load JSON: (Expecting value)|(No JSON).')
996
997  def testParseEnumValue(self):
998    message = json_format_proto3_pb2.TestMessage()
999    text = '{"enumValue": 0}'
1000    json_format.Parse(text, message)
1001    text = '{"enumValue": 1}'
1002    json_format.Parse(text, message)
1003    self.CheckError(
1004        '{"enumValue": "baz"}',
1005        'Failed to parse enumValue field: Invalid enum value baz '
1006        'for enum type proto3.EnumType at TestMessage.enumValue.',
1007    )
1008    # Proto3 accepts numeric unknown enums.
1009    text = '{"enumValue": 12345}'
1010    json_format.Parse(text, message)
1011    # Proto2 does not accept numeric unknown enums.
1012    message = unittest_pb2.TestAllTypes()
1013    self.assertRaisesRegex(
1014        json_format.ParseError,
1015        'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
1016        'for enum type protobuf_unittest.TestAllTypes.NestedEnum at '
1017        'TestAllTypes.optionalNestedEnum.',
1018        json_format.Parse,
1019        '{"optionalNestedEnum": 12345}',
1020        message,
1021    )
1022
1023  def testParseUnknownEnumStringValue_Scalar_Proto2(self):
1024    message = json_format_pb2.TestNumbers()
1025    text = '{"a": "UNKNOWN_STRING_VALUE"}'
1026    json_format.Parse(text, message, ignore_unknown_fields=True)
1027
1028    self.assertFalse(message.HasField('a'))
1029
1030  def testParseErrorForUnknownEnumValue_ScalarWithoutIgnore_Proto2(self):
1031    message = json_format_pb2.TestNumbers()
1032    self.assertRaisesRegex(
1033        json_format.ParseError,
1034        'Invalid enum value',
1035        json_format.Parse, '{"a": "UNKNOWN_STRING_VALUE"}', message)
1036
1037  def testParseUnknownEnumStringValue_Repeated_Proto2(self):
1038    message = json_format_pb2.TestRepeatedEnum()
1039    text = '{"repeatedEnum": ["UNKNOWN_STRING_VALUE", "BUFFER"]}'
1040    json_format.Parse(text, message, ignore_unknown_fields=True)
1041
1042    self.assertEqual(len(message.repeated_enum), 1)
1043    self.assertTrue(message.repeated_enum[0] == json_format_pb2.BUFFER)
1044
1045  def testParseUnknownEnumStringValue_Map_Proto2(self):
1046    message = json_format_pb2.TestMapOfEnums()
1047    text = '{"enumMap": {"key1": "BUFFER", "key2": "UNKNOWN_STRING_VALUE"}}'
1048    json_format.Parse(text, message, ignore_unknown_fields=True)
1049
1050    self.assertTrue(message.enum_map['key1'] == json_format_pb2.BUFFER)
1051    self.assertFalse('key2' in message.enum_map)
1052
1053  def testParseUnknownEnumStringValue_ExtensionField_Proto2(self):
1054    message = json_format_pb2.TestMessageWithExtension()
1055    text = """
1056        {"[protobuf_unittest.TestExtension.enum_ext]": "UNKNOWN_STRING_VALUE"}
1057    """
1058    json_format.Parse(text, message, ignore_unknown_fields=True)
1059
1060    self.assertFalse(json_format_pb2.TestExtension.enum_ext in
1061                     message.Extensions)
1062
1063  def testParseUnknownEnumStringValue_ExtensionFieldWithoutIgnore_Proto2(self):
1064    message = json_format_pb2.TestMessageWithExtension()
1065    text = """
1066        {"[protobuf_unittest.TestExtension.enum_ext]": "UNKNOWN_STRING_VALUE"}
1067    """
1068    self.assertRaisesRegex(
1069        json_format.ParseError,
1070        'Invalid enum value',
1071        json_format.Parse, text, message)
1072
1073  def testParseUnknownEnumStringValue_Scalar_Proto3(self):
1074    message = json_format_proto3_pb2.TestMessage()
1075    text = '{"enumValue": "UNKNOWN_STRING_VALUE"}'
1076
1077    json_format.Parse(text, message, ignore_unknown_fields=True)
1078    self.assertEqual(message.enum_value, 0)
1079
1080  def testParseUnknownEnumStringValue_Repeated_Proto3(self):
1081    message = json_format_proto3_pb2.TestMessage()
1082    text = '{"repeatedEnumValue": ["UNKNOWN_STRING_VALUE", "FOO"]}'
1083    json_format.Parse(text, message, ignore_unknown_fields=True)
1084
1085    self.assertEqual(len(message.repeated_enum_value), 1)
1086    self.assertTrue(message.repeated_enum_value[0] ==
1087                    json_format_proto3_pb2.FOO)
1088
1089  def testParseUnknownEnumStringValue_Map_Proto3(self):
1090    message = json_format_proto3_pb2.MapOfEnums()
1091    text = '{"map": {"key1": "FOO", "key2": "UNKNOWN_STRING_VALUE"}}'
1092    json_format.Parse(text, message, ignore_unknown_fields=True)
1093
1094    self.assertTrue(message.map['key1'] == json_format_proto3_pb2.FOO)
1095    self.assertFalse('key2' in message.map)
1096
1097  def testBytes(self):
1098    message = json_format_proto3_pb2.TestMessage()
1099    # Test url base64
1100    text = '{"bytesValue": "-_"}'
1101    json_format.Parse(text, message)
1102    self.assertEqual(message.bytes_value, b'\xfb')
1103    # Test padding
1104    text = '{"bytesValue": "AQI="}'
1105    json_format.Parse(text, message)
1106    self.assertEqual(message.bytes_value, b'\x01\x02')
1107    text = '{"bytesValue": "AQI"}'
1108    json_format.Parse(text, message)
1109    self.assertEqual(message.bytes_value, b'\x01\x02')
1110    text = '{"bytesValue": "AQI*"}'
1111    json_format.Parse(text, message)
1112    self.assertEqual(message.bytes_value, b'\x01\x02')
1113
1114  def testParseBadIdentifier(self):
1115    self.CheckError(
1116        '{int32Value: 1}',
1117        (
1118            r'Failed to load JSON: Expecting property name'
1119            r'( enclosed in double quotes)?: line 1'
1120        ),
1121    )
1122    self.CheckError(
1123        '{"unknownName": 1}',
1124        'Message type "proto3.TestMessage" has no field named '
1125        '"unknownName" at "TestMessage".',
1126    )
1127
1128  def testIgnoreUnknownField(self):
1129    text = '{"unknownName": 1}'
1130    parsed_message = json_format_proto3_pb2.TestMessage()
1131    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
1132    text = (
1133        '{\n'
1134        '  "repeatedValue": [ {\n'
1135        '    "@type": "type.googleapis.com/proto3.MessageType",\n'
1136        '    "unknownName": 1\n'
1137        '  }]\n'
1138        '}\n'
1139    )
1140    parsed_message = json_format_proto3_pb2.TestAny()
1141    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
1142
1143  def testDuplicateField(self):
1144    self.CheckError(
1145        '{"int32Value": 1,\n"int32Value":2}',
1146        'Failed to load JSON: duplicate key int32Value.',
1147    )
1148
1149  def testInvalidBoolValue(self):
1150    self.CheckError(
1151        '{"boolValue": 1}',
1152        'Failed to parse boolValue field: '
1153        'Expected true or false without quotes at TestMessage.boolValue.',
1154    )
1155    self.CheckError(
1156        '{"boolValue": "true"}',
1157        'Failed to parse boolValue field: '
1158        'Expected true or false without quotes at TestMessage.boolValue.',
1159    )
1160
1161  def testInvalidIntegerValue(self):
1162    message = json_format_proto3_pb2.TestMessage()
1163    text = '{"int32Value": 0x12345}'
1164    self.assertRaises(json_format.ParseError, json_format.Parse, text, message)
1165    self.CheckError(
1166        '{"int32Value": 1.5}',
1167        'Failed to parse int32Value field: '
1168        "Couldn't parse integer: 1.5 at TestMessage.int32Value.",
1169    )
1170    self.CheckError(
1171        '{"int32Value": 012345}',
1172        (r'Failed to load JSON: Expecting \'?,\'? delimiter: ' r'line 1.'),
1173    )
1174    self.CheckError(
1175        '{"int32Value": " 1 "}',
1176        'Failed to parse int32Value field: '
1177        'Couldn\'t parse integer: " 1 " at TestMessage.int32Value.',
1178    )
1179    self.CheckError(
1180        '{"int32Value": "1 "}',
1181        'Failed to parse int32Value field: '
1182        'Couldn\'t parse integer: "1 " at TestMessage.int32Value.',
1183    )
1184    self.CheckError(
1185        '{"int32Value": false}',
1186        'Failed to parse int32Value field: Bool value False '
1187        'is not acceptable for integer field at TestMessage.int32Value.',
1188    )
1189    self.CheckError(
1190        '{"int32Value": 12345678901234567890}',
1191        'Failed to parse int32Value field: Value out of range: '
1192        '12345678901234567890.',
1193    )
1194    self.CheckError(
1195        '{"uint32Value": -1}',
1196        'Failed to parse uint32Value field: Value out of range: -1.',
1197    )
1198
1199  def testInvalidFloatValue(self):
1200    self.CheckError(
1201        '{"floatValue": "nan"}',
1202        "Failed to parse floatValue field: Couldn't "
1203        'parse float "nan", use "NaN" instead at TestMessage.floatValue.',
1204    )
1205    self.CheckError(
1206        '{"floatValue": NaN}',
1207        "Failed to parse floatValue field: Couldn't "
1208        'parse NaN, use quoted "NaN" instead.',
1209    )
1210    self.CheckError(
1211        '{"floatValue": Infinity}',
1212        "Failed to parse floatValue field: Couldn't parse Infinity"
1213        ' or value too large, use quoted "Infinity" instead.',
1214    )
1215    self.CheckError(
1216        '{"floatValue": -Infinity}',
1217        "Failed to parse floatValue field: Couldn't parse "
1218        '-Infinity or value too small, '
1219        'use quoted "-Infinity" instead.',
1220    )
1221    self.CheckError(
1222        '{"doubleValue": -1.89769e+308}',
1223        "Failed to parse doubleValue field: Couldn't parse "
1224        '-Infinity or value too small, '
1225        'use quoted "-Infinity" instead.',
1226    )
1227    self.CheckError(
1228        '{"floatValue": 3.4028235e+39}',
1229        'Failed to parse floatValue field: Float value too large.',
1230    )
1231    self.CheckError(
1232        '{"floatValue": -3.502823e+38}',
1233        'Failed to parse floatValue field: Float value too small.',
1234    )
1235
1236  def testInvalidRepeated(self):
1237    self.CheckError(
1238        '{"repeatedInt32Value": 12345}',
1239        (
1240            r'Failed to parse repeatedInt32Value field: repeated field'
1241            r' repeatedInt32Value must be in \[\] which is 12345 at'
1242            r' TestMessage.'
1243        ),
1244    )
1245
1246  def testInvalidMap(self):
1247    message = json_format_proto3_pb2.TestMap()
1248    text = '{"int32Map": {"null": 2, "2": 3}}'
1249    self.assertRaisesRegex(
1250        json_format.ParseError,
1251        'Failed to parse int32Map field: invalid literal',
1252        json_format.Parse,
1253        text,
1254        message,
1255    )
1256    text = '{"int32Map": {1: 2, "2": 3}}'
1257    self.assertRaisesRegex(
1258        json_format.ParseError,
1259        (
1260            r'Failed to load JSON: Expecting property name'
1261            r'( enclosed in double quotes)?: line 1'
1262        ),
1263        json_format.Parse,
1264        text,
1265        message,
1266    )
1267    text = '{"boolMap": {"null": 1}}'
1268    self.assertRaisesRegex(
1269        json_format.ParseError,
1270        'Failed to parse boolMap field: Expected "true" or "false", not null at'
1271        ' TestMap.boolMap.key',
1272        json_format.Parse,
1273        text,
1274        message,
1275    )
1276    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
1277    self.assertRaisesRegex(
1278        json_format.ParseError,
1279        'Failed to load JSON: duplicate key a',
1280        json_format.Parse,
1281        text,
1282        message,
1283    )
1284    text = r'{"stringMap": 0}'
1285    self.assertRaisesRegex(
1286        json_format.ParseError,
1287        'Failed to parse stringMap field: Map field string_map must be '
1288        'in a dict which is 0 at TestMap.stringMap.',
1289        json_format.Parse,
1290        text,
1291        message,
1292    )
1293
1294  def testInvalidTimestamp(self):
1295    message = json_format_proto3_pb2.TestTimestamp()
1296    text = '{"value": "10000-01-01T00:00:00.00Z"}'
1297    self.assertRaisesRegex(
1298        json_format.ParseError,
1299        'Failed to parse value field: '
1300        "time data '10000-01-01T00:00:00' does not match"
1301        " format '%Y-%m-%dT%H:%M:%S' at TestTimestamp.value.",
1302        json_format.Parse,
1303        text,
1304        message,
1305    )
1306    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
1307    self.assertRaisesRegex(
1308        json_format.ParseError,
1309        'nanos 0123456789012 more than 9 fractional digits.',
1310        json_format.Parse,
1311        text,
1312        message,
1313    )
1314    text = '{"value": "1972-01-01T01:00:00.01+08"}'
1315    self.assertRaisesRegex(
1316        json_format.ParseError,
1317        r'Invalid timezone offset value: \+08.',
1318        json_format.Parse,
1319        text,
1320        message,
1321    )
1322    # Time smaller than minimum time.
1323    text = '{"value": "0000-01-01T00:00:00Z"}'
1324    self.assertRaisesRegex(
1325        json_format.ParseError,
1326        'Failed to parse value field: year (0 )?is out of range.',
1327        json_format.Parse,
1328        text,
1329        message,
1330    )
1331    # Time bigger than maximum time.
1332    message.value.seconds = 253402300800
1333    self.assertRaisesRegex(json_format.SerializeToJsonError,
1334                           'Timestamp is not valid',
1335                           json_format.MessageToJson, message)
1336    # Nanos smaller than 0
1337    message.value.seconds = 0
1338    message.value.nanos = -1
1339    self.assertRaisesRegex(
1340        json_format.SerializeToJsonError,
1341        'Timestamp is not valid',
1342        json_format.MessageToJson,
1343        message,
1344    )
1345    # Lower case t does not accept.
1346    text = '{"value": "0001-01-01t00:00:00Z"}'
1347    with self.assertRaises(json_format.ParseError) as e:
1348      json_format.Parse(text, message)
1349    self.assertEqual(
1350        'Failed to parse value field: '
1351        "time data '0001-01-01t00:00:00' does not match format "
1352        "'%Y-%m-%dT%H:%M:%S', lowercase 't' is not accepted "
1353        'at TestTimestamp.value.',
1354        str(e.exception),
1355    )
1356
1357  def testInvalidOneof(self):
1358    message = json_format_proto3_pb2.TestOneof()
1359    text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
1360    self.assertRaisesRegex(
1361        json_format.ParseError,
1362        'Message type "proto3.TestOneof"'
1363        ' should not have multiple "oneof_value" oneof fields at "TestOneof".',
1364        json_format.Parse,
1365        text,
1366        message,
1367    )
1368
1369  def testInvalidListValue(self):
1370    message = json_format_proto3_pb2.TestListValue()
1371    text = '{"value": 1234}'
1372    self.assertRaisesRegex(
1373        json_format.ParseError,
1374        r'Failed to parse value field: ListValue must be in \[\] which is '
1375        '1234 at TestListValue.value.',
1376        json_format.Parse,
1377        text,
1378        message,
1379    )
1380
1381    class UnknownClass(object):
1382
1383      def __str__(self):
1384        return 'v'
1385
1386    self.assertRaisesRegex(
1387        json_format.ParseError,
1388        r' at TestListValue.value\[1\].fake.',
1389        json_format.ParseDict,
1390        {'value': ['hello', {'fake': UnknownClass()}]},
1391        message,
1392    )
1393
1394  def testInvalidStruct(self):
1395    message = json_format_proto3_pb2.TestStruct()
1396    text = '{"value": 1234}'
1397    self.assertRaisesRegex(
1398        json_format.ParseError,
1399        'Failed to parse value field: Struct must be in a dict which is '
1400        '1234 at TestStruct.value',
1401        json_format.Parse,
1402        text,
1403        message,
1404    )
1405
1406  def testTimestampInvalidStringValue(self):
1407    message = json_format_proto3_pb2.TestTimestamp()
1408    text = '{"value": {"foo": 123}}'
1409    self.assertRaisesRegex(
1410        json_format.ParseError,
1411        r"Timestamp JSON value not a string: {u?'foo': 123}",
1412        json_format.Parse,
1413        text,
1414        message,
1415    )
1416
1417  def testDurationInvalidStringValue(self):
1418    message = json_format_proto3_pb2.TestDuration()
1419    text = '{"value": {"foo": 123}}'
1420    self.assertRaisesRegex(
1421        json_format.ParseError,
1422        r"Duration JSON value not a string: {u?'foo': 123}",
1423        json_format.Parse,
1424        text,
1425        message,
1426    )
1427
1428  def testFieldMaskInvalidStringValue(self):
1429    message = json_format_proto3_pb2.TestFieldMask()
1430    text = '{"value": {"foo": 123}}'
1431    self.assertRaisesRegex(
1432        json_format.ParseError,
1433        r"FieldMask JSON value not a string: {u?'foo': 123}",
1434        json_format.Parse,
1435        text,
1436        message,
1437    )
1438
1439  def testInvalidAny(self):
1440    message = any_pb2.Any()
1441    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
1442    self.assertRaisesRegex(json_format.ParseError, 'KeyError: \'value\'', json_format.Parse, text, message)
1443    text = '{"value": 1234}'
1444    self.assertRaisesRegex(
1445        json_format.ParseError,
1446        '@type is missing when parsing any message at Any',
1447        json_format.Parse,
1448        text,
1449        message,
1450    )
1451    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
1452    self.assertRaisesRegex(
1453        json_format.ParseError,
1454        'Can not find message descriptor by type_url: '
1455        'type.googleapis.com/MessageNotExist at Any',
1456        json_format.Parse,
1457        text,
1458        message,
1459    )
1460    # Only last part is to be used: b/25630112
1461    text = (
1462        r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
1463        r'"value": 1234}'
1464    )
1465    json_format.Parse(text, message)
1466
1467  def testPreservingProtoFieldNames(self):
1468    message = json_format_proto3_pb2.TestMessage()
1469    message.int32_value = 12345
1470    self.assertEqual(
1471        '{\n  "int32Value": 12345\n}', json_format.MessageToJson(message)
1472    )
1473    self.assertEqual(
1474        '{\n  "int32_value": 12345\n}',
1475        json_format.MessageToJson(
1476            message,
1477            always_print_fields_with_no_presence=False,
1478            preserving_proto_field_name=True,
1479        ),
1480    )
1481    # When always_print_fields_with_no_presence is True.
1482    message = json_format_proto3_pb2.TestTimestamp()
1483    self.assertEqual(
1484        '{\n  "repeatedValue": []\n}',
1485        json_format.MessageToJson(
1486            message,
1487            always_print_fields_with_no_presence=True,
1488        ),
1489    )
1490    self.assertEqual(
1491        '{\n  "repeated_value": []\n}',
1492        json_format.MessageToJson(
1493            message,
1494            always_print_fields_with_no_presence=True,
1495            preserving_proto_field_name=True,
1496        ),
1497    )
1498
1499    # Parsers accept both original proto field names and lowerCamelCase names.
1500    message = json_format_proto3_pb2.TestMessage()
1501    json_format.Parse('{"int32Value": 54321}', message)
1502    self.assertEqual(54321, message.int32_value)
1503    json_format.Parse('{"int32_value": 12345}', message)
1504    self.assertEqual(12345, message.int32_value)
1505
1506  def testIndent(self):
1507    message = json_format_proto3_pb2.TestMessage()
1508    message.int32_value = 12345
1509    self.assertEqual(
1510        '{\n"int32Value": 12345\n}',
1511        json_format.MessageToJson(message, indent=0),
1512    )
1513
1514  def testFormatEnumsAsInts(self):
1515    message = json_format_proto3_pb2.TestMessage()
1516    message.enum_value = json_format_proto3_pb2.BAR
1517    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
1518    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
1519    self.assertEqual(
1520        json.loads('{\n  "enumValue": 1,\n  "repeatedEnumValue": [0, 1]\n}\n'),
1521        json.loads(
1522            json_format.MessageToJson(message, use_integers_for_enums=True)
1523        ),
1524    )
1525
1526  def testParseDict(self):
1527    expected = 12345
1528    js_dict = {'int32Value': expected}
1529    message = json_format_proto3_pb2.TestMessage()
1530    json_format.ParseDict(js_dict, message)
1531    self.assertEqual(expected, message.int32_value)
1532
1533  def testParseDictAnyDescriptorPoolMissingType(self):
1534    # Confirm that ParseDict does not raise ParseError with default pool
1535    js_dict = {
1536        'any_value': {
1537            '@type': 'type.googleapis.com/proto3.MessageType',
1538            'value': 1234,
1539        }
1540    }
1541    json_format.ParseDict(js_dict, any_test_pb2.TestAny())
1542    # Check ParseDict raises ParseError with empty pool
1543    js_dict = {
1544        'any_value': {
1545            '@type': 'type.googleapis.com/proto3.MessageType',
1546            'value': 1234,
1547        }
1548    }
1549    with self.assertRaises(json_format.ParseError) as cm:
1550      empty_pool = descriptor_pool.DescriptorPool()
1551      json_format.ParseDict(
1552          js_dict, any_test_pb2.TestAny(), descriptor_pool=empty_pool
1553      )
1554    self.assertEqual(
1555        str(cm.exception),
1556        'Failed to parse any_value field: Can not find message descriptor by'
1557        ' type_url: type.googleapis.com/proto3.MessageType at '
1558        'TestAny.any_value.',
1559    )
1560
1561  def testParseDictUnknownValueType(self):
1562    class UnknownClass(object):
1563
1564      def __repr__(self):
1565        return 'v'
1566
1567    message = json_format_proto3_pb2.TestValue()
1568    self.assertRaisesRegex(
1569        json_format.ParseError,
1570        r"Value v has unexpected type <class '.*\.UnknownClass'>.",
1571        json_format.ParseDict,
1572        {'value': UnknownClass()},
1573        message,
1574    )
1575
1576  def testMessageToDict(self):
1577    message = json_format_proto3_pb2.TestMessage()
1578    message.int32_value = 12345
1579    expected = {'int32Value': 12345}
1580    self.assertEqual(expected, json_format.MessageToDict(message))
1581
1582  def testJsonName(self):
1583    message = json_format_proto3_pb2.TestCustomJsonName()
1584    message.value = 12345
1585    self.assertEqual(
1586        '{\n  "@value": 12345\n}', json_format.MessageToJson(message)
1587    )
1588    parsed_message = json_format_proto3_pb2.TestCustomJsonName()
1589    self.CheckParseBack(message, parsed_message)
1590
1591  def testSortKeys(self):
1592    # Testing sort_keys is not perfectly working, as by random luck we could
1593    # get the output sorted. We just use a selection of names.
1594    message = json_format_proto3_pb2.TestMessage(
1595        bool_value=True,
1596        int32_value=1,
1597        int64_value=3,
1598        uint32_value=4,
1599        string_value='bla',
1600    )
1601    self.assertEqual(
1602        json_format.MessageToJson(message, sort_keys=True),
1603        # We use json.dumps() instead of a hardcoded string due to differences
1604        # between Python 2 and Python 3.
1605        json.dumps(
1606            {
1607                'boolValue': True,
1608                'int32Value': 1,
1609                'int64Value': '3',
1610                'uint32Value': 4,
1611                'stringValue': 'bla',
1612            },
1613            indent=2,
1614            sort_keys=True,
1615        ),
1616    )
1617
1618  def testNestedRecursiveLimit(self):
1619    message = unittest_pb2.NestedTestAllTypes()
1620    self.assertRaisesRegex(
1621        json_format.ParseError,
1622        'Message too deep. Max recursion depth is 3',
1623        json_format.Parse,
1624        '{"child": {"child": {"child" : {}}}}',
1625        message,
1626        max_recursion_depth=3,
1627    )
1628    # The following one can pass
1629    json_format.Parse(
1630        '{"payload": {}, "child": {"child":{}}}', message, max_recursion_depth=3
1631    )
1632
1633  def testJsonNameConflictSerilize(self):
1634    message = more_messages_pb2.ConflictJsonName(value=2)
1635    self.assertEqual(
1636        json.loads('{"old_value": 2}'),
1637        json.loads(json_format.MessageToJson(message)),
1638    )
1639
1640    new_message = more_messages_pb2.ConflictJsonName(new_value=2)
1641    self.assertEqual(
1642        json.loads('{"value": 2}'),
1643        json.loads(json_format.MessageToJson(new_message)),
1644    )
1645
1646  def testJsonNameConflictParse(self):
1647    message = more_messages_pb2.ConflictJsonName()
1648    json_format.Parse('{"value": 2}', message)
1649    self.assertEqual(2, message.new_value)
1650    self.assertEqual(0, message.value)
1651
1652  def testJsonNameConflictRoundTrip(self):
1653    message = more_messages_pb2.ConflictJsonName(value=2)
1654    parsed_message = more_messages_pb2.ConflictJsonName()
1655    json_string = json_format.MessageToJson(message)
1656    json_format.Parse(json_string, parsed_message)
1657    self.assertEqual(message, parsed_message)
1658
1659    new_message = more_messages_pb2.ConflictJsonName(new_value=2)
1660    new_parsed_message = more_messages_pb2.ConflictJsonName()
1661    json_string = json_format.MessageToJson(new_message)
1662    json_format.Parse(json_string, new_parsed_message)
1663    self.assertEqual(new_message, new_parsed_message)
1664
1665  def testOtherParseErrors(self):
1666    self.CheckError(
1667        '9',
1668        "Failed to parse JSON: TypeError: 'int' object is not iterable.",
1669    )
1670
1671  def testManyRecursionsRaisesParseError(self):
1672    num_recursions = 1050
1673    text = ('{"a":' * num_recursions) + '""' + ('}' * num_recursions)
1674    with self.assertRaises(json_format.ParseError):
1675      json_format.Parse(text, json_format_proto3_pb2.TestMessage())
1676
1677if __name__ == '__main__':
1678  unittest.main()
1679