xref: /aosp_15_r20/external/cronet/third_party/protobuf/python/google/protobuf/internal/json_format_test.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc.  All rights reserved.
3# https://developers.google.com/protocol-buffers/
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Test for google.protobuf.json_format."""
32
33__author__ = '[email protected] (Jie Luo)'
34
35import json
36import math
37import struct
38
39import unittest
40
41from google.protobuf import any_pb2
42from google.protobuf import duration_pb2
43from google.protobuf import field_mask_pb2
44from google.protobuf import struct_pb2
45from google.protobuf import timestamp_pb2
46from google.protobuf import wrappers_pb2
47from google.protobuf import any_test_pb2
48from google.protobuf import unittest_mset_pb2
49from google.protobuf import unittest_pb2
50from google.protobuf.internal import test_proto3_optional_pb2
51from google.protobuf import descriptor_pool
52from google.protobuf import json_format
53from google.protobuf.util import json_format_pb2
54from google.protobuf.util import json_format_proto3_pb2
55
56
57class JsonFormatBase(unittest.TestCase):
58
59  def FillAllFields(self, message):
60    message.int32_value = 20
61    message.int64_value = -20
62    message.uint32_value = 3120987654
63    message.uint64_value = 12345678900
64    message.float_value = float('-inf')
65    message.double_value = 3.1415
66    message.bool_value = True
67    message.string_value = 'foo'
68    message.bytes_value = b'bar'
69    message.message_value.value = 10
70    message.enum_value = json_format_proto3_pb2.BAR
71    # Repeated
72    message.repeated_int32_value.append(0x7FFFFFFF)
73    message.repeated_int32_value.append(-2147483648)
74    message.repeated_int64_value.append(9007199254740992)
75    message.repeated_int64_value.append(-9007199254740992)
76    message.repeated_uint32_value.append(0xFFFFFFF)
77    message.repeated_uint32_value.append(0x7FFFFFF)
78    message.repeated_uint64_value.append(9007199254740992)
79    message.repeated_uint64_value.append(9007199254740991)
80    message.repeated_float_value.append(0)
81
82    message.repeated_double_value.append(1E-15)
83    message.repeated_double_value.append(float('inf'))
84    message.repeated_bool_value.append(True)
85    message.repeated_bool_value.append(False)
86    message.repeated_string_value.append('Few symbols!#$,;')
87    message.repeated_string_value.append('bar')
88    message.repeated_bytes_value.append(b'foo')
89    message.repeated_bytes_value.append(b'bar')
90    message.repeated_message_value.add().value = 10
91    message.repeated_message_value.add().value = 11
92    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
93    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
94    self.message = message
95
96  def CheckParseBack(self, message, parsed_message):
97    json_format.Parse(json_format.MessageToJson(message),
98                      parsed_message)
99    self.assertEqual(message, parsed_message)
100
101  def CheckError(self, text, error_message):
102    message = json_format_proto3_pb2.TestMessage()
103    self.assertRaisesRegex(json_format.ParseError, error_message,
104                           json_format.Parse, text, message)
105
106
107class JsonFormatTest(JsonFormatBase):
108
109  def testEmptyMessageToJson(self):
110    message = json_format_proto3_pb2.TestMessage()
111    self.assertEqual(json_format.MessageToJson(message),
112                     '{}')
113    parsed_message = json_format_proto3_pb2.TestMessage()
114    self.CheckParseBack(message, parsed_message)
115
116  def testPartialMessageToJson(self):
117    message = json_format_proto3_pb2.TestMessage(
118        string_value='test',
119        repeated_int32_value=[89, 4])
120    self.assertEqual(json.loads(json_format.MessageToJson(message)),
121                     json.loads('{"stringValue": "test", '
122                                '"repeatedInt32Value": [89, 4]}'))
123    parsed_message = json_format_proto3_pb2.TestMessage()
124    self.CheckParseBack(message, parsed_message)
125
126  def testAllFieldsToJson(self):
127    message = json_format_proto3_pb2.TestMessage()
128    text = ('{"int32Value": 20, '
129            '"int64Value": "-20", '
130            '"uint32Value": 3120987654,'
131            '"uint64Value": "12345678900",'
132            '"floatValue": "-Infinity",'
133            '"doubleValue": 3.1415,'
134            '"boolValue": true,'
135            '"stringValue": "foo",'
136            '"bytesValue": "YmFy",'
137            '"messageValue": {"value": 10},'
138            '"enumValue": "BAR",'
139            '"repeatedInt32Value": [2147483647, -2147483648],'
140            '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
141            '"repeatedUint32Value": [268435455, 134217727],'
142            '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
143            '"repeatedFloatValue": [0],'
144            '"repeatedDoubleValue": [1e-15, "Infinity"],'
145            '"repeatedBoolValue": [true, false],'
146            '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
147            '"repeatedBytesValue": ["Zm9v", "YmFy"],'
148            '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
149            '"repeatedEnumValue": ["FOO", "BAR"]'
150            '}')
151    self.FillAllFields(message)
152    self.assertEqual(
153        json.loads(json_format.MessageToJson(message)),
154        json.loads(text))
155    parsed_message = json_format_proto3_pb2.TestMessage()
156    json_format.Parse(text, parsed_message)
157    self.assertEqual(message, parsed_message)
158
159  def testUnknownEnumToJsonAndBack(self):
160    text = '{\n  "enumValue": 999\n}'
161    message = json_format_proto3_pb2.TestMessage()
162    message.enum_value = 999
163    self.assertEqual(json_format.MessageToJson(message),
164                     text)
165    parsed_message = json_format_proto3_pb2.TestMessage()
166    json_format.Parse(text, parsed_message)
167    self.assertEqual(message, parsed_message)
168
169  def testExtensionToJsonAndBack(self):
170    message = unittest_mset_pb2.TestMessageSetContainer()
171    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
172    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
173    message.message_set.Extensions[ext1].i = 23
174    message.message_set.Extensions[ext2].str = 'foo'
175    message_text = json_format.MessageToJson(
176        message
177    )
178    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
179    json_format.Parse(message_text, parsed_message)
180    self.assertEqual(message, parsed_message)
181
182  def testExtensionErrors(self):
183    self.CheckError('{"[extensionField]": {}}',
184                    'Message type proto3.TestMessage does not have extensions')
185
186  def testExtensionToDictAndBack(self):
187    message = unittest_mset_pb2.TestMessageSetContainer()
188    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
189    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
190    message.message_set.Extensions[ext1].i = 23
191    message.message_set.Extensions[ext2].str = 'foo'
192    message_dict = json_format.MessageToDict(
193        message
194    )
195    parsed_message = unittest_mset_pb2.TestMessageSetContainer()
196    json_format.ParseDict(message_dict, parsed_message)
197    self.assertEqual(message, parsed_message)
198
199  def testExtensionToDictAndBackWithScalar(self):
200    message = unittest_pb2.TestAllExtensions()
201    ext1 = unittest_pb2.TestNestedExtension.test
202    message.Extensions[ext1] = 'data'
203    message_dict = json_format.MessageToDict(
204        message
205    )
206    parsed_message = unittest_pb2.TestAllExtensions()
207    json_format.ParseDict(message_dict, parsed_message)
208    self.assertEqual(message, parsed_message)
209
210  def testJsonParseDictToAnyDoesNotAlterInput(self):
211    orig_dict = {
212        'int32Value': 20,
213        '@type': 'type.googleapis.com/proto3.TestMessage'
214    }
215    copied_dict = json.loads(json.dumps(orig_dict))
216    parsed_message = any_pb2.Any()
217    json_format.ParseDict(copied_dict, parsed_message)
218    self.assertEqual(copied_dict, orig_dict)
219
220  def testExtensionSerializationDictMatchesProto3Spec(self):
221    """See go/proto3-json-spec for spec.
222    """
223    message = unittest_mset_pb2.TestMessageSetContainer()
224    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
225    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
226    message.message_set.Extensions[ext1].i = 23
227    message.message_set.Extensions[ext2].str = 'foo'
228    message_dict = json_format.MessageToDict(
229        message
230    )
231    golden_dict = {
232        'messageSet': {
233            '[protobuf_unittest.'
234            'TestMessageSetExtension1.message_set_extension]': {
235                'i': 23,
236            },
237            '[protobuf_unittest.'
238            'TestMessageSetExtension2.message_set_extension]': {
239                'str': u'foo',
240            },
241        },
242    }
243    self.assertEqual(golden_dict, message_dict)
244    parsed_msg = unittest_mset_pb2.TestMessageSetContainer()
245    json_format.ParseDict(golden_dict, parsed_msg)
246    self.assertEqual(message, parsed_msg)
247
248  def testExtensionSerializationDictMatchesProto3SpecMore(self):
249    """See go/proto3-json-spec for spec.
250    """
251    message = json_format_pb2.TestMessageWithExtension()
252    ext = json_format_pb2.TestExtension.ext
253    message.Extensions[ext].value = 'stuff'
254    message_dict = json_format.MessageToDict(
255        message
256    )
257    expected_dict = {
258        '[protobuf_unittest.TestExtension.ext]': {
259            'value': u'stuff',
260        },
261    }
262    self.assertEqual(expected_dict, message_dict)
263
264  def testExtensionSerializationJsonMatchesProto3Spec(self):
265    """See go/proto3-json-spec for spec.
266    """
267    message = unittest_mset_pb2.TestMessageSetContainer()
268    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
269    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
270    message.message_set.Extensions[ext1].i = 23
271    message.message_set.Extensions[ext2].str = 'foo'
272    message_text = json_format.MessageToJson(
273        message
274    )
275    ext1_text = ('protobuf_unittest.TestMessageSetExtension1.'
276                 'message_set_extension')
277    ext2_text = ('protobuf_unittest.TestMessageSetExtension2.'
278                 'message_set_extension')
279    golden_text = ('{"messageSet": {'
280                   '    "[%s]": {'
281                   '        "i": 23'
282                   '    },'
283                   '    "[%s]": {'
284                   '        "str": "foo"'
285                   '    }'
286                   '}}') % (ext1_text, ext2_text)
287    self.assertEqual(json.loads(golden_text), json.loads(message_text))
288
289  def testJsonEscapeString(self):
290    message = json_format_proto3_pb2.TestMessage()
291    message.string_value = '&\n<\"\r>\b\t\f\\\001/'
292    message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
293    self.assertEqual(
294        json_format.MessageToJson(message),
295        '{\n  "stringValue": '
296        '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
297    parsed_message = json_format_proto3_pb2.TestMessage()
298    self.CheckParseBack(message, parsed_message)
299    text = u'{"int32Value": "\u0031"}'
300    json_format.Parse(text, message)
301    self.assertEqual(message.int32_value, 1)
302
303  def testAlwaysSeriliaze(self):
304    message = json_format_proto3_pb2.TestMessage(
305        string_value='foo')
306    self.assertEqual(
307        json.loads(json_format.MessageToJson(message, True)),
308        json.loads('{'
309                   '"repeatedStringValue": [],'
310                   '"stringValue": "foo",'
311                   '"repeatedBoolValue": [],'
312                   '"repeatedUint32Value": [],'
313                   '"repeatedInt32Value": [],'
314                   '"enumValue": "FOO",'
315                   '"int32Value": 0,'
316                   '"floatValue": 0,'
317                   '"int64Value": "0",'
318                   '"uint32Value": 0,'
319                   '"repeatedBytesValue": [],'
320                   '"repeatedUint64Value": [],'
321                   '"repeatedDoubleValue": [],'
322                   '"bytesValue": "",'
323                   '"boolValue": false,'
324                   '"repeatedEnumValue": [],'
325                   '"uint64Value": "0",'
326                   '"doubleValue": 0,'
327                   '"repeatedFloatValue": [],'
328                   '"repeatedInt64Value": [],'
329                   '"repeatedMessageValue": []}'))
330    parsed_message = json_format_proto3_pb2.TestMessage()
331    self.CheckParseBack(message, parsed_message)
332
333  def testProto3Optional(self):
334    message = test_proto3_optional_pb2.TestProto3Optional()
335    self.assertEqual(
336        json.loads(
337            json_format.MessageToJson(
338                message, including_default_value_fields=True)),
339        json.loads('{}'))
340    message.optional_int32 = 0
341    self.assertEqual(
342        json.loads(
343            json_format.MessageToJson(
344                message, including_default_value_fields=True)),
345        json.loads('{"optionalInt32": 0}'))
346
347  def testIntegersRepresentedAsFloat(self):
348    message = json_format_proto3_pb2.TestMessage()
349    json_format.Parse('{"int32Value": -2.147483648e9}', message)
350    self.assertEqual(message.int32_value, -2147483648)
351    json_format.Parse('{"int32Value": 1e5}', message)
352    self.assertEqual(message.int32_value, 100000)
353    json_format.Parse('{"int32Value": 1.0}', message)
354    self.assertEqual(message.int32_value, 1)
355
356  def testMapFields(self):
357    message = json_format_proto3_pb2.TestNestedMap()
358    self.assertEqual(
359        json.loads(json_format.MessageToJson(message, True)),
360        json.loads('{'
361                   '"boolMap": {},'
362                   '"int32Map": {},'
363                   '"int64Map": {},'
364                   '"uint32Map": {},'
365                   '"uint64Map": {},'
366                   '"stringMap": {},'
367                   '"mapMap": {}'
368                   '}'))
369    message.bool_map[True] = 1
370    message.bool_map[False] = 2
371    message.int32_map[1] = 2
372    message.int32_map[2] = 3
373    message.int64_map[1] = 2
374    message.int64_map[2] = 3
375    message.uint32_map[1] = 2
376    message.uint32_map[2] = 3
377    message.uint64_map[1] = 2
378    message.uint64_map[2] = 3
379    message.string_map['1'] = 2
380    message.string_map['null'] = 3
381    message.map_map['1'].bool_map[True] = 3
382    self.assertEqual(
383        json.loads(json_format.MessageToJson(message, False)),
384        json.loads('{'
385                   '"boolMap": {"false": 2, "true": 1},'
386                   '"int32Map": {"1": 2, "2": 3},'
387                   '"int64Map": {"1": 2, "2": 3},'
388                   '"uint32Map": {"1": 2, "2": 3},'
389                   '"uint64Map": {"1": 2, "2": 3},'
390                   '"stringMap": {"1": 2, "null": 3},'
391                   '"mapMap": {"1": {"boolMap": {"true": 3}}}'
392                   '}'))
393    parsed_message = json_format_proto3_pb2.TestNestedMap()
394    self.CheckParseBack(message, parsed_message)
395
396  def testOneofFields(self):
397    message = json_format_proto3_pb2.TestOneof()
398    # Always print does not affect oneof fields.
399    self.assertEqual(
400        json_format.MessageToJson(message, True),
401        '{}')
402    message.oneof_int32_value = 0
403    self.assertEqual(
404        json_format.MessageToJson(message, True),
405        '{\n'
406        '  "oneofInt32Value": 0\n'
407        '}')
408    parsed_message = json_format_proto3_pb2.TestOneof()
409    self.CheckParseBack(message, parsed_message)
410
411  def testSurrogates(self):
412    # Test correct surrogate handling.
413    message = json_format_proto3_pb2.TestMessage()
414    json_format.Parse('{"stringValue": "\\uD83D\\uDE01"}', message)
415    self.assertEqual(message.string_value,
416                     b'\xF0\x9F\x98\x81'.decode('utf-8', 'strict'))
417
418    # Error case: unpaired high surrogate.
419    self.CheckError(
420        '{"stringValue": "\\uD83D"}',
421        r'Invalid \\uXXXX escape|Unpaired.*surrogate')
422
423    # Unpaired low surrogate.
424    self.CheckError(
425        '{"stringValue": "\\uDE01"}',
426        r'Invalid \\uXXXX escape|Unpaired.*surrogate')
427
428  def testTimestampMessage(self):
429    message = json_format_proto3_pb2.TestTimestamp()
430    message.value.seconds = 0
431    message.value.nanos = 0
432    message.repeated_value.add().seconds = 20
433    message.repeated_value[0].nanos = 1
434    message.repeated_value.add().seconds = 0
435    message.repeated_value[1].nanos = 10000
436    message.repeated_value.add().seconds = 100000000
437    message.repeated_value[2].nanos = 0
438    # Maximum time
439    message.repeated_value.add().seconds = 253402300799
440    message.repeated_value[3].nanos = 999999999
441    # Minimum time
442    message.repeated_value.add().seconds = -62135596800
443    message.repeated_value[4].nanos = 0
444    self.assertEqual(
445        json.loads(json_format.MessageToJson(message, True)),
446        json.loads('{'
447                   '"value": "1970-01-01T00:00:00Z",'
448                   '"repeatedValue": ['
449                   '  "1970-01-01T00:00:20.000000001Z",'
450                   '  "1970-01-01T00:00:00.000010Z",'
451                   '  "1973-03-03T09:46:40Z",'
452                   '  "9999-12-31T23:59:59.999999999Z",'
453                   '  "0001-01-01T00:00:00Z"'
454                   ']'
455                   '}'))
456    parsed_message = json_format_proto3_pb2.TestTimestamp()
457    self.CheckParseBack(message, parsed_message)
458    text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
459            r'"repeatedValue":['
460            r'  "1970-01-01T00:00:00.01+08:30",'
461            r'  "1970-01-01T00:00:00.01-01:23"]}')
462    json_format.Parse(text, parsed_message)
463    self.assertEqual(parsed_message.value.seconds, -8 * 3600)
464    self.assertEqual(parsed_message.value.nanos, 10000000)
465    self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
466    self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
467
468  def testDurationMessage(self):
469    message = json_format_proto3_pb2.TestDuration()
470    message.value.seconds = 1
471    message.repeated_value.add().seconds = 0
472    message.repeated_value[0].nanos = 10
473    message.repeated_value.add().seconds = -1
474    message.repeated_value[1].nanos = -1000
475    message.repeated_value.add().seconds = 10
476    message.repeated_value[2].nanos = 11000000
477    message.repeated_value.add().seconds = -315576000000
478    message.repeated_value.add().seconds = 315576000000
479    self.assertEqual(
480        json.loads(json_format.MessageToJson(message, True)),
481        json.loads('{'
482                   '"value": "1s",'
483                   '"repeatedValue": ['
484                   '  "0.000000010s",'
485                   '  "-1.000001s",'
486                   '  "10.011s",'
487                   '  "-315576000000s",'
488                   '  "315576000000s"'
489                   ']'
490                   '}'))
491    parsed_message = json_format_proto3_pb2.TestDuration()
492    self.CheckParseBack(message, parsed_message)
493
494  def testFieldMaskMessage(self):
495    message = json_format_proto3_pb2.TestFieldMask()
496    message.value.paths.append('foo.bar')
497    message.value.paths.append('bar')
498    self.assertEqual(
499        json_format.MessageToJson(message, True),
500        '{\n'
501        '  "value": "foo.bar,bar"\n'
502        '}')
503    parsed_message = json_format_proto3_pb2.TestFieldMask()
504    self.CheckParseBack(message, parsed_message)
505
506    message.value.Clear()
507    self.assertEqual(
508        json_format.MessageToJson(message, True),
509        '{\n'
510        '  "value": ""\n'
511        '}')
512    self.CheckParseBack(message, parsed_message)
513
514  def testWrapperMessage(self):
515    message = json_format_proto3_pb2.TestWrapper()
516    message.bool_value.value = False
517    message.int32_value.value = 0
518    message.string_value.value = ''
519    message.bytes_value.value = b''
520    message.repeated_bool_value.add().value = True
521    message.repeated_bool_value.add().value = False
522    message.repeated_int32_value.add()
523    self.assertEqual(
524        json.loads(json_format.MessageToJson(message, True)),
525        json.loads('{\n'
526                   '  "int32Value": 0,'
527                   '  "boolValue": false,'
528                   '  "stringValue": "",'
529                   '  "bytesValue": "",'
530                   '  "repeatedBoolValue": [true, false],'
531                   '  "repeatedInt32Value": [0],'
532                   '  "repeatedUint32Value": [],'
533                   '  "repeatedFloatValue": [],'
534                   '  "repeatedDoubleValue": [],'
535                   '  "repeatedBytesValue": [],'
536                   '  "repeatedInt64Value": [],'
537                   '  "repeatedUint64Value": [],'
538                   '  "repeatedStringValue": []'
539                   '}'))
540    parsed_message = json_format_proto3_pb2.TestWrapper()
541    self.CheckParseBack(message, parsed_message)
542
543  def testStructMessage(self):
544    message = json_format_proto3_pb2.TestStruct()
545    message.value['name'] = 'Jim'
546    message.value['age'] = 10
547    message.value['attend'] = True
548    message.value['email'] = None
549    message.value.get_or_create_struct('address')['city'] = 'SFO'
550    message.value['address']['house_number'] = 1024
551    message.value.get_or_create_struct('empty_struct')
552    message.value.get_or_create_list('empty_list')
553    struct_list = message.value.get_or_create_list('list')
554    struct_list.extend([6, 'seven', True, False, None])
555    struct_list.add_struct()['subkey2'] = 9
556    message.repeated_value.add()['age'] = 11
557    message.repeated_value.add()
558    self.assertEqual(
559        json.loads(json_format.MessageToJson(message, False)),
560        json.loads(
561            '{'
562            '  "value": {'
563            '    "address": {'
564            '      "city": "SFO", '
565            '      "house_number": 1024'
566            '    }, '
567            '    "empty_struct": {}, '
568            '    "empty_list": [], '
569            '    "age": 10, '
570            '    "name": "Jim", '
571            '    "attend": true, '
572            '    "email": null, '
573            '    "list": [6, "seven", true, false, null, {"subkey2": 9}]'
574            '  },'
575            '  "repeatedValue": [{"age": 11}, {}]'
576            '}'))
577    parsed_message = json_format_proto3_pb2.TestStruct()
578    self.CheckParseBack(message, parsed_message)
579    # check for regression; this used to raise
580    parsed_message.value['empty_struct']
581    parsed_message.value['empty_list']
582
583  def testValueMessage(self):
584    message = json_format_proto3_pb2.TestValue()
585    message.value.string_value = 'hello'
586    message.repeated_value.add().number_value = 11.1
587    message.repeated_value.add().bool_value = False
588    message.repeated_value.add().null_value = 0
589    self.assertEqual(
590        json.loads(json_format.MessageToJson(message, False)),
591        json.loads(
592            '{'
593            '  "value": "hello",'
594            '  "repeatedValue": [11.1, false, null]'
595            '}'))
596    parsed_message = json_format_proto3_pb2.TestValue()
597    self.CheckParseBack(message, parsed_message)
598    # Can't parse back if the Value message is not set.
599    message.repeated_value.add()
600    self.assertEqual(
601        json.loads(json_format.MessageToJson(message, False)),
602        json.loads(
603            '{'
604            '  "value": "hello",'
605            '  "repeatedValue": [11.1, false, null, null]'
606            '}'))
607    message.Clear()
608    json_format.Parse('{"value": null}', message)
609    self.assertEqual(message.value.WhichOneof('kind'), 'null_value')
610
611  def testListValueMessage(self):
612    message = json_format_proto3_pb2.TestListValue()
613    message.value.values.add().number_value = 11.1
614    message.value.values.add().null_value = 0
615    message.value.values.add().bool_value = True
616    message.value.values.add().string_value = 'hello'
617    message.value.values.add().struct_value['name'] = 'Jim'
618    message.repeated_value.add().values.add().number_value = 1
619    message.repeated_value.add()
620    self.assertEqual(
621        json.loads(json_format.MessageToJson(message, False)),
622        json.loads(
623            '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
624            '"repeatedValue": [[1], []]}'))
625    parsed_message = json_format_proto3_pb2.TestListValue()
626    self.CheckParseBack(message, parsed_message)
627
628  def testNullValue(self):
629    message = json_format_proto3_pb2.TestOneof()
630    message.oneof_null_value = 0
631    self.assertEqual(json_format.MessageToJson(message),
632                     '{\n  "oneofNullValue": null\n}')
633    parsed_message = json_format_proto3_pb2.TestOneof()
634    self.CheckParseBack(message, parsed_message)
635    # Check old format is also accepted
636    new_message = json_format_proto3_pb2.TestOneof()
637    json_format.Parse('{\n  "oneofNullValue": "NULL_VALUE"\n}',
638                      new_message)
639    self.assertEqual(json_format.MessageToJson(new_message),
640                     '{\n  "oneofNullValue": null\n}')
641
642  def testAnyMessage(self):
643    message = json_format_proto3_pb2.TestAny()
644    value1 = json_format_proto3_pb2.MessageType()
645    value2 = json_format_proto3_pb2.MessageType()
646    value1.value = 1234
647    value2.value = 5678
648    message.value.Pack(value1)
649    message.repeated_value.add().Pack(value1)
650    message.repeated_value.add().Pack(value2)
651    message.repeated_value.add()
652    self.assertEqual(
653        json.loads(json_format.MessageToJson(message, True)),
654        json.loads(
655            '{\n'
656            '  "repeatedValue": [ {\n'
657            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
658            '    "value": 1234\n'
659            '  }, {\n'
660            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
661            '    "value": 5678\n'
662            '  },\n'
663            '  {}],\n'
664            '  "value": {\n'
665            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
666            '    "value": 1234\n'
667            '  }\n'
668            '}\n'))
669    parsed_message = json_format_proto3_pb2.TestAny()
670    self.CheckParseBack(message, parsed_message)
671    # Must print @type first
672    test_message = json_format_proto3_pb2.TestMessage(
673        bool_value=True,
674        int32_value=20,
675        int64_value=-20,
676        uint32_value=20,
677        uint64_value=20,
678        double_value=3.14,
679        string_value='foo')
680    message.Clear()
681    message.value.Pack(test_message)
682    self.assertEqual(
683        json_format.MessageToJson(message, False)[0:68],
684        '{\n'
685        '  "value": {\n'
686        '    "@type": "type.googleapis.com/proto3.TestMessage"')
687
688  def testAnyMessageDescriptorPoolMissingType(self):
689    packed_message = unittest_pb2.OneString()
690    packed_message.data = 'string'
691    message = any_test_pb2.TestAny()
692    message.any_value.Pack(packed_message)
693    empty_pool = descriptor_pool.DescriptorPool()
694    with self.assertRaises(TypeError) as cm:
695      json_format.MessageToJson(message, True, descriptor_pool=empty_pool)
696    self.assertEqual(
697        'Can not find message descriptor by type_url:'
698        ' type.googleapis.com/protobuf_unittest.OneString', str(cm.exception))
699
700  def testWellKnownInAnyMessage(self):
701    message = any_pb2.Any()
702    int32_value = wrappers_pb2.Int32Value()
703    int32_value.value = 1234
704    message.Pack(int32_value)
705    self.assertEqual(
706        json.loads(json_format.MessageToJson(message, True)),
707        json.loads(
708            '{\n'
709            '  "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
710            '  "value": 1234\n'
711            '}\n'))
712    parsed_message = any_pb2.Any()
713    self.CheckParseBack(message, parsed_message)
714
715    timestamp = timestamp_pb2.Timestamp()
716    message.Pack(timestamp)
717    self.assertEqual(
718        json.loads(json_format.MessageToJson(message, True)),
719        json.loads(
720            '{\n'
721            '  "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
722            '  "value": "1970-01-01T00:00:00Z"\n'
723            '}\n'))
724    self.CheckParseBack(message, parsed_message)
725
726    duration = duration_pb2.Duration()
727    duration.seconds = 1
728    message.Pack(duration)
729    self.assertEqual(
730        json.loads(json_format.MessageToJson(message, True)),
731        json.loads(
732            '{\n'
733            '  "@type": "type.googleapis.com/google.protobuf.Duration",\n'
734            '  "value": "1s"\n'
735            '}\n'))
736    self.CheckParseBack(message, parsed_message)
737
738    field_mask = field_mask_pb2.FieldMask()
739    field_mask.paths.append('foo.bar')
740    field_mask.paths.append('bar')
741    message.Pack(field_mask)
742    self.assertEqual(
743        json.loads(json_format.MessageToJson(message, True)),
744        json.loads(
745            '{\n'
746            '  "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
747            '  "value": "foo.bar,bar"\n'
748            '}\n'))
749    self.CheckParseBack(message, parsed_message)
750
751    struct_message = struct_pb2.Struct()
752    struct_message['name'] = 'Jim'
753    message.Pack(struct_message)
754    self.assertEqual(
755        json.loads(json_format.MessageToJson(message, True)),
756        json.loads(
757            '{\n'
758            '  "@type": "type.googleapis.com/google.protobuf.Struct",\n'
759            '  "value": {"name": "Jim"}\n'
760            '}\n'))
761    self.CheckParseBack(message, parsed_message)
762
763    nested_any = any_pb2.Any()
764    int32_value.value = 5678
765    nested_any.Pack(int32_value)
766    message.Pack(nested_any)
767    self.assertEqual(
768        json.loads(json_format.MessageToJson(message, True)),
769        json.loads(
770            '{\n'
771            '  "@type": "type.googleapis.com/google.protobuf.Any",\n'
772            '  "value": {\n'
773            '    "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
774            '    "value": 5678\n'
775            '  }\n'
776            '}\n'))
777    self.CheckParseBack(message, parsed_message)
778
779  def testParseNull(self):
780    message = json_format_proto3_pb2.TestMessage()
781    parsed_message = json_format_proto3_pb2.TestMessage()
782    self.FillAllFields(parsed_message)
783    json_format.Parse('{"int32Value": null, '
784                      '"int64Value": null, '
785                      '"uint32Value": null,'
786                      '"uint64Value": null,'
787                      '"floatValue": null,'
788                      '"doubleValue": null,'
789                      '"boolValue": null,'
790                      '"stringValue": null,'
791                      '"bytesValue": null,'
792                      '"messageValue": null,'
793                      '"enumValue": null,'
794                      '"repeatedInt32Value": null,'
795                      '"repeatedInt64Value": null,'
796                      '"repeatedUint32Value": null,'
797                      '"repeatedUint64Value": null,'
798                      '"repeatedFloatValue": null,'
799                      '"repeatedDoubleValue": null,'
800                      '"repeatedBoolValue": null,'
801                      '"repeatedStringValue": null,'
802                      '"repeatedBytesValue": null,'
803                      '"repeatedMessageValue": null,'
804                      '"repeatedEnumValue": null'
805                      '}',
806                      parsed_message)
807    self.assertEqual(message, parsed_message)
808    # Null and {} should have different behavior for sub message.
809    self.assertFalse(parsed_message.HasField('message_value'))
810    json_format.Parse('{"messageValue": {}}', parsed_message)
811    self.assertTrue(parsed_message.HasField('message_value'))
812    # Null is not allowed to be used as an element in repeated field.
813    self.assertRaisesRegex(
814        json_format.ParseError, r'Failed to parse repeatedInt32Value field: '
815        r'null is not allowed to be used as an element in a repeated field '
816        r'at TestMessage.repeatedInt32Value\[1\].', json_format.Parse,
817        '{"repeatedInt32Value":[1, null]}', parsed_message)
818    self.CheckError(
819        '{"repeatedMessageValue":[null]}',
820        r'Failed to parse repeatedMessageValue field: null is not'
821        r' allowed to be used as an element in a repeated field '
822        r'at TestMessage.repeatedMessageValue\[0\].')
823
824  def testNanFloat(self):
825    message = json_format_proto3_pb2.TestMessage()
826    message.float_value = float('nan')
827    text = '{\n  "floatValue": "NaN"\n}'
828    self.assertEqual(json_format.MessageToJson(message), text)
829    parsed_message = json_format_proto3_pb2.TestMessage()
830    json_format.Parse(text, parsed_message)
831    self.assertTrue(math.isnan(parsed_message.float_value))
832
833  def testParseDoubleToFloat(self):
834    message = json_format_proto3_pb2.TestMessage()
835    text = ('{"repeatedDoubleValue": [3.4028235e+39, 1.4028235e-39]\n}')
836    json_format.Parse(text, message)
837    self.assertEqual(message.repeated_double_value[0], 3.4028235e+39)
838    self.assertEqual(message.repeated_double_value[1], 1.4028235e-39)
839    text = ('{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}')
840    self.CheckError(
841        text, r'Failed to parse repeatedFloatValue field: '
842        r'Float value too large at TestMessage.repeatedFloatValue\[0\].')
843
844  def testFloatPrecision(self):
845    message = json_format_proto3_pb2.TestMessage()
846    message.float_value = 1.123456789
847    # Set to 8 valid digits.
848    text = '{\n  "floatValue": 1.1234568\n}'
849    self.assertEqual(
850        json_format.MessageToJson(message, float_precision=8), text)
851    # Set to 7 valid digits.
852    text = '{\n  "floatValue": 1.123457\n}'
853    self.assertEqual(
854        json_format.MessageToJson(message, float_precision=7), text)
855
856    # Default float_precision will automatic print shortest float.
857    message.float_value = 1.1000000011
858    text = '{\n  "floatValue": 1.1\n}'
859    self.assertEqual(
860        json_format.MessageToJson(message), text)
861    message.float_value = 1.00000075e-36
862    text = '{\n  "floatValue": 1.00000075e-36\n}'
863    self.assertEqual(
864        json_format.MessageToJson(message), text)
865    message.float_value = 12345678912345e+11
866    text = '{\n  "floatValue": 1.234568e+24\n}'
867    self.assertEqual(
868        json_format.MessageToJson(message), text)
869
870    # Test a bunch of data and check json encode/decode do not
871    # lose precision
872    value_list = [0x00, 0xD8, 0x6E, 0x00]
873    msg2 = json_format_proto3_pb2.TestMessage()
874    for a in range(0, 256):
875      value_list[3] = a
876      for b in range(0, 256):
877        value_list[0] = b
878        byte_array = bytearray(value_list)
879        message.float_value = struct.unpack('<f', byte_array)[0]
880        self.CheckParseBack(message, msg2)
881
882  def testParseEmptyText(self):
883    self.CheckError('',
884                    r'Failed to load JSON: (Expecting value)|(No JSON).')
885
886  def testParseEnumValue(self):
887    message = json_format_proto3_pb2.TestMessage()
888    text = '{"enumValue": 0}'
889    json_format.Parse(text, message)
890    text = '{"enumValue": 1}'
891    json_format.Parse(text, message)
892    self.CheckError(
893        '{"enumValue": "baz"}',
894        'Failed to parse enumValue field: Invalid enum value baz '
895        'for enum type proto3.EnumType at TestMessage.enumValue.')
896    # Proto3 accepts numeric unknown enums.
897    text = '{"enumValue": 12345}'
898    json_format.Parse(text, message)
899    # Proto2 does not accept unknown enums.
900    message = unittest_pb2.TestAllTypes()
901    self.assertRaisesRegex(
902        json_format.ParseError,
903        'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
904        'for enum type protobuf_unittest.TestAllTypes.NestedEnum at '
905        'TestAllTypes.optionalNestedEnum.', json_format.Parse,
906        '{"optionalNestedEnum": 12345}', message)
907
908  def testBytes(self):
909    message = json_format_proto3_pb2.TestMessage()
910    # Test url base64
911    text = '{"bytesValue": "-_"}'
912    json_format.Parse(text, message)
913    self.assertEqual(message.bytes_value, b'\xfb')
914    # Test padding
915    text = '{"bytesValue": "AQI="}'
916    json_format.Parse(text, message)
917    self.assertEqual(message.bytes_value, b'\x01\x02')
918    text = '{"bytesValue": "AQI"}'
919    json_format.Parse(text, message)
920    self.assertEqual(message.bytes_value, b'\x01\x02')
921    text = '{"bytesValue": "AQI*"}'
922    json_format.Parse(text, message)
923    self.assertEqual(message.bytes_value, b'\x01\x02')
924
925  def testParseBadIdentifer(self):
926    self.CheckError('{int32Value: 1}',
927                    (r'Failed to load JSON: Expecting property name'
928                     r'( enclosed in double quotes)?: line 1'))
929    self.CheckError(
930        '{"unknownName": 1}',
931        'Message type "proto3.TestMessage" has no field named '
932        '"unknownName" at "TestMessage".')
933
934  def testIgnoreUnknownField(self):
935    text = '{"unknownName": 1}'
936    parsed_message = json_format_proto3_pb2.TestMessage()
937    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
938    text = ('{\n'
939            '  "repeatedValue": [ {\n'
940            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
941            '    "unknownName": 1\n'
942            '  }]\n'
943            '}\n')
944    parsed_message = json_format_proto3_pb2.TestAny()
945    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
946
947  def testDuplicateField(self):
948    self.CheckError('{"int32Value": 1,\n"int32Value":2}',
949                    'Failed to load JSON: duplicate key int32Value.')
950
951  def testInvalidBoolValue(self):
952    self.CheckError(
953        '{"boolValue": 1}', 'Failed to parse boolValue field: '
954        'Expected true or false without quotes at TestMessage.boolValue.')
955    self.CheckError(
956        '{"boolValue": "true"}', 'Failed to parse boolValue field: '
957        'Expected true or false without quotes at TestMessage.boolValue.')
958
959  def testInvalidIntegerValue(self):
960    message = json_format_proto3_pb2.TestMessage()
961    text = '{"int32Value": 0x12345}'
962    self.assertRaises(json_format.ParseError,
963                      json_format.Parse, text, message)
964    self.CheckError(
965        '{"int32Value": 1.5}', 'Failed to parse int32Value field: '
966        'Couldn\'t parse integer: 1.5 at TestMessage.int32Value.')
967    self.CheckError('{"int32Value": 012345}',
968                    (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
969                     r'line 1.'))
970    self.CheckError(
971        '{"int32Value": " 1 "}', 'Failed to parse int32Value field: '
972        'Couldn\'t parse integer: " 1 " at TestMessage.int32Value.')
973    self.CheckError(
974        '{"int32Value": "1 "}', 'Failed to parse int32Value field: '
975        'Couldn\'t parse integer: "1 " at TestMessage.int32Value.')
976    self.CheckError(
977        '{"int32Value": false}',
978        'Failed to parse int32Value field: Bool value False '
979        'is not acceptable for integer field at TestMessage.int32Value.')
980    self.CheckError('{"int32Value": 12345678901234567890}',
981                    'Failed to parse int32Value field: Value out of range: '
982                    '12345678901234567890.')
983    self.CheckError('{"uint32Value": -1}',
984                    'Failed to parse uint32Value field: '
985                    'Value out of range: -1.')
986
987  def testInvalidFloatValue(self):
988    self.CheckError(
989        '{"floatValue": "nan"}', 'Failed to parse floatValue field: Couldn\'t '
990        'parse float "nan", use "NaN" instead at TestMessage.floatValue.')
991    self.CheckError('{"floatValue": NaN}',
992                    'Failed to parse floatValue field: Couldn\'t '
993                    'parse NaN, use quoted "NaN" instead.')
994    self.CheckError('{"floatValue": Infinity}',
995                    'Failed to parse floatValue field: Couldn\'t parse Infinity'
996                    ' or value too large, use quoted "Infinity" instead.')
997    self.CheckError('{"floatValue": -Infinity}',
998                    'Failed to parse floatValue field: Couldn\'t parse '
999                    '-Infinity or value too small, '
1000                    'use quoted "-Infinity" instead.')
1001    self.CheckError('{"doubleValue": -1.89769e+308}',
1002                    'Failed to parse doubleValue field: Couldn\'t parse '
1003                    '-Infinity or value too small, '
1004                    'use quoted "-Infinity" instead.')
1005    self.CheckError('{"floatValue": 3.4028235e+39}',
1006                    'Failed to parse floatValue field: Float value too large.')
1007    self.CheckError('{"floatValue": -3.502823e+38}',
1008                    'Failed to parse floatValue field: Float value too small.')
1009
1010  def testInvalidRepeated(self):
1011    self.CheckError(
1012        '{"repeatedInt32Value": 12345}',
1013        (r'Failed to parse repeatedInt32Value field: repeated field'
1014         r' repeatedInt32Value must be in \[\] which is 12345 at TestMessage.'))
1015
1016  def testInvalidMap(self):
1017    message = json_format_proto3_pb2.TestMap()
1018    text = '{"int32Map": {"null": 2, "2": 3}}'
1019    self.assertRaisesRegex(json_format.ParseError,
1020                           'Failed to parse int32Map field: invalid literal',
1021                           json_format.Parse, text, message)
1022    text = '{"int32Map": {1: 2, "2": 3}}'
1023    self.assertRaisesRegex(json_format.ParseError,
1024                           (r'Failed to load JSON: Expecting property name'
1025                            r'( enclosed in double quotes)?: line 1'),
1026                           json_format.Parse, text, message)
1027    text = '{"boolMap": {"null": 1}}'
1028    self.assertRaisesRegex(
1029        json_format.ParseError,
1030        'Failed to parse boolMap field: Expected "true" or "false", not null at '
1031        'TestMap.boolMap.key', json_format.Parse, text, message)
1032    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
1033    self.assertRaisesRegex(json_format.ParseError,
1034                           'Failed to load JSON: duplicate key a',
1035                           json_format.Parse, text, message)
1036    text = r'{"stringMap": 0}'
1037    self.assertRaisesRegex(
1038        json_format.ParseError,
1039        'Failed to parse stringMap field: Map field string_map must be '
1040        'in a dict which is 0 at TestMap.stringMap.', json_format.Parse, text,
1041        message)
1042
1043  def testInvalidTimestamp(self):
1044    message = json_format_proto3_pb2.TestTimestamp()
1045    text = '{"value": "10000-01-01T00:00:00.00Z"}'
1046    self.assertRaisesRegexp(
1047        json_format.ParseError, 'Failed to parse value field: '
1048        'time data \'10000-01-01T00:00:00\' does not match'
1049        ' format \'%Y-%m-%dT%H:%M:%S\' at TestTimestamp.value.',
1050        json_format.Parse, text, message)
1051    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
1052    self.assertRaisesRegex(
1053        json_format.ParseError,
1054        'nanos 0123456789012 more than 9 fractional digits.', json_format.Parse,
1055        text, message)
1056    text = '{"value": "1972-01-01T01:00:00.01+08"}'
1057    self.assertRaisesRegex(json_format.ParseError,
1058                           (r'Invalid timezone offset value: \+08.'),
1059                           json_format.Parse, text, message)
1060    # Time smaller than minimum time.
1061    text = '{"value": "0000-01-01T00:00:00Z"}'
1062    self.assertRaisesRegex(
1063        json_format.ParseError,
1064        'Failed to parse value field: year (0 )?is out of range.',
1065        json_format.Parse, text, message)
1066    # Time bigger than maximum time.
1067    message.value.seconds = 253402300800
1068    self.assertRaisesRegex(OverflowError, 'date value out of range',
1069                           json_format.MessageToJson, message)
1070    # Lower case t does not accept.
1071    text = '{"value": "0001-01-01t00:00:00Z"}'
1072    with self.assertRaises(json_format.ParseError) as e:
1073      json_format.Parse(text, message)
1074    self.assertEqual(
1075        'Failed to parse value field: '
1076        'time data \'0001-01-01t00:00:00\' does not match format '
1077        '\'%Y-%m-%dT%H:%M:%S\', lowercase \'t\' is not accepted '
1078        'at TestTimestamp.value.', str(e.exception))
1079
1080  def testInvalidOneof(self):
1081    message = json_format_proto3_pb2.TestOneof()
1082    text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
1083    self.assertRaisesRegexp(
1084        json_format.ParseError, 'Message type "proto3.TestOneof"'
1085        ' should not have multiple "oneof_value" oneof fields at "TestOneof".',
1086        json_format.Parse, text, message)
1087
1088  def testInvalidListValue(self):
1089    message = json_format_proto3_pb2.TestListValue()
1090    text = '{"value": 1234}'
1091    self.assertRaisesRegex(
1092        json_format.ParseError,
1093        r'Failed to parse value field: ListValue must be in \[\] which is '
1094        '1234 at TestListValue.value.', json_format.Parse, text, message)
1095
1096    class UnknownClass(object):
1097
1098      def __str__(self):
1099        return 'v'
1100    self.assertRaisesRegex(
1101        json_format.ParseError,
1102        r' at TestListValue.value\[1\].fake.',
1103        json_format.ParseDict,
1104        {'value': ['hello', {'fake': UnknownClass()}]}, message)
1105
1106  def testInvalidStruct(self):
1107    message = json_format_proto3_pb2.TestStruct()
1108    text = '{"value": 1234}'
1109    self.assertRaisesRegex(
1110        json_format.ParseError,
1111        'Failed to parse value field: Struct must be in a dict which is '
1112        '1234 at TestStruct.value', json_format.Parse, text, message)
1113
1114  def testTimestampInvalidStringValue(self):
1115    message = json_format_proto3_pb2.TestTimestamp()
1116    text = '{"value": {"foo": 123}}'
1117    self.assertRaisesRegex(
1118        json_format.ParseError,
1119        r"Timestamp JSON value not a string: {u?'foo': 123}", json_format.Parse,
1120        text, message)
1121
1122  def testDurationInvalidStringValue(self):
1123    message = json_format_proto3_pb2.TestDuration()
1124    text = '{"value": {"foo": 123}}'
1125    self.assertRaisesRegex(json_format.ParseError,
1126                           r"Duration JSON value not a string: {u?'foo': 123}",
1127                           json_format.Parse, text, message)
1128
1129  def testFieldMaskInvalidStringValue(self):
1130    message = json_format_proto3_pb2.TestFieldMask()
1131    text = '{"value": {"foo": 123}}'
1132    self.assertRaisesRegex(
1133        json_format.ParseError,
1134        r"FieldMask JSON value not a string: {u?'foo': 123}", json_format.Parse,
1135        text, message)
1136
1137  def testInvalidAny(self):
1138    message = any_pb2.Any()
1139    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
1140    self.assertRaisesRegex(KeyError, 'value', json_format.Parse, text, message)
1141    text = '{"value": 1234}'
1142    self.assertRaisesRegex(json_format.ParseError,
1143                           '@type is missing when parsing any message at Any',
1144                           json_format.Parse, text, message)
1145    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
1146    self.assertRaisesRegex(
1147        json_format.ParseError, 'Can not find message descriptor by type_url: '
1148        'type.googleapis.com/MessageNotExist at Any', json_format.Parse, text,
1149        message)
1150    # Only last part is to be used: b/25630112
1151    text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
1152            r'"value": 1234}')
1153    json_format.Parse(text, message)
1154
1155  def testPreservingProtoFieldNames(self):
1156    message = json_format_proto3_pb2.TestMessage()
1157    message.int32_value = 12345
1158    self.assertEqual('{\n  "int32Value": 12345\n}',
1159                     json_format.MessageToJson(message))
1160    self.assertEqual('{\n  "int32_value": 12345\n}',
1161                     json_format.MessageToJson(message, False, True))
1162    # When including_default_value_fields is True.
1163    message = json_format_proto3_pb2.TestTimestamp()
1164    self.assertEqual('{\n  "repeatedValue": []\n}',
1165                     json_format.MessageToJson(message, True, False))
1166    self.assertEqual('{\n  "repeated_value": []\n}',
1167                     json_format.MessageToJson(message, True, True))
1168
1169    # Parsers accept both original proto field names and lowerCamelCase names.
1170    message = json_format_proto3_pb2.TestMessage()
1171    json_format.Parse('{"int32Value": 54321}', message)
1172    self.assertEqual(54321, message.int32_value)
1173    json_format.Parse('{"int32_value": 12345}', message)
1174    self.assertEqual(12345, message.int32_value)
1175
1176  def testIndent(self):
1177    message = json_format_proto3_pb2.TestMessage()
1178    message.int32_value = 12345
1179    self.assertEqual('{\n"int32Value": 12345\n}',
1180                     json_format.MessageToJson(message, indent=0))
1181
1182  def testFormatEnumsAsInts(self):
1183    message = json_format_proto3_pb2.TestMessage()
1184    message.enum_value = json_format_proto3_pb2.BAR
1185    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
1186    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
1187    self.assertEqual(json.loads('{\n'
1188                                '  "enumValue": 1,\n'
1189                                '  "repeatedEnumValue": [0, 1]\n'
1190                                '}\n'),
1191                     json.loads(json_format.MessageToJson(
1192                         message, use_integers_for_enums=True)))
1193
1194  def testParseDict(self):
1195    expected = 12345
1196    js_dict = {'int32Value': expected}
1197    message = json_format_proto3_pb2.TestMessage()
1198    json_format.ParseDict(js_dict, message)
1199    self.assertEqual(expected, message.int32_value)
1200
1201  def testParseDictAnyDescriptorPoolMissingType(self):
1202    # Confirm that ParseDict does not raise ParseError with default pool
1203    js_dict = {
1204        'any_value': {
1205            '@type': 'type.googleapis.com/proto3.MessageType',
1206            'value': 1234
1207        }
1208    }
1209    json_format.ParseDict(js_dict, any_test_pb2.TestAny())
1210    # Check ParseDict raises ParseError with empty pool
1211    js_dict = {
1212        'any_value': {
1213            '@type': 'type.googleapis.com/proto3.MessageType',
1214            'value': 1234
1215        }
1216    }
1217    with self.assertRaises(json_format.ParseError) as cm:
1218      empty_pool = descriptor_pool.DescriptorPool()
1219      json_format.ParseDict(js_dict,
1220                            any_test_pb2.TestAny(),
1221                            descriptor_pool=empty_pool)
1222    self.assertEqual(
1223        str(cm.exception),
1224        'Failed to parse any_value field: Can not find message descriptor by'
1225        ' type_url: type.googleapis.com/proto3.MessageType at '
1226        'TestAny.any_value.'
1227    )
1228
1229  def testParseDictUnknownValueType(self):
1230    class UnknownClass(object):
1231
1232      def __repr__(self):
1233        return 'v'
1234    message = json_format_proto3_pb2.TestValue()
1235    self.assertRaisesRegex(
1236        json_format.ParseError,
1237        r"Value v has unexpected type <class '.*\.UnknownClass'>.",
1238        json_format.ParseDict, {'value': UnknownClass()}, message)
1239
1240  def testMessageToDict(self):
1241    message = json_format_proto3_pb2.TestMessage()
1242    message.int32_value = 12345
1243    expected = {'int32Value': 12345}
1244    self.assertEqual(expected,
1245                     json_format.MessageToDict(message))
1246
1247  def testJsonName(self):
1248    message = json_format_proto3_pb2.TestCustomJsonName()
1249    message.value = 12345
1250    self.assertEqual('{\n  "@value": 12345\n}',
1251                     json_format.MessageToJson(message))
1252    parsed_message = json_format_proto3_pb2.TestCustomJsonName()
1253    self.CheckParseBack(message, parsed_message)
1254
1255  def testSortKeys(self):
1256    # Testing sort_keys is not perfectly working, as by random luck we could
1257    # get the output sorted. We just use a selection of names.
1258    message = json_format_proto3_pb2.TestMessage(bool_value=True,
1259                                                 int32_value=1,
1260                                                 int64_value=3,
1261                                                 uint32_value=4,
1262                                                 string_value='bla')
1263    self.assertEqual(
1264        json_format.MessageToJson(message, sort_keys=True),
1265        # We use json.dumps() instead of a hardcoded string due to differences
1266        # between Python 2 and Python 3.
1267        json.dumps({'boolValue': True, 'int32Value': 1, 'int64Value': '3',
1268                    'uint32Value': 4, 'stringValue': 'bla'},
1269                   indent=2, sort_keys=True))
1270
1271  def testNestedRecursiveLimit(self):
1272    message = unittest_pb2.NestedTestAllTypes()
1273    self.assertRaisesRegex(
1274        json_format.ParseError,
1275        'Message too deep. Max recursion depth is 3',
1276        json_format.Parse,
1277        '{"child": {"child": {"child" : {}}}}',
1278        message,
1279        max_recursion_depth=3)
1280    # The following one can pass
1281    json_format.Parse('{"payload": {}, "child": {"child":{}}}',
1282                      message, max_recursion_depth=3)
1283
1284if __name__ == '__main__':
1285  unittest.main()
1286