aboutsummaryrefslogtreecommitdiff
path: root/python/google/protobuf/internal/json_format_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/google/protobuf/internal/json_format_test.py')
-rw-r--r--python/google/protobuf/internal/json_format_test.py305
1 files changed, 272 insertions, 33 deletions
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 69197865..bdc9f49a 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -39,9 +39,17 @@ import math
import sys
try:
- import unittest2 as unittest
+ import unittest2 as unittest #PY26
except ImportError:
import unittest
+
+from google.protobuf import any_pb2
+from google.protobuf import duration_pb2
+from google.protobuf import field_mask_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import timestamp_pb2
+from google.protobuf import wrappers_pb2
+from google.protobuf.internal import well_known_types
from google.protobuf import json_format
from google.protobuf.util import json_format_proto3_pb2
@@ -269,15 +277,15 @@ class JsonFormatTest(JsonFormatBase):
'}'))
parsed_message = json_format_proto3_pb2.TestTimestamp()
self.CheckParseBack(message, parsed_message)
- text = (r'{"value": "1972-01-01T01:00:00.01+08:00",'
+ text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
r'"repeatedValue":['
- r' "1972-01-01T01:00:00.01+08:30",'
- r' "1972-01-01T01:00:00.01-01:23"]}')
+ r' "1970-01-01T00:00:00.01+08:30",'
+ r' "1970-01-01T00:00:00.01-01:23"]}')
json_format.Parse(text, parsed_message)
- self.assertEqual(parsed_message.value.seconds, 63104400)
+ self.assertEqual(parsed_message.value.seconds, -8 * 3600)
self.assertEqual(parsed_message.value.nanos, 10000000)
- self.assertEqual(parsed_message.repeated_value[0].seconds, 63106200)
- self.assertEqual(parsed_message.repeated_value[1].seconds, 63070620)
+ self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
+ self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
def testDurationMessage(self):
message = json_format_proto3_pb2.TestDuration()
@@ -325,6 +333,7 @@ class JsonFormatTest(JsonFormatBase):
message.bytes_value.value = b''
message.repeated_bool_value.add().value = True
message.repeated_bool_value.add().value = False
+ message.repeated_int32_value.add()
self.assertEqual(
json.loads(json_format.MessageToJson(message, True)),
json.loads('{\n'
@@ -333,7 +342,7 @@ class JsonFormatTest(JsonFormatBase):
' "stringValue": "",'
' "bytesValue": "",'
' "repeatedBoolValue": [true, false],'
- ' "repeatedInt32Value": [],'
+ ' "repeatedInt32Value": [0],'
' "repeatedUint32Value": [],'
' "repeatedFloatValue": [],'
' "repeatedDoubleValue": [],'
@@ -345,11 +354,192 @@ class JsonFormatTest(JsonFormatBase):
parsed_message = json_format_proto3_pb2.TestWrapper()
self.CheckParseBack(message, parsed_message)
+ def testStructMessage(self):
+ message = json_format_proto3_pb2.TestStruct()
+ message.value['name'] = 'Jim'
+ message.value['age'] = 10
+ message.value['attend'] = True
+ message.value['email'] = None
+ message.value.get_or_create_struct('address')['city'] = 'SFO'
+ message.value['address']['house_number'] = 1024
+ struct_list = message.value.get_or_create_list('list')
+ struct_list.extend([6, 'seven', True, False, None])
+ struct_list.add_struct()['subkey2'] = 9
+ message.repeated_value.add()['age'] = 11
+ message.repeated_value.add()
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, False)),
+ json.loads(
+ '{'
+ ' "value": {'
+ ' "address": {'
+ ' "city": "SFO", '
+ ' "house_number": 1024'
+ ' }, '
+ ' "age": 10, '
+ ' "name": "Jim", '
+ ' "attend": true, '
+ ' "email": null, '
+ ' "list": [6, "seven", true, false, null, {"subkey2": 9}]'
+ ' },'
+ ' "repeatedValue": [{"age": 11}, {}]'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestStruct()
+ self.CheckParseBack(message, parsed_message)
+
+ def testValueMessage(self):
+ message = json_format_proto3_pb2.TestValue()
+ message.value.string_value = 'hello'
+ message.repeated_value.add().number_value = 11.1
+ message.repeated_value.add().bool_value = False
+ message.repeated_value.add().null_value = 0
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, False)),
+ json.loads(
+ '{'
+ ' "value": "hello",'
+ ' "repeatedValue": [11.1, false, null]'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestValue()
+ self.CheckParseBack(message, parsed_message)
+ # Can't parse back if the Value message is not set.
+ message.repeated_value.add()
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, False)),
+ json.loads(
+ '{'
+ ' "value": "hello",'
+ ' "repeatedValue": [11.1, false, null, null]'
+ '}'))
+
+ def testListValueMessage(self):
+ message = json_format_proto3_pb2.TestListValue()
+ message.value.values.add().number_value = 11.1
+ message.value.values.add().null_value = 0
+ message.value.values.add().bool_value = True
+ message.value.values.add().string_value = 'hello'
+ message.value.values.add().struct_value['name'] = 'Jim'
+ message.repeated_value.add().values.add().number_value = 1
+ message.repeated_value.add()
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, False)),
+ json.loads(
+ '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
+ '"repeatedValue": [[1], []]}'))
+ parsed_message = json_format_proto3_pb2.TestListValue()
+ self.CheckParseBack(message, parsed_message)
+
+ def testAnyMessage(self):
+ message = json_format_proto3_pb2.TestAny()
+ value1 = json_format_proto3_pb2.MessageType()
+ value2 = json_format_proto3_pb2.MessageType()
+ value1.value = 1234
+ value2.value = 5678
+ message.value.Pack(value1)
+ message.repeated_value.add().Pack(value1)
+ message.repeated_value.add().Pack(value2)
+ message.repeated_value.add()
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "repeatedValue": [ {\n'
+ ' "@type": "type.googleapis.com/proto3.MessageType",\n'
+ ' "value": 1234\n'
+ ' }, {\n'
+ ' "@type": "type.googleapis.com/proto3.MessageType",\n'
+ ' "value": 5678\n'
+ ' },\n'
+ ' {}],\n'
+ ' "value": {\n'
+ ' "@type": "type.googleapis.com/proto3.MessageType",\n'
+ ' "value": 1234\n'
+ ' }\n'
+ '}\n'))
+ parsed_message = json_format_proto3_pb2.TestAny()
+ self.CheckParseBack(message, parsed_message)
+
+ def testWellKnownInAnyMessage(self):
+ message = any_pb2.Any()
+ int32_value = wrappers_pb2.Int32Value()
+ int32_value.value = 1234
+ message.Pack(int32_value)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
+ ' "value": 1234\n'
+ '}\n'))
+ parsed_message = any_pb2.Any()
+ self.CheckParseBack(message, parsed_message)
+
+ timestamp = timestamp_pb2.Timestamp()
+ message.Pack(timestamp)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
+ ' "value": "1970-01-01T00:00:00Z"\n'
+ '}\n'))
+ self.CheckParseBack(message, parsed_message)
+
+ duration = duration_pb2.Duration()
+ duration.seconds = 1
+ message.Pack(duration)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": "type.googleapis.com/google.protobuf.Duration",\n'
+ ' "value": "1s"\n'
+ '}\n'))
+ self.CheckParseBack(message, parsed_message)
+
+ field_mask = field_mask_pb2.FieldMask()
+ field_mask.paths.append('foo.bar')
+ field_mask.paths.append('bar')
+ message.Pack(field_mask)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
+ ' "value": "foo.bar,bar"\n'
+ '}\n'))
+ self.CheckParseBack(message, parsed_message)
+
+ struct_message = struct_pb2.Struct()
+ struct_message['name'] = 'Jim'
+ message.Pack(struct_message)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": "type.googleapis.com/google.protobuf.Struct",\n'
+ ' "value": {"name": "Jim"}\n'
+ '}\n'))
+ self.CheckParseBack(message, parsed_message)
+
+ nested_any = any_pb2.Any()
+ int32_value.value = 5678
+ nested_any.Pack(int32_value)
+ message.Pack(nested_any)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads(
+ '{\n'
+ ' "@type": "type.googleapis.com/google.protobuf.Any",\n'
+ ' "value": {\n'
+ ' "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
+ ' "value": 5678\n'
+ ' }\n'
+ '}\n'))
+ self.CheckParseBack(message, parsed_message)
+
def testParseNull(self):
message = json_format_proto3_pb2.TestMessage()
- message.repeated_int32_value.append(1)
- message.repeated_int32_value.append(2)
- message.repeated_int32_value.append(3)
parsed_message = json_format_proto3_pb2.TestMessage()
self.FillAllFields(parsed_message)
json_format.Parse('{"int32Value": null, '
@@ -363,7 +553,7 @@ class JsonFormatTest(JsonFormatBase):
'"bytesValue": null,'
'"messageValue": null,'
'"enumValue": null,'
- '"repeatedInt32Value": [1, 2, null, 3],'
+ '"repeatedInt32Value": null,'
'"repeatedInt64Value": null,'
'"repeatedUint32Value": null,'
'"repeatedUint64Value": null,'
@@ -377,6 +567,13 @@ class JsonFormatTest(JsonFormatBase):
'}',
parsed_message)
self.assertEqual(message, parsed_message)
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse repeatedInt32Value field: '
+ 'null is not allowed to be used as an element in a repeated field.',
+ json_format.Parse,
+ '{"repeatedInt32Value":[1, null]}',
+ parsed_message)
def testNanFloat(self):
message = json_format_proto3_pb2.TestMessage()
@@ -389,7 +586,7 @@ class JsonFormatTest(JsonFormatBase):
def testParseEmptyText(self):
self.CheckError('',
- r'Failed to load JSON: (Expecting value)|(No JSON)')
+ r'Failed to load JSON: (Expecting value)|(No JSON).')
def testParseBadEnumValue(self):
self.CheckError(
@@ -414,7 +611,7 @@ class JsonFormatTest(JsonFormatBase):
if sys.version_info < (2, 7):
return
self.CheckError('{"int32Value": 1,\n"int32Value":2}',
- 'Failed to load JSON: duplicate key int32Value')
+ 'Failed to load JSON: duplicate key int32Value.')
def testInvalidBoolValue(self):
self.CheckError('{"boolValue": 1}',
@@ -431,39 +628,43 @@ class JsonFormatTest(JsonFormatBase):
json_format.Parse, text, message)
self.CheckError('{"int32Value": 012345}',
(r'Failed to load JSON: Expecting \'?,\'? delimiter: '
- r'line 1'))
+ r'line 1.'))
self.CheckError('{"int32Value": 1.0}',
'Failed to parse int32Value field: '
- 'Couldn\'t parse integer: 1.0')
+ 'Couldn\'t parse integer: 1.0.')
self.CheckError('{"int32Value": " 1 "}',
'Failed to parse int32Value field: '
- 'Couldn\'t parse integer: " 1 "')
+ 'Couldn\'t parse integer: " 1 ".')
+ self.CheckError('{"int32Value": "1 "}',
+ 'Failed to parse int32Value field: '
+ 'Couldn\'t parse integer: "1 ".')
self.CheckError('{"int32Value": 12345678901234567890}',
'Failed to parse int32Value field: Value out of range: '
- '12345678901234567890')
+ '12345678901234567890.')
self.CheckError('{"int32Value": 1e5}',
'Failed to parse int32Value field: '
- 'Couldn\'t parse integer: 100000.0')
+ 'Couldn\'t parse integer: 100000.0.')
self.CheckError('{"uint32Value": -1}',
- 'Failed to parse uint32Value field: Value out of range: -1')
+ 'Failed to parse uint32Value field: '
+ 'Value out of range: -1.')
def testInvalidFloatValue(self):
self.CheckError('{"floatValue": "nan"}',
'Failed to parse floatValue field: Couldn\'t '
- 'parse float "nan", use "NaN" instead')
+ 'parse float "nan", use "NaN" instead.')
def testInvalidBytesValue(self):
self.CheckError('{"bytesValue": "AQI"}',
- 'Failed to parse bytesValue field: Incorrect padding')
+ 'Failed to parse bytesValue field: Incorrect padding.')
self.CheckError('{"bytesValue": "AQI*"}',
- 'Failed to parse bytesValue field: Incorrect padding')
+ 'Failed to parse bytesValue field: Incorrect padding.')
def testInvalidMap(self):
message = json_format_proto3_pb2.TestMap()
text = '{"int32Map": {"null": 2, "2": 3}}'
self.assertRaisesRegexp(
json_format.ParseError,
- 'Failed to parse int32Map field: Couldn\'t parse integer: "null"',
+ 'Failed to parse int32Map field: invalid literal',
json_format.Parse, text, message)
text = '{"int32Map": {1: 2, "2": 3}}'
self.assertRaisesRegexp(
@@ -474,7 +675,7 @@ class JsonFormatTest(JsonFormatBase):
text = '{"boolMap": {"null": 1}}'
self.assertRaisesRegexp(
json_format.ParseError,
- 'Failed to parse boolMap field: Expect "true" or "false", not null.',
+ 'Failed to parse boolMap field: Expected "true" or "false", not null.',
json_format.Parse, text, message)
if sys.version_info < (2, 7):
return
@@ -490,30 +691,29 @@ class JsonFormatTest(JsonFormatBase):
self.assertRaisesRegexp(
json_format.ParseError,
'time data \'10000-01-01T00:00:00\' does not match'
- ' format \'%Y-%m-%dT%H:%M:%S\'',
+ ' format \'%Y-%m-%dT%H:%M:%S\'.',
json_format.Parse, text, message)
text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
self.assertRaisesRegexp(
- json_format.ParseError,
- 'Failed to parse value field: Failed to parse Timestamp: '
+ well_known_types.ParseError,
'nanos 0123456789012 more than 9 fractional digits.',
json_format.Parse, text, message)
text = '{"value": "1972-01-01T01:00:00.01+08"}'
self.assertRaisesRegexp(
- json_format.ParseError,
- (r'Failed to parse value field: Invalid timezone offset value: \+08'),
+ well_known_types.ParseError,
+ (r'Invalid timezone offset value: \+08.'),
json_format.Parse, text, message)
# Time smaller than minimum time.
text = '{"value": "0000-01-01T00:00:00Z"}'
self.assertRaisesRegexp(
json_format.ParseError,
- 'Failed to parse value field: year is out of range',
+ 'Failed to parse value field: year is out of range.',
json_format.Parse, text, message)
# Time bigger than maxinum time.
message.value.seconds = 253402300800
self.assertRaisesRegexp(
- json_format.SerializeToJsonError,
- 'Failed to serialize value field: year is out of range',
+ OverflowError,
+ 'date value out of range',
json_format.MessageToJson, message)
def testInvalidOneof(self):
@@ -525,6 +725,45 @@ class JsonFormatTest(JsonFormatBase):
' should not have multiple "oneof_value" oneof fields.',
json_format.Parse, text, message)
+ def testInvalidListValue(self):
+ message = json_format_proto3_pb2.TestListValue()
+ text = '{"value": 1234}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ r'Failed to parse value field: ListValue must be in \[\] which is 1234',
+ json_format.Parse, text, message)
+
+ def testInvalidStruct(self):
+ message = json_format_proto3_pb2.TestStruct()
+ text = '{"value": 1234}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse value field: Struct must be in a dict which is 1234',
+ json_format.Parse, text, message)
+
+ def testInvalidAny(self):
+ message = any_pb2.Any()
+ text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
+ self.assertRaisesRegexp(
+ KeyError,
+ 'value',
+ json_format.Parse, text, message)
+ text = '{"value": 1234}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ '@type is missing when parsing any message.',
+ json_format.Parse, text, message)
+ text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
+ self.assertRaisesRegexp(
+ TypeError,
+ 'Can not find message descriptor by type_url: '
+ 'type.googleapis.com/MessageNotExist.',
+ json_format.Parse, text, message)
+ # Only last part is to be used: b/25630112
+ text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
+ r'"value": 1234}')
+ json_format.Parse(text, message)
+
if __name__ == '__main__':
unittest.main()