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