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