Index: third_party/protobuf/python/google/protobuf/internal/text_format_test.py |
diff --git a/third_party/protobuf/python/google/protobuf/internal/text_format_test.py b/third_party/protobuf/python/google/protobuf/internal/text_format_test.py |
index 23b50eb530f05bce22810a33ef454b2544d38c91..0e14556c6f029af7940498231f558cc78db24e2d 100755 |
--- a/third_party/protobuf/python/google/protobuf/internal/text_format_test.py |
+++ b/third_party/protobuf/python/google/protobuf/internal/text_format_test.py |
@@ -1,8 +1,8 @@ |
-#! /usr/bin/python |
+#! /usr/bin/env python |
# |
# Protocol Buffers - Google's data interchange format |
# Copyright 2008 Google Inc. All rights reserved. |
-# http://code.google.com/p/protobuf/ |
+# https://developers.google.com/protocol-buffers/ |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions are |
@@ -34,90 +34,72 @@ |
__author__ = 'kenton@google.com (Kenton Varda)' |
-import difflib |
+ |
import re |
+import six |
+import string |
-import unittest |
-from google.protobuf import text_format |
-from google.protobuf.internal import test_util |
-from google.protobuf import unittest_pb2 |
+try: |
+ import unittest2 as unittest |
+except ImportError: |
+ import unittest |
+from google.protobuf.internal import _parameterized |
+ |
+from google.protobuf import map_unittest_pb2 |
from google.protobuf import unittest_mset_pb2 |
+from google.protobuf import unittest_pb2 |
+from google.protobuf import unittest_proto3_arena_pb2 |
+from google.protobuf.internal import api_implementation |
+from google.protobuf.internal import test_util |
+from google.protobuf.internal import message_set_extensions_pb2 |
+from google.protobuf import text_format |
+ |
+ |
+# Low-level nuts-n-bolts tests. |
+class SimpleTextFormatTests(unittest.TestCase): |
+ # The members of _QUOTES are formatted into a regexp template that |
+ # expects single characters. Therefore it's an error (in addition to being |
+ # non-sensical in the first place) to try to specify a "quote mark" that is |
+ # more than one character. |
+ def TestQuoteMarksAreSingleChars(self): |
+ for quote in text_format._QUOTES: |
+ self.assertEqual(1, len(quote)) |
+ |
+ |
+# Base class with some common functionality. |
+class TextFormatBase(unittest.TestCase): |
-class TextFormatTest(unittest.TestCase): |
def ReadGolden(self, golden_filename): |
- f = test_util.GoldenFile(golden_filename) |
- golden_lines = f.readlines() |
- f.close() |
- return golden_lines |
+ with test_util.GoldenFile(golden_filename) as f: |
+ return (f.readlines() if str is bytes else # PY3 |
+ [golden_line.decode('utf-8') for golden_line in f]) |
def CompareToGoldenFile(self, text, golden_filename): |
golden_lines = self.ReadGolden(golden_filename) |
- self.CompareToGoldenLines(text, golden_lines) |
+ self.assertMultiLineEqual(text, ''.join(golden_lines)) |
def CompareToGoldenText(self, text, golden_text): |
- self.CompareToGoldenLines(text, golden_text.splitlines(1)) |
- |
- def CompareToGoldenLines(self, text, golden_lines): |
- actual_lines = text.splitlines(1) |
- self.assertEqual(golden_lines, actual_lines, |
- "Text doesn't match golden. Diff:\n" + |
- ''.join(difflib.ndiff(golden_lines, actual_lines))) |
+ self.assertEqual(text, golden_text) |
- def testPrintAllFields(self): |
- message = unittest_pb2.TestAllTypes() |
- test_util.SetAllFields(message) |
- self.CompareToGoldenFile( |
- self.RemoveRedundantZeros(text_format.MessageToString(message)), |
- 'text_format_unittest_data.txt') |
- |
- def testPrintAllExtensions(self): |
- message = unittest_pb2.TestAllExtensions() |
- test_util.SetAllExtensions(message) |
- self.CompareToGoldenFile( |
- self.RemoveRedundantZeros(text_format.MessageToString(message)), |
- 'text_format_unittest_extensions_data.txt') |
+ def RemoveRedundantZeros(self, text): |
+ # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove |
+ # these zeros in order to match the golden file. |
+ text = text.replace('e+0','e+').replace('e+0','e+') \ |
+ .replace('e-0','e-').replace('e-0','e-') |
+ # Floating point fields are printed with .0 suffix even if they are |
+ # actualy integer numbers. |
+ text = re.compile('\.0$', re.MULTILINE).sub('', text) |
+ return text |
- def testPrintMessageSet(self): |
- message = unittest_mset_pb2.TestMessageSetContainer() |
- ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
- ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
- message.message_set.Extensions[ext1].i = 23 |
- message.message_set.Extensions[ext2].str = 'foo' |
- self.CompareToGoldenText(text_format.MessageToString(message), |
- 'message_set {\n' |
- ' [protobuf_unittest.TestMessageSetExtension1] {\n' |
- ' i: 23\n' |
- ' }\n' |
- ' [protobuf_unittest.TestMessageSetExtension2] {\n' |
- ' str: \"foo\"\n' |
- ' }\n' |
- '}\n') |
- |
- def testPrintBadEnumValue(self): |
- message = unittest_pb2.TestAllTypes() |
- message.optional_nested_enum = 100 |
- message.optional_foreign_enum = 101 |
- message.optional_import_enum = 102 |
- self.CompareToGoldenText( |
- text_format.MessageToString(message), |
- 'optional_nested_enum: 100\n' |
- 'optional_foreign_enum: 101\n' |
- 'optional_import_enum: 102\n') |
- def testPrintBadEnumValueExtensions(self): |
- message = unittest_pb2.TestAllExtensions() |
- message.Extensions[unittest_pb2.optional_nested_enum_extension] = 100 |
- message.Extensions[unittest_pb2.optional_foreign_enum_extension] = 101 |
- message.Extensions[unittest_pb2.optional_import_enum_extension] = 102 |
- self.CompareToGoldenText( |
- text_format.MessageToString(message), |
- '[protobuf_unittest.optional_nested_enum_extension]: 100\n' |
- '[protobuf_unittest.optional_foreign_enum_extension]: 101\n' |
- '[protobuf_unittest.optional_import_enum_extension]: 102\n') |
+@_parameterized.Parameters( |
+ (unittest_pb2), |
+ (unittest_proto3_arena_pb2)) |
+class TextFormatTest(TextFormatBase): |
- def testPrintExotic(self): |
- message = unittest_pb2.TestAllTypes() |
+ def testPrintExotic(self, message_module): |
+ message = message_module.TestAllTypes() |
message.repeated_int64.append(-9223372036854775808) |
message.repeated_uint64.append(18446744073709551615) |
message.repeated_double.append(123.456) |
@@ -126,62 +108,54 @@ class TextFormatTest(unittest.TestCase): |
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') |
message.repeated_string.append(u'\u00fc\ua71f') |
self.CompareToGoldenText( |
- self.RemoveRedundantZeros(text_format.MessageToString(message)), |
- 'repeated_int64: -9223372036854775808\n' |
- 'repeated_uint64: 18446744073709551615\n' |
- 'repeated_double: 123.456\n' |
- 'repeated_double: 1.23e+22\n' |
- 'repeated_double: 1.23e-18\n' |
- 'repeated_string: ' |
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
- 'repeated_string: "\\303\\274\\352\\234\\237"\n') |
- |
- def testPrintNestedMessageAsOneLine(self): |
- message = unittest_pb2.TestAllTypes() |
+ self.RemoveRedundantZeros(text_format.MessageToString(message)), |
+ 'repeated_int64: -9223372036854775808\n' |
+ 'repeated_uint64: 18446744073709551615\n' |
+ 'repeated_double: 123.456\n' |
+ 'repeated_double: 1.23e+22\n' |
+ 'repeated_double: 1.23e-18\n' |
+ 'repeated_string:' |
+ ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n') |
+ |
+ def testPrintExoticUnicodeSubclass(self, message_module): |
+ class UnicodeSub(six.text_type): |
+ pass |
+ message = message_module.TestAllTypes() |
+ message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f')) |
+ self.CompareToGoldenText( |
+ text_format.MessageToString(message), |
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n') |
+ |
+ def testPrintNestedMessageAsOneLine(self, message_module): |
+ message = message_module.TestAllTypes() |
msg = message.repeated_nested_message.add() |
- msg.bb = 42; |
+ msg.bb = 42 |
self.CompareToGoldenText( |
text_format.MessageToString(message, as_one_line=True), |
'repeated_nested_message { bb: 42 }') |
- def testPrintRepeatedFieldsAsOneLine(self): |
- message = unittest_pb2.TestAllTypes() |
+ def testPrintRepeatedFieldsAsOneLine(self, message_module): |
+ message = message_module.TestAllTypes() |
message.repeated_int32.append(1) |
message.repeated_int32.append(1) |
message.repeated_int32.append(3) |
- message.repeated_string.append("Google") |
- message.repeated_string.append("Zurich") |
+ message.repeated_string.append('Google') |
+ message.repeated_string.append('Zurich') |
self.CompareToGoldenText( |
text_format.MessageToString(message, as_one_line=True), |
'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 ' |
'repeated_string: "Google" repeated_string: "Zurich"') |
- def testPrintNestedNewLineInStringAsOneLine(self): |
- message = unittest_pb2.TestAllTypes() |
- message.optional_string = "a\nnew\nline" |
+ def testPrintNestedNewLineInStringAsOneLine(self, message_module): |
+ message = message_module.TestAllTypes() |
+ message.optional_string = 'a\nnew\nline' |
self.CompareToGoldenText( |
text_format.MessageToString(message, as_one_line=True), |
'optional_string: "a\\nnew\\nline"') |
- def testPrintMessageSetAsOneLine(self): |
- message = unittest_mset_pb2.TestMessageSetContainer() |
- ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
- ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
- message.message_set.Extensions[ext1].i = 23 |
- message.message_set.Extensions[ext2].str = 'foo' |
- self.CompareToGoldenText( |
- text_format.MessageToString(message, as_one_line=True), |
- 'message_set {' |
- ' [protobuf_unittest.TestMessageSetExtension1] {' |
- ' i: 23' |
- ' }' |
- ' [protobuf_unittest.TestMessageSetExtension2] {' |
- ' str: \"foo\"' |
- ' }' |
- ' }') |
- |
- def testPrintExoticAsOneLine(self): |
- message = unittest_pb2.TestAllTypes() |
+ def testPrintExoticAsOneLine(self, message_module): |
+ message = message_module.TestAllTypes() |
message.repeated_int64.append(-9223372036854775808) |
message.repeated_uint64.append(18446744073709551615) |
message.repeated_double.append(123.456) |
@@ -190,19 +164,19 @@ class TextFormatTest(unittest.TestCase): |
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') |
message.repeated_string.append(u'\u00fc\ua71f') |
self.CompareToGoldenText( |
- self.RemoveRedundantZeros( |
- text_format.MessageToString(message, as_one_line=True)), |
- 'repeated_int64: -9223372036854775808' |
- ' repeated_uint64: 18446744073709551615' |
- ' repeated_double: 123.456' |
- ' repeated_double: 1.23e+22' |
- ' repeated_double: 1.23e-18' |
- ' repeated_string: ' |
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""' |
- ' repeated_string: "\\303\\274\\352\\234\\237"') |
- |
- def testRoundTripExoticAsOneLine(self): |
- message = unittest_pb2.TestAllTypes() |
+ self.RemoveRedundantZeros( |
+ text_format.MessageToString(message, as_one_line=True)), |
+ 'repeated_int64: -9223372036854775808' |
+ ' repeated_uint64: 18446744073709551615' |
+ ' repeated_double: 123.456' |
+ ' repeated_double: 1.23e+22' |
+ ' repeated_double: 1.23e-18' |
+ ' repeated_string: ' |
+ '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""' |
+ ' repeated_string: "\\303\\274\\352\\234\\237"') |
+ |
+ def testRoundTripExoticAsOneLine(self, message_module): |
+ message = message_module.TestAllTypes() |
message.repeated_int64.append(-9223372036854775808) |
message.repeated_uint64.append(18446744073709551615) |
message.repeated_double.append(123.456) |
@@ -214,84 +188,429 @@ class TextFormatTest(unittest.TestCase): |
# Test as_utf8 = False. |
wire_text = text_format.MessageToString( |
message, as_one_line=True, as_utf8=False) |
- parsed_message = unittest_pb2.TestAllTypes() |
- text_format.Merge(wire_text, parsed_message) |
- self.assertEquals(message, parsed_message) |
+ parsed_message = message_module.TestAllTypes() |
+ r = text_format.Parse(wire_text, parsed_message) |
+ self.assertIs(r, parsed_message) |
+ self.assertEqual(message, parsed_message) |
# Test as_utf8 = True. |
wire_text = text_format.MessageToString( |
message, as_one_line=True, as_utf8=True) |
- parsed_message = unittest_pb2.TestAllTypes() |
- text_format.Merge(wire_text, parsed_message) |
- self.assertEquals(message, parsed_message) |
- |
- def testPrintRawUtf8String(self): |
- message = unittest_pb2.TestAllTypes() |
+ parsed_message = message_module.TestAllTypes() |
+ r = text_format.Parse(wire_text, parsed_message) |
+ self.assertIs(r, parsed_message) |
+ self.assertEqual(message, parsed_message, |
+ '\n%s != %s' % (message, parsed_message)) |
+ |
+ def testPrintRawUtf8String(self, message_module): |
+ message = message_module.TestAllTypes() |
message.repeated_string.append(u'\u00fc\ua71f') |
- text = text_format.MessageToString(message, as_utf8 = True) |
+ text = text_format.MessageToString(message, as_utf8=True) |
self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n') |
- parsed_message = unittest_pb2.TestAllTypes() |
- text_format.Merge(text, parsed_message) |
- self.assertEquals(message, parsed_message) |
+ parsed_message = message_module.TestAllTypes() |
+ text_format.Parse(text, parsed_message) |
+ self.assertEqual(message, parsed_message, |
+ '\n%s != %s' % (message, parsed_message)) |
+ |
+ def testPrintFloatFormat(self, message_module): |
+ # Check that float_format argument is passed to sub-message formatting. |
+ message = message_module.NestedTestAllTypes() |
+ # We use 1.25 as it is a round number in binary. The proto 32-bit float |
+ # will not gain additional imprecise digits as a 64-bit Python float and |
+ # show up in its str. 32-bit 1.2 is noisy when extended to 64-bit: |
+ # >>> struct.unpack('f', struct.pack('f', 1.2))[0] |
+ # 1.2000000476837158 |
+ # >>> struct.unpack('f', struct.pack('f', 1.25))[0] |
+ # 1.25 |
+ message.payload.optional_float = 1.25 |
+ # Check rounding at 15 significant digits |
+ message.payload.optional_double = -.000003456789012345678 |
+ # Check no decimal point. |
+ message.payload.repeated_float.append(-5642) |
+ # Check no trailing zeros. |
+ message.payload.repeated_double.append(.000078900) |
+ formatted_fields = ['optional_float: 1.25', |
+ 'optional_double: -3.45678901234568e-6', |
+ 'repeated_float: -5642', |
+ 'repeated_double: 7.89e-5'] |
+ text_message = text_format.MessageToString(message, float_format='.15g') |
+ self.CompareToGoldenText( |
+ self.RemoveRedundantZeros(text_message), |
+ 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(*formatted_fields)) |
+ # as_one_line=True is a separate code branch where float_format is passed. |
+ text_message = text_format.MessageToString(message, as_one_line=True, |
+ float_format='.15g') |
+ self.CompareToGoldenText( |
+ self.RemoveRedundantZeros(text_message), |
+ 'payload {{ {0} {1} {2} {3} }}'.format(*formatted_fields)) |
- def testMessageToString(self): |
- message = unittest_pb2.ForeignMessage() |
+ def testMessageToString(self, message_module): |
+ message = message_module.ForeignMessage() |
message.c = 123 |
self.assertEqual('c: 123\n', str(message)) |
- def RemoveRedundantZeros(self, text): |
- # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove |
- # these zeros in order to match the golden file. |
- text = text.replace('e+0','e+').replace('e+0','e+') \ |
- .replace('e-0','e-').replace('e-0','e-') |
- # Floating point fields are printed with .0 suffix even if they are |
- # actualy integer numbers. |
- text = re.compile('\.0$', re.MULTILINE).sub('', text) |
- return text |
+ def testParseAllFields(self, message_module): |
+ message = message_module.TestAllTypes() |
+ test_util.SetAllFields(message) |
+ ascii_text = text_format.MessageToString(message) |
+ |
+ parsed_message = message_module.TestAllTypes() |
+ text_format.Parse(ascii_text, parsed_message) |
+ self.assertEqual(message, parsed_message) |
+ if message_module is unittest_pb2: |
+ test_util.ExpectAllFieldsSet(self, message) |
+ |
+ def testParseExotic(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = ('repeated_int64: -9223372036854775808\n' |
+ 'repeated_uint64: 18446744073709551615\n' |
+ 'repeated_double: 123.456\n' |
+ 'repeated_double: 1.23e+22\n' |
+ 'repeated_double: 1.23e-18\n' |
+ 'repeated_string: \n' |
+ '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
+ 'repeated_string: "foo" \'corge\' "grault"\n' |
+ 'repeated_string: "\\303\\274\\352\\234\\237"\n' |
+ 'repeated_string: "\\xc3\\xbc"\n' |
+ 'repeated_string: "\xc3\xbc"\n') |
+ text_format.Parse(text, message) |
+ |
+ self.assertEqual(-9223372036854775808, message.repeated_int64[0]) |
+ self.assertEqual(18446744073709551615, message.repeated_uint64[0]) |
+ self.assertEqual(123.456, message.repeated_double[0]) |
+ self.assertEqual(1.23e22, message.repeated_double[1]) |
+ self.assertEqual(1.23e-18, message.repeated_double[2]) |
+ self.assertEqual( |
+ '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0]) |
+ self.assertEqual('foocorgegrault', message.repeated_string[1]) |
+ self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2]) |
+ self.assertEqual(u'\u00fc', message.repeated_string[3]) |
+ |
+ def testParseTrailingCommas(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = ('repeated_int64: 100;\n' |
+ 'repeated_int64: 200;\n' |
+ 'repeated_int64: 300,\n' |
+ 'repeated_string: "one",\n' |
+ 'repeated_string: "two";\n') |
+ text_format.Parse(text, message) |
+ |
+ self.assertEqual(100, message.repeated_int64[0]) |
+ self.assertEqual(200, message.repeated_int64[1]) |
+ self.assertEqual(300, message.repeated_int64[2]) |
+ self.assertEqual(u'one', message.repeated_string[0]) |
+ self.assertEqual(u'two', message.repeated_string[1]) |
+ |
+ def testParseRepeatedScalarShortFormat(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = ('repeated_int64: [100, 200];\n' |
+ 'repeated_int64: 300,\n' |
+ 'repeated_string: ["one", "two"];\n') |
+ text_format.Parse(text, message) |
+ |
+ self.assertEqual(100, message.repeated_int64[0]) |
+ self.assertEqual(200, message.repeated_int64[1]) |
+ self.assertEqual(300, message.repeated_int64[2]) |
+ self.assertEqual(u'one', message.repeated_string[0]) |
+ self.assertEqual(u'two', message.repeated_string[1]) |
+ |
+ def testParseEmptyText(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = '' |
+ text_format.Parse(text, message) |
+ self.assertEqual(message_module.TestAllTypes(), message) |
+ |
+ def testParseInvalidUtf8(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = 'repeated_string: "\\xc3\\xc3"' |
+ self.assertRaises(text_format.ParseError, text_format.Parse, text, message) |
+ |
+ def testParseSingleWord(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = 'foo' |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' |
+ r'"foo".'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseUnknownField(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = 'unknown_field: 8\n' |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' |
+ r'"unknown_field".'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseBadEnumValue(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = 'optional_nested_enum: BARR' |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" ' |
+ r'has no value named BARR.'), |
+ text_format.Parse, text, message) |
+ |
+ message = message_module.TestAllTypes() |
+ text = 'optional_nested_enum: 100' |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" ' |
+ r'has no value with number 100.'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseBadIntValue(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = 'optional_int32: bork' |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ ('1:17 : Couldn\'t parse integer: bork'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseStringFieldUnescape(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = r'''repeated_string: "\xf\x62" |
+ repeated_string: "\\xf\\x62" |
+ repeated_string: "\\\xf\\\x62" |
+ repeated_string: "\\\\xf\\\\x62" |
+ repeated_string: "\\\\\xf\\\\\x62" |
+ repeated_string: "\x5cx20"''' |
+ text_format.Parse(text, message) |
+ |
+ SLASH = '\\' |
+ self.assertEqual('\x0fb', message.repeated_string[0]) |
+ self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1]) |
+ self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2]) |
+ self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62', |
+ message.repeated_string[3]) |
+ self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b', |
+ message.repeated_string[4]) |
+ self.assertEqual(SLASH + 'x20', message.repeated_string[5]) |
+ |
+ def testMergeDuplicateScalars(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = ('optional_int32: 42 ' |
+ 'optional_int32: 67') |
+ r = text_format.Merge(text, message) |
+ self.assertIs(r, message) |
+ self.assertEqual(67, message.optional_int32) |
+ |
+ def testMergeDuplicateNestedMessageScalars(self, message_module): |
+ message = message_module.TestAllTypes() |
+ text = ('optional_nested_message { bb: 1 } ' |
+ 'optional_nested_message { bb: 2 }') |
+ r = text_format.Merge(text, message) |
+ self.assertTrue(r is message) |
+ self.assertEqual(2, message.optional_nested_message.bb) |
+ |
+ def testParseOneof(self, message_module): |
+ m = message_module.TestAllTypes() |
+ m.oneof_uint32 = 11 |
+ m2 = message_module.TestAllTypes() |
+ text_format.Parse(text_format.MessageToString(m), m2) |
+ self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) |
+ |
+ |
+# These are tests that aren't fundamentally specific to proto2, but are at |
+# the moment because of differences between the proto2 and proto3 test schemas. |
+# Ideally the schemas would be made more similar so these tests could pass. |
+class OnlyWorksWithProto2RightNowTests(TextFormatBase): |
+ |
+ def testPrintAllFieldsPointy(self): |
+ message = unittest_pb2.TestAllTypes() |
+ test_util.SetAllFields(message) |
+ self.CompareToGoldenFile( |
+ self.RemoveRedundantZeros( |
+ text_format.MessageToString(message, pointy_brackets=True)), |
+ 'text_format_unittest_data_pointy_oneof.txt') |
- def testMergeGolden(self): |
+ def testParseGolden(self): |
golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) |
parsed_message = unittest_pb2.TestAllTypes() |
- text_format.Merge(golden_text, parsed_message) |
+ r = text_format.Parse(golden_text, parsed_message) |
+ self.assertIs(r, parsed_message) |
message = unittest_pb2.TestAllTypes() |
test_util.SetAllFields(message) |
- self.assertEquals(message, parsed_message) |
- |
- def testMergeGoldenExtensions(self): |
- golden_text = '\n'.join(self.ReadGolden( |
- 'text_format_unittest_extensions_data.txt')) |
- parsed_message = unittest_pb2.TestAllExtensions() |
- text_format.Merge(golden_text, parsed_message) |
+ self.assertEqual(message, parsed_message) |
- message = unittest_pb2.TestAllExtensions() |
- test_util.SetAllExtensions(message) |
- self.assertEquals(message, parsed_message) |
+ def testPrintAllFields(self): |
+ message = unittest_pb2.TestAllTypes() |
+ test_util.SetAllFields(message) |
+ self.CompareToGoldenFile( |
+ self.RemoveRedundantZeros(text_format.MessageToString(message)), |
+ 'text_format_unittest_data_oneof_implemented.txt') |
- def testMergeAllFields(self): |
+ def testPrintAllFieldsPointy(self): |
message = unittest_pb2.TestAllTypes() |
test_util.SetAllFields(message) |
- ascii_text = text_format.MessageToString(message) |
+ self.CompareToGoldenFile( |
+ self.RemoveRedundantZeros( |
+ text_format.MessageToString(message, pointy_brackets=True)), |
+ 'text_format_unittest_data_pointy_oneof.txt') |
+ |
+ def testPrintInIndexOrder(self): |
+ message = unittest_pb2.TestFieldOrderings() |
+ message.my_string = '115' |
+ message.my_int = 101 |
+ message.my_float = 111 |
+ message.optional_nested_message.oo = 0 |
+ message.optional_nested_message.bb = 1 |
+ self.CompareToGoldenText( |
+ self.RemoveRedundantZeros(text_format.MessageToString( |
+ message, use_index_order=True)), |
+ 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n' |
+ 'optional_nested_message {\n oo: 0\n bb: 1\n}\n') |
+ self.CompareToGoldenText( |
+ self.RemoveRedundantZeros(text_format.MessageToString( |
+ message)), |
+ 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n' |
+ 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') |
+ def testMergeLinesGolden(self): |
+ opened = self.ReadGolden('text_format_unittest_data.txt') |
parsed_message = unittest_pb2.TestAllTypes() |
- text_format.Merge(ascii_text, parsed_message) |
+ r = text_format.MergeLines(opened, parsed_message) |
+ self.assertIs(r, parsed_message) |
+ |
+ message = unittest_pb2.TestAllTypes() |
+ test_util.SetAllFields(message) |
self.assertEqual(message, parsed_message) |
- test_util.ExpectAllFieldsSet(self, message) |
- def testMergeAllExtensions(self): |
- message = unittest_pb2.TestAllExtensions() |
- test_util.SetAllExtensions(message) |
- ascii_text = text_format.MessageToString(message) |
+ def testParseLinesGolden(self): |
+ opened = self.ReadGolden('text_format_unittest_data.txt') |
+ parsed_message = unittest_pb2.TestAllTypes() |
+ r = text_format.ParseLines(opened, parsed_message) |
+ self.assertIs(r, parsed_message) |
- parsed_message = unittest_pb2.TestAllExtensions() |
- text_format.Merge(ascii_text, parsed_message) |
+ message = unittest_pb2.TestAllTypes() |
+ test_util.SetAllFields(message) |
self.assertEqual(message, parsed_message) |
- def testMergeMessageSet(self): |
+ def testPrintMap(self): |
+ message = map_unittest_pb2.TestMap() |
+ |
+ message.map_int32_int32[-123] = -456 |
+ message.map_int64_int64[-2**33] = -2**34 |
+ message.map_uint32_uint32[123] = 456 |
+ message.map_uint64_uint64[2**33] = 2**34 |
+ message.map_string_string["abc"] = "123" |
+ message.map_int32_foreign_message[111].c = 5 |
+ |
+ # Maps are serialized to text format using their underlying repeated |
+ # representation. |
+ self.CompareToGoldenText( |
+ text_format.MessageToString(message), |
+ 'map_int32_int32 {\n' |
+ ' key: -123\n' |
+ ' value: -456\n' |
+ '}\n' |
+ 'map_int64_int64 {\n' |
+ ' key: -8589934592\n' |
+ ' value: -17179869184\n' |
+ '}\n' |
+ 'map_uint32_uint32 {\n' |
+ ' key: 123\n' |
+ ' value: 456\n' |
+ '}\n' |
+ 'map_uint64_uint64 {\n' |
+ ' key: 8589934592\n' |
+ ' value: 17179869184\n' |
+ '}\n' |
+ 'map_string_string {\n' |
+ ' key: "abc"\n' |
+ ' value: "123"\n' |
+ '}\n' |
+ 'map_int32_foreign_message {\n' |
+ ' key: 111\n' |
+ ' value {\n' |
+ ' c: 5\n' |
+ ' }\n' |
+ '}\n') |
+ |
+ def testMapOrderEnforcement(self): |
+ message = map_unittest_pb2.TestMap() |
+ for letter in string.ascii_uppercase[13:26]: |
+ message.map_string_string[letter] = 'dummy' |
+ for letter in reversed(string.ascii_uppercase[0:13]): |
+ message.map_string_string[letter] = 'dummy' |
+ golden = ''.join(( |
+ 'map_string_string {\n key: "%c"\n value: "dummy"\n}\n' % (letter,) |
+ for letter in string.ascii_uppercase)) |
+ self.CompareToGoldenText(text_format.MessageToString(message), golden) |
+ |
+ def testMapOrderSemantics(self): |
+ golden_lines = self.ReadGolden('map_test_data.txt') |
+ # The C++ implementation emits defaulted-value fields, while the Python |
+ # implementation does not. Adjusting for this is awkward, but it is |
+ # valuable to test against a common golden file. |
+ line_blacklist = (' key: 0\n', |
+ ' value: 0\n', |
+ ' key: false\n', |
+ ' value: false\n') |
+ golden_lines = [line for line in golden_lines if line not in line_blacklist] |
+ |
+ message = map_unittest_pb2.TestMap() |
+ text_format.ParseLines(golden_lines, message) |
+ candidate = text_format.MessageToString(message) |
+ # The Python implementation emits "1.0" for the double value that the C++ |
+ # implementation emits as "1". |
+ candidate = candidate.replace('1.0', '1', 2) |
+ self.assertMultiLineEqual(candidate, ''.join(golden_lines)) |
+ |
+ |
+# Tests of proto2-only features (MessageSet, extensions, etc.). |
+class Proto2Tests(TextFormatBase): |
+ |
+ def testPrintMessageSet(self): |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
+ message.message_set.Extensions[ext1].i = 23 |
+ message.message_set.Extensions[ext2].str = 'foo' |
+ self.CompareToGoldenText( |
+ text_format.MessageToString(message), |
+ 'message_set {\n' |
+ ' [protobuf_unittest.TestMessageSetExtension1] {\n' |
+ ' i: 23\n' |
+ ' }\n' |
+ ' [protobuf_unittest.TestMessageSetExtension2] {\n' |
+ ' str: \"foo\"\n' |
+ ' }\n' |
+ '}\n') |
+ |
+ message = message_set_extensions_pb2.TestMessageSet() |
+ ext = message_set_extensions_pb2.message_set_extension3 |
+ message.Extensions[ext].text = 'bar' |
+ self.CompareToGoldenText( |
+ text_format.MessageToString(message), |
+ '[google.protobuf.internal.TestMessageSetExtension3] {\n' |
+ ' text: \"bar\"\n' |
+ '}\n') |
+ |
+ def testPrintMessageSetAsOneLine(self): |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
+ message.message_set.Extensions[ext1].i = 23 |
+ message.message_set.Extensions[ext2].str = 'foo' |
+ self.CompareToGoldenText( |
+ text_format.MessageToString(message, as_one_line=True), |
+ 'message_set {' |
+ ' [protobuf_unittest.TestMessageSetExtension1] {' |
+ ' i: 23' |
+ ' }' |
+ ' [protobuf_unittest.TestMessageSetExtension2] {' |
+ ' str: \"foo\"' |
+ ' }' |
+ ' }') |
+ |
+ def testParseMessageSet(self): |
message = unittest_pb2.TestAllTypes() |
text = ('repeated_uint64: 1\n' |
'repeated_uint64: 2\n') |
- text_format.Merge(text, message) |
+ text_format.Parse(text, message) |
self.assertEqual(1, message.repeated_uint64[0]) |
self.assertEqual(2, message.repeated_uint64[1]) |
@@ -304,149 +623,272 @@ class TextFormatTest(unittest.TestCase): |
' str: \"foo\"\n' |
' }\n' |
'}\n') |
- text_format.Merge(text, message) |
+ text_format.Parse(text, message) |
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
- self.assertEquals(23, message.message_set.Extensions[ext1].i) |
- self.assertEquals('foo', message.message_set.Extensions[ext2].str) |
+ self.assertEqual(23, message.message_set.Extensions[ext1].i) |
+ self.assertEqual('foo', message.message_set.Extensions[ext2].str) |
- def testMergeExotic(self): |
- message = unittest_pb2.TestAllTypes() |
- text = ('repeated_int64: -9223372036854775808\n' |
- 'repeated_uint64: 18446744073709551615\n' |
- 'repeated_double: 123.456\n' |
- 'repeated_double: 1.23e+22\n' |
- 'repeated_double: 1.23e-18\n' |
- 'repeated_string: \n' |
- '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
- 'repeated_string: "foo" \'corge\' "grault"\n' |
- 'repeated_string: "\\303\\274\\352\\234\\237"\n' |
- 'repeated_string: "\\xc3\\xbc"\n' |
- 'repeated_string: "\xc3\xbc"\n') |
- text_format.Merge(text, message) |
+ def testPrintAllExtensions(self): |
+ message = unittest_pb2.TestAllExtensions() |
+ test_util.SetAllExtensions(message) |
+ self.CompareToGoldenFile( |
+ self.RemoveRedundantZeros(text_format.MessageToString(message)), |
+ 'text_format_unittest_extensions_data.txt') |
- self.assertEqual(-9223372036854775808, message.repeated_int64[0]) |
- self.assertEqual(18446744073709551615, message.repeated_uint64[0]) |
- self.assertEqual(123.456, message.repeated_double[0]) |
- self.assertEqual(1.23e22, message.repeated_double[1]) |
- self.assertEqual(1.23e-18, message.repeated_double[2]) |
- self.assertEqual( |
- '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0]) |
- self.assertEqual('foocorgegrault', message.repeated_string[1]) |
- self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2]) |
- self.assertEqual(u'\u00fc', message.repeated_string[3]) |
+ def testPrintAllExtensionsPointy(self): |
+ message = unittest_pb2.TestAllExtensions() |
+ test_util.SetAllExtensions(message) |
+ self.CompareToGoldenFile( |
+ self.RemoveRedundantZeros(text_format.MessageToString( |
+ message, pointy_brackets=True)), |
+ 'text_format_unittest_extensions_data_pointy.txt') |
- def testMergeEmptyText(self): |
- message = unittest_pb2.TestAllTypes() |
- text = '' |
- text_format.Merge(text, message) |
- self.assertEquals(unittest_pb2.TestAllTypes(), message) |
+ def testParseGoldenExtensions(self): |
+ golden_text = '\n'.join(self.ReadGolden( |
+ 'text_format_unittest_extensions_data.txt')) |
+ parsed_message = unittest_pb2.TestAllExtensions() |
+ text_format.Parse(golden_text, parsed_message) |
- def testMergeInvalidUtf8(self): |
- message = unittest_pb2.TestAllTypes() |
- text = 'repeated_string: "\\xc3\\xc3"' |
- self.assertRaises(text_format.ParseError, text_format.Merge, text, message) |
+ message = unittest_pb2.TestAllExtensions() |
+ test_util.SetAllExtensions(message) |
+ self.assertEqual(message, parsed_message) |
- def testMergeSingleWord(self): |
- message = unittest_pb2.TestAllTypes() |
- text = 'foo' |
- self.assertRaisesWithMessage( |
- text_format.ParseError, |
- ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named ' |
- '"foo".'), |
- text_format.Merge, text, message) |
+ def testParseAllExtensions(self): |
+ message = unittest_pb2.TestAllExtensions() |
+ test_util.SetAllExtensions(message) |
+ ascii_text = text_format.MessageToString(message) |
- def testMergeUnknownField(self): |
- message = unittest_pb2.TestAllTypes() |
- text = 'unknown_field: 8\n' |
- self.assertRaisesWithMessage( |
- text_format.ParseError, |
- ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named ' |
- '"unknown_field".'), |
- text_format.Merge, text, message) |
+ parsed_message = unittest_pb2.TestAllExtensions() |
+ text_format.Parse(ascii_text, parsed_message) |
+ self.assertEqual(message, parsed_message) |
+ |
+ def testParseAllowedUnknownExtension(self): |
+ # Skip over unknown extension correctly. |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ text = ('message_set {\n' |
+ ' [unknown_extension] {\n' |
+ ' i: 23\n' |
+ ' [nested_unknown_ext]: {\n' |
+ ' i: 23\n' |
+ ' test: "test_string"\n' |
+ ' floaty_float: -0.315\n' |
+ ' num: -inf\n' |
+ ' multiline_str: "abc"\n' |
+ ' "def"\n' |
+ ' "xyz."\n' |
+ ' [nested_unknown_ext]: <\n' |
+ ' i: 23\n' |
+ ' i: 24\n' |
+ ' pointfloat: .3\n' |
+ ' test: "test_string"\n' |
+ ' floaty_float: -0.315\n' |
+ ' num: -inf\n' |
+ ' long_string: "test" "test2" \n' |
+ ' >\n' |
+ ' }\n' |
+ ' }\n' |
+ ' [unknown_extension]: 5\n' |
+ '}\n') |
+ text_format.Parse(text, message, allow_unknown_extension=True) |
+ golden = 'message_set {\n}\n' |
+ self.CompareToGoldenText(text_format.MessageToString(message), golden) |
- def testMergeBadExtension(self): |
+ # Catch parse errors in unknown extension. |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ malformed = ('message_set {\n' |
+ ' [unknown_extension] {\n' |
+ ' i:\n' # Missing value. |
+ ' }\n' |
+ '}\n') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ 'Invalid field value: }', |
+ text_format.Parse, malformed, message, |
+ allow_unknown_extension=True) |
+ |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ malformed = ('message_set {\n' |
+ ' [unknown_extension] {\n' |
+ ' str: "malformed string\n' # Missing closing quote. |
+ ' }\n' |
+ '}\n') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ 'Invalid field value: "', |
+ text_format.Parse, malformed, message, |
+ allow_unknown_extension=True) |
+ |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ malformed = ('message_set {\n' |
+ ' [unknown_extension] {\n' |
+ ' str: "malformed\n multiline\n string\n' |
+ ' }\n' |
+ '}\n') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ 'Invalid field value: "', |
+ text_format.Parse, malformed, message, |
+ allow_unknown_extension=True) |
+ |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ malformed = ('message_set {\n' |
+ ' [malformed_extension] <\n' |
+ ' i: -5\n' |
+ ' \n' # Missing '>' here. |
+ '}\n') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ '5:1 : Expected ">".', |
+ text_format.Parse, malformed, message, |
+ allow_unknown_extension=True) |
+ |
+ # Don't allow unknown fields with allow_unknown_extension=True. |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ malformed = ('message_set {\n' |
+ ' unknown_field: true\n' |
+ ' \n' # Missing '>' here. |
+ '}\n') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ ('2:3 : Message type ' |
+ '"proto2_wireformat_unittest.TestMessageSet" has no' |
+ ' field named "unknown_field".'), |
+ text_format.Parse, malformed, message, |
+ allow_unknown_extension=True) |
+ |
+ # Parse known extension correcty. |
+ message = unittest_mset_pb2.TestMessageSetContainer() |
+ text = ('message_set {\n' |
+ ' [protobuf_unittest.TestMessageSetExtension1] {\n' |
+ ' i: 23\n' |
+ ' }\n' |
+ ' [protobuf_unittest.TestMessageSetExtension2] {\n' |
+ ' str: \"foo\"\n' |
+ ' }\n' |
+ '}\n') |
+ text_format.Parse(text, message, allow_unknown_extension=True) |
+ ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
+ ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
+ self.assertEqual(23, message.message_set.Extensions[ext1].i) |
+ self.assertEqual('foo', message.message_set.Extensions[ext2].str) |
+ |
+ def testParseBadExtension(self): |
message = unittest_pb2.TestAllExtensions() |
text = '[unknown_extension]: 8\n' |
- self.assertRaisesWithMessage( |
+ six.assertRaisesRegex(self, |
text_format.ParseError, |
'1:2 : Extension "unknown_extension" not registered.', |
- text_format.Merge, text, message) |
+ text_format.Parse, text, message) |
message = unittest_pb2.TestAllTypes() |
- self.assertRaisesWithMessage( |
+ six.assertRaisesRegex(self, |
text_format.ParseError, |
('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have ' |
'extensions.'), |
- text_format.Merge, text, message) |
+ text_format.Parse, text, message) |
- def testMergeGroupNotClosed(self): |
+ def testMergeDuplicateExtensionScalars(self): |
+ message = unittest_pb2.TestAllExtensions() |
+ text = ('[protobuf_unittest.optional_int32_extension]: 42 ' |
+ '[protobuf_unittest.optional_int32_extension]: 67') |
+ text_format.Merge(text, message) |
+ self.assertEqual( |
+ 67, |
+ message.Extensions[unittest_pb2.optional_int32_extension]) |
+ |
+ def testParseDuplicateExtensionScalars(self): |
+ message = unittest_pb2.TestAllExtensions() |
+ text = ('[protobuf_unittest.optional_int32_extension]: 42 ' |
+ '[protobuf_unittest.optional_int32_extension]: 67') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ ('1:96 : Message type "protobuf_unittest.TestAllExtensions" ' |
+ 'should not have multiple ' |
+ '"protobuf_unittest.optional_int32_extension" extensions.'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseDuplicateNestedMessageScalars(self): |
+ message = unittest_pb2.TestAllTypes() |
+ text = ('optional_nested_message { bb: 1 } ' |
+ 'optional_nested_message { bb: 2 }') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" ' |
+ 'should not have multiple "bb" fields.'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseDuplicateScalars(self): |
+ message = unittest_pb2.TestAllTypes() |
+ text = ('optional_int32: 42 ' |
+ 'optional_int32: 67') |
+ six.assertRaisesRegex(self, |
+ text_format.ParseError, |
+ ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not ' |
+ 'have multiple "optional_int32" fields.'), |
+ text_format.Parse, text, message) |
+ |
+ def testParseGroupNotClosed(self): |
message = unittest_pb2.TestAllTypes() |
text = 'RepeatedGroup: <' |
- self.assertRaisesWithMessage( |
+ six.assertRaisesRegex(self, |
text_format.ParseError, '1:16 : Expected ">".', |
- text_format.Merge, text, message) |
- |
+ text_format.Parse, text, message) |
text = 'RepeatedGroup: {' |
- self.assertRaisesWithMessage( |
+ six.assertRaisesRegex(self, |
text_format.ParseError, '1:16 : Expected "}".', |
- text_format.Merge, text, message) |
+ text_format.Parse, text, message) |
- def testMergeEmptyGroup(self): |
+ def testParseEmptyGroup(self): |
message = unittest_pb2.TestAllTypes() |
text = 'OptionalGroup: {}' |
- text_format.Merge(text, message) |
+ text_format.Parse(text, message) |
self.assertTrue(message.HasField('optionalgroup')) |
message.Clear() |
message = unittest_pb2.TestAllTypes() |
text = 'OptionalGroup: <>' |
- text_format.Merge(text, message) |
+ text_format.Parse(text, message) |
self.assertTrue(message.HasField('optionalgroup')) |
- def testMergeBadEnumValue(self): |
- message = unittest_pb2.TestAllTypes() |
- text = 'optional_nested_enum: BARR' |
- self.assertRaisesWithMessage( |
- text_format.ParseError, |
- ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" ' |
- 'has no value named BARR.'), |
- text_format.Merge, text, message) |
- |
- message = unittest_pb2.TestAllTypes() |
- text = 'optional_nested_enum: 100' |
- self.assertRaisesWithMessage( |
- text_format.ParseError, |
- ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" ' |
- 'has no value with number 100.'), |
- text_format.Merge, text, message) |
+ # Maps aren't really proto2-only, but our test schema only has maps for |
+ # proto2. |
+ def testParseMap(self): |
+ text = ('map_int32_int32 {\n' |
+ ' key: -123\n' |
+ ' value: -456\n' |
+ '}\n' |
+ 'map_int64_int64 {\n' |
+ ' key: -8589934592\n' |
+ ' value: -17179869184\n' |
+ '}\n' |
+ 'map_uint32_uint32 {\n' |
+ ' key: 123\n' |
+ ' value: 456\n' |
+ '}\n' |
+ 'map_uint64_uint64 {\n' |
+ ' key: 8589934592\n' |
+ ' value: 17179869184\n' |
+ '}\n' |
+ 'map_string_string {\n' |
+ ' key: "abc"\n' |
+ ' value: "123"\n' |
+ '}\n' |
+ 'map_int32_foreign_message {\n' |
+ ' key: 111\n' |
+ ' value {\n' |
+ ' c: 5\n' |
+ ' }\n' |
+ '}\n') |
+ message = map_unittest_pb2.TestMap() |
+ text_format.Parse(text, message) |
- def testMergeBadIntValue(self): |
- message = unittest_pb2.TestAllTypes() |
- text = 'optional_int32: bork' |
- self.assertRaisesWithMessage( |
- text_format.ParseError, |
- ('1:17 : Couldn\'t parse integer: bork'), |
- text_format.Merge, text, message) |
- |
- def assertRaisesWithMessage(self, e_class, e, func, *args, **kwargs): |
- """Same as assertRaises, but also compares the exception message.""" |
- if hasattr(e_class, '__name__'): |
- exc_name = e_class.__name__ |
- else: |
- exc_name = str(e_class) |
- |
- try: |
- func(*args, **kwargs) |
- except e_class as expr: |
- if str(expr) != e: |
- msg = '%s raised, but with wrong message: "%s" instead of "%s"' |
- raise self.failureException(msg % (exc_name, |
- str(expr).encode('string_escape'), |
- e.encode('string_escape'))) |
- return |
- else: |
- raise self.failureException('%s not raised' % exc_name) |
+ self.assertEqual(-456, message.map_int32_int32[-123]) |
+ self.assertEqual(-2**34, message.map_int64_int64[-2**33]) |
+ self.assertEqual(456, message.map_uint32_uint32[123]) |
+ self.assertEqual(2**34, message.map_uint64_uint64[2**33]) |
+ self.assertEqual("123", message.map_string_string["abc"]) |
+ self.assertEqual(5, message.map_int32_foreign_message[111].c) |
class TokenizerTest(unittest.TestCase): |
@@ -458,8 +900,8 @@ class TokenizerTest(unittest.TestCase): |
'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n' |
'ID9: 22 ID10: -111111111111111111 ID11: -22\n' |
'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f ' |
- 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ' ) |
- tokenizer = text_format._Tokenizer(text) |
+ 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ') |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), |
':', |
(tokenizer.ConsumeString, 'string1'), |
@@ -545,7 +987,7 @@ class TokenizerTest(unittest.TestCase): |
int64_max = (1 << 63) - 1 |
uint32_max = (1 << 32) - 1 |
text = '-1 %d %d' % (uint32_max + 1, int64_max + 1) |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64) |
self.assertEqual(-1, tokenizer.ConsumeInt32()) |
@@ -559,7 +1001,7 @@ class TokenizerTest(unittest.TestCase): |
self.assertTrue(tokenizer.AtEnd()) |
text = '-0 -0 0 0' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertEqual(0, tokenizer.ConsumeUint32()) |
self.assertEqual(0, tokenizer.ConsumeUint64()) |
self.assertEqual(0, tokenizer.ConsumeUint32()) |
@@ -568,28 +1010,28 @@ class TokenizerTest(unittest.TestCase): |
def testConsumeByteString(self): |
text = '"string1\'' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
text = 'string1"' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
text = '\n"\\xt"' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
text = '\n"\\"' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
text = '\n"\\x"' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
def testConsumeBool(self): |
text = 'not-a-bool' |
- tokenizer = text_format._Tokenizer(text) |
+ tokenizer = text_format._Tokenizer(text.splitlines()) |
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool) |