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