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