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