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