blob: bdc9f49a4071ad077807f1db56f88149999a4998 [file] [log] [blame]
Jisi Liu46e8ff62015-10-05 11:59:43 -07001#! /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 sys
40
Jisi Liudbea00a2015-10-05 16:08:22 -070041try:
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070042 import unittest2 as unittest #PY26
Jisi Liudbea00a2015-10-05 16:08:22 -070043except ImportError:
44 import unittest
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070045
CH Albach5477f8c2016-01-29 18:10:50 -080046from google.protobuf import any_pb2
47from google.protobuf import duration_pb2
48from google.protobuf import field_mask_pb2
49from google.protobuf import struct_pb2
50from google.protobuf import timestamp_pb2
51from google.protobuf import wrappers_pb2
Feng Xiaoe841bac2015-12-11 17:09:20 -080052from google.protobuf.internal import well_known_types
Jisi Liu46e8ff62015-10-05 11:59:43 -070053from google.protobuf import json_format
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.assertRaisesRegexp(
104 json_format.ParseError,
105 error_message,
106 json_format.Parse, text, message)
107
108
109class JsonFormatTest(JsonFormatBase):
110
111 def testEmptyMessageToJson(self):
112 message = json_format_proto3_pb2.TestMessage()
113 self.assertEqual(json_format.MessageToJson(message),
114 '{}')
115 parsed_message = json_format_proto3_pb2.TestMessage()
116 self.CheckParseBack(message, parsed_message)
117
118 def testPartialMessageToJson(self):
119 message = json_format_proto3_pb2.TestMessage(
120 string_value='test',
121 repeated_int32_value=[89, 4])
122 self.assertEqual(json.loads(json_format.MessageToJson(message)),
123 json.loads('{"stringValue": "test", '
124 '"repeatedInt32Value": [89, 4]}'))
125 parsed_message = json_format_proto3_pb2.TestMessage()
126 self.CheckParseBack(message, parsed_message)
127
128 def testAllFieldsToJson(self):
129 message = json_format_proto3_pb2.TestMessage()
130 text = ('{"int32Value": 20, '
131 '"int64Value": "-20", '
132 '"uint32Value": 3120987654,'
133 '"uint64Value": "12345678900",'
134 '"floatValue": "-Infinity",'
135 '"doubleValue": 3.1415,'
136 '"boolValue": true,'
137 '"stringValue": "foo",'
138 '"bytesValue": "YmFy",'
139 '"messageValue": {"value": 10},'
140 '"enumValue": "BAR",'
141 '"repeatedInt32Value": [2147483647, -2147483648],'
142 '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
143 '"repeatedUint32Value": [268435455, 134217727],'
144 '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
145 '"repeatedFloatValue": [0],'
146 '"repeatedDoubleValue": [1e-15, "Infinity"],'
147 '"repeatedBoolValue": [true, false],'
148 '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
149 '"repeatedBytesValue": ["Zm9v", "YmFy"],'
150 '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
151 '"repeatedEnumValue": ["FOO", "BAR"]'
152 '}')
153 self.FillAllFields(message)
154 self.assertEqual(
155 json.loads(json_format.MessageToJson(message)),
156 json.loads(text))
157 parsed_message = json_format_proto3_pb2.TestMessage()
158 json_format.Parse(text, parsed_message)
159 self.assertEqual(message, parsed_message)
160
161 def testJsonEscapeString(self):
162 message = json_format_proto3_pb2.TestMessage()
163 if sys.version_info[0] < 3:
164 message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
165 else:
166 message.string_value = '&\n<\"\r>\b\t\f\\\001/'
167 message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
168 self.assertEqual(
169 json_format.MessageToJson(message),
170 '{\n "stringValue": '
171 '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
172 parsed_message = json_format_proto3_pb2.TestMessage()
173 self.CheckParseBack(message, parsed_message)
174 text = u'{"int32Value": "\u0031"}'
175 json_format.Parse(text, message)
176 self.assertEqual(message.int32_value, 1)
177
178 def testAlwaysSeriliaze(self):
179 message = json_format_proto3_pb2.TestMessage(
180 string_value='foo')
181 self.assertEqual(
182 json.loads(json_format.MessageToJson(message, True)),
183 json.loads('{'
184 '"repeatedStringValue": [],'
185 '"stringValue": "foo",'
186 '"repeatedBoolValue": [],'
187 '"repeatedUint32Value": [],'
188 '"repeatedInt32Value": [],'
189 '"enumValue": "FOO",'
190 '"int32Value": 0,'
191 '"floatValue": 0,'
192 '"int64Value": "0",'
193 '"uint32Value": 0,'
194 '"repeatedBytesValue": [],'
195 '"repeatedUint64Value": [],'
196 '"repeatedDoubleValue": [],'
197 '"bytesValue": "",'
198 '"boolValue": false,'
199 '"repeatedEnumValue": [],'
200 '"uint64Value": "0",'
201 '"doubleValue": 0,'
202 '"repeatedFloatValue": [],'
203 '"repeatedInt64Value": [],'
204 '"repeatedMessageValue": []}'))
205 parsed_message = json_format_proto3_pb2.TestMessage()
206 self.CheckParseBack(message, parsed_message)
207
208 def testMapFields(self):
209 message = json_format_proto3_pb2.TestMap()
210 message.bool_map[True] = 1
211 message.bool_map[False] = 2
212 message.int32_map[1] = 2
213 message.int32_map[2] = 3
214 message.int64_map[1] = 2
215 message.int64_map[2] = 3
216 message.uint32_map[1] = 2
217 message.uint32_map[2] = 3
218 message.uint64_map[1] = 2
219 message.uint64_map[2] = 3
220 message.string_map['1'] = 2
221 message.string_map['null'] = 3
222 self.assertEqual(
223 json.loads(json_format.MessageToJson(message, True)),
224 json.loads('{'
225 '"boolMap": {"false": 2, "true": 1},'
226 '"int32Map": {"1": 2, "2": 3},'
227 '"int64Map": {"1": 2, "2": 3},'
228 '"uint32Map": {"1": 2, "2": 3},'
229 '"uint64Map": {"1": 2, "2": 3},'
230 '"stringMap": {"1": 2, "null": 3}'
231 '}'))
232 parsed_message = json_format_proto3_pb2.TestMap()
233 self.CheckParseBack(message, parsed_message)
234
235 def testOneofFields(self):
236 message = json_format_proto3_pb2.TestOneof()
237 # Always print does not affect oneof fields.
238 self.assertEqual(
239 json_format.MessageToJson(message, True),
240 '{}')
241 message.oneof_int32_value = 0
242 self.assertEqual(
243 json_format.MessageToJson(message, True),
244 '{\n'
245 ' "oneofInt32Value": 0\n'
246 '}')
247 parsed_message = json_format_proto3_pb2.TestOneof()
248 self.CheckParseBack(message, parsed_message)
249
250 def testTimestampMessage(self):
251 message = json_format_proto3_pb2.TestTimestamp()
252 message.value.seconds = 0
253 message.value.nanos = 0
254 message.repeated_value.add().seconds = 20
255 message.repeated_value[0].nanos = 1
256 message.repeated_value.add().seconds = 0
257 message.repeated_value[1].nanos = 10000
258 message.repeated_value.add().seconds = 100000000
259 message.repeated_value[2].nanos = 0
260 # Maximum time
261 message.repeated_value.add().seconds = 253402300799
262 message.repeated_value[3].nanos = 999999999
263 # Minimum time
264 message.repeated_value.add().seconds = -62135596800
265 message.repeated_value[4].nanos = 0
266 self.assertEqual(
267 json.loads(json_format.MessageToJson(message, True)),
268 json.loads('{'
269 '"value": "1970-01-01T00:00:00Z",'
270 '"repeatedValue": ['
271 ' "1970-01-01T00:00:20.000000001Z",'
272 ' "1970-01-01T00:00:00.000010Z",'
273 ' "1973-03-03T09:46:40Z",'
274 ' "9999-12-31T23:59:59.999999999Z",'
275 ' "0001-01-01T00:00:00Z"'
276 ']'
277 '}'))
278 parsed_message = json_format_proto3_pb2.TestTimestamp()
279 self.CheckParseBack(message, parsed_message)
Feng Xiaoe841bac2015-12-11 17:09:20 -0800280 text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
Jisi Liu46e8ff62015-10-05 11:59:43 -0700281 r'"repeatedValue":['
Feng Xiaoe841bac2015-12-11 17:09:20 -0800282 r' "1970-01-01T00:00:00.01+08:30",'
283 r' "1970-01-01T00:00:00.01-01:23"]}')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700284 json_format.Parse(text, parsed_message)
Feng Xiaoe841bac2015-12-11 17:09:20 -0800285 self.assertEqual(parsed_message.value.seconds, -8 * 3600)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700286 self.assertEqual(parsed_message.value.nanos, 10000000)
Feng Xiaoe841bac2015-12-11 17:09:20 -0800287 self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
288 self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700289
290 def testDurationMessage(self):
291 message = json_format_proto3_pb2.TestDuration()
292 message.value.seconds = 1
293 message.repeated_value.add().seconds = 0
294 message.repeated_value[0].nanos = 10
295 message.repeated_value.add().seconds = -1
296 message.repeated_value[1].nanos = -1000
297 message.repeated_value.add().seconds = 10
298 message.repeated_value[2].nanos = 11000000
299 message.repeated_value.add().seconds = -315576000000
300 message.repeated_value.add().seconds = 315576000000
301 self.assertEqual(
302 json.loads(json_format.MessageToJson(message, True)),
303 json.loads('{'
304 '"value": "1s",'
305 '"repeatedValue": ['
306 ' "0.000000010s",'
307 ' "-1.000001s",'
308 ' "10.011s",'
309 ' "-315576000000s",'
310 ' "315576000000s"'
311 ']'
312 '}'))
313 parsed_message = json_format_proto3_pb2.TestDuration()
314 self.CheckParseBack(message, parsed_message)
315
316 def testFieldMaskMessage(self):
317 message = json_format_proto3_pb2.TestFieldMask()
318 message.value.paths.append('foo.bar')
319 message.value.paths.append('bar')
320 self.assertEqual(
321 json_format.MessageToJson(message, True),
322 '{\n'
323 ' "value": "foo.bar,bar"\n'
324 '}')
325 parsed_message = json_format_proto3_pb2.TestFieldMask()
326 self.CheckParseBack(message, parsed_message)
327
328 def testWrapperMessage(self):
329 message = json_format_proto3_pb2.TestWrapper()
330 message.bool_value.value = False
331 message.int32_value.value = 0
332 message.string_value.value = ''
333 message.bytes_value.value = b''
334 message.repeated_bool_value.add().value = True
335 message.repeated_bool_value.add().value = False
CH Albach5477f8c2016-01-29 18:10:50 -0800336 message.repeated_int32_value.add()
Jisi Liu46e8ff62015-10-05 11:59:43 -0700337 self.assertEqual(
338 json.loads(json_format.MessageToJson(message, True)),
339 json.loads('{\n'
340 ' "int32Value": 0,'
341 ' "boolValue": false,'
342 ' "stringValue": "",'
343 ' "bytesValue": "",'
344 ' "repeatedBoolValue": [true, false],'
CH Albach5477f8c2016-01-29 18:10:50 -0800345 ' "repeatedInt32Value": [0],'
Jisi Liu46e8ff62015-10-05 11:59:43 -0700346 ' "repeatedUint32Value": [],'
347 ' "repeatedFloatValue": [],'
348 ' "repeatedDoubleValue": [],'
349 ' "repeatedBytesValue": [],'
350 ' "repeatedInt64Value": [],'
351 ' "repeatedUint64Value": [],'
352 ' "repeatedStringValue": []'
353 '}'))
354 parsed_message = json_format_proto3_pb2.TestWrapper()
355 self.CheckParseBack(message, parsed_message)
356
CH Albach5477f8c2016-01-29 18:10:50 -0800357 def testStructMessage(self):
358 message = json_format_proto3_pb2.TestStruct()
359 message.value['name'] = 'Jim'
360 message.value['age'] = 10
361 message.value['attend'] = True
362 message.value['email'] = None
363 message.value.get_or_create_struct('address')['city'] = 'SFO'
364 message.value['address']['house_number'] = 1024
365 struct_list = message.value.get_or_create_list('list')
366 struct_list.extend([6, 'seven', True, False, None])
367 struct_list.add_struct()['subkey2'] = 9
368 message.repeated_value.add()['age'] = 11
369 message.repeated_value.add()
370 self.assertEqual(
371 json.loads(json_format.MessageToJson(message, False)),
372 json.loads(
373 '{'
374 ' "value": {'
375 ' "address": {'
376 ' "city": "SFO", '
377 ' "house_number": 1024'
378 ' }, '
379 ' "age": 10, '
380 ' "name": "Jim", '
381 ' "attend": true, '
382 ' "email": null, '
383 ' "list": [6, "seven", true, false, null, {"subkey2": 9}]'
384 ' },'
385 ' "repeatedValue": [{"age": 11}, {}]'
386 '}'))
387 parsed_message = json_format_proto3_pb2.TestStruct()
388 self.CheckParseBack(message, parsed_message)
389
390 def testValueMessage(self):
391 message = json_format_proto3_pb2.TestValue()
392 message.value.string_value = 'hello'
393 message.repeated_value.add().number_value = 11.1
394 message.repeated_value.add().bool_value = False
395 message.repeated_value.add().null_value = 0
396 self.assertEqual(
397 json.loads(json_format.MessageToJson(message, False)),
398 json.loads(
399 '{'
400 ' "value": "hello",'
401 ' "repeatedValue": [11.1, false, null]'
402 '}'))
403 parsed_message = json_format_proto3_pb2.TestValue()
404 self.CheckParseBack(message, parsed_message)
405 # Can't parse back if the Value message is not set.
406 message.repeated_value.add()
407 self.assertEqual(
408 json.loads(json_format.MessageToJson(message, False)),
409 json.loads(
410 '{'
411 ' "value": "hello",'
412 ' "repeatedValue": [11.1, false, null, null]'
413 '}'))
414
415 def testListValueMessage(self):
416 message = json_format_proto3_pb2.TestListValue()
417 message.value.values.add().number_value = 11.1
418 message.value.values.add().null_value = 0
419 message.value.values.add().bool_value = True
420 message.value.values.add().string_value = 'hello'
421 message.value.values.add().struct_value['name'] = 'Jim'
422 message.repeated_value.add().values.add().number_value = 1
423 message.repeated_value.add()
424 self.assertEqual(
425 json.loads(json_format.MessageToJson(message, False)),
426 json.loads(
427 '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
428 '"repeatedValue": [[1], []]}'))
429 parsed_message = json_format_proto3_pb2.TestListValue()
430 self.CheckParseBack(message, parsed_message)
431
432 def testAnyMessage(self):
433 message = json_format_proto3_pb2.TestAny()
434 value1 = json_format_proto3_pb2.MessageType()
435 value2 = json_format_proto3_pb2.MessageType()
436 value1.value = 1234
437 value2.value = 5678
438 message.value.Pack(value1)
439 message.repeated_value.add().Pack(value1)
440 message.repeated_value.add().Pack(value2)
441 message.repeated_value.add()
442 self.assertEqual(
443 json.loads(json_format.MessageToJson(message, True)),
444 json.loads(
445 '{\n'
446 ' "repeatedValue": [ {\n'
447 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
448 ' "value": 1234\n'
449 ' }, {\n'
450 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
451 ' "value": 5678\n'
452 ' },\n'
453 ' {}],\n'
454 ' "value": {\n'
455 ' "@type": "type.googleapis.com/proto3.MessageType",\n'
456 ' "value": 1234\n'
457 ' }\n'
458 '}\n'))
459 parsed_message = json_format_proto3_pb2.TestAny()
460 self.CheckParseBack(message, parsed_message)
461
462 def testWellKnownInAnyMessage(self):
463 message = any_pb2.Any()
464 int32_value = wrappers_pb2.Int32Value()
465 int32_value.value = 1234
466 message.Pack(int32_value)
467 self.assertEqual(
468 json.loads(json_format.MessageToJson(message, True)),
469 json.loads(
470 '{\n'
471 ' "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
472 ' "value": 1234\n'
473 '}\n'))
474 parsed_message = any_pb2.Any()
475 self.CheckParseBack(message, parsed_message)
476
477 timestamp = timestamp_pb2.Timestamp()
478 message.Pack(timestamp)
479 self.assertEqual(
480 json.loads(json_format.MessageToJson(message, True)),
481 json.loads(
482 '{\n'
483 ' "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
484 ' "value": "1970-01-01T00:00:00Z"\n'
485 '}\n'))
486 self.CheckParseBack(message, parsed_message)
487
488 duration = duration_pb2.Duration()
489 duration.seconds = 1
490 message.Pack(duration)
491 self.assertEqual(
492 json.loads(json_format.MessageToJson(message, True)),
493 json.loads(
494 '{\n'
495 ' "@type": "type.googleapis.com/google.protobuf.Duration",\n'
496 ' "value": "1s"\n'
497 '}\n'))
498 self.CheckParseBack(message, parsed_message)
499
500 field_mask = field_mask_pb2.FieldMask()
501 field_mask.paths.append('foo.bar')
502 field_mask.paths.append('bar')
503 message.Pack(field_mask)
504 self.assertEqual(
505 json.loads(json_format.MessageToJson(message, True)),
506 json.loads(
507 '{\n'
508 ' "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
509 ' "value": "foo.bar,bar"\n'
510 '}\n'))
511 self.CheckParseBack(message, parsed_message)
512
513 struct_message = struct_pb2.Struct()
514 struct_message['name'] = 'Jim'
515 message.Pack(struct_message)
516 self.assertEqual(
517 json.loads(json_format.MessageToJson(message, True)),
518 json.loads(
519 '{\n'
520 ' "@type": "type.googleapis.com/google.protobuf.Struct",\n'
521 ' "value": {"name": "Jim"}\n'
522 '}\n'))
523 self.CheckParseBack(message, parsed_message)
524
525 nested_any = any_pb2.Any()
526 int32_value.value = 5678
527 nested_any.Pack(int32_value)
528 message.Pack(nested_any)
529 self.assertEqual(
530 json.loads(json_format.MessageToJson(message, True)),
531 json.loads(
532 '{\n'
533 ' "@type": "type.googleapis.com/google.protobuf.Any",\n'
534 ' "value": {\n'
535 ' "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
536 ' "value": 5678\n'
537 ' }\n'
538 '}\n'))
539 self.CheckParseBack(message, parsed_message)
540
Jisi Liu46e8ff62015-10-05 11:59:43 -0700541 def testParseNull(self):
542 message = json_format_proto3_pb2.TestMessage()
Jisi Liu46e8ff62015-10-05 11:59:43 -0700543 parsed_message = json_format_proto3_pb2.TestMessage()
544 self.FillAllFields(parsed_message)
545 json_format.Parse('{"int32Value": null, '
546 '"int64Value": null, '
547 '"uint32Value": null,'
548 '"uint64Value": null,'
549 '"floatValue": null,'
550 '"doubleValue": null,'
551 '"boolValue": null,'
552 '"stringValue": null,'
553 '"bytesValue": null,'
554 '"messageValue": null,'
555 '"enumValue": null,'
CH Albach5477f8c2016-01-29 18:10:50 -0800556 '"repeatedInt32Value": null,'
Jisi Liu46e8ff62015-10-05 11:59:43 -0700557 '"repeatedInt64Value": null,'
558 '"repeatedUint32Value": null,'
559 '"repeatedUint64Value": null,'
560 '"repeatedFloatValue": null,'
561 '"repeatedDoubleValue": null,'
562 '"repeatedBoolValue": null,'
563 '"repeatedStringValue": null,'
564 '"repeatedBytesValue": null,'
565 '"repeatedMessageValue": null,'
566 '"repeatedEnumValue": null'
567 '}',
568 parsed_message)
569 self.assertEqual(message, parsed_message)
CH Albach5477f8c2016-01-29 18:10:50 -0800570 self.assertRaisesRegexp(
571 json_format.ParseError,
572 'Failed to parse repeatedInt32Value field: '
573 'null is not allowed to be used as an element in a repeated field.',
574 json_format.Parse,
575 '{"repeatedInt32Value":[1, null]}',
576 parsed_message)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700577
578 def testNanFloat(self):
579 message = json_format_proto3_pb2.TestMessage()
580 message.float_value = float('nan')
581 text = '{\n "floatValue": "NaN"\n}'
582 self.assertEqual(json_format.MessageToJson(message), text)
583 parsed_message = json_format_proto3_pb2.TestMessage()
584 json_format.Parse(text, parsed_message)
585 self.assertTrue(math.isnan(parsed_message.float_value))
586
587 def testParseEmptyText(self):
588 self.CheckError('',
Feng Xiaoe841bac2015-12-11 17:09:20 -0800589 r'Failed to load JSON: (Expecting value)|(No JSON).')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700590
591 def testParseBadEnumValue(self):
592 self.CheckError(
593 '{"enumValue": 1}',
594 'Enum value must be a string literal with double quotes. '
595 'Type "proto3.EnumType" has no value named 1.')
596 self.CheckError(
597 '{"enumValue": "baz"}',
598 'Enum value must be a string literal with double quotes. '
599 'Type "proto3.EnumType" has no value named baz.')
600
601 def testParseBadIdentifer(self):
602 self.CheckError('{int32Value: 1}',
Jisi Liua783eaf2015-10-05 15:06:06 -0700603 (r'Failed to load JSON: Expecting property name'
604 r'( enclosed in double quotes)?: line 1'))
Jisi Liu46e8ff62015-10-05 11:59:43 -0700605 self.CheckError('{"unknownName": 1}',
606 'Message type "proto3.TestMessage" has no field named '
607 '"unknownName".')
608
609 def testDuplicateField(self):
Jie Luo2850a982015-10-09 17:07:03 -0700610 # Duplicate key check is not supported for python2.6
611 if sys.version_info < (2, 7):
612 return
Jisi Liu46e8ff62015-10-05 11:59:43 -0700613 self.CheckError('{"int32Value": 1,\n"int32Value":2}',
Feng Xiaoe841bac2015-12-11 17:09:20 -0800614 'Failed to load JSON: duplicate key int32Value.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700615
616 def testInvalidBoolValue(self):
617 self.CheckError('{"boolValue": 1}',
618 'Failed to parse boolValue field: '
619 'Expected true or false without quotes.')
620 self.CheckError('{"boolValue": "true"}',
621 'Failed to parse boolValue field: '
622 'Expected true or false without quotes.')
623
624 def testInvalidIntegerValue(self):
625 message = json_format_proto3_pb2.TestMessage()
626 text = '{"int32Value": 0x12345}'
627 self.assertRaises(json_format.ParseError,
628 json_format.Parse, text, message)
629 self.CheckError('{"int32Value": 012345}',
Jisi Liua783eaf2015-10-05 15:06:06 -0700630 (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800631 r'line 1.'))
Jisi Liu46e8ff62015-10-05 11:59:43 -0700632 self.CheckError('{"int32Value": 1.0}',
633 'Failed to parse int32Value field: '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800634 'Couldn\'t parse integer: 1.0.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700635 self.CheckError('{"int32Value": " 1 "}',
636 'Failed to parse int32Value field: '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800637 'Couldn\'t parse integer: " 1 ".')
638 self.CheckError('{"int32Value": "1 "}',
639 'Failed to parse int32Value field: '
640 'Couldn\'t parse integer: "1 ".')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700641 self.CheckError('{"int32Value": 12345678901234567890}',
642 'Failed to parse int32Value field: Value out of range: '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800643 '12345678901234567890.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700644 self.CheckError('{"int32Value": 1e5}',
645 'Failed to parse int32Value field: '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800646 'Couldn\'t parse integer: 100000.0.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700647 self.CheckError('{"uint32Value": -1}',
Feng Xiaoe841bac2015-12-11 17:09:20 -0800648 'Failed to parse uint32Value field: '
649 'Value out of range: -1.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700650
651 def testInvalidFloatValue(self):
652 self.CheckError('{"floatValue": "nan"}',
653 'Failed to parse floatValue field: Couldn\'t '
Feng Xiaoe841bac2015-12-11 17:09:20 -0800654 'parse float "nan", use "NaN" instead.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700655
656 def testInvalidBytesValue(self):
657 self.CheckError('{"bytesValue": "AQI"}',
Feng Xiaoe841bac2015-12-11 17:09:20 -0800658 'Failed to parse bytesValue field: Incorrect padding.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700659 self.CheckError('{"bytesValue": "AQI*"}',
Feng Xiaoe841bac2015-12-11 17:09:20 -0800660 'Failed to parse bytesValue field: Incorrect padding.')
Jisi Liu46e8ff62015-10-05 11:59:43 -0700661
662 def testInvalidMap(self):
663 message = json_format_proto3_pb2.TestMap()
664 text = '{"int32Map": {"null": 2, "2": 3}}'
665 self.assertRaisesRegexp(
666 json_format.ParseError,
Feng Xiaoe841bac2015-12-11 17:09:20 -0800667 'Failed to parse int32Map field: invalid literal',
Jisi Liu46e8ff62015-10-05 11:59:43 -0700668 json_format.Parse, text, message)
669 text = '{"int32Map": {1: 2, "2": 3}}'
670 self.assertRaisesRegexp(
671 json_format.ParseError,
Jisi Liua783eaf2015-10-05 15:06:06 -0700672 (r'Failed to load JSON: Expecting property name'
673 r'( enclosed in double quotes)?: line 1'),
Jisi Liu46e8ff62015-10-05 11:59:43 -0700674 json_format.Parse, text, message)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700675 text = '{"boolMap": {"null": 1}}'
676 self.assertRaisesRegexp(
677 json_format.ParseError,
Feng Xiaoe841bac2015-12-11 17:09:20 -0800678 'Failed to parse boolMap field: Expected "true" or "false", not null.',
Jisi Liu46e8ff62015-10-05 11:59:43 -0700679 json_format.Parse, text, message)
Jie Luo2850a982015-10-09 17:07:03 -0700680 if sys.version_info < (2, 7):
681 return
682 text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
683 self.assertRaisesRegexp(
684 json_format.ParseError,
685 'Failed to load JSON: duplicate key a',
686 json_format.Parse, text, message)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700687
688 def testInvalidTimestamp(self):
689 message = json_format_proto3_pb2.TestTimestamp()
690 text = '{"value": "10000-01-01T00:00:00.00Z"}'
691 self.assertRaisesRegexp(
692 json_format.ParseError,
693 'time data \'10000-01-01T00:00:00\' does not match'
Feng Xiaoe841bac2015-12-11 17:09:20 -0800694 ' format \'%Y-%m-%dT%H:%M:%S\'.',
Jisi Liu46e8ff62015-10-05 11:59:43 -0700695 json_format.Parse, text, message)
696 text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
697 self.assertRaisesRegexp(
Feng Xiaoe841bac2015-12-11 17:09:20 -0800698 well_known_types.ParseError,
Jisi Liu46e8ff62015-10-05 11:59:43 -0700699 'nanos 0123456789012 more than 9 fractional digits.',
700 json_format.Parse, text, message)
701 text = '{"value": "1972-01-01T01:00:00.01+08"}'
702 self.assertRaisesRegexp(
Feng Xiaoe841bac2015-12-11 17:09:20 -0800703 well_known_types.ParseError,
704 (r'Invalid timezone offset value: \+08.'),
Jisi Liu46e8ff62015-10-05 11:59:43 -0700705 json_format.Parse, text, message)
706 # Time smaller than minimum time.
707 text = '{"value": "0000-01-01T00:00:00Z"}'
708 self.assertRaisesRegexp(
709 json_format.ParseError,
Feng Xiaoe841bac2015-12-11 17:09:20 -0800710 'Failed to parse value field: year is out of range.',
Jisi Liu46e8ff62015-10-05 11:59:43 -0700711 json_format.Parse, text, message)
712 # Time bigger than maxinum time.
713 message.value.seconds = 253402300800
714 self.assertRaisesRegexp(
Feng Xiaoe841bac2015-12-11 17:09:20 -0800715 OverflowError,
716 'date value out of range',
Jisi Liu46e8ff62015-10-05 11:59:43 -0700717 json_format.MessageToJson, message)
718
719 def testInvalidOneof(self):
720 message = json_format_proto3_pb2.TestOneof()
721 text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
722 self.assertRaisesRegexp(
723 json_format.ParseError,
724 'Message type "proto3.TestOneof"'
725 ' should not have multiple "oneof_value" oneof fields.',
726 json_format.Parse, text, message)
727
CH Albach5477f8c2016-01-29 18:10:50 -0800728 def testInvalidListValue(self):
729 message = json_format_proto3_pb2.TestListValue()
730 text = '{"value": 1234}'
731 self.assertRaisesRegexp(
732 json_format.ParseError,
733 r'Failed to parse value field: ListValue must be in \[\] which is 1234',
734 json_format.Parse, text, message)
735
736 def testInvalidStruct(self):
737 message = json_format_proto3_pb2.TestStruct()
738 text = '{"value": 1234}'
739 self.assertRaisesRegexp(
740 json_format.ParseError,
741 'Failed to parse value field: Struct must be in a dict which is 1234',
742 json_format.Parse, text, message)
743
744 def testInvalidAny(self):
745 message = any_pb2.Any()
746 text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
747 self.assertRaisesRegexp(
748 KeyError,
749 'value',
750 json_format.Parse, text, message)
751 text = '{"value": 1234}'
752 self.assertRaisesRegexp(
753 json_format.ParseError,
754 '@type is missing when parsing any message.',
755 json_format.Parse, text, message)
756 text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
757 self.assertRaisesRegexp(
758 TypeError,
759 'Can not find message descriptor by type_url: '
760 'type.googleapis.com/MessageNotExist.',
761 json_format.Parse, text, message)
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700762 # Only last part is to be used: b/25630112
CH Albach5477f8c2016-01-29 18:10:50 -0800763 text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
764 r'"value": 1234}')
765 json_format.Parse(text, message)
766
Jisi Liu46e8ff62015-10-05 11:59:43 -0700767
768if __name__ == '__main__':
769 unittest.main()