| OLD | NEW |
| 1 #! /usr/bin/python | 1 #! /usr/bin/env python |
| 2 # | 2 # |
| 3 # Protocol Buffers - Google's data interchange format | 3 # Protocol Buffers - Google's data interchange format |
| 4 # Copyright 2008 Google Inc. All rights reserved. | 4 # Copyright 2008 Google Inc. All rights reserved. |
| 5 # http://code.google.com/p/protobuf/ | 5 # https://developers.google.com/protocol-buffers/ |
| 6 # | 6 # |
| 7 # Redistribution and use in source and binary forms, with or without | 7 # Redistribution and use in source and binary forms, with or without |
| 8 # modification, are permitted provided that the following conditions are | 8 # modification, are permitted provided that the following conditions are |
| 9 # met: | 9 # met: |
| 10 # | 10 # |
| 11 # * Redistributions of source code must retain the above copyright | 11 # * Redistributions of source code must retain the above copyright |
| 12 # notice, this list of conditions and the following disclaimer. | 12 # notice, this list of conditions and the following disclaimer. |
| 13 # * Redistributions in binary form must reproduce the above | 13 # * Redistributions in binary form must reproduce the above |
| 14 # copyright notice, this list of conditions and the following disclaimer | 14 # copyright notice, this list of conditions and the following disclaimer |
| 15 # in the documentation and/or other materials provided with the | 15 # in the documentation and/or other materials provided with the |
| (...skipping 11 matching lines...) Expand all Loading... |
| 27 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 27 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 28 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 28 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 29 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 29 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 30 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 31 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 32 | 32 |
| 33 """Test for google.protobuf.text_format.""" | 33 """Test for google.protobuf.text_format.""" |
| 34 | 34 |
| 35 __author__ = 'kenton@google.com (Kenton Varda)' | 35 __author__ = 'kenton@google.com (Kenton Varda)' |
| 36 | 36 |
| 37 import difflib | |
| 38 import re | 37 import re |
| 38 import unittest |
| 39 | 39 |
| 40 import unittest | 40 import unittest |
| 41 from google.protobuf.internal import _parameterized |
| 42 |
| 43 from google.protobuf import map_unittest_pb2 |
| 44 from google.protobuf import unittest_mset_pb2 |
| 45 from google.protobuf import unittest_pb2 |
| 46 from google.protobuf import unittest_proto3_arena_pb2 |
| 47 from google.protobuf.internal import api_implementation |
| 48 from google.protobuf.internal import test_util |
| 41 from google.protobuf import text_format | 49 from google.protobuf import text_format |
| 42 from google.protobuf.internal import test_util | |
| 43 from google.protobuf import unittest_pb2 | |
| 44 from google.protobuf import unittest_mset_pb2 | |
| 45 | 50 |
| 51 # Base class with some common functionality. |
| 52 class TextFormatBase(unittest.TestCase): |
| 46 | 53 |
| 47 class TextFormatTest(unittest.TestCase): | |
| 48 def ReadGolden(self, golden_filename): | 54 def ReadGolden(self, golden_filename): |
| 49 f = test_util.GoldenFile(golden_filename) | 55 with test_util.GoldenFile(golden_filename) as f: |
| 50 golden_lines = f.readlines() | 56 return (f.readlines() if str is bytes else # PY3 |
| 51 f.close() | 57 [golden_line.decode('utf-8') for golden_line in f]) |
| 52 return golden_lines | |
| 53 | 58 |
| 54 def CompareToGoldenFile(self, text, golden_filename): | 59 def CompareToGoldenFile(self, text, golden_filename): |
| 55 golden_lines = self.ReadGolden(golden_filename) | 60 golden_lines = self.ReadGolden(golden_filename) |
| 56 self.CompareToGoldenLines(text, golden_lines) | 61 self.assertMultiLineEqual(text, ''.join(golden_lines)) |
| 57 | 62 |
| 58 def CompareToGoldenText(self, text, golden_text): | 63 def CompareToGoldenText(self, text, golden_text): |
| 59 self.CompareToGoldenLines(text, golden_text.splitlines(1)) | 64 self.assertMultiLineEqual(text, golden_text) |
| 60 | 65 |
| 61 def CompareToGoldenLines(self, text, golden_lines): | 66 def RemoveRedundantZeros(self, text): |
| 62 actual_lines = text.splitlines(1) | 67 # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove |
| 63 self.assertEqual(golden_lines, actual_lines, | 68 # these zeros in order to match the golden file. |
| 64 "Text doesn't match golden. Diff:\n" + | 69 text = text.replace('e+0','e+').replace('e+0','e+') \ |
| 65 ''.join(difflib.ndiff(golden_lines, actual_lines))) | 70 .replace('e-0','e-').replace('e-0','e-') |
| 71 # Floating point fields are printed with .0 suffix even if they are |
| 72 # actualy integer numbers. |
| 73 text = re.compile('\.0$', re.MULTILINE).sub('', text) |
| 74 return text |
| 66 | 75 |
| 67 def testPrintAllFields(self): | |
| 68 message = unittest_pb2.TestAllTypes() | |
| 69 test_util.SetAllFields(message) | |
| 70 self.CompareToGoldenFile( | |
| 71 self.RemoveRedundantZeros(text_format.MessageToString(message)), | |
| 72 'text_format_unittest_data.txt') | |
| 73 | 76 |
| 74 def testPrintAllExtensions(self): | 77 @_parameterized.Parameters( |
| 75 message = unittest_pb2.TestAllExtensions() | 78 (unittest_pb2), |
| 76 test_util.SetAllExtensions(message) | 79 (unittest_proto3_arena_pb2)) |
| 77 self.CompareToGoldenFile( | 80 class TextFormatTest(TextFormatBase): |
| 78 self.RemoveRedundantZeros(text_format.MessageToString(message)), | |
| 79 'text_format_unittest_extensions_data.txt') | |
| 80 | 81 |
| 81 def testPrintMessageSet(self): | 82 def testPrintExotic(self, message_module): |
| 82 message = unittest_mset_pb2.TestMessageSetContainer() | 83 message = message_module.TestAllTypes() |
| 83 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension | |
| 84 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension | |
| 85 message.message_set.Extensions[ext1].i = 23 | |
| 86 message.message_set.Extensions[ext2].str = 'foo' | |
| 87 self.CompareToGoldenText(text_format.MessageToString(message), | |
| 88 'message_set {\n' | |
| 89 ' [protobuf_unittest.TestMessageSetExtension1] {\n' | |
| 90 ' i: 23\n' | |
| 91 ' }\n' | |
| 92 ' [protobuf_unittest.TestMessageSetExtension2] {\n' | |
| 93 ' str: \"foo\"\n' | |
| 94 ' }\n' | |
| 95 '}\n') | |
| 96 | |
| 97 def testPrintBadEnumValue(self): | |
| 98 message = unittest_pb2.TestAllTypes() | |
| 99 message.optional_nested_enum = 100 | |
| 100 message.optional_foreign_enum = 101 | |
| 101 message.optional_import_enum = 102 | |
| 102 self.CompareToGoldenText( | |
| 103 text_format.MessageToString(message), | |
| 104 'optional_nested_enum: 100\n' | |
| 105 'optional_foreign_enum: 101\n' | |
| 106 'optional_import_enum: 102\n') | |
| 107 | |
| 108 def testPrintBadEnumValueExtensions(self): | |
| 109 message = unittest_pb2.TestAllExtensions() | |
| 110 message.Extensions[unittest_pb2.optional_nested_enum_extension] = 100 | |
| 111 message.Extensions[unittest_pb2.optional_foreign_enum_extension] = 101 | |
| 112 message.Extensions[unittest_pb2.optional_import_enum_extension] = 102 | |
| 113 self.CompareToGoldenText( | |
| 114 text_format.MessageToString(message), | |
| 115 '[protobuf_unittest.optional_nested_enum_extension]: 100\n' | |
| 116 '[protobuf_unittest.optional_foreign_enum_extension]: 101\n' | |
| 117 '[protobuf_unittest.optional_import_enum_extension]: 102\n') | |
| 118 | |
| 119 def testPrintExotic(self): | |
| 120 message = unittest_pb2.TestAllTypes() | |
| 121 message.repeated_int64.append(-9223372036854775808) | 84 message.repeated_int64.append(-9223372036854775808) |
| 122 message.repeated_uint64.append(18446744073709551615) | 85 message.repeated_uint64.append(18446744073709551615) |
| 123 message.repeated_double.append(123.456) | 86 message.repeated_double.append(123.456) |
| 124 message.repeated_double.append(1.23e22) | 87 message.repeated_double.append(1.23e22) |
| 125 message.repeated_double.append(1.23e-18) | 88 message.repeated_double.append(1.23e-18) |
| 126 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') | 89 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') |
| 127 message.repeated_string.append(u'\u00fc\ua71f') | 90 message.repeated_string.append(u'\u00fc\ua71f') |
| 128 self.CompareToGoldenText( | 91 self.CompareToGoldenText( |
| 129 self.RemoveRedundantZeros(text_format.MessageToString(message)), | 92 self.RemoveRedundantZeros(text_format.MessageToString(message)), |
| 130 'repeated_int64: -9223372036854775808\n' | 93 'repeated_int64: -9223372036854775808\n' |
| 131 'repeated_uint64: 18446744073709551615\n' | 94 'repeated_uint64: 18446744073709551615\n' |
| 132 'repeated_double: 123.456\n' | 95 'repeated_double: 123.456\n' |
| 133 'repeated_double: 1.23e+22\n' | 96 'repeated_double: 1.23e+22\n' |
| 134 'repeated_double: 1.23e-18\n' | 97 'repeated_double: 1.23e-18\n' |
| 135 'repeated_string: ' | 98 'repeated_string:' |
| 136 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' | 99 ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
| 137 'repeated_string: "\\303\\274\\352\\234\\237"\n') | 100 'repeated_string: "\\303\\274\\352\\234\\237"\n') |
| 138 | 101 |
| 139 def testPrintNestedMessageAsOneLine(self): | 102 def testPrintExoticUnicodeSubclass(self, message_module): |
| 140 message = unittest_pb2.TestAllTypes() | 103 class UnicodeSub(unicode): |
| 104 pass |
| 105 message = message_module.TestAllTypes() |
| 106 message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f')) |
| 107 self.CompareToGoldenText( |
| 108 text_format.MessageToString(message), |
| 109 'repeated_string: "\\303\\274\\352\\234\\237"\n') |
| 110 |
| 111 def testPrintNestedMessageAsOneLine(self, message_module): |
| 112 message = message_module.TestAllTypes() |
| 141 msg = message.repeated_nested_message.add() | 113 msg = message.repeated_nested_message.add() |
| 142 msg.bb = 42; | 114 msg.bb = 42 |
| 143 self.CompareToGoldenText( | 115 self.CompareToGoldenText( |
| 144 text_format.MessageToString(message, as_one_line=True), | 116 text_format.MessageToString(message, as_one_line=True), |
| 145 'repeated_nested_message { bb: 42 }') | 117 'repeated_nested_message { bb: 42 }') |
| 146 | 118 |
| 147 def testPrintRepeatedFieldsAsOneLine(self): | 119 def testPrintRepeatedFieldsAsOneLine(self, message_module): |
| 148 message = unittest_pb2.TestAllTypes() | 120 message = message_module.TestAllTypes() |
| 149 message.repeated_int32.append(1) | 121 message.repeated_int32.append(1) |
| 150 message.repeated_int32.append(1) | 122 message.repeated_int32.append(1) |
| 151 message.repeated_int32.append(3) | 123 message.repeated_int32.append(3) |
| 152 message.repeated_string.append("Google") | 124 message.repeated_string.append('Google') |
| 153 message.repeated_string.append("Zurich") | 125 message.repeated_string.append('Zurich') |
| 154 self.CompareToGoldenText( | 126 self.CompareToGoldenText( |
| 155 text_format.MessageToString(message, as_one_line=True), | 127 text_format.MessageToString(message, as_one_line=True), |
| 156 'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 ' | 128 'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 ' |
| 157 'repeated_string: "Google" repeated_string: "Zurich"') | 129 'repeated_string: "Google" repeated_string: "Zurich"') |
| 158 | 130 |
| 159 def testPrintNestedNewLineInStringAsOneLine(self): | 131 def testPrintNestedNewLineInStringAsOneLine(self, message_module): |
| 160 message = unittest_pb2.TestAllTypes() | 132 message = message_module.TestAllTypes() |
| 161 message.optional_string = "a\nnew\nline" | 133 message.optional_string = 'a\nnew\nline' |
| 162 self.CompareToGoldenText( | 134 self.CompareToGoldenText( |
| 163 text_format.MessageToString(message, as_one_line=True), | 135 text_format.MessageToString(message, as_one_line=True), |
| 164 'optional_string: "a\\nnew\\nline"') | 136 'optional_string: "a\\nnew\\nline"') |
| 165 | 137 |
| 166 def testPrintMessageSetAsOneLine(self): | 138 def testPrintExoticAsOneLine(self, message_module): |
| 167 message = unittest_mset_pb2.TestMessageSetContainer() | 139 message = message_module.TestAllTypes() |
| 168 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension | |
| 169 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension | |
| 170 message.message_set.Extensions[ext1].i = 23 | |
| 171 message.message_set.Extensions[ext2].str = 'foo' | |
| 172 self.CompareToGoldenText( | |
| 173 text_format.MessageToString(message, as_one_line=True), | |
| 174 'message_set {' | |
| 175 ' [protobuf_unittest.TestMessageSetExtension1] {' | |
| 176 ' i: 23' | |
| 177 ' }' | |
| 178 ' [protobuf_unittest.TestMessageSetExtension2] {' | |
| 179 ' str: \"foo\"' | |
| 180 ' }' | |
| 181 ' }') | |
| 182 | |
| 183 def testPrintExoticAsOneLine(self): | |
| 184 message = unittest_pb2.TestAllTypes() | |
| 185 message.repeated_int64.append(-9223372036854775808) | 140 message.repeated_int64.append(-9223372036854775808) |
| 186 message.repeated_uint64.append(18446744073709551615) | 141 message.repeated_uint64.append(18446744073709551615) |
| 187 message.repeated_double.append(123.456) | 142 message.repeated_double.append(123.456) |
| 188 message.repeated_double.append(1.23e22) | 143 message.repeated_double.append(1.23e22) |
| 189 message.repeated_double.append(1.23e-18) | 144 message.repeated_double.append(1.23e-18) |
| 190 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') | 145 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') |
| 191 message.repeated_string.append(u'\u00fc\ua71f') | 146 message.repeated_string.append(u'\u00fc\ua71f') |
| 192 self.CompareToGoldenText( | 147 self.CompareToGoldenText( |
| 193 self.RemoveRedundantZeros( | 148 self.RemoveRedundantZeros( |
| 194 text_format.MessageToString(message, as_one_line=True)), | 149 text_format.MessageToString(message, as_one_line=True)), |
| 195 'repeated_int64: -9223372036854775808' | 150 'repeated_int64: -9223372036854775808' |
| 196 ' repeated_uint64: 18446744073709551615' | 151 ' repeated_uint64: 18446744073709551615' |
| 197 ' repeated_double: 123.456' | 152 ' repeated_double: 123.456' |
| 198 ' repeated_double: 1.23e+22' | 153 ' repeated_double: 1.23e+22' |
| 199 ' repeated_double: 1.23e-18' | 154 ' repeated_double: 1.23e-18' |
| 200 ' repeated_string: ' | 155 ' repeated_string: ' |
| 201 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""' | 156 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""' |
| 202 ' repeated_string: "\\303\\274\\352\\234\\237"') | 157 ' repeated_string: "\\303\\274\\352\\234\\237"') |
| 203 | 158 |
| 204 def testRoundTripExoticAsOneLine(self): | 159 def testRoundTripExoticAsOneLine(self, message_module): |
| 205 message = unittest_pb2.TestAllTypes() | 160 message = message_module.TestAllTypes() |
| 206 message.repeated_int64.append(-9223372036854775808) | 161 message.repeated_int64.append(-9223372036854775808) |
| 207 message.repeated_uint64.append(18446744073709551615) | 162 message.repeated_uint64.append(18446744073709551615) |
| 208 message.repeated_double.append(123.456) | 163 message.repeated_double.append(123.456) |
| 209 message.repeated_double.append(1.23e22) | 164 message.repeated_double.append(1.23e22) |
| 210 message.repeated_double.append(1.23e-18) | 165 message.repeated_double.append(1.23e-18) |
| 211 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') | 166 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') |
| 212 message.repeated_string.append(u'\u00fc\ua71f') | 167 message.repeated_string.append(u'\u00fc\ua71f') |
| 213 | 168 |
| 214 # Test as_utf8 = False. | 169 # Test as_utf8 = False. |
| 215 wire_text = text_format.MessageToString( | 170 wire_text = text_format.MessageToString( |
| 216 message, as_one_line=True, as_utf8=False) | 171 message, as_one_line=True, as_utf8=False) |
| 217 parsed_message = unittest_pb2.TestAllTypes() | 172 parsed_message = message_module.TestAllTypes() |
| 218 text_format.Merge(wire_text, parsed_message) | 173 r = text_format.Parse(wire_text, parsed_message) |
| 174 self.assertIs(r, parsed_message) |
| 219 self.assertEquals(message, parsed_message) | 175 self.assertEquals(message, parsed_message) |
| 220 | 176 |
| 221 # Test as_utf8 = True. | 177 # Test as_utf8 = True. |
| 222 wire_text = text_format.MessageToString( | 178 wire_text = text_format.MessageToString( |
| 223 message, as_one_line=True, as_utf8=True) | 179 message, as_one_line=True, as_utf8=True) |
| 224 parsed_message = unittest_pb2.TestAllTypes() | 180 parsed_message = message_module.TestAllTypes() |
| 225 text_format.Merge(wire_text, parsed_message) | 181 r = text_format.Parse(wire_text, parsed_message) |
| 226 self.assertEquals(message, parsed_message) | 182 self.assertIs(r, parsed_message) |
| 227 | 183 self.assertEquals(message, parsed_message, |
| 228 def testPrintRawUtf8String(self): | 184 '\n%s != %s' % (message, parsed_message)) |
| 229 message = unittest_pb2.TestAllTypes() | 185 |
| 186 def testPrintRawUtf8String(self, message_module): |
| 187 message = message_module.TestAllTypes() |
| 230 message.repeated_string.append(u'\u00fc\ua71f') | 188 message.repeated_string.append(u'\u00fc\ua71f') |
| 231 text = text_format.MessageToString(message, as_utf8 = True) | 189 text = text_format.MessageToString(message, as_utf8=True) |
| 232 self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n') | 190 self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n') |
| 233 parsed_message = unittest_pb2.TestAllTypes() | 191 parsed_message = message_module.TestAllTypes() |
| 234 text_format.Merge(text, parsed_message) | 192 text_format.Parse(text, parsed_message) |
| 235 self.assertEquals(message, parsed_message) | 193 self.assertEquals(message, parsed_message, |
| 236 | 194 '\n%s != %s' % (message, parsed_message)) |
| 237 def testMessageToString(self): | 195 |
| 238 message = unittest_pb2.ForeignMessage() | 196 def testPrintFloatFormat(self, message_module): |
| 197 # Check that float_format argument is passed to sub-message formatting. |
| 198 message = message_module.NestedTestAllTypes() |
| 199 # We use 1.25 as it is a round number in binary. The proto 32-bit float |
| 200 # will not gain additional imprecise digits as a 64-bit Python float and |
| 201 # show up in its str. 32-bit 1.2 is noisy when extended to 64-bit: |
| 202 # >>> struct.unpack('f', struct.pack('f', 1.2))[0] |
| 203 # 1.2000000476837158 |
| 204 # >>> struct.unpack('f', struct.pack('f', 1.25))[0] |
| 205 # 1.25 |
| 206 message.payload.optional_float = 1.25 |
| 207 # Check rounding at 15 significant digits |
| 208 message.payload.optional_double = -.000003456789012345678 |
| 209 # Check no decimal point. |
| 210 message.payload.repeated_float.append(-5642) |
| 211 # Check no trailing zeros. |
| 212 message.payload.repeated_double.append(.000078900) |
| 213 formatted_fields = ['optional_float: 1.25', |
| 214 'optional_double: -3.45678901234568e-6', |
| 215 'repeated_float: -5642', |
| 216 'repeated_double: 7.89e-5'] |
| 217 text_message = text_format.MessageToString(message, float_format='.15g') |
| 218 self.CompareToGoldenText( |
| 219 self.RemoveRedundantZeros(text_message), |
| 220 'payload {{\n {}\n {}\n {}\n {}\n}}\n'.format(*formatted_fields)) |
| 221 # as_one_line=True is a separate code branch where float_format is passed. |
| 222 text_message = text_format.MessageToString(message, as_one_line=True, |
| 223 float_format='.15g') |
| 224 self.CompareToGoldenText( |
| 225 self.RemoveRedundantZeros(text_message), |
| 226 'payload {{ {} {} {} {} }}'.format(*formatted_fields)) |
| 227 |
| 228 def testMessageToString(self, message_module): |
| 229 message = message_module.ForeignMessage() |
| 239 message.c = 123 | 230 message.c = 123 |
| 240 self.assertEqual('c: 123\n', str(message)) | 231 self.assertEqual('c: 123\n', str(message)) |
| 241 | 232 |
| 242 def RemoveRedundantZeros(self, text): | 233 def testParseAllFields(self, message_module): |
| 243 # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove | 234 message = message_module.TestAllTypes() |
| 244 # these zeros in order to match the golden file. | 235 test_util.SetAllFields(message) |
| 245 text = text.replace('e+0','e+').replace('e+0','e+') \ | 236 ascii_text = text_format.MessageToString(message) |
| 246 .replace('e-0','e-').replace('e-0','e-') | 237 |
| 247 # Floating point fields are printed with .0 suffix even if they are | 238 parsed_message = message_module.TestAllTypes() |
| 248 # actualy integer numbers. | 239 text_format.Parse(ascii_text, parsed_message) |
| 249 text = re.compile('\.0$', re.MULTILINE).sub('', text) | 240 self.assertEqual(message, parsed_message) |
| 250 return text | 241 if message_module is unittest_pb2: |
| 251 | 242 test_util.ExpectAllFieldsSet(self, message) |
| 252 def testMergeGolden(self): | 243 |
| 244 def testParseExotic(self, message_module): |
| 245 message = message_module.TestAllTypes() |
| 246 text = ('repeated_int64: -9223372036854775808\n' |
| 247 'repeated_uint64: 18446744073709551615\n' |
| 248 'repeated_double: 123.456\n' |
| 249 'repeated_double: 1.23e+22\n' |
| 250 'repeated_double: 1.23e-18\n' |
| 251 'repeated_string: \n' |
| 252 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' |
| 253 'repeated_string: "foo" \'corge\' "grault"\n' |
| 254 'repeated_string: "\\303\\274\\352\\234\\237"\n' |
| 255 'repeated_string: "\\xc3\\xbc"\n' |
| 256 'repeated_string: "\xc3\xbc"\n') |
| 257 text_format.Parse(text, message) |
| 258 |
| 259 self.assertEqual(-9223372036854775808, message.repeated_int64[0]) |
| 260 self.assertEqual(18446744073709551615, message.repeated_uint64[0]) |
| 261 self.assertEqual(123.456, message.repeated_double[0]) |
| 262 self.assertEqual(1.23e22, message.repeated_double[1]) |
| 263 self.assertEqual(1.23e-18, message.repeated_double[2]) |
| 264 self.assertEqual( |
| 265 '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0]) |
| 266 self.assertEqual('foocorgegrault', message.repeated_string[1]) |
| 267 self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2]) |
| 268 self.assertEqual(u'\u00fc', message.repeated_string[3]) |
| 269 |
| 270 def testParseTrailingCommas(self, message_module): |
| 271 message = message_module.TestAllTypes() |
| 272 text = ('repeated_int64: 100;\n' |
| 273 'repeated_int64: 200;\n' |
| 274 'repeated_int64: 300,\n' |
| 275 'repeated_string: "one",\n' |
| 276 'repeated_string: "two";\n') |
| 277 text_format.Parse(text, message) |
| 278 |
| 279 self.assertEqual(100, message.repeated_int64[0]) |
| 280 self.assertEqual(200, message.repeated_int64[1]) |
| 281 self.assertEqual(300, message.repeated_int64[2]) |
| 282 self.assertEqual(u'one', message.repeated_string[0]) |
| 283 self.assertEqual(u'two', message.repeated_string[1]) |
| 284 |
| 285 def testParseEmptyText(self, message_module): |
| 286 message = message_module.TestAllTypes() |
| 287 text = '' |
| 288 text_format.Parse(text, message) |
| 289 self.assertEquals(message_module.TestAllTypes(), message) |
| 290 |
| 291 def testParseInvalidUtf8(self, message_module): |
| 292 message = message_module.TestAllTypes() |
| 293 text = 'repeated_string: "\\xc3\\xc3"' |
| 294 self.assertRaises(text_format.ParseError, text_format.Parse, text, message) |
| 295 |
| 296 def testParseSingleWord(self, message_module): |
| 297 message = message_module.TestAllTypes() |
| 298 text = 'foo' |
| 299 self.assertRaisesRegexp( |
| 300 text_format.ParseError, |
| 301 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' |
| 302 r'"foo".'), |
| 303 text_format.Parse, text, message) |
| 304 |
| 305 def testParseUnknownField(self, message_module): |
| 306 message = message_module.TestAllTypes() |
| 307 text = 'unknown_field: 8\n' |
| 308 self.assertRaisesRegexp( |
| 309 text_format.ParseError, |
| 310 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' |
| 311 r'"unknown_field".'), |
| 312 text_format.Parse, text, message) |
| 313 |
| 314 def testParseBadEnumValue(self, message_module): |
| 315 message = message_module.TestAllTypes() |
| 316 text = 'optional_nested_enum: BARR' |
| 317 self.assertRaisesRegexp( |
| 318 text_format.ParseError, |
| 319 (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" ' |
| 320 r'has no value named BARR.'), |
| 321 text_format.Parse, text, message) |
| 322 |
| 323 message = message_module.TestAllTypes() |
| 324 text = 'optional_nested_enum: 100' |
| 325 self.assertRaisesRegexp( |
| 326 text_format.ParseError, |
| 327 (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" ' |
| 328 r'has no value with number 100.'), |
| 329 text_format.Parse, text, message) |
| 330 |
| 331 def testParseBadIntValue(self, message_module): |
| 332 message = message_module.TestAllTypes() |
| 333 text = 'optional_int32: bork' |
| 334 self.assertRaisesRegexp( |
| 335 text_format.ParseError, |
| 336 ('1:17 : Couldn\'t parse integer: bork'), |
| 337 text_format.Parse, text, message) |
| 338 |
| 339 def testParseStringFieldUnescape(self, message_module): |
| 340 message = message_module.TestAllTypes() |
| 341 text = r'''repeated_string: "\xf\x62" |
| 342 repeated_string: "\\xf\\x62" |
| 343 repeated_string: "\\\xf\\\x62" |
| 344 repeated_string: "\\\\xf\\\\x62" |
| 345 repeated_string: "\\\\\xf\\\\\x62" |
| 346 repeated_string: "\x5cx20"''' |
| 347 text_format.Parse(text, message) |
| 348 |
| 349 SLASH = '\\' |
| 350 self.assertEqual('\x0fb', message.repeated_string[0]) |
| 351 self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1]) |
| 352 self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2]) |
| 353 self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62', |
| 354 message.repeated_string[3]) |
| 355 self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b', |
| 356 message.repeated_string[4]) |
| 357 self.assertEqual(SLASH + 'x20', message.repeated_string[5]) |
| 358 |
| 359 def testMergeDuplicateScalars(self, message_module): |
| 360 message = message_module.TestAllTypes() |
| 361 text = ('optional_int32: 42 ' |
| 362 'optional_int32: 67') |
| 363 r = text_format.Merge(text, message) |
| 364 self.assertIs(r, message) |
| 365 self.assertEqual(67, message.optional_int32) |
| 366 |
| 367 def testMergeDuplicateNestedMessageScalars(self, message_module): |
| 368 message = message_module.TestAllTypes() |
| 369 text = ('optional_nested_message { bb: 1 } ' |
| 370 'optional_nested_message { bb: 2 }') |
| 371 r = text_format.Merge(text, message) |
| 372 self.assertTrue(r is message) |
| 373 self.assertEqual(2, message.optional_nested_message.bb) |
| 374 |
| 375 def testParseOneof(self, message_module): |
| 376 m = message_module.TestAllTypes() |
| 377 m.oneof_uint32 = 11 |
| 378 m2 = message_module.TestAllTypes() |
| 379 text_format.Parse(text_format.MessageToString(m), m2) |
| 380 self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) |
| 381 |
| 382 |
| 383 # These are tests that aren't fundamentally specific to proto2, but are at |
| 384 # the moment because of differences between the proto2 and proto3 test schemas. |
| 385 # Ideally the schemas would be made more similar so these tests could pass. |
| 386 class OnlyWorksWithProto2RightNowTests(TextFormatBase): |
| 387 |
| 388 def testPrintAllFieldsPointy(self, message_module): |
| 389 message = unittest_pb2.TestAllTypes() |
| 390 test_util.SetAllFields(message) |
| 391 self.CompareToGoldenFile( |
| 392 self.RemoveRedundantZeros( |
| 393 text_format.MessageToString(message, pointy_brackets=True)), |
| 394 'text_format_unittest_data_pointy_oneof.txt') |
| 395 |
| 396 def testParseGolden(self): |
| 253 golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) | 397 golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) |
| 254 parsed_message = unittest_pb2.TestAllTypes() | 398 parsed_message = unittest_pb2.TestAllTypes() |
| 255 text_format.Merge(golden_text, parsed_message) | 399 r = text_format.Parse(golden_text, parsed_message) |
| 400 self.assertIs(r, parsed_message) |
| 256 | 401 |
| 257 message = unittest_pb2.TestAllTypes() | 402 message = unittest_pb2.TestAllTypes() |
| 258 test_util.SetAllFields(message) | 403 test_util.SetAllFields(message) |
| 259 self.assertEquals(message, parsed_message) | 404 self.assertEquals(message, parsed_message) |
| 260 | 405 |
| 261 def testMergeGoldenExtensions(self): | 406 def testPrintAllFields(self): |
| 262 golden_text = '\n'.join(self.ReadGolden( | 407 message = unittest_pb2.TestAllTypes() |
| 263 'text_format_unittest_extensions_data.txt')) | 408 test_util.SetAllFields(message) |
| 264 parsed_message = unittest_pb2.TestAllExtensions() | 409 self.CompareToGoldenFile( |
| 265 text_format.Merge(golden_text, parsed_message) | 410 self.RemoveRedundantZeros(text_format.MessageToString(message)), |
| 266 | 411 'text_format_unittest_data_oneof_implemented.txt') |
| 267 message = unittest_pb2.TestAllExtensions() | 412 |
| 268 test_util.SetAllExtensions(message) | 413 def testPrintAllFieldsPointy(self): |
| 414 message = unittest_pb2.TestAllTypes() |
| 415 test_util.SetAllFields(message) |
| 416 self.CompareToGoldenFile( |
| 417 self.RemoveRedundantZeros( |
| 418 text_format.MessageToString(message, pointy_brackets=True)), |
| 419 'text_format_unittest_data_pointy_oneof.txt') |
| 420 |
| 421 def testPrintInIndexOrder(self): |
| 422 message = unittest_pb2.TestFieldOrderings() |
| 423 message.my_string = '115' |
| 424 message.my_int = 101 |
| 425 message.my_float = 111 |
| 426 message.optional_nested_message.oo = 0 |
| 427 message.optional_nested_message.bb = 1 |
| 428 self.CompareToGoldenText( |
| 429 self.RemoveRedundantZeros(text_format.MessageToString( |
| 430 message, use_index_order=True)), |
| 431 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n' |
| 432 'optional_nested_message {\n oo: 0\n bb: 1\n}\n') |
| 433 self.CompareToGoldenText( |
| 434 self.RemoveRedundantZeros(text_format.MessageToString( |
| 435 message)), |
| 436 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n' |
| 437 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') |
| 438 |
| 439 def testMergeLinesGolden(self): |
| 440 opened = self.ReadGolden('text_format_unittest_data.txt') |
| 441 parsed_message = unittest_pb2.TestAllTypes() |
| 442 r = text_format.MergeLines(opened, parsed_message) |
| 443 self.assertIs(r, parsed_message) |
| 444 |
| 445 message = unittest_pb2.TestAllTypes() |
| 446 test_util.SetAllFields(message) |
| 447 self.assertEqual(message, parsed_message) |
| 448 |
| 449 def testParseLinesGolden(self): |
| 450 opened = self.ReadGolden('text_format_unittest_data.txt') |
| 451 parsed_message = unittest_pb2.TestAllTypes() |
| 452 r = text_format.ParseLines(opened, parsed_message) |
| 453 self.assertIs(r, parsed_message) |
| 454 |
| 455 message = unittest_pb2.TestAllTypes() |
| 456 test_util.SetAllFields(message) |
| 269 self.assertEquals(message, parsed_message) | 457 self.assertEquals(message, parsed_message) |
| 270 | 458 |
| 271 def testMergeAllFields(self): | 459 def testPrintMap(self): |
| 272 message = unittest_pb2.TestAllTypes() | 460 message = map_unittest_pb2.TestMap() |
| 273 test_util.SetAllFields(message) | 461 |
| 274 ascii_text = text_format.MessageToString(message) | 462 message.map_int32_int32[-123] = -456 |
| 275 | 463 message.map_int64_int64[-2**33] = -2**34 |
| 276 parsed_message = unittest_pb2.TestAllTypes() | 464 message.map_uint32_uint32[123] = 456 |
| 277 text_format.Merge(ascii_text, parsed_message) | 465 message.map_uint64_uint64[2**33] = 2**34 |
| 278 self.assertEqual(message, parsed_message) | 466 message.map_string_string["abc"] = "123" |
| 279 test_util.ExpectAllFieldsSet(self, message) | 467 message.map_int32_foreign_message[111].c = 5 |
| 280 | 468 |
| 281 def testMergeAllExtensions(self): | 469 # Maps are serialized to text format using their underlying repeated |
| 282 message = unittest_pb2.TestAllExtensions() | 470 # representation. |
| 283 test_util.SetAllExtensions(message) | 471 self.CompareToGoldenText( |
| 284 ascii_text = text_format.MessageToString(message) | 472 text_format.MessageToString(message), |
| 285 | 473 'map_int32_int32 {\n' |
| 286 parsed_message = unittest_pb2.TestAllExtensions() | 474 ' key: -123\n' |
| 287 text_format.Merge(ascii_text, parsed_message) | 475 ' value: -456\n' |
| 288 self.assertEqual(message, parsed_message) | 476 '}\n' |
| 289 | 477 'map_int64_int64 {\n' |
| 290 def testMergeMessageSet(self): | 478 ' key: -8589934592\n' |
| 479 ' value: -17179869184\n' |
| 480 '}\n' |
| 481 'map_uint32_uint32 {\n' |
| 482 ' key: 123\n' |
| 483 ' value: 456\n' |
| 484 '}\n' |
| 485 'map_uint64_uint64 {\n' |
| 486 ' key: 8589934592\n' |
| 487 ' value: 17179869184\n' |
| 488 '}\n' |
| 489 'map_string_string {\n' |
| 490 ' key: "abc"\n' |
| 491 ' value: "123"\n' |
| 492 '}\n' |
| 493 'map_int32_foreign_message {\n' |
| 494 ' key: 111\n' |
| 495 ' value {\n' |
| 496 ' c: 5\n' |
| 497 ' }\n' |
| 498 '}\n') |
| 499 |
| 500 |
| 501 # Tests of proto2-only features (MessageSet, extensions, etc.). |
| 502 class Proto2Tests(TextFormatBase): |
| 503 |
| 504 def testPrintMessageSet(self): |
| 505 message = unittest_mset_pb2.TestMessageSetContainer() |
| 506 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
| 507 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
| 508 message.message_set.Extensions[ext1].i = 23 |
| 509 message.message_set.Extensions[ext2].str = 'foo' |
| 510 self.CompareToGoldenText( |
| 511 text_format.MessageToString(message), |
| 512 'message_set {\n' |
| 513 ' [protobuf_unittest.TestMessageSetExtension1] {\n' |
| 514 ' i: 23\n' |
| 515 ' }\n' |
| 516 ' [protobuf_unittest.TestMessageSetExtension2] {\n' |
| 517 ' str: \"foo\"\n' |
| 518 ' }\n' |
| 519 '}\n') |
| 520 |
| 521 def testPrintMessageSetAsOneLine(self): |
| 522 message = unittest_mset_pb2.TestMessageSetContainer() |
| 523 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
| 524 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
| 525 message.message_set.Extensions[ext1].i = 23 |
| 526 message.message_set.Extensions[ext2].str = 'foo' |
| 527 self.CompareToGoldenText( |
| 528 text_format.MessageToString(message, as_one_line=True), |
| 529 'message_set {' |
| 530 ' [protobuf_unittest.TestMessageSetExtension1] {' |
| 531 ' i: 23' |
| 532 ' }' |
| 533 ' [protobuf_unittest.TestMessageSetExtension2] {' |
| 534 ' str: \"foo\"' |
| 535 ' }' |
| 536 ' }') |
| 537 |
| 538 def testParseMessageSet(self): |
| 291 message = unittest_pb2.TestAllTypes() | 539 message = unittest_pb2.TestAllTypes() |
| 292 text = ('repeated_uint64: 1\n' | 540 text = ('repeated_uint64: 1\n' |
| 293 'repeated_uint64: 2\n') | 541 'repeated_uint64: 2\n') |
| 294 text_format.Merge(text, message) | 542 text_format.Parse(text, message) |
| 295 self.assertEqual(1, message.repeated_uint64[0]) | 543 self.assertEqual(1, message.repeated_uint64[0]) |
| 296 self.assertEqual(2, message.repeated_uint64[1]) | 544 self.assertEqual(2, message.repeated_uint64[1]) |
| 297 | 545 |
| 298 message = unittest_mset_pb2.TestMessageSetContainer() | 546 message = unittest_mset_pb2.TestMessageSetContainer() |
| 299 text = ('message_set {\n' | 547 text = ('message_set {\n' |
| 300 ' [protobuf_unittest.TestMessageSetExtension1] {\n' | 548 ' [protobuf_unittest.TestMessageSetExtension1] {\n' |
| 301 ' i: 23\n' | 549 ' i: 23\n' |
| 302 ' }\n' | 550 ' }\n' |
| 303 ' [protobuf_unittest.TestMessageSetExtension2] {\n' | 551 ' [protobuf_unittest.TestMessageSetExtension2] {\n' |
| 304 ' str: \"foo\"\n' | 552 ' str: \"foo\"\n' |
| 305 ' }\n' | 553 ' }\n' |
| 306 '}\n') | 554 '}\n') |
| 307 text_format.Merge(text, message) | 555 text_format.Parse(text, message) |
| 308 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension | 556 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension |
| 309 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension | 557 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension |
| 310 self.assertEquals(23, message.message_set.Extensions[ext1].i) | 558 self.assertEquals(23, message.message_set.Extensions[ext1].i) |
| 311 self.assertEquals('foo', message.message_set.Extensions[ext2].str) | 559 self.assertEquals('foo', message.message_set.Extensions[ext2].str) |
| 312 | 560 |
| 313 def testMergeExotic(self): | 561 def testPrintAllExtensions(self): |
| 314 message = unittest_pb2.TestAllTypes() | 562 message = unittest_pb2.TestAllExtensions() |
| 315 text = ('repeated_int64: -9223372036854775808\n' | 563 test_util.SetAllExtensions(message) |
| 316 'repeated_uint64: 18446744073709551615\n' | 564 self.CompareToGoldenFile( |
| 317 'repeated_double: 123.456\n' | 565 self.RemoveRedundantZeros(text_format.MessageToString(message)), |
| 318 'repeated_double: 1.23e+22\n' | 566 'text_format_unittest_extensions_data.txt') |
| 319 'repeated_double: 1.23e-18\n' | |
| 320 'repeated_string: \n' | |
| 321 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' | |
| 322 'repeated_string: "foo" \'corge\' "grault"\n' | |
| 323 'repeated_string: "\\303\\274\\352\\234\\237"\n' | |
| 324 'repeated_string: "\\xc3\\xbc"\n' | |
| 325 'repeated_string: "\xc3\xbc"\n') | |
| 326 text_format.Merge(text, message) | |
| 327 | 567 |
| 328 self.assertEqual(-9223372036854775808, message.repeated_int64[0]) | 568 def testPrintAllExtensionsPointy(self): |
| 329 self.assertEqual(18446744073709551615, message.repeated_uint64[0]) | 569 message = unittest_pb2.TestAllExtensions() |
| 330 self.assertEqual(123.456, message.repeated_double[0]) | 570 test_util.SetAllExtensions(message) |
| 331 self.assertEqual(1.23e22, message.repeated_double[1]) | 571 self.CompareToGoldenFile( |
| 332 self.assertEqual(1.23e-18, message.repeated_double[2]) | 572 self.RemoveRedundantZeros(text_format.MessageToString( |
| 333 self.assertEqual( | 573 message, pointy_brackets=True)), |
| 334 '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0]) | 574 'text_format_unittest_extensions_data_pointy.txt') |
| 335 self.assertEqual('foocorgegrault', message.repeated_string[1]) | |
| 336 self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2]) | |
| 337 self.assertEqual(u'\u00fc', message.repeated_string[3]) | |
| 338 | 575 |
| 339 def testMergeEmptyText(self): | 576 def testParseGoldenExtensions(self): |
| 340 message = unittest_pb2.TestAllTypes() | 577 golden_text = '\n'.join(self.ReadGolden( |
| 341 text = '' | 578 'text_format_unittest_extensions_data.txt')) |
| 342 text_format.Merge(text, message) | 579 parsed_message = unittest_pb2.TestAllExtensions() |
| 343 self.assertEquals(unittest_pb2.TestAllTypes(), message) | 580 text_format.Parse(golden_text, parsed_message) |
| 344 | 581 |
| 345 def testMergeInvalidUtf8(self): | 582 message = unittest_pb2.TestAllExtensions() |
| 346 message = unittest_pb2.TestAllTypes() | 583 test_util.SetAllExtensions(message) |
| 347 text = 'repeated_string: "\\xc3\\xc3"' | 584 self.assertEquals(message, parsed_message) |
| 348 self.assertRaises(text_format.ParseError, text_format.Merge, text, message) | |
| 349 | 585 |
| 350 def testMergeSingleWord(self): | 586 def testParseAllExtensions(self): |
| 351 message = unittest_pb2.TestAllTypes() | 587 message = unittest_pb2.TestAllExtensions() |
| 352 text = 'foo' | 588 test_util.SetAllExtensions(message) |
| 353 self.assertRaisesWithMessage( | 589 ascii_text = text_format.MessageToString(message) |
| 354 text_format.ParseError, | |
| 355 ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named
' | |
| 356 '"foo".'), | |
| 357 text_format.Merge, text, message) | |
| 358 | 590 |
| 359 def testMergeUnknownField(self): | 591 parsed_message = unittest_pb2.TestAllExtensions() |
| 360 message = unittest_pb2.TestAllTypes() | 592 text_format.Parse(ascii_text, parsed_message) |
| 361 text = 'unknown_field: 8\n' | 593 self.assertEqual(message, parsed_message) |
| 362 self.assertRaisesWithMessage( | |
| 363 text_format.ParseError, | |
| 364 ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named
' | |
| 365 '"unknown_field".'), | |
| 366 text_format.Merge, text, message) | |
| 367 | 594 |
| 368 def testMergeBadExtension(self): | 595 def testParseBadExtension(self): |
| 369 message = unittest_pb2.TestAllExtensions() | 596 message = unittest_pb2.TestAllExtensions() |
| 370 text = '[unknown_extension]: 8\n' | 597 text = '[unknown_extension]: 8\n' |
| 371 self.assertRaisesWithMessage( | 598 self.assertRaisesRegexp( |
| 372 text_format.ParseError, | 599 text_format.ParseError, |
| 373 '1:2 : Extension "unknown_extension" not registered.', | 600 '1:2 : Extension "unknown_extension" not registered.', |
| 374 text_format.Merge, text, message) | 601 text_format.Parse, text, message) |
| 375 message = unittest_pb2.TestAllTypes() | 602 message = unittest_pb2.TestAllTypes() |
| 376 self.assertRaisesWithMessage( | 603 self.assertRaisesRegexp( |
| 377 text_format.ParseError, | 604 text_format.ParseError, |
| 378 ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have ' | 605 ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have ' |
| 379 'extensions.'), | 606 'extensions.'), |
| 380 text_format.Merge, text, message) | 607 text_format.Parse, text, message) |
| 381 | 608 |
| 382 def testMergeGroupNotClosed(self): | 609 def testMergeDuplicateExtensionScalars(self): |
| 610 message = unittest_pb2.TestAllExtensions() |
| 611 text = ('[protobuf_unittest.optional_int32_extension]: 42 ' |
| 612 '[protobuf_unittest.optional_int32_extension]: 67') |
| 613 text_format.Merge(text, message) |
| 614 self.assertEqual( |
| 615 67, |
| 616 message.Extensions[unittest_pb2.optional_int32_extension]) |
| 617 |
| 618 def testParseDuplicateExtensionScalars(self): |
| 619 message = unittest_pb2.TestAllExtensions() |
| 620 text = ('[protobuf_unittest.optional_int32_extension]: 42 ' |
| 621 '[protobuf_unittest.optional_int32_extension]: 67') |
| 622 self.assertRaisesRegexp( |
| 623 text_format.ParseError, |
| 624 ('1:96 : Message type "protobuf_unittest.TestAllExtensions" ' |
| 625 'should not have multiple ' |
| 626 '"protobuf_unittest.optional_int32_extension" extensions.'), |
| 627 text_format.Parse, text, message) |
| 628 |
| 629 def testParseDuplicateNestedMessageScalars(self): |
| 630 message = unittest_pb2.TestAllTypes() |
| 631 text = ('optional_nested_message { bb: 1 } ' |
| 632 'optional_nested_message { bb: 2 }') |
| 633 self.assertRaisesRegexp( |
| 634 text_format.ParseError, |
| 635 ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" ' |
| 636 'should not have multiple "bb" fields.'), |
| 637 text_format.Parse, text, message) |
| 638 |
| 639 def testParseDuplicateScalars(self): |
| 640 message = unittest_pb2.TestAllTypes() |
| 641 text = ('optional_int32: 42 ' |
| 642 'optional_int32: 67') |
| 643 self.assertRaisesRegexp( |
| 644 text_format.ParseError, |
| 645 ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not ' |
| 646 'have multiple "optional_int32" fields.'), |
| 647 text_format.Parse, text, message) |
| 648 |
| 649 def testParseGroupNotClosed(self): |
| 383 message = unittest_pb2.TestAllTypes() | 650 message = unittest_pb2.TestAllTypes() |
| 384 text = 'RepeatedGroup: <' | 651 text = 'RepeatedGroup: <' |
| 385 self.assertRaisesWithMessage( | 652 self.assertRaisesRegexp( |
| 386 text_format.ParseError, '1:16 : Expected ">".', | 653 text_format.ParseError, '1:16 : Expected ">".', |
| 387 text_format.Merge, text, message) | 654 text_format.Parse, text, message) |
| 655 text = 'RepeatedGroup: {' |
| 656 self.assertRaisesRegexp( |
| 657 text_format.ParseError, '1:16 : Expected "}".', |
| 658 text_format.Parse, text, message) |
| 388 | 659 |
| 389 text = 'RepeatedGroup: {' | 660 def testParseEmptyGroup(self): |
| 390 self.assertRaisesWithMessage( | |
| 391 text_format.ParseError, '1:16 : Expected "}".', | |
| 392 text_format.Merge, text, message) | |
| 393 | |
| 394 def testMergeEmptyGroup(self): | |
| 395 message = unittest_pb2.TestAllTypes() | 661 message = unittest_pb2.TestAllTypes() |
| 396 text = 'OptionalGroup: {}' | 662 text = 'OptionalGroup: {}' |
| 397 text_format.Merge(text, message) | 663 text_format.Parse(text, message) |
| 398 self.assertTrue(message.HasField('optionalgroup')) | 664 self.assertTrue(message.HasField('optionalgroup')) |
| 399 | 665 |
| 400 message.Clear() | 666 message.Clear() |
| 401 | 667 |
| 402 message = unittest_pb2.TestAllTypes() | 668 message = unittest_pb2.TestAllTypes() |
| 403 text = 'OptionalGroup: <>' | 669 text = 'OptionalGroup: <>' |
| 404 text_format.Merge(text, message) | 670 text_format.Parse(text, message) |
| 405 self.assertTrue(message.HasField('optionalgroup')) | 671 self.assertTrue(message.HasField('optionalgroup')) |
| 406 | 672 |
| 407 def testMergeBadEnumValue(self): | 673 # Maps aren't really proto2-only, but our test schema only has maps for |
| 408 message = unittest_pb2.TestAllTypes() | 674 # proto2. |
| 409 text = 'optional_nested_enum: BARR' | 675 def testParseMap(self): |
| 410 self.assertRaisesWithMessage( | 676 text = ('map_int32_int32 {\n' |
| 411 text_format.ParseError, | 677 ' key: -123\n' |
| 412 ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" ' | 678 ' value: -456\n' |
| 413 'has no value named BARR.'), | 679 '}\n' |
| 414 text_format.Merge, text, message) | 680 'map_int64_int64 {\n' |
| 681 ' key: -8589934592\n' |
| 682 ' value: -17179869184\n' |
| 683 '}\n' |
| 684 'map_uint32_uint32 {\n' |
| 685 ' key: 123\n' |
| 686 ' value: 456\n' |
| 687 '}\n' |
| 688 'map_uint64_uint64 {\n' |
| 689 ' key: 8589934592\n' |
| 690 ' value: 17179869184\n' |
| 691 '}\n' |
| 692 'map_string_string {\n' |
| 693 ' key: "abc"\n' |
| 694 ' value: "123"\n' |
| 695 '}\n' |
| 696 'map_int32_foreign_message {\n' |
| 697 ' key: 111\n' |
| 698 ' value {\n' |
| 699 ' c: 5\n' |
| 700 ' }\n' |
| 701 '}\n') |
| 702 message = map_unittest_pb2.TestMap() |
| 703 text_format.Parse(text, message) |
| 415 | 704 |
| 416 message = unittest_pb2.TestAllTypes() | 705 self.assertEqual(-456, message.map_int32_int32[-123]) |
| 417 text = 'optional_nested_enum: 100' | 706 self.assertEqual(-2**34, message.map_int64_int64[-2**33]) |
| 418 self.assertRaisesWithMessage( | 707 self.assertEqual(456, message.map_uint32_uint32[123]) |
| 419 text_format.ParseError, | 708 self.assertEqual(2**34, message.map_uint64_uint64[2**33]) |
| 420 ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" ' | 709 self.assertEqual("123", message.map_string_string["abc"]) |
| 421 'has no value with number 100.'), | 710 self.assertEqual(5, message.map_int32_foreign_message[111].c) |
| 422 text_format.Merge, text, message) | |
| 423 | |
| 424 def testMergeBadIntValue(self): | |
| 425 message = unittest_pb2.TestAllTypes() | |
| 426 text = 'optional_int32: bork' | |
| 427 self.assertRaisesWithMessage( | |
| 428 text_format.ParseError, | |
| 429 ('1:17 : Couldn\'t parse integer: bork'), | |
| 430 text_format.Merge, text, message) | |
| 431 | |
| 432 def assertRaisesWithMessage(self, e_class, e, func, *args, **kwargs): | |
| 433 """Same as assertRaises, but also compares the exception message.""" | |
| 434 if hasattr(e_class, '__name__'): | |
| 435 exc_name = e_class.__name__ | |
| 436 else: | |
| 437 exc_name = str(e_class) | |
| 438 | |
| 439 try: | |
| 440 func(*args, **kwargs) | |
| 441 except e_class as expr: | |
| 442 if str(expr) != e: | |
| 443 msg = '%s raised, but with wrong message: "%s" instead of "%s"' | |
| 444 raise self.failureException(msg % (exc_name, | |
| 445 str(expr).encode('string_escape'), | |
| 446 e.encode('string_escape'))) | |
| 447 return | |
| 448 else: | |
| 449 raise self.failureException('%s not raised' % exc_name) | |
| 450 | 711 |
| 451 | 712 |
| 452 class TokenizerTest(unittest.TestCase): | 713 class TokenizerTest(unittest.TestCase): |
| 453 | 714 |
| 454 def testSimpleTokenCases(self): | 715 def testSimpleTokenCases(self): |
| 455 text = ('identifier1:"string1"\n \n\n' | 716 text = ('identifier1:"string1"\n \n\n' |
| 456 'identifier2 : \n \n123 \n identifier3 :\'string\'\n' | 717 'identifier2 : \n \n123 \n identifier3 :\'string\'\n' |
| 457 'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n' | 718 'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n' |
| 458 'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n' | 719 'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n' |
| 459 'ID9: 22 ID10: -111111111111111111 ID11: -22\n' | 720 'ID9: 22 ID10: -111111111111111111 ID11: -22\n' |
| 460 'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f ' | 721 'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f ' |
| 461 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ' ) | 722 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ') |
| 462 tokenizer = text_format._Tokenizer(text) | 723 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 463 methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), | 724 methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), |
| 464 ':', | 725 ':', |
| 465 (tokenizer.ConsumeString, 'string1'), | 726 (tokenizer.ConsumeString, 'string1'), |
| 466 (tokenizer.ConsumeIdentifier, 'identifier2'), | 727 (tokenizer.ConsumeIdentifier, 'identifier2'), |
| 467 ':', | 728 ':', |
| 468 (tokenizer.ConsumeInt32, 123), | 729 (tokenizer.ConsumeInt32, 123), |
| 469 (tokenizer.ConsumeIdentifier, 'identifier3'), | 730 (tokenizer.ConsumeIdentifier, 'identifier3'), |
| 470 ':', | 731 ':', |
| 471 (tokenizer.ConsumeString, 'string'), | 732 (tokenizer.ConsumeString, 'string'), |
| 472 (tokenizer.ConsumeIdentifier, 'identifiER_4'), | 733 (tokenizer.ConsumeIdentifier, 'identifiER_4'), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 else: | 799 else: |
| 539 self.assertEqual(m[1], m[0]()) | 800 self.assertEqual(m[1], m[0]()) |
| 540 i += 1 | 801 i += 1 |
| 541 | 802 |
| 542 def testConsumeIntegers(self): | 803 def testConsumeIntegers(self): |
| 543 # This test only tests the failures in the integer parsing methods as well | 804 # This test only tests the failures in the integer parsing methods as well |
| 544 # as the '0' special cases. | 805 # as the '0' special cases. |
| 545 int64_max = (1 << 63) - 1 | 806 int64_max = (1 << 63) - 1 |
| 546 uint32_max = (1 << 32) - 1 | 807 uint32_max = (1 << 32) - 1 |
| 547 text = '-1 %d %d' % (uint32_max + 1, int64_max + 1) | 808 text = '-1 %d %d' % (uint32_max + 1, int64_max + 1) |
| 548 tokenizer = text_format._Tokenizer(text) | 809 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 549 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32) | 810 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32) |
| 550 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64) | 811 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64) |
| 551 self.assertEqual(-1, tokenizer.ConsumeInt32()) | 812 self.assertEqual(-1, tokenizer.ConsumeInt32()) |
| 552 | 813 |
| 553 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32) | 814 self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32) |
| 554 self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32) | 815 self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32) |
| 555 self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64()) | 816 self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64()) |
| 556 | 817 |
| 557 self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64) | 818 self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64) |
| 558 self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64()) | 819 self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64()) |
| 559 self.assertTrue(tokenizer.AtEnd()) | 820 self.assertTrue(tokenizer.AtEnd()) |
| 560 | 821 |
| 561 text = '-0 -0 0 0' | 822 text = '-0 -0 0 0' |
| 562 tokenizer = text_format._Tokenizer(text) | 823 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 563 self.assertEqual(0, tokenizer.ConsumeUint32()) | 824 self.assertEqual(0, tokenizer.ConsumeUint32()) |
| 564 self.assertEqual(0, tokenizer.ConsumeUint64()) | 825 self.assertEqual(0, tokenizer.ConsumeUint64()) |
| 565 self.assertEqual(0, tokenizer.ConsumeUint32()) | 826 self.assertEqual(0, tokenizer.ConsumeUint32()) |
| 566 self.assertEqual(0, tokenizer.ConsumeUint64()) | 827 self.assertEqual(0, tokenizer.ConsumeUint64()) |
| 567 self.assertTrue(tokenizer.AtEnd()) | 828 self.assertTrue(tokenizer.AtEnd()) |
| 568 | 829 |
| 569 def testConsumeByteString(self): | 830 def testConsumeByteString(self): |
| 570 text = '"string1\'' | 831 text = '"string1\'' |
| 571 tokenizer = text_format._Tokenizer(text) | 832 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 572 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) | 833 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
| 573 | 834 |
| 574 text = 'string1"' | 835 text = 'string1"' |
| 575 tokenizer = text_format._Tokenizer(text) | 836 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 576 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) | 837 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
| 577 | 838 |
| 578 text = '\n"\\xt"' | 839 text = '\n"\\xt"' |
| 579 tokenizer = text_format._Tokenizer(text) | 840 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 580 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) | 841 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
| 581 | 842 |
| 582 text = '\n"\\"' | 843 text = '\n"\\"' |
| 583 tokenizer = text_format._Tokenizer(text) | 844 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 584 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) | 845 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
| 585 | 846 |
| 586 text = '\n"\\x"' | 847 text = '\n"\\x"' |
| 587 tokenizer = text_format._Tokenizer(text) | 848 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 588 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) | 849 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) |
| 589 | 850 |
| 590 def testConsumeBool(self): | 851 def testConsumeBool(self): |
| 591 text = 'not-a-bool' | 852 text = 'not-a-bool' |
| 592 tokenizer = text_format._Tokenizer(text) | 853 tokenizer = text_format._Tokenizer(text.splitlines()) |
| 593 self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool) | 854 self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool) |
| 594 | 855 |
| 595 | 856 |
| 596 if __name__ == '__main__': | 857 if __name__ == '__main__': |
| 597 unittest.main() | 858 unittest.main() |
| OLD | NEW |