1# -*- coding: utf-8 -*- 2# Protocol Buffers - Google's data interchange format 3# Copyright 2008 Google Inc. All rights reserved. 4# https://developers.google.com/protocol-buffers/ 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: 9# 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above 13# copyright notice, this list of conditions and the following disclaimer 14# in the documentation and/or other materials provided with the 15# distribution. 16# * Neither the name of Google Inc. nor the names of its 17# contributors may be used to endorse or promote products derived from 18# this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32"""Test for google.protobuf.text_format.""" 33 34import io 35import math 36import re 37import string 38import textwrap 39 40import unittest 41 42from google.protobuf import any_pb2 43from google.protobuf import any_test_pb2 44from google.protobuf import map_unittest_pb2 45from google.protobuf import unittest_custom_options_pb2 46from google.protobuf import unittest_mset_pb2 47from google.protobuf import unittest_pb2 48from google.protobuf import unittest_proto3_arena_pb2 49from google.protobuf import descriptor_pb2 50from google.protobuf.internal import any_test_pb2 as test_extend_any 51from google.protobuf.internal import message_set_extensions_pb2 52from google.protobuf.internal import test_proto3_optional_pb2 53from google.protobuf.internal import test_util 54from google.protobuf import descriptor_pool 55from google.protobuf import text_format 56from google.protobuf.internal import _parameterized 57# pylint: enable=g-import-not-at-top 58 59 60# Low-level nuts-n-bolts tests. 61class SimpleTextFormatTests(unittest.TestCase): 62 63 # The members of _QUOTES are formatted into a regexp template that 64 # expects single characters. Therefore it's an error (in addition to being 65 # non-sensical in the first place) to try to specify a "quote mark" that is 66 # more than one character. 67 def testQuoteMarksAreSingleChars(self): 68 for quote in text_format._QUOTES: 69 self.assertEqual(1, len(quote)) 70 71 72# Base class with some common functionality. 73class TextFormatBase(unittest.TestCase): 74 75 def ReadGolden(self, golden_filename): 76 with test_util.GoldenFile(golden_filename) as f: 77 return (f.readlines() if str is bytes else # PY3 78 [golden_line.decode('utf-8') for golden_line in f]) 79 80 def CompareToGoldenFile(self, text, golden_filename): 81 golden_lines = self.ReadGolden(golden_filename) 82 self.assertMultiLineEqual(text, ''.join(golden_lines)) 83 84 def CompareToGoldenText(self, text, golden_text): 85 self.assertEqual(text, golden_text) 86 87 def RemoveRedundantZeros(self, text): 88 # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove 89 # these zeros in order to match the golden file. 90 text = text.replace('e+0','e+').replace('e+0','e+') \ 91 .replace('e-0','e-').replace('e-0','e-') 92 # Floating point fields are printed with .0 suffix even if they are 93 # actually integer numbers. 94 text = re.compile(r'\.0$', re.MULTILINE).sub('', text) 95 return text 96 97 98@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2) 99class TextFormatMessageToStringTests(TextFormatBase): 100 101 def testPrintExotic(self, message_module): 102 message = message_module.TestAllTypes() 103 message.repeated_int64.append(-9223372036854775808) 104 message.repeated_uint64.append(18446744073709551615) 105 message.repeated_double.append(123.456) 106 message.repeated_double.append(1.23e22) 107 message.repeated_double.append(1.23e-18) 108 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') 109 message.repeated_string.append(u'\u00fc\ua71f') 110 self.CompareToGoldenText( 111 self.RemoveRedundantZeros(text_format.MessageToString(message)), 112 'repeated_int64: -9223372036854775808\n' 113 'repeated_uint64: 18446744073709551615\n' 114 'repeated_double: 123.456\n' 115 'repeated_double: 1.23e+22\n' 116 'repeated_double: 1.23e-18\n' 117 'repeated_string:' 118 ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' 119 'repeated_string: "\\303\\274\\352\\234\\237"\n') 120 121 def testPrintFloatPrecision(self, message_module): 122 message = message_module.TestAllTypes() 123 124 message.repeated_float.append(0.0) 125 message.repeated_float.append(0.8) 126 message.repeated_float.append(1.0) 127 message.repeated_float.append(1.2) 128 message.repeated_float.append(1.23) 129 message.repeated_float.append(1.234) 130 message.repeated_float.append(1.2345) 131 message.repeated_float.append(1.23456) 132 message.repeated_float.append(1.2e10) 133 message.repeated_float.append(1.23e10) 134 message.repeated_float.append(1.234e10) 135 message.repeated_float.append(1.2345e10) 136 message.repeated_float.append(1.23456e10) 137 message.repeated_float.append(float('NaN')) 138 message.repeated_float.append(float('inf')) 139 message.repeated_double.append(0.0) 140 message.repeated_double.append(0.8) 141 message.repeated_double.append(1.0) 142 message.repeated_double.append(1.2) 143 message.repeated_double.append(1.23) 144 message.repeated_double.append(1.234) 145 message.repeated_double.append(1.2345) 146 message.repeated_double.append(1.23456) 147 message.repeated_double.append(1.234567) 148 message.repeated_double.append(1.2345678) 149 message.repeated_double.append(1.23456789) 150 message.repeated_double.append(1.234567898) 151 message.repeated_double.append(1.2345678987) 152 message.repeated_double.append(1.23456789876) 153 message.repeated_double.append(1.234567898765) 154 message.repeated_double.append(1.2345678987654) 155 message.repeated_double.append(1.23456789876543) 156 message.repeated_double.append(1.2e100) 157 message.repeated_double.append(1.23e100) 158 message.repeated_double.append(1.234e100) 159 message.repeated_double.append(1.2345e100) 160 message.repeated_double.append(1.23456e100) 161 message.repeated_double.append(1.234567e100) 162 message.repeated_double.append(1.2345678e100) 163 message.repeated_double.append(1.23456789e100) 164 message.repeated_double.append(1.234567898e100) 165 message.repeated_double.append(1.2345678987e100) 166 message.repeated_double.append(1.23456789876e100) 167 message.repeated_double.append(1.234567898765e100) 168 message.repeated_double.append(1.2345678987654e100) 169 message.repeated_double.append(1.23456789876543e100) 170 # pylint: disable=g-long-ternary 171 self.CompareToGoldenText( 172 self.RemoveRedundantZeros(text_format.MessageToString(message)), 173 'repeated_float: 0\n' 174 'repeated_float: 0.8\n' 175 'repeated_float: 1\n' 176 'repeated_float: 1.2\n' 177 'repeated_float: 1.23\n' 178 'repeated_float: 1.234\n' 179 'repeated_float: 1.2345\n' 180 'repeated_float: 1.23456\n' 181 # Note that these don't use scientific notation. 182 'repeated_float: 12000000000\n' 183 'repeated_float: 12300000000\n' 184 'repeated_float: 12340000000\n' 185 'repeated_float: 12345000000\n' 186 'repeated_float: 12345600000\n' 187 'repeated_float: nan\n' 188 'repeated_float: inf\n' 189 'repeated_double: 0\n' 190 'repeated_double: 0.8\n' 191 'repeated_double: 1\n' 192 'repeated_double: 1.2\n' 193 'repeated_double: 1.23\n' 194 'repeated_double: 1.234\n' 195 'repeated_double: 1.2345\n' 196 'repeated_double: 1.23456\n' 197 'repeated_double: 1.234567\n' 198 'repeated_double: 1.2345678\n' 199 'repeated_double: 1.23456789\n' 200 'repeated_double: 1.234567898\n' 201 'repeated_double: 1.2345678987\n' 202 'repeated_double: 1.23456789876\n' 203 'repeated_double: 1.234567898765\n' 204 'repeated_double: 1.2345678987654\n' 205 'repeated_double: 1.23456789876543\n' 206 'repeated_double: 1.2e+100\n' 207 'repeated_double: 1.23e+100\n' 208 'repeated_double: 1.234e+100\n' 209 'repeated_double: 1.2345e+100\n' 210 'repeated_double: 1.23456e+100\n' 211 'repeated_double: 1.234567e+100\n' 212 'repeated_double: 1.2345678e+100\n' 213 'repeated_double: 1.23456789e+100\n' 214 'repeated_double: 1.234567898e+100\n' 215 'repeated_double: 1.2345678987e+100\n' 216 'repeated_double: 1.23456789876e+100\n' 217 'repeated_double: 1.234567898765e+100\n' 218 'repeated_double: 1.2345678987654e+100\n' 219 'repeated_double: 1.23456789876543e+100\n') 220 221 def testPrintExoticUnicodeSubclass(self, message_module): 222 223 class UnicodeSub(str): 224 pass 225 226 message = message_module.TestAllTypes() 227 message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f')) 228 self.CompareToGoldenText( 229 text_format.MessageToString(message), 230 'repeated_string: "\\303\\274\\352\\234\\237"\n') 231 232 def testPrintNestedMessageAsOneLine(self, message_module): 233 message = message_module.TestAllTypes() 234 msg = message.repeated_nested_message.add() 235 msg.bb = 42 236 self.CompareToGoldenText( 237 text_format.MessageToString(message, as_one_line=True), 238 'repeated_nested_message { bb: 42 }') 239 240 def testPrintRepeatedFieldsAsOneLine(self, message_module): 241 message = message_module.TestAllTypes() 242 message.repeated_int32.append(1) 243 message.repeated_int32.append(1) 244 message.repeated_int32.append(3) 245 message.repeated_string.append('Google') 246 message.repeated_string.append('Zurich') 247 self.CompareToGoldenText( 248 text_format.MessageToString(message, as_one_line=True), 249 'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 ' 250 'repeated_string: "Google" repeated_string: "Zurich"') 251 252 def VerifyPrintShortFormatRepeatedFields(self, message_module, as_one_line): 253 message = message_module.TestAllTypes() 254 message.repeated_int32.append(1) 255 message.repeated_string.append('Google') 256 message.repeated_string.append('Hello,World') 257 message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_FOO) 258 message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR) 259 message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ) 260 message.optional_nested_message.bb = 3 261 for i in (21, 32): 262 msg = message.repeated_nested_message.add() 263 msg.bb = i 264 expected_ascii = ( 265 'optional_nested_message {\n bb: 3\n}\n' 266 'repeated_int32: [1]\n' 267 'repeated_string: "Google"\n' 268 'repeated_string: "Hello,World"\n' 269 'repeated_nested_message {\n bb: 21\n}\n' 270 'repeated_nested_message {\n bb: 32\n}\n' 271 'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n') 272 if as_one_line: 273 expected_ascii = expected_ascii.replace('\n', ' ') 274 expected_ascii = re.sub(r'\s+', ' ', expected_ascii) 275 expected_ascii = re.sub(r'\s$', '', expected_ascii) 276 277 actual_ascii = text_format.MessageToString( 278 message, use_short_repeated_primitives=True, 279 as_one_line=as_one_line) 280 self.CompareToGoldenText(actual_ascii, expected_ascii) 281 parsed_message = message_module.TestAllTypes() 282 text_format.Parse(actual_ascii, parsed_message) 283 self.assertEqual(parsed_message, message) 284 285 def testPrintShortFormatRepeatedFields(self, message_module): 286 self.VerifyPrintShortFormatRepeatedFields(message_module, False) 287 self.VerifyPrintShortFormatRepeatedFields(message_module, True) 288 289 def testPrintNestedNewLineInStringAsOneLine(self, message_module): 290 message = message_module.TestAllTypes() 291 message.optional_string = 'a\nnew\nline' 292 self.CompareToGoldenText( 293 text_format.MessageToString(message, as_one_line=True), 294 'optional_string: "a\\nnew\\nline"') 295 296 def testPrintExoticAsOneLine(self, message_module): 297 message = message_module.TestAllTypes() 298 message.repeated_int64.append(-9223372036854775808) 299 message.repeated_uint64.append(18446744073709551615) 300 message.repeated_double.append(123.456) 301 message.repeated_double.append(1.23e22) 302 message.repeated_double.append(1.23e-18) 303 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') 304 message.repeated_string.append(u'\u00fc\ua71f') 305 self.CompareToGoldenText( 306 self.RemoveRedundantZeros(text_format.MessageToString( 307 message, as_one_line=True)), 308 'repeated_int64: -9223372036854775808' 309 ' repeated_uint64: 18446744073709551615' 310 ' repeated_double: 123.456' 311 ' repeated_double: 1.23e+22' 312 ' repeated_double: 1.23e-18' 313 ' repeated_string: ' 314 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""' 315 ' repeated_string: "\\303\\274\\352\\234\\237"') 316 317 def testRoundTripExoticAsOneLine(self, message_module): 318 message = message_module.TestAllTypes() 319 message.repeated_int64.append(-9223372036854775808) 320 message.repeated_uint64.append(18446744073709551615) 321 message.repeated_double.append(123.456) 322 message.repeated_double.append(1.23e22) 323 message.repeated_double.append(1.23e-18) 324 message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"') 325 message.repeated_string.append(u'\u00fc\ua71f') 326 327 # Test as_utf8 = False. 328 wire_text = text_format.MessageToString(message, 329 as_one_line=True, 330 as_utf8=False) 331 parsed_message = message_module.TestAllTypes() 332 r = text_format.Parse(wire_text, parsed_message) 333 self.assertIs(r, parsed_message) 334 self.assertEqual(message, parsed_message) 335 336 # Test as_utf8 = True. 337 wire_text = text_format.MessageToString(message, 338 as_one_line=True, 339 as_utf8=True) 340 parsed_message = message_module.TestAllTypes() 341 r = text_format.Parse(wire_text, parsed_message) 342 self.assertIs(r, parsed_message) 343 self.assertEqual(message, parsed_message, 344 '\n%s != %s' % (message, parsed_message)) 345 346 def testPrintRawUtf8String(self, message_module): 347 message = message_module.TestAllTypes() 348 message.repeated_string.append(u'\u00fc\t\ua71f') 349 text = text_format.MessageToString(message, as_utf8=True) 350 golden_unicode = u'repeated_string: "\u00fc\\t\ua71f"\n' 351 golden_text = golden_unicode 352 # MessageToString always returns a native str. 353 self.CompareToGoldenText(text, golden_text) 354 parsed_message = message_module.TestAllTypes() 355 text_format.Parse(text, parsed_message) 356 self.assertEqual( 357 message, parsed_message, '\n%s != %s (%s != %s)' % 358 (message, parsed_message, message.repeated_string[0], 359 parsed_message.repeated_string[0])) 360 361 def testPrintFloatFormat(self, message_module): 362 # Check that float_format argument is passed to sub-message formatting. 363 message = message_module.NestedTestAllTypes() 364 message.payload.optional_float = 1.25 365 # Check rounding at 15 significant digits 366 message.payload.optional_double = -.000003456789012345678 367 # Check no decimal point. 368 message.payload.repeated_float.append(-5642) 369 # Check no trailing zeros. 370 message.payload.repeated_double.append(.000078900) 371 formatted_fields = ['optional_float: 1.25', 372 'optional_double: -3.45678901234568e-6', 373 'repeated_float: -5642', 'repeated_double: 7.89e-5'] 374 text_message = text_format.MessageToString(message, float_format='.15g') 375 self.CompareToGoldenText( 376 self.RemoveRedundantZeros(text_message), 377 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format( 378 *formatted_fields)) 379 # as_one_line=True is a separate code branch where float_format is passed. 380 text_message = text_format.MessageToString(message, 381 as_one_line=True, 382 float_format='.15g') 383 self.CompareToGoldenText( 384 self.RemoveRedundantZeros(text_message), 385 'payload {{ {0} {1} {2} {3} }}'.format(*formatted_fields)) 386 387 # 32-bit 1.2 is noisy when extended to 64-bit: 388 # >>> struct.unpack('f', struct.pack('f', 1.2))[0] 389 # 1.2000000476837158 390 message.payload.optional_float = 1.2 391 formatted_fields = ['optional_float: 1.2', 392 'optional_double: -3.45678901234568e-6', 393 'repeated_float: -5642', 'repeated_double: 7.89e-5'] 394 text_message = text_format.MessageToString(message, float_format='.7g', 395 double_format='.15g') 396 self.CompareToGoldenText( 397 self.RemoveRedundantZeros(text_message), 398 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format( 399 *formatted_fields)) 400 401 # Test only set float_format affect both float and double fields. 402 formatted_fields = ['optional_float: 1.2', 403 'optional_double: -3.456789e-6', 404 'repeated_float: -5642', 'repeated_double: 7.89e-5'] 405 text_message = text_format.MessageToString(message, float_format='.7g') 406 self.CompareToGoldenText( 407 self.RemoveRedundantZeros(text_message), 408 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format( 409 *formatted_fields)) 410 411 # Test default float_format will automatic print shortest float. 412 message.payload.optional_float = 1.2345678912 413 message.payload.optional_double = 1.2345678912 414 formatted_fields = ['optional_float: 1.2345679', 415 'optional_double: 1.2345678912', 416 'repeated_float: -5642', 'repeated_double: 7.89e-5'] 417 text_message = text_format.MessageToString(message) 418 self.CompareToGoldenText( 419 self.RemoveRedundantZeros(text_message), 420 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format( 421 *formatted_fields)) 422 423 message.Clear() 424 message.payload.optional_float = 1.1000000000011 425 self.assertEqual(text_format.MessageToString(message), 426 'payload {\n optional_float: 1.1\n}\n') 427 message.payload.optional_float = 1.00000075e-36 428 self.assertEqual(text_format.MessageToString(message), 429 'payload {\n optional_float: 1.00000075e-36\n}\n') 430 message.payload.optional_float = 12345678912345e+11 431 self.assertEqual(text_format.MessageToString(message), 432 'payload {\n optional_float: 1.234568e+24\n}\n') 433 434 def testMessageToString(self, message_module): 435 message = message_module.ForeignMessage() 436 message.c = 123 437 self.assertEqual('c: 123\n', str(message)) 438 439 def testMessageToStringUnicode(self, message_module): 440 golden_unicode = u'Á short desçription and a .' 441 golden_bytes = golden_unicode.encode('utf-8') 442 message = message_module.TestAllTypes() 443 message.optional_string = golden_unicode 444 message.optional_bytes = golden_bytes 445 text = text_format.MessageToString(message, as_utf8=True) 446 golden_message = textwrap.dedent( 447 'optional_string: "Á short desçription and a ."\n' 448 'optional_bytes: ' 449 r'"\303\201 short des\303\247ription and a \360\237\215\214."' 450 '\n') 451 self.CompareToGoldenText(text, golden_message) 452 453 def testMessageToStringASCII(self, message_module): 454 golden_unicode = u'Á short desçription and a .' 455 golden_bytes = golden_unicode.encode('utf-8') 456 message = message_module.TestAllTypes() 457 message.optional_string = golden_unicode 458 message.optional_bytes = golden_bytes 459 text = text_format.MessageToString(message, as_utf8=False) # ASCII 460 golden_message = ( 461 'optional_string: ' 462 r'"\303\201 short des\303\247ription and a \360\237\215\214."' 463 '\n' 464 'optional_bytes: ' 465 r'"\303\201 short des\303\247ription and a \360\237\215\214."' 466 '\n') 467 self.CompareToGoldenText(text, golden_message) 468 469 def testPrintField(self, message_module): 470 message = message_module.TestAllTypes() 471 field = message.DESCRIPTOR.fields_by_name['optional_float'] 472 value = message.optional_float 473 out = text_format.TextWriter(False) 474 text_format.PrintField(field, value, out) 475 self.assertEqual('optional_float: 0.0\n', out.getvalue()) 476 out.close() 477 # Test Printer 478 out = text_format.TextWriter(False) 479 printer = text_format._Printer(out) 480 printer.PrintField(field, value) 481 self.assertEqual('optional_float: 0.0\n', out.getvalue()) 482 out.close() 483 484 def testPrintFieldValue(self, message_module): 485 message = message_module.TestAllTypes() 486 field = message.DESCRIPTOR.fields_by_name['optional_float'] 487 value = message.optional_float 488 out = text_format.TextWriter(False) 489 text_format.PrintFieldValue(field, value, out) 490 self.assertEqual('0.0', out.getvalue()) 491 out.close() 492 # Test Printer 493 out = text_format.TextWriter(False) 494 printer = text_format._Printer(out) 495 printer.PrintFieldValue(field, value) 496 self.assertEqual('0.0', out.getvalue()) 497 out.close() 498 499 def testCustomOptions(self, message_module): 500 message_descriptor = (unittest_custom_options_pb2. 501 TestMessageWithCustomOptions.DESCRIPTOR) 502 message_proto = descriptor_pb2.DescriptorProto() 503 message_descriptor.CopyToProto(message_proto) 504 expected_text = ( 505 'name: "TestMessageWithCustomOptions"\n' 506 'field {\n' 507 ' name: "field1"\n' 508 ' number: 1\n' 509 ' label: LABEL_OPTIONAL\n' 510 ' type: TYPE_STRING\n' 511 ' options {\n' 512 ' ctype: CORD\n' 513 ' [protobuf_unittest.field_opt1]: 8765432109\n' 514 ' }\n' 515 '}\n' 516 'field {\n' 517 ' name: "oneof_field"\n' 518 ' number: 2\n' 519 ' label: LABEL_OPTIONAL\n' 520 ' type: TYPE_INT32\n' 521 ' oneof_index: 0\n' 522 '}\n' 523 'field {\n' 524 ' name: "map_field"\n' 525 ' number: 3\n' 526 ' label: LABEL_REPEATED\n' 527 ' type: TYPE_MESSAGE\n' 528 ' type_name: ".protobuf_unittest.TestMessageWithCustomOptions.' 529 'MapFieldEntry"\n' 530 ' options {\n' 531 ' [protobuf_unittest.field_opt1]: 12345\n' 532 ' }\n' 533 '}\n' 534 'nested_type {\n' 535 ' name: "MapFieldEntry"\n' 536 ' field {\n' 537 ' name: "key"\n' 538 ' number: 1\n' 539 ' label: LABEL_OPTIONAL\n' 540 ' type: TYPE_STRING\n' 541 ' }\n' 542 ' field {\n' 543 ' name: "value"\n' 544 ' number: 2\n' 545 ' label: LABEL_OPTIONAL\n' 546 ' type: TYPE_STRING\n' 547 ' }\n' 548 ' options {\n' 549 ' map_entry: true\n' 550 ' }\n' 551 '}\n' 552 'enum_type {\n' 553 ' name: "AnEnum"\n' 554 ' value {\n' 555 ' name: "ANENUM_VAL1"\n' 556 ' number: 1\n' 557 ' }\n' 558 ' value {\n' 559 ' name: "ANENUM_VAL2"\n' 560 ' number: 2\n' 561 ' options {\n' 562 ' [protobuf_unittest.enum_value_opt1]: 123\n' 563 ' }\n' 564 ' }\n' 565 ' options {\n' 566 ' [protobuf_unittest.enum_opt1]: -789\n' 567 ' }\n' 568 '}\n' 569 'options {\n' 570 ' message_set_wire_format: false\n' 571 ' [protobuf_unittest.message_opt1]: -56\n' 572 '}\n' 573 'oneof_decl {\n' 574 ' name: "AnOneof"\n' 575 ' options {\n' 576 ' [protobuf_unittest.oneof_opt1]: -99\n' 577 ' }\n' 578 '}\n') 579 self.assertEqual(expected_text, 580 text_format.MessageToString(message_proto)) 581 parsed_proto = descriptor_pb2.DescriptorProto() 582 text_format.Parse(expected_text, parsed_proto) 583 self.assertEqual(message_proto, parsed_proto) 584 585 def testPrintUnknownFieldsEmbeddedMessageInBytes(self, message_module): 586 inner_msg = message_module.TestAllTypes() 587 inner_msg.optional_int32 = 101 588 inner_msg.optional_double = 102.0 589 inner_msg.optional_string = u'hello' 590 inner_msg.optional_bytes = b'103' 591 inner_msg.optional_nested_message.bb = 105 592 inner_data = inner_msg.SerializeToString() 593 outer_message = message_module.TestAllTypes() 594 outer_message.optional_int32 = 101 595 outer_message.optional_bytes = inner_data 596 all_data = outer_message.SerializeToString() 597 empty_message = message_module.TestEmptyMessage() 598 empty_message.ParseFromString(all_data) 599 600 self.assertEqual(' 1: 101\n' 601 ' 15 {\n' 602 ' 1: 101\n' 603 ' 12: 4636878028842991616\n' 604 ' 14: "hello"\n' 605 ' 15: "103"\n' 606 ' 18 {\n' 607 ' 1: 105\n' 608 ' }\n' 609 ' }\n', 610 text_format.MessageToString(empty_message, 611 indent=2, 612 print_unknown_fields=True)) 613 self.assertEqual('1: 101 ' 614 '15 { ' 615 '1: 101 ' 616 '12: 4636878028842991616 ' 617 '14: "hello" ' 618 '15: "103" ' 619 '18 { 1: 105 } ' 620 '}', 621 text_format.MessageToString(empty_message, 622 print_unknown_fields=True, 623 as_one_line=True)) 624 625 626@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2) 627class TextFormatMessageToTextBytesTests(TextFormatBase): 628 629 def testMessageToBytes(self, message_module): 630 message = message_module.ForeignMessage() 631 message.c = 123 632 self.assertEqual(b'c: 123\n', text_format.MessageToBytes(message)) 633 634 def testRawUtf8RoundTrip(self, message_module): 635 message = message_module.TestAllTypes() 636 message.repeated_string.append(u'\u00fc\t\ua71f') 637 utf8_text = text_format.MessageToBytes(message, as_utf8=True) 638 golden_bytes = b'repeated_string: "\xc3\xbc\\t\xea\x9c\x9f"\n' 639 self.CompareToGoldenText(utf8_text, golden_bytes) 640 parsed_message = message_module.TestAllTypes() 641 text_format.Parse(utf8_text, parsed_message) 642 self.assertEqual( 643 message, parsed_message, '\n%s != %s (%s != %s)' % 644 (message, parsed_message, message.repeated_string[0], 645 parsed_message.repeated_string[0])) 646 647 def testEscapedUtf8ASCIIRoundTrip(self, message_module): 648 message = message_module.TestAllTypes() 649 message.repeated_string.append(u'\u00fc\t\ua71f') 650 ascii_text = text_format.MessageToBytes(message) # as_utf8=False default 651 golden_bytes = b'repeated_string: "\\303\\274\\t\\352\\234\\237"\n' 652 self.CompareToGoldenText(ascii_text, golden_bytes) 653 parsed_message = message_module.TestAllTypes() 654 text_format.Parse(ascii_text, parsed_message) 655 self.assertEqual( 656 message, parsed_message, '\n%s != %s (%s != %s)' % 657 (message, parsed_message, message.repeated_string[0], 658 parsed_message.repeated_string[0])) 659 660 661@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2) 662class TextFormatParserTests(TextFormatBase): 663 664 def testParseAllFields(self, message_module): 665 message = message_module.TestAllTypes() 666 test_util.SetAllFields(message) 667 ascii_text = text_format.MessageToString(message) 668 669 parsed_message = message_module.TestAllTypes() 670 text_format.Parse(ascii_text, parsed_message) 671 self.assertEqual(message, parsed_message) 672 if message_module is unittest_pb2: 673 test_util.ExpectAllFieldsSet(self, message) 674 675 def testParseAndMergeUtf8(self, message_module): 676 message = message_module.TestAllTypes() 677 test_util.SetAllFields(message) 678 ascii_text = text_format.MessageToString(message) 679 ascii_text = ascii_text.encode('utf-8') 680 681 parsed_message = message_module.TestAllTypes() 682 text_format.Parse(ascii_text, parsed_message) 683 self.assertEqual(message, parsed_message) 684 if message_module is unittest_pb2: 685 test_util.ExpectAllFieldsSet(self, message) 686 687 parsed_message.Clear() 688 text_format.Merge(ascii_text, parsed_message) 689 self.assertEqual(message, parsed_message) 690 if message_module is unittest_pb2: 691 test_util.ExpectAllFieldsSet(self, message) 692 693 msg2 = message_module.TestAllTypes() 694 text = (u'optional_string: "café"') 695 text_format.Merge(text, msg2) 696 self.assertEqual(msg2.optional_string, u'café') 697 msg2.Clear() 698 self.assertEqual(msg2.optional_string, u'') 699 text_format.Parse(text, msg2) 700 self.assertEqual(msg2.optional_string, u'café') 701 702 def testParseDoubleToFloat(self, message_module): 703 message = message_module.TestAllTypes() 704 text = ('repeated_float: 3.4028235e+39\n' 705 'repeated_float: 1.4028235e-39\n') 706 text_format.Parse(text, message) 707 self.assertEqual(message.repeated_float[0], float('inf')) 708 self.assertAlmostEqual(message.repeated_float[1], 1.4028235e-39) 709 710 def testParseExotic(self, message_module): 711 message = message_module.TestAllTypes() 712 text = ('repeated_int64: -9223372036854775808\n' 713 'repeated_uint64: 18446744073709551615\n' 714 'repeated_double: 123.456\n' 715 'repeated_double: 1.23e+22\n' 716 'repeated_double: 1.23e-18\n' 717 'repeated_string: \n' 718 '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n' 719 'repeated_string: "foo" \'corge\' "grault"\n' 720 'repeated_string: "\\303\\274\\352\\234\\237"\n' 721 'repeated_string: "\\xc3\\xbc"\n' 722 'repeated_string: "\xc3\xbc"\n') 723 text_format.Parse(text, message) 724 725 self.assertEqual(-9223372036854775808, message.repeated_int64[0]) 726 self.assertEqual(18446744073709551615, message.repeated_uint64[0]) 727 self.assertEqual(123.456, message.repeated_double[0]) 728 self.assertEqual(1.23e22, message.repeated_double[1]) 729 self.assertEqual(1.23e-18, message.repeated_double[2]) 730 self.assertEqual('\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0]) 731 self.assertEqual('foocorgegrault', message.repeated_string[1]) 732 self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2]) 733 self.assertEqual(u'\u00fc', message.repeated_string[3]) 734 735 def testParseTrailingCommas(self, message_module): 736 message = message_module.TestAllTypes() 737 text = ('repeated_int64: 100;\n' 738 'repeated_int64: 200;\n' 739 'repeated_int64: 300,\n' 740 'repeated_string: "one",\n' 741 'repeated_string: "two";\n') 742 text_format.Parse(text, message) 743 744 self.assertEqual(100, message.repeated_int64[0]) 745 self.assertEqual(200, message.repeated_int64[1]) 746 self.assertEqual(300, message.repeated_int64[2]) 747 self.assertEqual(u'one', message.repeated_string[0]) 748 self.assertEqual(u'two', message.repeated_string[1]) 749 750 def testParseRepeatedScalarShortFormat(self, message_module): 751 message = message_module.TestAllTypes() 752 text = ('repeated_int64: [100, 200];\n' 753 'repeated_int64: []\n' 754 'repeated_int64: 300,\n' 755 'repeated_string: ["one", "two"];\n') 756 text_format.Parse(text, message) 757 758 self.assertEqual(100, message.repeated_int64[0]) 759 self.assertEqual(200, message.repeated_int64[1]) 760 self.assertEqual(300, message.repeated_int64[2]) 761 self.assertEqual(u'one', message.repeated_string[0]) 762 self.assertEqual(u'two', message.repeated_string[1]) 763 764 def testParseRepeatedMessageShortFormat(self, message_module): 765 message = message_module.TestAllTypes() 766 text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n' 767 'repeated_nested_message: {bb: 300}\n' 768 'repeated_nested_message [{bb: 400}];\n') 769 text_format.Parse(text, message) 770 771 self.assertEqual(100, message.repeated_nested_message[0].bb) 772 self.assertEqual(200, message.repeated_nested_message[1].bb) 773 self.assertEqual(300, message.repeated_nested_message[2].bb) 774 self.assertEqual(400, message.repeated_nested_message[3].bb) 775 776 def testParseEmptyText(self, message_module): 777 message = message_module.TestAllTypes() 778 text = '' 779 text_format.Parse(text, message) 780 self.assertEqual(message_module.TestAllTypes(), message) 781 782 def testParseInvalidUtf8(self, message_module): 783 message = message_module.TestAllTypes() 784 text = 'repeated_string: "\\xc3\\xc3"' 785 with self.assertRaises(text_format.ParseError) as e: 786 text_format.Parse(text, message) 787 self.assertEqual(e.exception.GetLine(), 1) 788 self.assertEqual(e.exception.GetColumn(), 28) 789 790 def testParseSingleWord(self, message_module): 791 message = message_module.TestAllTypes() 792 text = 'foo' 793 self.assertRaisesRegex( 794 text_format.ParseError, 795 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' 796 r'"foo".'), text_format.Parse, text, message) 797 798 def testParseUnknownField(self, message_module): 799 message = message_module.TestAllTypes() 800 text = 'unknown_field: 8\n' 801 self.assertRaisesRegex( 802 text_format.ParseError, 803 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' 804 r'"unknown_field".'), text_format.Parse, text, message) 805 text = ('optional_int32: 123\n' 806 'unknown_field: 8\n' 807 'optional_nested_message { bb: 45 }') 808 text_format.Parse(text, message, allow_unknown_field=True) 809 self.assertEqual(message.optional_nested_message.bb, 45) 810 self.assertEqual(message.optional_int32, 123) 811 812 def testParseBadEnumValue(self, message_module): 813 message = message_module.TestAllTypes() 814 text = 'optional_nested_enum: BARR' 815 self.assertRaisesRegex(text_format.ParseError, 816 (r'1:23 : \'optional_nested_enum: BARR\': ' 817 r'Enum type "\w+.TestAllTypes.NestedEnum" ' 818 r'has no value named BARR.'), text_format.Parse, 819 text, message) 820 821 def testParseBadIntValue(self, message_module): 822 message = message_module.TestAllTypes() 823 text = 'optional_int32: bork' 824 self.assertRaisesRegex(text_format.ParseError, 825 ('1:17 : \'optional_int32: bork\': ' 826 'Couldn\'t parse integer: bork'), text_format.Parse, 827 text, message) 828 829 def testParseStringFieldUnescape(self, message_module): 830 message = message_module.TestAllTypes() 831 text = r'''repeated_string: "\xf\x62" 832 repeated_string: "\\xf\\x62" 833 repeated_string: "\\\xf\\\x62" 834 repeated_string: "\\\\xf\\\\x62" 835 repeated_string: "\\\\\xf\\\\\x62" 836 repeated_string: "\x5cx20"''' 837 838 text_format.Parse(text, message) 839 840 SLASH = '\\' 841 self.assertEqual('\x0fb', message.repeated_string[0]) 842 self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1]) 843 self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2]) 844 self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62', 845 message.repeated_string[3]) 846 self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b', 847 message.repeated_string[4]) 848 self.assertEqual(SLASH + 'x20', message.repeated_string[5]) 849 850 def testParseOneof(self, message_module): 851 m = message_module.TestAllTypes() 852 m.oneof_uint32 = 11 853 m2 = message_module.TestAllTypes() 854 text_format.Parse(text_format.MessageToString(m), m2) 855 self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) 856 857 def testParseMultipleOneof(self, message_module): 858 m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"']) 859 m2 = message_module.TestAllTypes() 860 with self.assertRaisesRegex(text_format.ParseError, 861 ' is specified along with field '): 862 text_format.Parse(m_string, m2) 863 864 # This example contains non-ASCII codepoint unicode data as literals 865 # which should come through as utf-8 for bytes, and as the unicode 866 # itself for string fields. It also demonstrates escaped binary data. 867 # The ur"" string prefix is unfortunately missing from Python 3 868 # so we resort to double escaping our \s so that they come through. 869 _UNICODE_SAMPLE = u""" 870 optional_bytes: 'Á short desçription' 871 optional_string: 'Á short desçription' 872 repeated_bytes: '\\303\\201 short des\\303\\247ription' 873 repeated_bytes: '\\x12\\x34\\x56\\x78\\x90\\xab\\xcd\\xef' 874 repeated_string: '\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82' 875 """ 876 _BYTES_SAMPLE = _UNICODE_SAMPLE.encode('utf-8') 877 _GOLDEN_UNICODE = u'Á short desçription' 878 _GOLDEN_BYTES = _GOLDEN_UNICODE.encode('utf-8') 879 _GOLDEN_BYTES_1 = b'\x12\x34\x56\x78\x90\xab\xcd\xef' 880 _GOLDEN_STR_0 = u'Привет' 881 882 def testParseUnicode(self, message_module): 883 m = message_module.TestAllTypes() 884 text_format.Parse(self._UNICODE_SAMPLE, m) 885 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 886 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 887 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 888 # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data. 889 self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1) 890 # repeated_string[0] contained \ escaped data representing the UTF-8 891 # representation of _GOLDEN_STR_0 - it needs to decode as such. 892 self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0) 893 894 def testParseBytes(self, message_module): 895 m = message_module.TestAllTypes() 896 text_format.Parse(self._BYTES_SAMPLE, m) 897 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 898 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 899 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 900 # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data. 901 self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1) 902 # repeated_string[0] contained \ escaped data representing the UTF-8 903 # representation of _GOLDEN_STR_0 - it needs to decode as such. 904 self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0) 905 906 def testFromBytesFile(self, message_module): 907 m = message_module.TestAllTypes() 908 f = io.BytesIO(self._BYTES_SAMPLE) 909 text_format.ParseLines(f, m) 910 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 911 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 912 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 913 914 def testFromUnicodeFile(self, message_module): 915 m = message_module.TestAllTypes() 916 f = io.StringIO(self._UNICODE_SAMPLE) 917 text_format.ParseLines(f, m) 918 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 919 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 920 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 921 922 def testFromBytesLines(self, message_module): 923 m = message_module.TestAllTypes() 924 text_format.ParseLines(self._BYTES_SAMPLE.split(b'\n'), m) 925 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 926 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 927 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 928 929 def testFromUnicodeLines(self, message_module): 930 m = message_module.TestAllTypes() 931 text_format.ParseLines(self._UNICODE_SAMPLE.split(u'\n'), m) 932 self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES) 933 self.assertEqual(m.optional_string, self._GOLDEN_UNICODE) 934 self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES) 935 936 def testParseDuplicateMessages(self, message_module): 937 message = message_module.TestAllTypes() 938 text = ('optional_nested_message { bb: 1 } ' 939 'optional_nested_message { bb: 2 }') 940 self.assertRaisesRegex( 941 text_format.ParseError, 942 (r'1:59 : Message type "\w+.TestAllTypes" ' 943 r'should not have multiple "optional_nested_message" fields.'), 944 text_format.Parse, text, message) 945 946 def testParseDuplicateScalars(self, message_module): 947 message = message_module.TestAllTypes() 948 text = ('optional_int32: 42 ' 'optional_int32: 67') 949 self.assertRaisesRegex( 950 text_format.ParseError, 951 (r'1:36 : Message type "\w+.TestAllTypes" should not ' 952 r'have multiple "optional_int32" fields.'), text_format.Parse, text, 953 message) 954 955 def testParseExistingScalarInMessage(self, message_module): 956 message = message_module.TestAllTypes(optional_int32=42) 957 text = 'optional_int32: 67' 958 self.assertRaisesRegex(text_format.ParseError, 959 (r'Message type "\w+.TestAllTypes" should not ' 960 r'have multiple "optional_int32" fields.'), 961 text_format.Parse, text, message) 962 963 964@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2) 965class TextFormatMergeTests(TextFormatBase): 966 967 def testMergeDuplicateScalarsInText(self, message_module): 968 message = message_module.TestAllTypes() 969 text = ('optional_int32: 42 ' 'optional_int32: 67') 970 r = text_format.Merge(text, message) 971 self.assertIs(r, message) 972 self.assertEqual(67, message.optional_int32) 973 974 def testMergeDuplicateNestedMessageScalars(self, message_module): 975 message = message_module.TestAllTypes() 976 text = ('optional_nested_message { bb: 1 } ' 977 'optional_nested_message { bb: 2 }') 978 r = text_format.Merge(text, message) 979 self.assertTrue(r is message) 980 self.assertEqual(2, message.optional_nested_message.bb) 981 982 def testReplaceScalarInMessage(self, message_module): 983 message = message_module.TestAllTypes(optional_int32=42) 984 text = 'optional_int32: 67' 985 r = text_format.Merge(text, message) 986 self.assertIs(r, message) 987 self.assertEqual(67, message.optional_int32) 988 989 def testReplaceMessageInMessage(self, message_module): 990 message = message_module.TestAllTypes( 991 optional_int32=42, optional_nested_message=dict()) 992 self.assertTrue(message.HasField('optional_nested_message')) 993 text = 'optional_nested_message{ bb: 3 }' 994 r = text_format.Merge(text, message) 995 self.assertIs(r, message) 996 self.assertEqual(3, message.optional_nested_message.bb) 997 998 def testMergeMultipleOneof(self, message_module): 999 m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"']) 1000 m2 = message_module.TestAllTypes() 1001 text_format.Merge(m_string, m2) 1002 self.assertEqual('oneof_string', m2.WhichOneof('oneof_field')) 1003 1004 1005# These are tests that aren't fundamentally specific to proto2, but are at 1006# the moment because of differences between the proto2 and proto3 test schemas. 1007# Ideally the schemas would be made more similar so these tests could pass. 1008class OnlyWorksWithProto2RightNowTests(TextFormatBase): 1009 1010 def testPrintAllFieldsPointy(self): 1011 message = unittest_pb2.TestAllTypes() 1012 test_util.SetAllFields(message) 1013 self.CompareToGoldenFile( 1014 self.RemoveRedundantZeros(text_format.MessageToString( 1015 message, pointy_brackets=True)), 1016 'text_format_unittest_data_pointy_oneof.txt') 1017 1018 def testParseGolden(self): 1019 golden_text = '\n'.join(self.ReadGolden( 1020 'text_format_unittest_data_oneof_implemented.txt')) 1021 parsed_message = unittest_pb2.TestAllTypes() 1022 r = text_format.Parse(golden_text, parsed_message) 1023 self.assertIs(r, parsed_message) 1024 1025 message = unittest_pb2.TestAllTypes() 1026 test_util.SetAllFields(message) 1027 self.assertEqual(message, parsed_message) 1028 1029 def testPrintAllFields(self): 1030 message = unittest_pb2.TestAllTypes() 1031 test_util.SetAllFields(message) 1032 self.CompareToGoldenFile( 1033 self.RemoveRedundantZeros(text_format.MessageToString(message)), 1034 'text_format_unittest_data_oneof_implemented.txt') 1035 1036 def testPrintUnknownFields(self): 1037 message = unittest_pb2.TestAllTypes() 1038 message.optional_int32 = 101 1039 message.optional_double = 102.0 1040 message.optional_string = u'hello' 1041 message.optional_bytes = b'103' 1042 message.optionalgroup.a = 104 1043 message.optional_nested_message.bb = 105 1044 all_data = message.SerializeToString() 1045 empty_message = unittest_pb2.TestEmptyMessage() 1046 empty_message.ParseFromString(all_data) 1047 self.assertEqual(' 1: 101\n' 1048 ' 12: 4636878028842991616\n' 1049 ' 14: "hello"\n' 1050 ' 15: "103"\n' 1051 ' 16 {\n' 1052 ' 17: 104\n' 1053 ' }\n' 1054 ' 18 {\n' 1055 ' 1: 105\n' 1056 ' }\n', 1057 text_format.MessageToString(empty_message, 1058 indent=2, 1059 print_unknown_fields=True)) 1060 self.assertEqual('1: 101 ' 1061 '12: 4636878028842991616 ' 1062 '14: "hello" ' 1063 '15: "103" ' 1064 '16 { 17: 104 } ' 1065 '18 { 1: 105 }', 1066 text_format.MessageToString(empty_message, 1067 print_unknown_fields=True, 1068 as_one_line=True)) 1069 1070 def testPrintInIndexOrder(self): 1071 message = unittest_pb2.TestFieldOrderings() 1072 # Fields are listed in index order instead of field number. 1073 message.my_string = 'str' 1074 message.my_int = 101 1075 message.my_float = 111 1076 message.optional_nested_message.oo = 0 1077 message.optional_nested_message.bb = 1 1078 message.Extensions[unittest_pb2.my_extension_string] = 'ext_str0' 1079 # Extensions are listed based on the order of extension number. 1080 # Extension number 12. 1081 message.Extensions[unittest_pb2.TestExtensionOrderings2. 1082 test_ext_orderings2].my_string = 'ext_str2' 1083 # Extension number 13. 1084 message.Extensions[unittest_pb2.TestExtensionOrderings1. 1085 test_ext_orderings1].my_string = 'ext_str1' 1086 # Extension number 14. 1087 message.Extensions[ 1088 unittest_pb2.TestExtensionOrderings2.TestExtensionOrderings3. 1089 test_ext_orderings3].my_string = 'ext_str3' 1090 1091 # Print in index order. 1092 self.CompareToGoldenText( 1093 self.RemoveRedundantZeros( 1094 text_format.MessageToString(message, use_index_order=True)), 1095 'my_string: "str"\n' 1096 'my_int: 101\n' 1097 'my_float: 111\n' 1098 'optional_nested_message {\n' 1099 ' oo: 0\n' 1100 ' bb: 1\n' 1101 '}\n' 1102 '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n' 1103 ' my_string: "ext_str2"\n' 1104 '}\n' 1105 '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n' 1106 ' my_string: "ext_str1"\n' 1107 '}\n' 1108 '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3' 1109 '.test_ext_orderings3] {\n' 1110 ' my_string: "ext_str3"\n' 1111 '}\n' 1112 '[protobuf_unittest.my_extension_string]: "ext_str0"\n') 1113 # By default, print in field number order. 1114 self.CompareToGoldenText( 1115 self.RemoveRedundantZeros(text_format.MessageToString(message)), 1116 'my_int: 101\n' 1117 'my_string: "str"\n' 1118 '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n' 1119 ' my_string: "ext_str2"\n' 1120 '}\n' 1121 '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n' 1122 ' my_string: "ext_str1"\n' 1123 '}\n' 1124 '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3' 1125 '.test_ext_orderings3] {\n' 1126 ' my_string: "ext_str3"\n' 1127 '}\n' 1128 '[protobuf_unittest.my_extension_string]: "ext_str0"\n' 1129 'my_float: 111\n' 1130 'optional_nested_message {\n' 1131 ' bb: 1\n' 1132 ' oo: 0\n' 1133 '}\n') 1134 1135 def testMergeLinesGolden(self): 1136 opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') 1137 parsed_message = unittest_pb2.TestAllTypes() 1138 r = text_format.MergeLines(opened, parsed_message) 1139 self.assertIs(r, parsed_message) 1140 1141 message = unittest_pb2.TestAllTypes() 1142 test_util.SetAllFields(message) 1143 self.assertEqual(message, parsed_message) 1144 1145 def testParseLinesGolden(self): 1146 opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') 1147 parsed_message = unittest_pb2.TestAllTypes() 1148 r = text_format.ParseLines(opened, parsed_message) 1149 self.assertIs(r, parsed_message) 1150 1151 message = unittest_pb2.TestAllTypes() 1152 test_util.SetAllFields(message) 1153 self.assertEqual(message, parsed_message) 1154 1155 def testPrintMap(self): 1156 message = map_unittest_pb2.TestMap() 1157 1158 message.map_int32_int32[-123] = -456 1159 message.map_int64_int64[-2**33] = -2**34 1160 message.map_uint32_uint32[123] = 456 1161 message.map_uint64_uint64[2**33] = 2**34 1162 message.map_string_string['abc'] = '123' 1163 message.map_int32_foreign_message[111].c = 5 1164 1165 # Maps are serialized to text format using their underlying repeated 1166 # representation. 1167 self.CompareToGoldenText( 1168 text_format.MessageToString(message), 'map_int32_int32 {\n' 1169 ' key: -123\n' 1170 ' value: -456\n' 1171 '}\n' 1172 'map_int64_int64 {\n' 1173 ' key: -8589934592\n' 1174 ' value: -17179869184\n' 1175 '}\n' 1176 'map_uint32_uint32 {\n' 1177 ' key: 123\n' 1178 ' value: 456\n' 1179 '}\n' 1180 'map_uint64_uint64 {\n' 1181 ' key: 8589934592\n' 1182 ' value: 17179869184\n' 1183 '}\n' 1184 'map_string_string {\n' 1185 ' key: "abc"\n' 1186 ' value: "123"\n' 1187 '}\n' 1188 'map_int32_foreign_message {\n' 1189 ' key: 111\n' 1190 ' value {\n' 1191 ' c: 5\n' 1192 ' }\n' 1193 '}\n') 1194 1195 def testDuplicateMapKey(self): 1196 message = map_unittest_pb2.TestMap() 1197 text = ( 1198 'map_uint64_uint64 {\n' 1199 ' key: 123\n' 1200 ' value: 17179869184\n' 1201 '}\n' 1202 'map_string_string {\n' 1203 ' key: "abc"\n' 1204 ' value: "first"\n' 1205 '}\n' 1206 'map_int32_foreign_message {\n' 1207 ' key: 111\n' 1208 ' value {\n' 1209 ' c: 5\n' 1210 ' }\n' 1211 '}\n' 1212 'map_uint64_uint64 {\n' 1213 ' key: 123\n' 1214 ' value: 321\n' 1215 '}\n' 1216 'map_string_string {\n' 1217 ' key: "abc"\n' 1218 ' value: "second"\n' 1219 '}\n' 1220 'map_int32_foreign_message {\n' 1221 ' key: 111\n' 1222 ' value {\n' 1223 ' d: 5\n' 1224 ' }\n' 1225 '}\n') 1226 text_format.Parse(text, message) 1227 self.CompareToGoldenText( 1228 text_format.MessageToString(message), 'map_uint64_uint64 {\n' 1229 ' key: 123\n' 1230 ' value: 321\n' 1231 '}\n' 1232 'map_string_string {\n' 1233 ' key: "abc"\n' 1234 ' value: "second"\n' 1235 '}\n' 1236 'map_int32_foreign_message {\n' 1237 ' key: 111\n' 1238 ' value {\n' 1239 ' d: 5\n' 1240 ' }\n' 1241 '}\n') 1242 1243 # In cpp implementation, __str__ calls the cpp implementation of text format. 1244 def testPrintMapUsingCppImplementation(self): 1245 message = map_unittest_pb2.TestMap() 1246 inner_msg = message.map_int32_foreign_message[111] 1247 inner_msg.c = 1 1248 self.assertEqual( 1249 str(message), 1250 'map_int32_foreign_message {\n' 1251 ' key: 111\n' 1252 ' value {\n' 1253 ' c: 1\n' 1254 ' }\n' 1255 '}\n') 1256 inner_msg.c = 2 1257 self.assertEqual( 1258 str(message), 1259 'map_int32_foreign_message {\n' 1260 ' key: 111\n' 1261 ' value {\n' 1262 ' c: 2\n' 1263 ' }\n' 1264 '}\n') 1265 1266 def testMapOrderEnforcement(self): 1267 message = map_unittest_pb2.TestMap() 1268 for letter in string.ascii_uppercase[13:26]: 1269 message.map_string_string[letter] = 'dummy' 1270 for letter in reversed(string.ascii_uppercase[0:13]): 1271 message.map_string_string[letter] = 'dummy' 1272 golden = ''.join(('map_string_string {\n key: "%c"\n value: "dummy"\n}\n' 1273 % (letter,) for letter in string.ascii_uppercase)) 1274 self.CompareToGoldenText(text_format.MessageToString(message), golden) 1275 1276 # TODO(teboring): In c/137553523, not serializing default value for map entry 1277 # message has been fixed. This test needs to be disabled in order to submit 1278 # that cl. Add this back when c/137553523 has been submitted. 1279 # def testMapOrderSemantics(self): 1280 # golden_lines = self.ReadGolden('map_test_data.txt') 1281 1282 # message = map_unittest_pb2.TestMap() 1283 # text_format.ParseLines(golden_lines, message) 1284 # candidate = text_format.MessageToString(message) 1285 # # The Python implementation emits "1.0" for the double value that the C++ 1286 # # implementation emits as "1". 1287 # candidate = candidate.replace('1.0', '1', 2) 1288 # candidate = candidate.replace('0.0', '0', 2) 1289 # self.assertMultiLineEqual(candidate, ''.join(golden_lines)) 1290 1291 1292# Tests of proto2-only features (MessageSet, extensions, etc.). 1293class Proto2Tests(TextFormatBase): 1294 1295 def testPrintMessageSet(self): 1296 message = unittest_mset_pb2.TestMessageSetContainer() 1297 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1298 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1299 message.message_set.Extensions[ext1].i = 23 1300 message.message_set.Extensions[ext2].str = 'foo' 1301 self.CompareToGoldenText( 1302 text_format.MessageToString(message), 'message_set {\n' 1303 ' [protobuf_unittest.TestMessageSetExtension1] {\n' 1304 ' i: 23\n' 1305 ' }\n' 1306 ' [protobuf_unittest.TestMessageSetExtension2] {\n' 1307 ' str: \"foo\"\n' 1308 ' }\n' 1309 '}\n') 1310 1311 message = message_set_extensions_pb2.TestMessageSet() 1312 ext = message_set_extensions_pb2.message_set_extension3 1313 message.Extensions[ext].text = 'bar' 1314 self.CompareToGoldenText( 1315 text_format.MessageToString(message), 1316 '[google.protobuf.internal.TestMessageSetExtension3] {\n' 1317 ' text: \"bar\"\n' 1318 '}\n') 1319 1320 def testPrintMessageSetByFieldNumber(self): 1321 out = text_format.TextWriter(False) 1322 message = unittest_mset_pb2.TestMessageSetContainer() 1323 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1324 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1325 message.message_set.Extensions[ext1].i = 23 1326 message.message_set.Extensions[ext2].str = 'foo' 1327 text_format.PrintMessage(message, out, use_field_number=True) 1328 self.CompareToGoldenText(out.getvalue(), '1 {\n' 1329 ' 1545008 {\n' 1330 ' 15: 23\n' 1331 ' }\n' 1332 ' 1547769 {\n' 1333 ' 25: \"foo\"\n' 1334 ' }\n' 1335 '}\n') 1336 out.close() 1337 1338 def testPrintMessageSetAsOneLine(self): 1339 message = unittest_mset_pb2.TestMessageSetContainer() 1340 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1341 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1342 message.message_set.Extensions[ext1].i = 23 1343 message.message_set.Extensions[ext2].str = 'foo' 1344 self.CompareToGoldenText( 1345 text_format.MessageToString(message, as_one_line=True), 1346 'message_set {' 1347 ' [protobuf_unittest.TestMessageSetExtension1] {' 1348 ' i: 23' 1349 ' }' 1350 ' [protobuf_unittest.TestMessageSetExtension2] {' 1351 ' str: \"foo\"' 1352 ' }' 1353 ' }') 1354 1355 def testParseMessageSet(self): 1356 message = unittest_pb2.TestAllTypes() 1357 text = ('repeated_uint64: 1\n' 'repeated_uint64: 2\n') 1358 text_format.Parse(text, message) 1359 self.assertEqual(1, message.repeated_uint64[0]) 1360 self.assertEqual(2, message.repeated_uint64[1]) 1361 1362 message = unittest_mset_pb2.TestMessageSetContainer() 1363 text = ('message_set {\n' 1364 ' [protobuf_unittest.TestMessageSetExtension1] {\n' 1365 ' i: 23\n' 1366 ' }\n' 1367 ' [protobuf_unittest.TestMessageSetExtension2] {\n' 1368 ' str: \"foo\"\n' 1369 ' }\n' 1370 '}\n') 1371 text_format.Parse(text, message) 1372 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1373 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1374 self.assertEqual(23, message.message_set.Extensions[ext1].i) 1375 self.assertEqual('foo', message.message_set.Extensions[ext2].str) 1376 1377 def testExtensionInsideAnyMessage(self): 1378 message = test_extend_any.TestAny() 1379 text = ('value {\n' 1380 ' [type.googleapis.com/google.protobuf.internal.TestAny] {\n' 1381 ' [google.protobuf.internal.TestAnyExtension1.extension1] {\n' 1382 ' i: 10\n' 1383 ' }\n' 1384 ' }\n' 1385 '}\n') 1386 text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default()) 1387 self.CompareToGoldenText( 1388 text_format.MessageToString( 1389 message, descriptor_pool=descriptor_pool.Default()), 1390 text) 1391 1392 def testParseMessageByFieldNumber(self): 1393 message = unittest_pb2.TestAllTypes() 1394 text = ('34: 1\n' 'repeated_uint64: 2\n') 1395 text_format.Parse(text, message, allow_field_number=True) 1396 self.assertEqual(1, message.repeated_uint64[0]) 1397 self.assertEqual(2, message.repeated_uint64[1]) 1398 1399 message = unittest_mset_pb2.TestMessageSetContainer() 1400 text = ('1 {\n' 1401 ' 1545008 {\n' 1402 ' 15: 23\n' 1403 ' }\n' 1404 ' 1547769 {\n' 1405 ' 25: \"foo\"\n' 1406 ' }\n' 1407 '}\n') 1408 text_format.Parse(text, message, allow_field_number=True) 1409 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1410 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1411 self.assertEqual(23, message.message_set.Extensions[ext1].i) 1412 self.assertEqual('foo', message.message_set.Extensions[ext2].str) 1413 1414 # Can't parse field number without set allow_field_number=True. 1415 message = unittest_pb2.TestAllTypes() 1416 text = '34:1\n' 1417 self.assertRaisesRegex( 1418 text_format.ParseError, 1419 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' 1420 r'"34".'), text_format.Parse, text, message) 1421 1422 # Can't parse if field number is not found. 1423 text = '1234:1\n' 1424 self.assertRaisesRegex( 1425 text_format.ParseError, 1426 (r'1:1 : Message type "\w+.TestAllTypes" has no field named ' 1427 r'"1234".'), 1428 text_format.Parse, 1429 text, 1430 message, 1431 allow_field_number=True) 1432 1433 def testPrintAllExtensions(self): 1434 message = unittest_pb2.TestAllExtensions() 1435 test_util.SetAllExtensions(message) 1436 self.CompareToGoldenFile( 1437 self.RemoveRedundantZeros(text_format.MessageToString(message)), 1438 'text_format_unittest_extensions_data.txt') 1439 1440 def testPrintAllExtensionsPointy(self): 1441 message = unittest_pb2.TestAllExtensions() 1442 test_util.SetAllExtensions(message) 1443 self.CompareToGoldenFile( 1444 self.RemoveRedundantZeros(text_format.MessageToString( 1445 message, pointy_brackets=True)), 1446 'text_format_unittest_extensions_data_pointy.txt') 1447 1448 def testParseGoldenExtensions(self): 1449 golden_text = '\n'.join(self.ReadGolden( 1450 'text_format_unittest_extensions_data.txt')) 1451 parsed_message = unittest_pb2.TestAllExtensions() 1452 text_format.Parse(golden_text, parsed_message) 1453 1454 message = unittest_pb2.TestAllExtensions() 1455 test_util.SetAllExtensions(message) 1456 self.assertEqual(message, parsed_message) 1457 1458 def testParseAllExtensions(self): 1459 message = unittest_pb2.TestAllExtensions() 1460 test_util.SetAllExtensions(message) 1461 ascii_text = text_format.MessageToString(message) 1462 1463 parsed_message = unittest_pb2.TestAllExtensions() 1464 text_format.Parse(ascii_text, parsed_message) 1465 self.assertEqual(message, parsed_message) 1466 1467 def testParseAllowedUnknownExtension(self): 1468 # Skip over unknown extension correctly. 1469 message = unittest_mset_pb2.TestMessageSetContainer() 1470 text = ('message_set {\n' 1471 ' [unknown_extension] {\n' 1472 ' i: 23\n' 1473 ' bin: "\xe0"' 1474 ' [nested_unknown_ext]: {\n' 1475 ' i: 23\n' 1476 ' x: x\n' 1477 ' test: "test_string"\n' 1478 ' floaty_float: -0.315\n' 1479 ' num: -inf\n' 1480 ' multiline_str: "abc"\n' 1481 ' "def"\n' 1482 ' "xyz."\n' 1483 ' [nested_unknown_ext.ext]: <\n' 1484 ' i: 23\n' 1485 ' i: 24\n' 1486 ' pointfloat: .3\n' 1487 ' test: "test_string"\n' 1488 ' floaty_float: -0.315\n' 1489 ' num: -inf\n' 1490 ' long_string: "test" "test2" \n' 1491 ' >\n' 1492 ' }\n' 1493 ' }\n' 1494 ' [unknown_extension]: 5\n' 1495 ' [unknown_extension_with_number_field] {\n' 1496 ' 1: "some_field"\n' 1497 ' 2: -0.451\n' 1498 ' }\n' 1499 '}\n') 1500 text_format.Parse(text, message, allow_unknown_extension=True) 1501 golden = 'message_set {\n}\n' 1502 self.CompareToGoldenText(text_format.MessageToString(message), golden) 1503 1504 # Catch parse errors in unknown extension. 1505 message = unittest_mset_pb2.TestMessageSetContainer() 1506 malformed = ('message_set {\n' 1507 ' [unknown_extension] {\n' 1508 ' i:\n' # Missing value. 1509 ' }\n' 1510 '}\n') 1511 self.assertRaisesRegex( 1512 text_format.ParseError, 1513 'Invalid field value: }', 1514 text_format.Parse, 1515 malformed, 1516 message, 1517 allow_unknown_extension=True) 1518 1519 message = unittest_mset_pb2.TestMessageSetContainer() 1520 malformed = ('message_set {\n' 1521 ' [unknown_extension] {\n' 1522 ' str: "malformed string\n' # Missing closing quote. 1523 ' }\n' 1524 '}\n') 1525 self.assertRaisesRegex( 1526 text_format.ParseError, 1527 'Invalid field value: "', 1528 text_format.Parse, 1529 malformed, 1530 message, 1531 allow_unknown_extension=True) 1532 1533 message = unittest_mset_pb2.TestMessageSetContainer() 1534 malformed = ('message_set {\n' 1535 ' [unknown_extension] {\n' 1536 ' str: "malformed\n multiline\n string\n' 1537 ' }\n' 1538 '}\n') 1539 self.assertRaisesRegex( 1540 text_format.ParseError, 1541 'Invalid field value: "', 1542 text_format.Parse, 1543 malformed, 1544 message, 1545 allow_unknown_extension=True) 1546 1547 message = unittest_mset_pb2.TestMessageSetContainer() 1548 malformed = ('message_set {\n' 1549 ' [malformed_extension] <\n' 1550 ' i: -5\n' 1551 ' \n' # Missing '>' here. 1552 '}\n') 1553 self.assertRaisesRegex( 1554 text_format.ParseError, 1555 '5:1 : \'}\': Expected ">".', 1556 text_format.Parse, 1557 malformed, 1558 message, 1559 allow_unknown_extension=True) 1560 1561 # Don't allow unknown fields with allow_unknown_extension=True. 1562 message = unittest_mset_pb2.TestMessageSetContainer() 1563 malformed = ('message_set {\n' 1564 ' unknown_field: true\n' 1565 '}\n') 1566 self.assertRaisesRegex( 1567 text_format.ParseError, 1568 ('2:3 : Message type ' 1569 '"proto2_wireformat_unittest.TestMessageSet" has no' 1570 ' field named "unknown_field".'), 1571 text_format.Parse, 1572 malformed, 1573 message, 1574 allow_unknown_extension=True) 1575 1576 # Parse known extension correctly. 1577 message = unittest_mset_pb2.TestMessageSetContainer() 1578 text = ('message_set {\n' 1579 ' [protobuf_unittest.TestMessageSetExtension1] {\n' 1580 ' i: 23\n' 1581 ' }\n' 1582 ' [protobuf_unittest.TestMessageSetExtension2] {\n' 1583 ' str: \"foo\"\n' 1584 ' }\n' 1585 '}\n') 1586 text_format.Parse(text, message, allow_unknown_extension=True) 1587 ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension 1588 ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension 1589 self.assertEqual(23, message.message_set.Extensions[ext1].i) 1590 self.assertEqual('foo', message.message_set.Extensions[ext2].str) 1591 1592 def testParseBadIdentifier(self): 1593 message = unittest_pb2.TestAllTypes() 1594 text = ('optional_nested_message { "bb": 1 }') 1595 with self.assertRaises(text_format.ParseError) as e: 1596 text_format.Parse(text, message) 1597 self.assertEqual(str(e.exception), 1598 '1:27 : \'optional_nested_message { "bb": 1 }\': ' 1599 'Expected identifier or number, got "bb".') 1600 1601 def testParseBadExtension(self): 1602 message = unittest_pb2.TestAllExtensions() 1603 text = '[unknown_extension]: 8\n' 1604 self.assertRaisesRegex( 1605 text_format.ParseError, 1606 '1:2 : Extension "unknown_extension" not registered.', 1607 text_format.Parse, text, message) 1608 message = unittest_pb2.TestAllTypes() 1609 self.assertRaisesRegex( 1610 text_format.ParseError, 1611 ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have ' 1612 'extensions.'), text_format.Parse, text, message) 1613 1614 def testParseNumericUnknownEnum(self): 1615 message = unittest_pb2.TestAllTypes() 1616 text = 'optional_nested_enum: 100' 1617 self.assertRaisesRegex(text_format.ParseError, 1618 (r'1:23 : \'optional_nested_enum: 100\': ' 1619 r'Enum type "\w+.TestAllTypes.NestedEnum" ' 1620 r'has no value with number 100.'), 1621 text_format.Parse, text, message) 1622 1623 def testMergeDuplicateExtensionScalars(self): 1624 message = unittest_pb2.TestAllExtensions() 1625 text = ('[protobuf_unittest.optional_int32_extension]: 42 ' 1626 '[protobuf_unittest.optional_int32_extension]: 67') 1627 text_format.Merge(text, message) 1628 self.assertEqual(67, 1629 message.Extensions[unittest_pb2.optional_int32_extension]) 1630 1631 def testParseDuplicateExtensionScalars(self): 1632 message = unittest_pb2.TestAllExtensions() 1633 text = ('[protobuf_unittest.optional_int32_extension]: 42 ' 1634 '[protobuf_unittest.optional_int32_extension]: 67') 1635 self.assertRaisesRegex( 1636 text_format.ParseError, 1637 ('1:96 : Message type "protobuf_unittest.TestAllExtensions" ' 1638 'should not have multiple ' 1639 '"protobuf_unittest.optional_int32_extension" extensions.'), 1640 text_format.Parse, text, message) 1641 1642 def testParseDuplicateExtensionMessages(self): 1643 message = unittest_pb2.TestAllExtensions() 1644 text = ('[protobuf_unittest.optional_nested_message_extension]: {} ' 1645 '[protobuf_unittest.optional_nested_message_extension]: {}') 1646 self.assertRaisesRegex( 1647 text_format.ParseError, 1648 ('1:114 : Message type "protobuf_unittest.TestAllExtensions" ' 1649 'should not have multiple ' 1650 '"protobuf_unittest.optional_nested_message_extension" extensions.'), 1651 text_format.Parse, text, message) 1652 1653 def testParseGroupNotClosed(self): 1654 message = unittest_pb2.TestAllTypes() 1655 text = 'RepeatedGroup: <' 1656 self.assertRaisesRegex(text_format.ParseError, '1:16 : Expected ">".', 1657 text_format.Parse, text, message) 1658 text = 'RepeatedGroup: {' 1659 self.assertRaisesRegex(text_format.ParseError, '1:16 : Expected "}".', 1660 text_format.Parse, text, message) 1661 1662 def testParseEmptyGroup(self): 1663 message = unittest_pb2.TestAllTypes() 1664 text = 'OptionalGroup: {}' 1665 text_format.Parse(text, message) 1666 self.assertTrue(message.HasField('optionalgroup')) 1667 1668 message.Clear() 1669 1670 message = unittest_pb2.TestAllTypes() 1671 text = 'OptionalGroup: <>' 1672 text_format.Parse(text, message) 1673 self.assertTrue(message.HasField('optionalgroup')) 1674 1675 # Maps aren't really proto2-only, but our test schema only has maps for 1676 # proto2. 1677 def testParseMap(self): 1678 text = ('map_int32_int32 {\n' 1679 ' key: -123\n' 1680 ' value: -456\n' 1681 '}\n' 1682 'map_int64_int64 {\n' 1683 ' key: -8589934592\n' 1684 ' value: -17179869184\n' 1685 '}\n' 1686 'map_uint32_uint32 {\n' 1687 ' key: 123\n' 1688 ' value: 456\n' 1689 '}\n' 1690 'map_uint64_uint64 {\n' 1691 ' key: 8589934592\n' 1692 ' value: 17179869184\n' 1693 '}\n' 1694 'map_string_string {\n' 1695 ' key: "abc"\n' 1696 ' value: "123"\n' 1697 '}\n' 1698 'map_int32_foreign_message {\n' 1699 ' key: 111\n' 1700 ' value {\n' 1701 ' c: 5\n' 1702 ' }\n' 1703 '}\n') 1704 message = map_unittest_pb2.TestMap() 1705 text_format.Parse(text, message) 1706 1707 self.assertEqual(-456, message.map_int32_int32[-123]) 1708 self.assertEqual(-2**34, message.map_int64_int64[-2**33]) 1709 self.assertEqual(456, message.map_uint32_uint32[123]) 1710 self.assertEqual(2**34, message.map_uint64_uint64[2**33]) 1711 self.assertEqual('123', message.map_string_string['abc']) 1712 self.assertEqual(5, message.map_int32_foreign_message[111].c) 1713 1714 1715class Proto3Tests(unittest.TestCase): 1716 1717 def testPrintMessageExpandAny(self): 1718 packed_message = unittest_pb2.OneString() 1719 packed_message.data = 'string' 1720 message = any_test_pb2.TestAny() 1721 message.any_value.Pack(packed_message) 1722 self.assertEqual( 1723 text_format.MessageToString(message, 1724 descriptor_pool=descriptor_pool.Default()), 1725 'any_value {\n' 1726 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1727 ' data: "string"\n' 1728 ' }\n' 1729 '}\n') 1730 1731 def testTopAnyMessage(self): 1732 packed_msg = unittest_pb2.OneString() 1733 msg = any_pb2.Any() 1734 msg.Pack(packed_msg) 1735 text = text_format.MessageToString(msg) 1736 other_msg = text_format.Parse(text, any_pb2.Any()) 1737 self.assertEqual(msg, other_msg) 1738 1739 def testPrintMessageExpandAnyRepeated(self): 1740 packed_message = unittest_pb2.OneString() 1741 message = any_test_pb2.TestAny() 1742 packed_message.data = 'string0' 1743 message.repeated_any_value.add().Pack(packed_message) 1744 packed_message.data = 'string1' 1745 message.repeated_any_value.add().Pack(packed_message) 1746 self.assertEqual( 1747 text_format.MessageToString(message), 1748 'repeated_any_value {\n' 1749 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1750 ' data: "string0"\n' 1751 ' }\n' 1752 '}\n' 1753 'repeated_any_value {\n' 1754 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1755 ' data: "string1"\n' 1756 ' }\n' 1757 '}\n') 1758 1759 def testPrintMessageExpandAnyDescriptorPoolMissingType(self): 1760 packed_message = unittest_pb2.OneString() 1761 packed_message.data = 'string' 1762 message = any_test_pb2.TestAny() 1763 message.any_value.Pack(packed_message) 1764 empty_pool = descriptor_pool.DescriptorPool() 1765 self.assertEqual( 1766 text_format.MessageToString(message, descriptor_pool=empty_pool), 1767 'any_value {\n' 1768 ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n' 1769 ' value: "\\n\\006string"\n' 1770 '}\n') 1771 1772 def testPrintMessageExpandAnyPointyBrackets(self): 1773 packed_message = unittest_pb2.OneString() 1774 packed_message.data = 'string' 1775 message = any_test_pb2.TestAny() 1776 message.any_value.Pack(packed_message) 1777 self.assertEqual( 1778 text_format.MessageToString(message, 1779 pointy_brackets=True), 1780 'any_value <\n' 1781 ' [type.googleapis.com/protobuf_unittest.OneString] <\n' 1782 ' data: "string"\n' 1783 ' >\n' 1784 '>\n') 1785 1786 def testPrintMessageExpandAnyAsOneLine(self): 1787 packed_message = unittest_pb2.OneString() 1788 packed_message.data = 'string' 1789 message = any_test_pb2.TestAny() 1790 message.any_value.Pack(packed_message) 1791 self.assertEqual( 1792 text_format.MessageToString(message, 1793 as_one_line=True), 1794 'any_value {' 1795 ' [type.googleapis.com/protobuf_unittest.OneString]' 1796 ' { data: "string" } ' 1797 '}') 1798 1799 def testPrintMessageExpandAnyAsOneLinePointyBrackets(self): 1800 packed_message = unittest_pb2.OneString() 1801 packed_message.data = 'string' 1802 message = any_test_pb2.TestAny() 1803 message.any_value.Pack(packed_message) 1804 self.assertEqual( 1805 text_format.MessageToString(message, 1806 as_one_line=True, 1807 pointy_brackets=True, 1808 descriptor_pool=descriptor_pool.Default()), 1809 'any_value <' 1810 ' [type.googleapis.com/protobuf_unittest.OneString]' 1811 ' < data: "string" > ' 1812 '>') 1813 1814 def testPrintAndParseMessageInvalidAny(self): 1815 packed_message = unittest_pb2.OneString() 1816 packed_message.data = 'string' 1817 message = any_test_pb2.TestAny() 1818 message.any_value.Pack(packed_message) 1819 # Only include string after last '/' in type_url. 1820 message.any_value.type_url = message.any_value.TypeName() 1821 text = text_format.MessageToString(message) 1822 self.assertEqual( 1823 text, 'any_value {\n' 1824 ' type_url: "protobuf_unittest.OneString"\n' 1825 ' value: "\\n\\006string"\n' 1826 '}\n') 1827 1828 parsed_message = any_test_pb2.TestAny() 1829 text_format.Parse(text, parsed_message) 1830 self.assertEqual(message, parsed_message) 1831 1832 def testUnknownEnums(self): 1833 message = unittest_proto3_arena_pb2.TestAllTypes() 1834 message2 = unittest_proto3_arena_pb2.TestAllTypes() 1835 message.optional_nested_enum = 999 1836 text_string = text_format.MessageToString(message) 1837 text_format.Parse(text_string, message2) 1838 self.assertEqual(999, message2.optional_nested_enum) 1839 1840 def testMergeExpandedAny(self): 1841 message = any_test_pb2.TestAny() 1842 text = ('any_value {\n' 1843 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1844 ' data: "string"\n' 1845 ' }\n' 1846 '}\n') 1847 text_format.Merge(text, message) 1848 packed_message = unittest_pb2.OneString() 1849 message.any_value.Unpack(packed_message) 1850 self.assertEqual('string', packed_message.data) 1851 message.Clear() 1852 text_format.Parse(text, message) 1853 packed_message = unittest_pb2.OneString() 1854 message.any_value.Unpack(packed_message) 1855 self.assertEqual('string', packed_message.data) 1856 1857 def testMergeExpandedAnyRepeated(self): 1858 message = any_test_pb2.TestAny() 1859 text = ('repeated_any_value {\n' 1860 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1861 ' data: "string0"\n' 1862 ' }\n' 1863 '}\n' 1864 'repeated_any_value {\n' 1865 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1866 ' data: "string1"\n' 1867 ' }\n' 1868 '}\n') 1869 text_format.Merge(text, message) 1870 packed_message = unittest_pb2.OneString() 1871 message.repeated_any_value[0].Unpack(packed_message) 1872 self.assertEqual('string0', packed_message.data) 1873 message.repeated_any_value[1].Unpack(packed_message) 1874 self.assertEqual('string1', packed_message.data) 1875 1876 def testMergeExpandedAnyPointyBrackets(self): 1877 message = any_test_pb2.TestAny() 1878 text = ('any_value {\n' 1879 ' [type.googleapis.com/protobuf_unittest.OneString] <\n' 1880 ' data: "string"\n' 1881 ' >\n' 1882 '}\n') 1883 text_format.Merge(text, message) 1884 packed_message = unittest_pb2.OneString() 1885 message.any_value.Unpack(packed_message) 1886 self.assertEqual('string', packed_message.data) 1887 1888 def testMergeAlternativeUrl(self): 1889 message = any_test_pb2.TestAny() 1890 text = ('any_value {\n' 1891 ' [type.otherapi.com/protobuf_unittest.OneString] {\n' 1892 ' data: "string"\n' 1893 ' }\n' 1894 '}\n') 1895 text_format.Merge(text, message) 1896 packed_message = unittest_pb2.OneString() 1897 self.assertEqual('type.otherapi.com/protobuf_unittest.OneString', 1898 message.any_value.type_url) 1899 1900 def testMergeExpandedAnyDescriptorPoolMissingType(self): 1901 message = any_test_pb2.TestAny() 1902 text = ('any_value {\n' 1903 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1904 ' data: "string"\n' 1905 ' }\n' 1906 '}\n') 1907 with self.assertRaises(text_format.ParseError) as e: 1908 empty_pool = descriptor_pool.DescriptorPool() 1909 text_format.Merge(text, message, descriptor_pool=empty_pool) 1910 self.assertEqual( 1911 str(e.exception), 1912 'Type protobuf_unittest.OneString not found in descriptor pool') 1913 1914 def testMergeUnexpandedAny(self): 1915 text = ('any_value {\n' 1916 ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n' 1917 ' value: "\\n\\006string"\n' 1918 '}\n') 1919 message = any_test_pb2.TestAny() 1920 text_format.Merge(text, message) 1921 packed_message = unittest_pb2.OneString() 1922 message.any_value.Unpack(packed_message) 1923 self.assertEqual('string', packed_message.data) 1924 1925 def testMergeMissingAnyEndToken(self): 1926 message = any_test_pb2.TestAny() 1927 text = ('any_value {\n' 1928 ' [type.googleapis.com/protobuf_unittest.OneString] {\n' 1929 ' data: "string"\n') 1930 with self.assertRaises(text_format.ParseError) as e: 1931 text_format.Merge(text, message) 1932 self.assertEqual(str(e.exception), '3:11 : Expected "}".') 1933 1934 def testProto3Optional(self): 1935 msg = test_proto3_optional_pb2.TestProto3Optional() 1936 self.assertEqual(text_format.MessageToString(msg), '') 1937 msg.optional_int32 = 0 1938 msg.optional_float = 0.0 1939 msg.optional_string = '' 1940 msg.optional_nested_message.bb = 0 1941 text = ('optional_int32: 0\n' 1942 'optional_float: 0.0\n' 1943 'optional_string: ""\n' 1944 'optional_nested_message {\n' 1945 ' bb: 0\n' 1946 '}\n') 1947 self.assertEqual(text_format.MessageToString(msg), text) 1948 msg2 = test_proto3_optional_pb2.TestProto3Optional() 1949 text_format.Parse(text, msg2) 1950 self.assertEqual(text_format.MessageToString(msg2), text) 1951 1952 1953class TokenizerTest(unittest.TestCase): 1954 1955 def testSimpleTokenCases(self): 1956 text = ('identifier1:"string1"\n \n\n' 1957 'identifier2 : \n \n123 \n identifier3 :\'string\'\n' 1958 'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n' 1959 'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n' 1960 'ID9: 22 ID10: -111111111111111111 ID11: -22\n' 1961 'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f ' 1962 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ' 1963 'False_bool: False True_bool: True X:iNf Y:-inF Z:nAN') 1964 tokenizer = text_format.Tokenizer(text.splitlines()) 1965 methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), ':', 1966 (tokenizer.ConsumeString, 'string1'), 1967 (tokenizer.ConsumeIdentifier, 'identifier2'), ':', 1968 (tokenizer.ConsumeInteger, 123), 1969 (tokenizer.ConsumeIdentifier, 'identifier3'), ':', 1970 (tokenizer.ConsumeString, 'string'), 1971 (tokenizer.ConsumeIdentifier, 'identifiER_4'), ':', 1972 (tokenizer.ConsumeFloat, 1.1e+2), 1973 (tokenizer.ConsumeIdentifier, 'ID5'), ':', 1974 (tokenizer.ConsumeFloat, -0.23), 1975 (tokenizer.ConsumeIdentifier, 'ID6'), ':', 1976 (tokenizer.ConsumeString, 'aaaa\'bbbb'), 1977 (tokenizer.ConsumeIdentifier, 'ID7'), ':', 1978 (tokenizer.ConsumeString, 'aa\"bb'), 1979 (tokenizer.ConsumeIdentifier, 'ID8'), ':', '{', 1980 (tokenizer.ConsumeIdentifier, 'A'), ':', 1981 (tokenizer.ConsumeFloat, float('inf')), 1982 (tokenizer.ConsumeIdentifier, 'B'), ':', 1983 (tokenizer.ConsumeFloat, -float('inf')), 1984 (tokenizer.ConsumeIdentifier, 'C'), ':', 1985 (tokenizer.ConsumeBool, True), 1986 (tokenizer.ConsumeIdentifier, 'D'), ':', 1987 (tokenizer.ConsumeBool, False), '}', 1988 (tokenizer.ConsumeIdentifier, 'ID9'), ':', 1989 (tokenizer.ConsumeInteger, 22), 1990 (tokenizer.ConsumeIdentifier, 'ID10'), ':', 1991 (tokenizer.ConsumeInteger, -111111111111111111), 1992 (tokenizer.ConsumeIdentifier, 'ID11'), ':', 1993 (tokenizer.ConsumeInteger, -22), 1994 (tokenizer.ConsumeIdentifier, 'ID12'), ':', 1995 (tokenizer.ConsumeInteger, 2222222222222222222), 1996 (tokenizer.ConsumeIdentifier, 'ID13'), ':', 1997 (tokenizer.ConsumeFloat, 1.23456), 1998 (tokenizer.ConsumeIdentifier, 'ID14'), ':', 1999 (tokenizer.ConsumeFloat, 1.2e+2), 2000 (tokenizer.ConsumeIdentifier, 'false_bool'), ':', 2001 (tokenizer.ConsumeBool, False), 2002 (tokenizer.ConsumeIdentifier, 'true_BOOL'), ':', 2003 (tokenizer.ConsumeBool, True), 2004 (tokenizer.ConsumeIdentifier, 'true_bool1'), ':', 2005 (tokenizer.ConsumeBool, True), 2006 (tokenizer.ConsumeIdentifier, 'false_BOOL1'), ':', 2007 (tokenizer.ConsumeBool, False), 2008 (tokenizer.ConsumeIdentifier, 'False_bool'), ':', 2009 (tokenizer.ConsumeBool, False), 2010 (tokenizer.ConsumeIdentifier, 'True_bool'), ':', 2011 (tokenizer.ConsumeBool, True), 2012 (tokenizer.ConsumeIdentifier, 'X'), ':', 2013 (tokenizer.ConsumeFloat, float('inf')), 2014 (tokenizer.ConsumeIdentifier, 'Y'), ':', 2015 (tokenizer.ConsumeFloat, float('-inf')), 2016 (tokenizer.ConsumeIdentifier, 'Z'), ':', 2017 (tokenizer.ConsumeFloat, float('nan'))] 2018 2019 i = 0 2020 while not tokenizer.AtEnd(): 2021 m = methods[i] 2022 if isinstance(m, str): 2023 token = tokenizer.token 2024 self.assertEqual(token, m) 2025 tokenizer.NextToken() 2026 elif isinstance(m[1], float) and math.isnan(m[1]): 2027 self.assertTrue(math.isnan(m[0]())) 2028 else: 2029 self.assertEqual(m[1], m[0]()) 2030 i += 1 2031 2032 def testConsumeAbstractIntegers(self): 2033 # This test only tests the failures in the integer parsing methods as well 2034 # as the '0' special cases. 2035 int64_max = (1 << 63) - 1 2036 uint32_max = (1 << 32) - 1 2037 text = '-1 %d %d' % (uint32_max + 1, int64_max + 1) 2038 tokenizer = text_format.Tokenizer(text.splitlines()) 2039 self.assertEqual(-1, tokenizer.ConsumeInteger()) 2040 2041 self.assertEqual(uint32_max + 1, tokenizer.ConsumeInteger()) 2042 2043 self.assertEqual(int64_max + 1, tokenizer.ConsumeInteger()) 2044 self.assertTrue(tokenizer.AtEnd()) 2045 2046 text = '-0 0 0 1.2' 2047 tokenizer = text_format.Tokenizer(text.splitlines()) 2048 self.assertEqual(0, tokenizer.ConsumeInteger()) 2049 self.assertEqual(0, tokenizer.ConsumeInteger()) 2050 self.assertEqual(True, tokenizer.TryConsumeInteger()) 2051 self.assertEqual(False, tokenizer.TryConsumeInteger()) 2052 with self.assertRaises(text_format.ParseError): 2053 tokenizer.ConsumeInteger() 2054 self.assertEqual(1.2, tokenizer.ConsumeFloat()) 2055 self.assertTrue(tokenizer.AtEnd()) 2056 2057 def testConsumeIntegers(self): 2058 # This test only tests the failures in the integer parsing methods as well 2059 # as the '0' special cases. 2060 int64_max = (1 << 63) - 1 2061 uint32_max = (1 << 32) - 1 2062 text = '-1 %d %d' % (uint32_max + 1, int64_max + 1) 2063 tokenizer = text_format.Tokenizer(text.splitlines()) 2064 self.assertRaises(text_format.ParseError, 2065 text_format._ConsumeUint32, tokenizer) 2066 self.assertRaises(text_format.ParseError, 2067 text_format._ConsumeUint64, tokenizer) 2068 self.assertEqual(-1, text_format._ConsumeInt32(tokenizer)) 2069 2070 self.assertRaises(text_format.ParseError, 2071 text_format._ConsumeUint32, tokenizer) 2072 self.assertRaises(text_format.ParseError, 2073 text_format._ConsumeInt32, tokenizer) 2074 self.assertEqual(uint32_max + 1, text_format._ConsumeInt64(tokenizer)) 2075 2076 self.assertRaises(text_format.ParseError, 2077 text_format._ConsumeInt64, tokenizer) 2078 self.assertEqual(int64_max + 1, text_format._ConsumeUint64(tokenizer)) 2079 self.assertTrue(tokenizer.AtEnd()) 2080 2081 text = '-0 -0 0 0' 2082 tokenizer = text_format.Tokenizer(text.splitlines()) 2083 self.assertEqual(0, text_format._ConsumeUint32(tokenizer)) 2084 self.assertEqual(0, text_format._ConsumeUint64(tokenizer)) 2085 self.assertEqual(0, text_format._ConsumeUint32(tokenizer)) 2086 self.assertEqual(0, text_format._ConsumeUint64(tokenizer)) 2087 self.assertTrue(tokenizer.AtEnd()) 2088 2089 def testConsumeOctalIntegers(self): 2090 """Test support for C style octal integers.""" 2091 text = '00 -00 04 0755 -010 007 -0033 08 -09 01' 2092 tokenizer = text_format.Tokenizer(text.splitlines()) 2093 self.assertEqual(0, tokenizer.ConsumeInteger()) 2094 self.assertEqual(0, tokenizer.ConsumeInteger()) 2095 self.assertEqual(4, tokenizer.ConsumeInteger()) 2096 self.assertEqual(0o755, tokenizer.ConsumeInteger()) 2097 self.assertEqual(-0o10, tokenizer.ConsumeInteger()) 2098 self.assertEqual(7, tokenizer.ConsumeInteger()) 2099 self.assertEqual(-0o033, tokenizer.ConsumeInteger()) 2100 with self.assertRaises(text_format.ParseError): 2101 tokenizer.ConsumeInteger() # 08 2102 tokenizer.NextToken() 2103 with self.assertRaises(text_format.ParseError): 2104 tokenizer.ConsumeInteger() # -09 2105 tokenizer.NextToken() 2106 self.assertEqual(1, tokenizer.ConsumeInteger()) 2107 self.assertTrue(tokenizer.AtEnd()) 2108 2109 def testConsumeByteString(self): 2110 text = '"string1\'' 2111 tokenizer = text_format.Tokenizer(text.splitlines()) 2112 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) 2113 2114 text = 'string1"' 2115 tokenizer = text_format.Tokenizer(text.splitlines()) 2116 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) 2117 2118 text = '\n"\\xt"' 2119 tokenizer = text_format.Tokenizer(text.splitlines()) 2120 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) 2121 2122 text = '\n"\\"' 2123 tokenizer = text_format.Tokenizer(text.splitlines()) 2124 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) 2125 2126 text = '\n"\\x"' 2127 tokenizer = text_format.Tokenizer(text.splitlines()) 2128 self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString) 2129 2130 def testConsumeBool(self): 2131 text = 'not-a-bool' 2132 tokenizer = text_format.Tokenizer(text.splitlines()) 2133 self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool) 2134 2135 def testSkipComment(self): 2136 tokenizer = text_format.Tokenizer('# some comment'.splitlines()) 2137 self.assertTrue(tokenizer.AtEnd()) 2138 self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment) 2139 2140 def testConsumeComment(self): 2141 tokenizer = text_format.Tokenizer('# some comment'.splitlines(), 2142 skip_comments=False) 2143 self.assertFalse(tokenizer.AtEnd()) 2144 self.assertEqual('# some comment', tokenizer.ConsumeComment()) 2145 self.assertTrue(tokenizer.AtEnd()) 2146 2147 def testConsumeTwoComments(self): 2148 text = '# some comment\n# another comment' 2149 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2150 self.assertEqual('# some comment', tokenizer.ConsumeComment()) 2151 self.assertFalse(tokenizer.AtEnd()) 2152 self.assertEqual('# another comment', tokenizer.ConsumeComment()) 2153 self.assertTrue(tokenizer.AtEnd()) 2154 2155 def testConsumeTrailingComment(self): 2156 text = 'some_number: 4\n# some comment' 2157 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2158 self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment) 2159 2160 self.assertEqual('some_number', tokenizer.ConsumeIdentifier()) 2161 self.assertEqual(tokenizer.token, ':') 2162 tokenizer.NextToken() 2163 self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment) 2164 self.assertEqual(4, tokenizer.ConsumeInteger()) 2165 self.assertFalse(tokenizer.AtEnd()) 2166 2167 self.assertEqual('# some comment', tokenizer.ConsumeComment()) 2168 self.assertTrue(tokenizer.AtEnd()) 2169 2170 def testConsumeLineComment(self): 2171 tokenizer = text_format.Tokenizer('# some comment'.splitlines(), 2172 skip_comments=False) 2173 self.assertFalse(tokenizer.AtEnd()) 2174 self.assertEqual((False, '# some comment'), 2175 tokenizer.ConsumeCommentOrTrailingComment()) 2176 self.assertTrue(tokenizer.AtEnd()) 2177 2178 def testConsumeTwoLineComments(self): 2179 text = '# some comment\n# another comment' 2180 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2181 self.assertEqual((False, '# some comment'), 2182 tokenizer.ConsumeCommentOrTrailingComment()) 2183 self.assertFalse(tokenizer.AtEnd()) 2184 self.assertEqual((False, '# another comment'), 2185 tokenizer.ConsumeCommentOrTrailingComment()) 2186 self.assertTrue(tokenizer.AtEnd()) 2187 2188 def testConsumeAndCheckTrailingComment(self): 2189 text = 'some_number: 4 # some comment' # trailing comment on the same line 2190 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2191 self.assertRaises(text_format.ParseError, 2192 tokenizer.ConsumeCommentOrTrailingComment) 2193 2194 self.assertEqual('some_number', tokenizer.ConsumeIdentifier()) 2195 self.assertEqual(tokenizer.token, ':') 2196 tokenizer.NextToken() 2197 self.assertRaises(text_format.ParseError, 2198 tokenizer.ConsumeCommentOrTrailingComment) 2199 self.assertEqual(4, tokenizer.ConsumeInteger()) 2200 self.assertFalse(tokenizer.AtEnd()) 2201 2202 self.assertEqual((True, '# some comment'), 2203 tokenizer.ConsumeCommentOrTrailingComment()) 2204 self.assertTrue(tokenizer.AtEnd()) 2205 2206 def testHashinComment(self): 2207 text = 'some_number: 4 # some comment # not a new comment' 2208 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2209 self.assertEqual('some_number', tokenizer.ConsumeIdentifier()) 2210 self.assertEqual(tokenizer.token, ':') 2211 tokenizer.NextToken() 2212 self.assertEqual(4, tokenizer.ConsumeInteger()) 2213 self.assertEqual((True, '# some comment # not a new comment'), 2214 tokenizer.ConsumeCommentOrTrailingComment()) 2215 self.assertTrue(tokenizer.AtEnd()) 2216 2217 def testHugeString(self): 2218 # With pathologic backtracking, fails with Forge OOM. 2219 text = '"' + 'a' * (10 * 1024 * 1024) + '"' 2220 tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False) 2221 tokenizer.ConsumeString() 2222 2223 2224# Tests for pretty printer functionality. 2225@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2)) 2226class PrettyPrinterTest(TextFormatBase): 2227 2228 def testPrettyPrintNoMatch(self, message_module): 2229 2230 def printer(message, indent, as_one_line): 2231 del message, indent, as_one_line 2232 return None 2233 2234 message = message_module.TestAllTypes() 2235 msg = message.repeated_nested_message.add() 2236 msg.bb = 42 2237 self.CompareToGoldenText( 2238 text_format.MessageToString( 2239 message, as_one_line=True, message_formatter=printer), 2240 'repeated_nested_message { bb: 42 }') 2241 2242 def testPrettyPrintOneLine(self, message_module): 2243 2244 def printer(m, indent, as_one_line): 2245 del indent, as_one_line 2246 if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR: 2247 return 'My lucky number is %s' % m.bb 2248 2249 message = message_module.TestAllTypes() 2250 msg = message.repeated_nested_message.add() 2251 msg.bb = 42 2252 self.CompareToGoldenText( 2253 text_format.MessageToString( 2254 message, as_one_line=True, message_formatter=printer), 2255 'repeated_nested_message { My lucky number is 42 }') 2256 2257 def testPrettyPrintMultiLine(self, message_module): 2258 2259 def printer(m, indent, as_one_line): 2260 if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR: 2261 line_deliminator = (' ' if as_one_line else '\n') + ' ' * indent 2262 return 'My lucky number is:%s%s' % (line_deliminator, m.bb) 2263 return None 2264 2265 message = message_module.TestAllTypes() 2266 msg = message.repeated_nested_message.add() 2267 msg.bb = 42 2268 self.CompareToGoldenText( 2269 text_format.MessageToString( 2270 message, as_one_line=True, message_formatter=printer), 2271 'repeated_nested_message { My lucky number is: 42 }') 2272 self.CompareToGoldenText( 2273 text_format.MessageToString( 2274 message, as_one_line=False, message_formatter=printer), 2275 'repeated_nested_message {\n My lucky number is:\n 42\n}\n') 2276 2277 def testPrettyPrintEntireMessage(self, message_module): 2278 2279 def printer(m, indent, as_one_line): 2280 del indent, as_one_line 2281 if m.DESCRIPTOR == message_module.TestAllTypes.DESCRIPTOR: 2282 return 'The is the message!' 2283 return None 2284 2285 message = message_module.TestAllTypes() 2286 self.CompareToGoldenText( 2287 text_format.MessageToString( 2288 message, as_one_line=False, message_formatter=printer), 2289 'The is the message!\n') 2290 self.CompareToGoldenText( 2291 text_format.MessageToString( 2292 message, as_one_line=True, message_formatter=printer), 2293 'The is the message!') 2294 2295 def testPrettyPrintMultipleParts(self, message_module): 2296 2297 def printer(m, indent, as_one_line): 2298 del indent, as_one_line 2299 if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR: 2300 return 'My lucky number is %s' % m.bb 2301 return None 2302 2303 message = message_module.TestAllTypes() 2304 message.optional_int32 = 61 2305 msg = message.repeated_nested_message.add() 2306 msg.bb = 42 2307 msg = message.repeated_nested_message.add() 2308 msg.bb = 99 2309 msg = message.optional_nested_message 2310 msg.bb = 1 2311 self.CompareToGoldenText( 2312 text_format.MessageToString( 2313 message, as_one_line=True, message_formatter=printer), 2314 ('optional_int32: 61 ' 2315 'optional_nested_message { My lucky number is 1 } ' 2316 'repeated_nested_message { My lucky number is 42 } ' 2317 'repeated_nested_message { My lucky number is 99 }')) 2318 2319 out = text_format.TextWriter(False) 2320 text_format.PrintField( 2321 message_module.TestAllTypes.DESCRIPTOR.fields_by_name[ 2322 'optional_nested_message'], 2323 message.optional_nested_message, 2324 out, 2325 message_formatter=printer) 2326 self.assertEqual( 2327 'optional_nested_message {\n My lucky number is 1\n}\n', 2328 out.getvalue()) 2329 out.close() 2330 2331 out = text_format.TextWriter(False) 2332 text_format.PrintFieldValue( 2333 message_module.TestAllTypes.DESCRIPTOR.fields_by_name[ 2334 'optional_nested_message'], 2335 message.optional_nested_message, 2336 out, 2337 message_formatter=printer) 2338 self.assertEqual( 2339 '{\n My lucky number is 1\n}', 2340 out.getvalue()) 2341 out.close() 2342 2343 2344class WhitespaceTest(TextFormatBase): 2345 2346 def setUp(self): 2347 self.out = text_format.TextWriter(False) 2348 self.addCleanup(self.out.close) 2349 self.message = unittest_pb2.NestedTestAllTypes() 2350 self.message.child.payload.optional_string = 'value' 2351 self.field = self.message.DESCRIPTOR.fields_by_name['child'] 2352 self.value = self.message.child 2353 2354 def testMessageToString(self): 2355 self.CompareToGoldenText( 2356 text_format.MessageToString(self.message), 2357 textwrap.dedent("""\ 2358 child { 2359 payload { 2360 optional_string: "value" 2361 } 2362 } 2363 """)) 2364 2365 def testPrintMessage(self): 2366 text_format.PrintMessage(self.message, self.out) 2367 self.CompareToGoldenText( 2368 self.out.getvalue(), 2369 textwrap.dedent("""\ 2370 child { 2371 payload { 2372 optional_string: "value" 2373 } 2374 } 2375 """)) 2376 2377 def testPrintField(self): 2378 text_format.PrintField(self.field, self.value, self.out) 2379 self.CompareToGoldenText( 2380 self.out.getvalue(), 2381 textwrap.dedent("""\ 2382 child { 2383 payload { 2384 optional_string: "value" 2385 } 2386 } 2387 """)) 2388 2389 def testPrintFieldValue(self): 2390 text_format.PrintFieldValue( 2391 self.field, self.value, self.out) 2392 self.CompareToGoldenText( 2393 self.out.getvalue(), 2394 textwrap.dedent("""\ 2395 { 2396 payload { 2397 optional_string: "value" 2398 } 2399 }""")) 2400 2401 2402class OptionalColonMessageToStringTest(unittest.TestCase): 2403 2404 def testForcePrintOptionalColon(self): 2405 packed_message = unittest_pb2.OneString() 2406 packed_message.data = 'string' 2407 message = any_test_pb2.TestAny() 2408 message.any_value.Pack(packed_message) 2409 output = text_format.MessageToString( 2410 message, 2411 force_colon=True) 2412 expected = ('any_value: {\n' 2413 ' [type.googleapis.com/protobuf_unittest.OneString]: {\n' 2414 ' data: "string"\n' 2415 ' }\n' 2416 '}\n') 2417 self.assertEqual(expected, output) 2418 2419 def testPrintShortFormatRepeatedFields(self): 2420 message = unittest_pb2.TestAllTypes() 2421 message.repeated_int32.append(1) 2422 output = text_format.MessageToString( 2423 message, use_short_repeated_primitives=True, force_colon=True) 2424 self.assertEqual('repeated_int32: [1]\n', output) 2425 2426 2427if __name__ == '__main__': 2428 unittest.main() 2429