diff options
Diffstat (limited to 'python/google/protobuf/internal/json_format_test.py')
-rw-r--r-- | python/google/protobuf/internal/json_format_test.py | 305 |
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() |