• 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 testNullValue(self):
640    message = json_format_proto3_pb2.TestOneof()
641    message.oneof_null_value = 0
642    self.assertEqual(json_format.MessageToJson(message),
643                     '{\n  "oneofNullValue": null\n}')
644    parsed_message = json_format_proto3_pb2.TestOneof()
645    self.CheckParseBack(message, parsed_message)
646    # Check old format is also accepted
647    new_message = json_format_proto3_pb2.TestOneof()
648    json_format.Parse('{\n  "oneofNullValue": "NULL_VALUE"\n}',
649                      new_message)
650    self.assertEqual(json_format.MessageToJson(new_message),
651                     '{\n  "oneofNullValue": null\n}')
652
653  def testAnyMessage(self):
654    message = json_format_proto3_pb2.TestAny()
655    value1 = json_format_proto3_pb2.MessageType()
656    value2 = json_format_proto3_pb2.MessageType()
657    value1.value = 1234
658    value2.value = 5678
659    message.value.Pack(value1)
660    message.repeated_value.add().Pack(value1)
661    message.repeated_value.add().Pack(value2)
662    message.repeated_value.add()
663    self.assertEqual(
664        json.loads(json_format.MessageToJson(message, True)),
665        json.loads(
666            '{\n'
667            '  "repeatedValue": [ {\n'
668            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
669            '    "value": 1234\n'
670            '  }, {\n'
671            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
672            '    "value": 5678\n'
673            '  },\n'
674            '  {}],\n'
675            '  "value": {\n'
676            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
677            '    "value": 1234\n'
678            '  }\n'
679            '}\n'))
680    parsed_message = json_format_proto3_pb2.TestAny()
681    self.CheckParseBack(message, parsed_message)
682    # Must print @type first
683    test_message = json_format_proto3_pb2.TestMessage(
684        bool_value=True,
685        int32_value=20,
686        int64_value=-20,
687        uint32_value=20,
688        uint64_value=20,
689        double_value=3.14,
690        string_value='foo')
691    message.Clear()
692    message.value.Pack(test_message)
693    self.assertEqual(
694        json_format.MessageToJson(message, False)[0:68],
695        '{\n'
696        '  "value": {\n'
697        '    "@type": "type.googleapis.com/proto3.TestMessage"')
698
699  def testAnyMessageDescriptorPoolMissingType(self):
700    packed_message = unittest_pb2.OneString()
701    packed_message.data = 'string'
702    message = any_test_pb2.TestAny()
703    message.any_value.Pack(packed_message)
704    empty_pool = descriptor_pool.DescriptorPool()
705    with self.assertRaises(TypeError) as cm:
706      json_format.MessageToJson(message, True, descriptor_pool=empty_pool)
707    self.assertEqual(
708        'Can not find message descriptor by type_url:'
709        ' type.googleapis.com/protobuf_unittest.OneString.',
710        str(cm.exception))
711
712  def testWellKnownInAnyMessage(self):
713    message = any_pb2.Any()
714    int32_value = wrappers_pb2.Int32Value()
715    int32_value.value = 1234
716    message.Pack(int32_value)
717    self.assertEqual(
718        json.loads(json_format.MessageToJson(message, True)),
719        json.loads(
720            '{\n'
721            '  "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
722            '  "value": 1234\n'
723            '}\n'))
724    parsed_message = any_pb2.Any()
725    self.CheckParseBack(message, parsed_message)
726
727    timestamp = timestamp_pb2.Timestamp()
728    message.Pack(timestamp)
729    self.assertEqual(
730        json.loads(json_format.MessageToJson(message, True)),
731        json.loads(
732            '{\n'
733            '  "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
734            '  "value": "1970-01-01T00:00:00Z"\n'
735            '}\n'))
736    self.CheckParseBack(message, parsed_message)
737
738    duration = duration_pb2.Duration()
739    duration.seconds = 1
740    message.Pack(duration)
741    self.assertEqual(
742        json.loads(json_format.MessageToJson(message, True)),
743        json.loads(
744            '{\n'
745            '  "@type": "type.googleapis.com/google.protobuf.Duration",\n'
746            '  "value": "1s"\n'
747            '}\n'))
748    self.CheckParseBack(message, parsed_message)
749
750    field_mask = field_mask_pb2.FieldMask()
751    field_mask.paths.append('foo.bar')
752    field_mask.paths.append('bar')
753    message.Pack(field_mask)
754    self.assertEqual(
755        json.loads(json_format.MessageToJson(message, True)),
756        json.loads(
757            '{\n'
758            '  "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
759            '  "value": "foo.bar,bar"\n'
760            '}\n'))
761    self.CheckParseBack(message, parsed_message)
762
763    struct_message = struct_pb2.Struct()
764    struct_message['name'] = 'Jim'
765    message.Pack(struct_message)
766    self.assertEqual(
767        json.loads(json_format.MessageToJson(message, True)),
768        json.loads(
769            '{\n'
770            '  "@type": "type.googleapis.com/google.protobuf.Struct",\n'
771            '  "value": {"name": "Jim"}\n'
772            '}\n'))
773    self.CheckParseBack(message, parsed_message)
774
775    nested_any = any_pb2.Any()
776    int32_value.value = 5678
777    nested_any.Pack(int32_value)
778    message.Pack(nested_any)
779    self.assertEqual(
780        json.loads(json_format.MessageToJson(message, True)),
781        json.loads(
782            '{\n'
783            '  "@type": "type.googleapis.com/google.protobuf.Any",\n'
784            '  "value": {\n'
785            '    "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
786            '    "value": 5678\n'
787            '  }\n'
788            '}\n'))
789    self.CheckParseBack(message, parsed_message)
790
791  def testParseNull(self):
792    message = json_format_proto3_pb2.TestMessage()
793    parsed_message = json_format_proto3_pb2.TestMessage()
794    self.FillAllFields(parsed_message)
795    json_format.Parse('{"int32Value": null, '
796                      '"int64Value": null, '
797                      '"uint32Value": null,'
798                      '"uint64Value": null,'
799                      '"floatValue": null,'
800                      '"doubleValue": null,'
801                      '"boolValue": null,'
802                      '"stringValue": null,'
803                      '"bytesValue": null,'
804                      '"messageValue": null,'
805                      '"enumValue": null,'
806                      '"repeatedInt32Value": null,'
807                      '"repeatedInt64Value": null,'
808                      '"repeatedUint32Value": null,'
809                      '"repeatedUint64Value": null,'
810                      '"repeatedFloatValue": null,'
811                      '"repeatedDoubleValue": null,'
812                      '"repeatedBoolValue": null,'
813                      '"repeatedStringValue": null,'
814                      '"repeatedBytesValue": null,'
815                      '"repeatedMessageValue": null,'
816                      '"repeatedEnumValue": null'
817                      '}',
818                      parsed_message)
819    self.assertEqual(message, parsed_message)
820    # Null and {} should have different behavior for sub message.
821    self.assertFalse(parsed_message.HasField('message_value'))
822    json_format.Parse('{"messageValue": {}}', parsed_message)
823    self.assertTrue(parsed_message.HasField('message_value'))
824    # Null is not allowed to be used as an element in repeated field.
825    self.assertRaisesRegexp(
826        json_format.ParseError,
827        'Failed to parse repeatedInt32Value field: '
828        'null is not allowed to be used as an element in a repeated field.',
829        json_format.Parse,
830        '{"repeatedInt32Value":[1, null]}',
831        parsed_message)
832    self.CheckError('{"repeatedMessageValue":[null]}',
833                    'Failed to parse repeatedMessageValue field: null is not'
834                    ' allowed to be used as an element in a repeated field.')
835
836  def testNanFloat(self):
837    message = json_format_proto3_pb2.TestMessage()
838    message.float_value = float('nan')
839    text = '{\n  "floatValue": "NaN"\n}'
840    self.assertEqual(json_format.MessageToJson(message), text)
841    parsed_message = json_format_proto3_pb2.TestMessage()
842    json_format.Parse(text, parsed_message)
843    self.assertTrue(math.isnan(parsed_message.float_value))
844
845  def testParseDoubleToFloat(self):
846    message = json_format_proto3_pb2.TestMessage()
847    text = ('{"repeatedDoubleValue": [3.4028235e+39, 1.4028235e-39]\n}')
848    json_format.Parse(text, message)
849    self.assertEqual(message.repeated_double_value[0], 3.4028235e+39)
850    self.assertEqual(message.repeated_double_value[1], 1.4028235e-39)
851    text = ('{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}')
852    self.CheckError(text,
853                    'Failed to parse repeatedFloatValue field: '
854                    'Float value too large.')
855
856  def testFloatPrecision(self):
857    message = json_format_proto3_pb2.TestMessage()
858    message.float_value = 1.123456789
859    # Set to 8 valid digits.
860    text = '{\n  "floatValue": 1.1234568\n}'
861    self.assertEqual(
862        json_format.MessageToJson(message, float_precision=8), text)
863    # Set to 7 valid digits.
864    text = '{\n  "floatValue": 1.123457\n}'
865    self.assertEqual(
866        json_format.MessageToJson(message, float_precision=7), text)
867
868    # Default float_precision will automatic print shortest float.
869    message.float_value = 1.1000000011
870    text = '{\n  "floatValue": 1.1\n}'
871    self.assertEqual(
872        json_format.MessageToJson(message), text)
873    message.float_value = 1.00000075e-36
874    text = '{\n  "floatValue": 1.00000075e-36\n}'
875    self.assertEqual(
876        json_format.MessageToJson(message), text)
877    message.float_value = 12345678912345e+11
878    text = '{\n  "floatValue": 1.234568e+24\n}'
879    self.assertEqual(
880        json_format.MessageToJson(message), text)
881
882    # Test a bunch of data and check json encode/decode do not
883    # lose precision
884    value_list = [0x00, 0xD8, 0x6E, 0x00]
885    msg2 = json_format_proto3_pb2.TestMessage()
886    for a in range(0, 256):
887      value_list[3] = a
888      for b in range(0, 256):
889        value_list[0] = b
890        byte_array = bytearray(value_list)
891        message.float_value = struct.unpack('<f', byte_array)[0]
892        self.CheckParseBack(message, msg2)
893
894  def testParseEmptyText(self):
895    self.CheckError('',
896                    r'Failed to load JSON: (Expecting value)|(No JSON).')
897
898  def testParseEnumValue(self):
899    message = json_format_proto3_pb2.TestMessage()
900    text = '{"enumValue": 0}'
901    json_format.Parse(text, message)
902    text = '{"enumValue": 1}'
903    json_format.Parse(text, message)
904    self.CheckError(
905        '{"enumValue": "baz"}',
906        'Failed to parse enumValue field: Invalid enum value baz '
907        'for enum type proto3.EnumType.')
908    # Proto3 accepts numeric unknown enums.
909    text = '{"enumValue": 12345}'
910    json_format.Parse(text, message)
911    # Proto2 does not accept unknown enums.
912    message = unittest_pb2.TestAllTypes()
913    self.assertRaisesRegexp(
914        json_format.ParseError,
915        'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
916        'for enum type protobuf_unittest.TestAllTypes.NestedEnum.',
917        json_format.Parse, '{"optionalNestedEnum": 12345}', message)
918
919  def testBytes(self):
920    message = json_format_proto3_pb2.TestMessage()
921    # Test url base64
922    text = '{"bytesValue": "-_"}'
923    json_format.Parse(text, message)
924    self.assertEqual(message.bytes_value, b'\xfb')
925    # Test padding
926    text = '{"bytesValue": "AQI="}'
927    json_format.Parse(text, message)
928    self.assertEqual(message.bytes_value, b'\x01\x02')
929    text = '{"bytesValue": "AQI"}'
930    json_format.Parse(text, message)
931    self.assertEqual(message.bytes_value, b'\x01\x02')
932    text = '{"bytesValue": "AQI*"}'
933    json_format.Parse(text, message)
934    self.assertEqual(message.bytes_value, b'\x01\x02')
935
936  def testParseBadIdentifer(self):
937    self.CheckError('{int32Value: 1}',
938                    (r'Failed to load JSON: Expecting property name'
939                     r'( enclosed in double quotes)?: line 1'))
940    self.CheckError('{"unknownName": 1}',
941                    'Message type "proto3.TestMessage" has no field named '
942                    '"unknownName".')
943
944  def testIgnoreUnknownField(self):
945    text = '{"unknownName": 1}'
946    parsed_message = json_format_proto3_pb2.TestMessage()
947    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
948    text = ('{\n'
949            '  "repeatedValue": [ {\n'
950            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
951            '    "unknownName": 1\n'
952            '  }]\n'
953            '}\n')
954    parsed_message = json_format_proto3_pb2.TestAny()
955    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
956
957  def testDuplicateField(self):
958    self.CheckError('{"int32Value": 1,\n"int32Value":2}',
959                    'Failed to load JSON: duplicate key int32Value.')
960
961  def testInvalidBoolValue(self):
962    self.CheckError('{"boolValue": 1}',
963                    'Failed to parse boolValue field: '
964                    'Expected true or false without quotes.')
965    self.CheckError('{"boolValue": "true"}',
966                    'Failed to parse boolValue field: '
967                    'Expected true or false without quotes.')
968
969  def testInvalidIntegerValue(self):
970    message = json_format_proto3_pb2.TestMessage()
971    text = '{"int32Value": 0x12345}'
972    self.assertRaises(json_format.ParseError,
973                      json_format.Parse, text, message)
974    self.CheckError('{"int32Value": 1.5}',
975                    'Failed to parse int32Value field: '
976                    'Couldn\'t parse integer: 1.5.')
977    self.CheckError('{"int32Value": 012345}',
978                    (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
979                     r'line 1.'))
980    self.CheckError('{"int32Value": " 1 "}',
981                    'Failed to parse int32Value field: '
982                    'Couldn\'t parse integer: " 1 ".')
983    self.CheckError('{"int32Value": "1 "}',
984                    'Failed to parse int32Value field: '
985                    'Couldn\'t parse integer: "1 ".')
986    self.CheckError('{"int32Value": false}',
987                    'Failed to parse int32Value field: Bool value False '
988                    'is not acceptable for integer field.')
989    self.CheckError('{"int32Value": 12345678901234567890}',
990                    'Failed to parse int32Value field: Value out of range: '
991                    '12345678901234567890.')
992    self.CheckError('{"uint32Value": -1}',
993                    'Failed to parse uint32Value field: '
994                    'Value out of range: -1.')
995
996  def testInvalidFloatValue(self):
997    self.CheckError('{"floatValue": "nan"}',
998                    'Failed to parse floatValue field: Couldn\'t '
999                    'parse float "nan", use "NaN" instead.')
1000    self.CheckError('{"floatValue": NaN}',
1001                    'Failed to parse floatValue field: Couldn\'t '
1002                    'parse NaN, use quoted "NaN" instead.')
1003    self.CheckError('{"floatValue": Infinity}',
1004                    'Failed to parse floatValue field: Couldn\'t parse Infinity'
1005                    ' or value too large, use quoted "Infinity" instead.')
1006    self.CheckError('{"floatValue": -Infinity}',
1007                    'Failed to parse floatValue field: Couldn\'t parse '
1008                    '-Infinity or value too small, '
1009                    'use quoted "-Infinity" instead.')
1010    self.CheckError('{"doubleValue": -1.89769e+308}',
1011                    'Failed to parse doubleValue field: Couldn\'t parse '
1012                    '-Infinity or value too small, '
1013                    'use quoted "-Infinity" instead.')
1014    self.CheckError('{"floatValue": 3.4028235e+39}',
1015                    'Failed to parse floatValue field: Float value too large.')
1016    self.CheckError('{"floatValue": -3.502823e+38}',
1017                    'Failed to parse floatValue field: Float value too small.')
1018
1019  def testInvalidRepeated(self):
1020    self.CheckError('{"repeatedInt32Value": 12345}',
1021                    (r'Failed to parse repeatedInt32Value field: repeated field'
1022                     r' repeatedInt32Value must be in \[\] which is 12345.'))
1023
1024  def testInvalidMap(self):
1025    message = json_format_proto3_pb2.TestMap()
1026    text = '{"int32Map": {"null": 2, "2": 3}}'
1027    self.assertRaisesRegexp(
1028        json_format.ParseError,
1029        'Failed to parse int32Map field: invalid literal',
1030        json_format.Parse, text, message)
1031    text = '{"int32Map": {1: 2, "2": 3}}'
1032    self.assertRaisesRegexp(
1033        json_format.ParseError,
1034        (r'Failed to load JSON: Expecting property name'
1035         r'( enclosed in double quotes)?: line 1'),
1036        json_format.Parse, text, message)
1037    text = '{"boolMap": {"null": 1}}'
1038    self.assertRaisesRegexp(
1039        json_format.ParseError,
1040        'Failed to parse boolMap field: Expected "true" or "false", not null.',
1041        json_format.Parse, text, message)
1042    if sys.version_info < (2, 7):
1043      return
1044    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
1045    self.assertRaisesRegexp(
1046        json_format.ParseError,
1047        'Failed to load JSON: duplicate key a',
1048        json_format.Parse, text, message)
1049    text = r'{"stringMap": 0}'
1050    self.assertRaisesRegexp(
1051        json_format.ParseError,
1052        'Failed to parse stringMap field: Map field string_map must be '
1053        'in a dict which is 0.',
1054        json_format.Parse, text, message)
1055
1056  def testInvalidTimestamp(self):
1057    message = json_format_proto3_pb2.TestTimestamp()
1058    text = '{"value": "10000-01-01T00:00:00.00Z"}'
1059    self.assertRaisesRegexp(
1060        json_format.ParseError,
1061        'Failed to parse value field: '
1062        'time data \'10000-01-01T00:00:00\' does not match'
1063        ' format \'%Y-%m-%dT%H:%M:%S\'.',
1064        json_format.Parse, text, message)
1065    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
1066    self.assertRaisesRegexp(
1067        json_format.ParseError,
1068        'nanos 0123456789012 more than 9 fractional digits.',
1069        json_format.Parse, text, message)
1070    text = '{"value": "1972-01-01T01:00:00.01+08"}'
1071    self.assertRaisesRegexp(
1072        json_format.ParseError,
1073        (r'Invalid timezone offset value: \+08.'),
1074        json_format.Parse, text, message)
1075    # Time smaller than minimum time.
1076    text = '{"value": "0000-01-01T00:00:00Z"}'
1077    self.assertRaisesRegexp(
1078        json_format.ParseError,
1079        'Failed to parse value field: year (0 )?is out of range.',
1080        json_format.Parse, text, message)
1081    # Time bigger than maximum time.
1082    message.value.seconds = 253402300800
1083    self.assertRaisesRegexp(
1084        OverflowError,
1085        'date value out of range',
1086        json_format.MessageToJson, message)
1087    # Lower case t does not accept.
1088    text = '{"value": "0001-01-01t00:00:00Z"}'
1089    with self.assertRaises(json_format.ParseError) as e:
1090      json_format.Parse(text, message)
1091    self.assertEqual(
1092        'Failed to parse value field: '
1093        'time data \'0001-01-01t00:00:00\' does not match format '
1094        '\'%Y-%m-%dT%H:%M:%S\', lowercase \'t\' is not accepted.',
1095        str(e.exception))
1096
1097  def testInvalidOneof(self):
1098    message = json_format_proto3_pb2.TestOneof()
1099    text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
1100    self.assertRaisesRegexp(
1101        json_format.ParseError,
1102        'Message type "proto3.TestOneof"'
1103        ' should not have multiple "oneof_value" oneof fields.',
1104        json_format.Parse, text, message)
1105
1106  def testInvalidListValue(self):
1107    message = json_format_proto3_pb2.TestListValue()
1108    text = '{"value": 1234}'
1109    self.assertRaisesRegexp(
1110        json_format.ParseError,
1111        r'Failed to parse value field: ListValue must be in \[\] which is 1234',
1112        json_format.Parse, text, message)
1113
1114  def testInvalidStruct(self):
1115    message = json_format_proto3_pb2.TestStruct()
1116    text = '{"value": 1234}'
1117    self.assertRaisesRegexp(
1118        json_format.ParseError,
1119        'Failed to parse value field: Struct must be in a dict which is 1234',
1120        json_format.Parse, text, message)
1121
1122  def testInvalidAny(self):
1123    message = any_pb2.Any()
1124    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
1125    self.assertRaisesRegexp(
1126        KeyError,
1127        'value',
1128        json_format.Parse, text, message)
1129    text = '{"value": 1234}'
1130    self.assertRaisesRegexp(
1131        json_format.ParseError,
1132        '@type is missing when parsing any message.',
1133        json_format.Parse, text, message)
1134    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
1135    self.assertRaisesRegexp(
1136        TypeError,
1137        'Can not find message descriptor by type_url: '
1138        'type.googleapis.com/MessageNotExist.',
1139        json_format.Parse, text, message)
1140    # Only last part is to be used: b/25630112
1141    text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
1142            r'"value": 1234}')
1143    json_format.Parse(text, message)
1144
1145  def testPreservingProtoFieldNames(self):
1146    message = json_format_proto3_pb2.TestMessage()
1147    message.int32_value = 12345
1148    self.assertEqual('{\n  "int32Value": 12345\n}',
1149                     json_format.MessageToJson(message))
1150    self.assertEqual('{\n  "int32_value": 12345\n}',
1151                     json_format.MessageToJson(message, False, True))
1152    # When including_default_value_fields is True.
1153    message = json_format_proto3_pb2.TestTimestamp()
1154    self.assertEqual('{\n  "repeatedValue": []\n}',
1155                     json_format.MessageToJson(message, True, False))
1156    self.assertEqual('{\n  "repeated_value": []\n}',
1157                     json_format.MessageToJson(message, True, True))
1158
1159    # Parsers accept both original proto field names and lowerCamelCase names.
1160    message = json_format_proto3_pb2.TestMessage()
1161    json_format.Parse('{"int32Value": 54321}', message)
1162    self.assertEqual(54321, message.int32_value)
1163    json_format.Parse('{"int32_value": 12345}', message)
1164    self.assertEqual(12345, message.int32_value)
1165
1166  def testIndent(self):
1167    message = json_format_proto3_pb2.TestMessage()
1168    message.int32_value = 12345
1169    self.assertEqual('{\n"int32Value": 12345\n}',
1170                     json_format.MessageToJson(message, indent=0))
1171
1172  def testFormatEnumsAsInts(self):
1173    message = json_format_proto3_pb2.TestMessage()
1174    message.enum_value = json_format_proto3_pb2.BAR
1175    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
1176    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
1177    self.assertEqual(json.loads('{\n'
1178                                '  "enumValue": 1,\n'
1179                                '  "repeatedEnumValue": [0, 1]\n'
1180                                '}\n'),
1181                     json.loads(json_format.MessageToJson(
1182                         message, use_integers_for_enums=True)))
1183
1184  def testParseDict(self):
1185    expected = 12345
1186    js_dict = {'int32Value': expected}
1187    message = json_format_proto3_pb2.TestMessage()
1188    json_format.ParseDict(js_dict, message)
1189    self.assertEqual(expected, message.int32_value)
1190
1191  def testParseDictAnyDescriptorPoolMissingType(self):
1192    # Confirm that ParseDict does not raise ParseError with default pool
1193    js_dict = {
1194        'any_value': {
1195            '@type': 'type.googleapis.com/proto3.MessageType',
1196            'value': 1234
1197        }
1198    }
1199    json_format.ParseDict(js_dict, any_test_pb2.TestAny())
1200    # Check ParseDict raises ParseError with empty pool
1201    js_dict = {
1202        'any_value': {
1203            '@type': 'type.googleapis.com/proto3.MessageType',
1204            'value': 1234
1205        }
1206    }
1207    with self.assertRaises(json_format.ParseError) as cm:
1208      empty_pool = descriptor_pool.DescriptorPool()
1209      json_format.ParseDict(js_dict,
1210                            any_test_pb2.TestAny(),
1211                            descriptor_pool=empty_pool)
1212    self.assertEqual(
1213        str(cm.exception),
1214        'Failed to parse any_value field: Can not find message descriptor by'
1215        ' type_url: type.googleapis.com/proto3.MessageType..')
1216
1217  def testParseDictUnknownValueType(self):
1218    class UnknownClass(object):
1219
1220      def __str__(self):
1221        return 'v'
1222    message = json_format_proto3_pb2.TestValue()
1223    self.assertRaisesRegexp(
1224        json_format.ParseError,
1225        r"Value v has unexpected type <class '.*\.UnknownClass'>.",
1226        json_format.ParseDict,
1227        {'value': UnknownClass()},
1228        message)
1229
1230  def testMessageToDict(self):
1231    message = json_format_proto3_pb2.TestMessage()
1232    message.int32_value = 12345
1233    expected = {'int32Value': 12345}
1234    self.assertEqual(expected,
1235                     json_format.MessageToDict(message))
1236
1237  def testJsonName(self):
1238    message = json_format_proto3_pb2.TestCustomJsonName()
1239    message.value = 12345
1240    self.assertEqual('{\n  "@value": 12345\n}',
1241                     json_format.MessageToJson(message))
1242    parsed_message = json_format_proto3_pb2.TestCustomJsonName()
1243    self.CheckParseBack(message, parsed_message)
1244
1245  def testSortKeys(self):
1246    # Testing sort_keys is not perfectly working, as by random luck we could
1247    # get the output sorted. We just use a selection of names.
1248    message = json_format_proto3_pb2.TestMessage(bool_value=True,
1249                                                 int32_value=1,
1250                                                 int64_value=3,
1251                                                 uint32_value=4,
1252                                                 string_value='bla')
1253    self.assertEqual(
1254        json_format.MessageToJson(message, sort_keys=True),
1255        # We use json.dumps() instead of a hardcoded string due to differences
1256        # between Python 2 and Python 3.
1257        json.dumps({'boolValue': True, 'int32Value': 1, 'int64Value': '3',
1258                    'uint32Value': 4, 'stringValue': 'bla'},
1259                   indent=2, sort_keys=True))
1260
1261
1262if __name__ == '__main__':
1263  unittest.main()
1264