text_format_test.py 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. #! /usr/bin/env python
  2. #
  3. # Protocol Buffers - Google's data interchange format
  4. # Copyright 2008 Google Inc. All rights reserved.
  5. # https://developers.google.com/protocol-buffers/
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions are
  9. # met:
  10. #
  11. # * Redistributions of source code must retain the above copyright
  12. # notice, this list of conditions and the following disclaimer.
  13. # * Redistributions in binary form must reproduce the above
  14. # copyright notice, this list of conditions and the following disclaimer
  15. # in the documentation and/or other materials provided with the
  16. # distribution.
  17. # * Neither the name of Google Inc. nor the names of its
  18. # contributors may be used to endorse or promote products derived from
  19. # this software without specific prior written permission.
  20. #
  21. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. """Test for google.protobuf.text_format."""
  33. __author__ = 'kenton@google.com (Kenton Varda)'
  34. import re
  35. import six
  36. import string
  37. try:
  38. import unittest2 as unittest # PY26, pylint: disable=g-import-not-at-top
  39. except ImportError:
  40. import unittest # pylint: disable=g-import-not-at-top
  41. from google.protobuf.internal import _parameterized
  42. from google.protobuf import any_test_pb2
  43. from google.protobuf import map_unittest_pb2
  44. from google.protobuf import unittest_mset_pb2
  45. from google.protobuf import unittest_pb2
  46. from google.protobuf import unittest_proto3_arena_pb2
  47. from google.protobuf.internal import api_implementation
  48. from google.protobuf.internal import test_util
  49. from google.protobuf.internal import message_set_extensions_pb2
  50. from google.protobuf import descriptor_pool
  51. from google.protobuf import text_format
  52. # Low-level nuts-n-bolts tests.
  53. class SimpleTextFormatTests(unittest.TestCase):
  54. # The members of _QUOTES are formatted into a regexp template that
  55. # expects single characters. Therefore it's an error (in addition to being
  56. # non-sensical in the first place) to try to specify a "quote mark" that is
  57. # more than one character.
  58. def testQuoteMarksAreSingleChars(self):
  59. for quote in text_format._QUOTES:
  60. self.assertEqual(1, len(quote))
  61. # Base class with some common functionality.
  62. class TextFormatBase(unittest.TestCase):
  63. def ReadGolden(self, golden_filename):
  64. with test_util.GoldenFile(golden_filename) as f:
  65. return (f.readlines() if str is bytes else # PY3
  66. [golden_line.decode('utf-8') for golden_line in f])
  67. def CompareToGoldenFile(self, text, golden_filename):
  68. golden_lines = self.ReadGolden(golden_filename)
  69. self.assertMultiLineEqual(text, ''.join(golden_lines))
  70. def CompareToGoldenText(self, text, golden_text):
  71. self.assertEqual(text, golden_text)
  72. def RemoveRedundantZeros(self, text):
  73. # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove
  74. # these zeros in order to match the golden file.
  75. text = text.replace('e+0','e+').replace('e+0','e+') \
  76. .replace('e-0','e-').replace('e-0','e-')
  77. # Floating point fields are printed with .0 suffix even if they are
  78. # actualy integer numbers.
  79. text = re.compile(r'\.0$', re.MULTILINE).sub('', text)
  80. return text
  81. @_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
  82. class TextFormatTest(TextFormatBase):
  83. def testPrintExotic(self, message_module):
  84. message = message_module.TestAllTypes()
  85. message.repeated_int64.append(-9223372036854775808)
  86. message.repeated_uint64.append(18446744073709551615)
  87. message.repeated_double.append(123.456)
  88. message.repeated_double.append(1.23e22)
  89. message.repeated_double.append(1.23e-18)
  90. message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
  91. message.repeated_string.append(u'\u00fc\ua71f')
  92. self.CompareToGoldenText(
  93. self.RemoveRedundantZeros(text_format.MessageToString(message)),
  94. 'repeated_int64: -9223372036854775808\n'
  95. 'repeated_uint64: 18446744073709551615\n'
  96. 'repeated_double: 123.456\n'
  97. 'repeated_double: 1.23e+22\n'
  98. 'repeated_double: 1.23e-18\n'
  99. 'repeated_string:'
  100. ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
  101. 'repeated_string: "\\303\\274\\352\\234\\237"\n')
  102. def testPrintExoticUnicodeSubclass(self, message_module):
  103. class UnicodeSub(six.text_type):
  104. pass
  105. message = message_module.TestAllTypes()
  106. message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
  107. self.CompareToGoldenText(
  108. text_format.MessageToString(message),
  109. 'repeated_string: "\\303\\274\\352\\234\\237"\n')
  110. def testPrintNestedMessageAsOneLine(self, message_module):
  111. message = message_module.TestAllTypes()
  112. msg = message.repeated_nested_message.add()
  113. msg.bb = 42
  114. self.CompareToGoldenText(
  115. text_format.MessageToString(message, as_one_line=True),
  116. 'repeated_nested_message { bb: 42 }')
  117. def testPrintRepeatedFieldsAsOneLine(self, message_module):
  118. message = message_module.TestAllTypes()
  119. message.repeated_int32.append(1)
  120. message.repeated_int32.append(1)
  121. message.repeated_int32.append(3)
  122. message.repeated_string.append('Google')
  123. message.repeated_string.append('Zurich')
  124. self.CompareToGoldenText(
  125. text_format.MessageToString(message, as_one_line=True),
  126. 'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
  127. 'repeated_string: "Google" repeated_string: "Zurich"')
  128. def testPrintNestedNewLineInStringAsOneLine(self, message_module):
  129. message = message_module.TestAllTypes()
  130. message.optional_string = 'a\nnew\nline'
  131. self.CompareToGoldenText(
  132. text_format.MessageToString(message, as_one_line=True),
  133. 'optional_string: "a\\nnew\\nline"')
  134. def testPrintExoticAsOneLine(self, message_module):
  135. message = message_module.TestAllTypes()
  136. message.repeated_int64.append(-9223372036854775808)
  137. message.repeated_uint64.append(18446744073709551615)
  138. message.repeated_double.append(123.456)
  139. message.repeated_double.append(1.23e22)
  140. message.repeated_double.append(1.23e-18)
  141. message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
  142. message.repeated_string.append(u'\u00fc\ua71f')
  143. self.CompareToGoldenText(
  144. self.RemoveRedundantZeros(text_format.MessageToString(
  145. message, as_one_line=True)),
  146. 'repeated_int64: -9223372036854775808'
  147. ' repeated_uint64: 18446744073709551615'
  148. ' repeated_double: 123.456'
  149. ' repeated_double: 1.23e+22'
  150. ' repeated_double: 1.23e-18'
  151. ' repeated_string: '
  152. '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""'
  153. ' repeated_string: "\\303\\274\\352\\234\\237"')
  154. def testRoundTripExoticAsOneLine(self, message_module):
  155. message = message_module.TestAllTypes()
  156. message.repeated_int64.append(-9223372036854775808)
  157. message.repeated_uint64.append(18446744073709551615)
  158. message.repeated_double.append(123.456)
  159. message.repeated_double.append(1.23e22)
  160. message.repeated_double.append(1.23e-18)
  161. message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
  162. message.repeated_string.append(u'\u00fc\ua71f')
  163. # Test as_utf8 = False.
  164. wire_text = text_format.MessageToString(message,
  165. as_one_line=True,
  166. as_utf8=False)
  167. parsed_message = message_module.TestAllTypes()
  168. r = text_format.Parse(wire_text, parsed_message)
  169. self.assertIs(r, parsed_message)
  170. self.assertEqual(message, parsed_message)
  171. # Test as_utf8 = True.
  172. wire_text = text_format.MessageToString(message,
  173. as_one_line=True,
  174. as_utf8=True)
  175. parsed_message = message_module.TestAllTypes()
  176. r = text_format.Parse(wire_text, parsed_message)
  177. self.assertIs(r, parsed_message)
  178. self.assertEqual(message, parsed_message,
  179. '\n%s != %s' % (message, parsed_message))
  180. def testPrintRawUtf8String(self, message_module):
  181. message = message_module.TestAllTypes()
  182. message.repeated_string.append(u'\u00fc\ua71f')
  183. text = text_format.MessageToString(message, as_utf8=True)
  184. self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n')
  185. parsed_message = message_module.TestAllTypes()
  186. text_format.Parse(text, parsed_message)
  187. self.assertEqual(message, parsed_message,
  188. '\n%s != %s' % (message, parsed_message))
  189. def testPrintFloatFormat(self, message_module):
  190. # Check that float_format argument is passed to sub-message formatting.
  191. message = message_module.NestedTestAllTypes()
  192. # We use 1.25 as it is a round number in binary. The proto 32-bit float
  193. # will not gain additional imprecise digits as a 64-bit Python float and
  194. # show up in its str. 32-bit 1.2 is noisy when extended to 64-bit:
  195. # >>> struct.unpack('f', struct.pack('f', 1.2))[0]
  196. # 1.2000000476837158
  197. # >>> struct.unpack('f', struct.pack('f', 1.25))[0]
  198. # 1.25
  199. message.payload.optional_float = 1.25
  200. # Check rounding at 15 significant digits
  201. message.payload.optional_double = -.000003456789012345678
  202. # Check no decimal point.
  203. message.payload.repeated_float.append(-5642)
  204. # Check no trailing zeros.
  205. message.payload.repeated_double.append(.000078900)
  206. formatted_fields = ['optional_float: 1.25',
  207. 'optional_double: -3.45678901234568e-6',
  208. 'repeated_float: -5642', 'repeated_double: 7.89e-5']
  209. text_message = text_format.MessageToString(message, float_format='.15g')
  210. self.CompareToGoldenText(
  211. self.RemoveRedundantZeros(text_message),
  212. 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(
  213. *formatted_fields))
  214. # as_one_line=True is a separate code branch where float_format is passed.
  215. text_message = text_format.MessageToString(message,
  216. as_one_line=True,
  217. float_format='.15g')
  218. self.CompareToGoldenText(
  219. self.RemoveRedundantZeros(text_message),
  220. 'payload {{ {0} {1} {2} {3} }}'.format(*formatted_fields))
  221. def testMessageToString(self, message_module):
  222. message = message_module.ForeignMessage()
  223. message.c = 123
  224. self.assertEqual('c: 123\n', str(message))
  225. def testPrintField(self, message_module):
  226. message = message_module.TestAllTypes()
  227. field = message.DESCRIPTOR.fields_by_name['optional_float']
  228. value = message.optional_float
  229. out = text_format.TextWriter(False)
  230. text_format.PrintField(field, value, out)
  231. self.assertEqual('optional_float: 0.0\n', out.getvalue())
  232. out.close()
  233. # Test Printer
  234. out = text_format.TextWriter(False)
  235. printer = text_format._Printer(out)
  236. printer.PrintField(field, value)
  237. self.assertEqual('optional_float: 0.0\n', out.getvalue())
  238. out.close()
  239. def testPrintFieldValue(self, message_module):
  240. message = message_module.TestAllTypes()
  241. field = message.DESCRIPTOR.fields_by_name['optional_float']
  242. value = message.optional_float
  243. out = text_format.TextWriter(False)
  244. text_format.PrintFieldValue(field, value, out)
  245. self.assertEqual('0.0', out.getvalue())
  246. out.close()
  247. # Test Printer
  248. out = text_format.TextWriter(False)
  249. printer = text_format._Printer(out)
  250. printer.PrintFieldValue(field, value)
  251. self.assertEqual('0.0', out.getvalue())
  252. out.close()
  253. def testParseAllFields(self, message_module):
  254. message = message_module.TestAllTypes()
  255. test_util.SetAllFields(message)
  256. ascii_text = text_format.MessageToString(message)
  257. parsed_message = message_module.TestAllTypes()
  258. text_format.Parse(ascii_text, parsed_message)
  259. self.assertEqual(message, parsed_message)
  260. if message_module is unittest_pb2:
  261. test_util.ExpectAllFieldsSet(self, message)
  262. def testParseExotic(self, message_module):
  263. message = message_module.TestAllTypes()
  264. text = ('repeated_int64: -9223372036854775808\n'
  265. 'repeated_uint64: 18446744073709551615\n'
  266. 'repeated_double: 123.456\n'
  267. 'repeated_double: 1.23e+22\n'
  268. 'repeated_double: 1.23e-18\n'
  269. 'repeated_string: \n'
  270. '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
  271. 'repeated_string: "foo" \'corge\' "grault"\n'
  272. 'repeated_string: "\\303\\274\\352\\234\\237"\n'
  273. 'repeated_string: "\\xc3\\xbc"\n'
  274. 'repeated_string: "\xc3\xbc"\n')
  275. text_format.Parse(text, message)
  276. self.assertEqual(-9223372036854775808, message.repeated_int64[0])
  277. self.assertEqual(18446744073709551615, message.repeated_uint64[0])
  278. self.assertEqual(123.456, message.repeated_double[0])
  279. self.assertEqual(1.23e22, message.repeated_double[1])
  280. self.assertEqual(1.23e-18, message.repeated_double[2])
  281. self.assertEqual('\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
  282. self.assertEqual('foocorgegrault', message.repeated_string[1])
  283. self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
  284. self.assertEqual(u'\u00fc', message.repeated_string[3])
  285. def testParseTrailingCommas(self, message_module):
  286. message = message_module.TestAllTypes()
  287. text = ('repeated_int64: 100;\n'
  288. 'repeated_int64: 200;\n'
  289. 'repeated_int64: 300,\n'
  290. 'repeated_string: "one",\n'
  291. 'repeated_string: "two";\n')
  292. text_format.Parse(text, message)
  293. self.assertEqual(100, message.repeated_int64[0])
  294. self.assertEqual(200, message.repeated_int64[1])
  295. self.assertEqual(300, message.repeated_int64[2])
  296. self.assertEqual(u'one', message.repeated_string[0])
  297. self.assertEqual(u'two', message.repeated_string[1])
  298. def testParseRepeatedScalarShortFormat(self, message_module):
  299. message = message_module.TestAllTypes()
  300. text = ('repeated_int64: [100, 200];\n'
  301. 'repeated_int64: 300,\n'
  302. 'repeated_string: ["one", "two"];\n')
  303. text_format.Parse(text, message)
  304. self.assertEqual(100, message.repeated_int64[0])
  305. self.assertEqual(200, message.repeated_int64[1])
  306. self.assertEqual(300, message.repeated_int64[2])
  307. self.assertEqual(u'one', message.repeated_string[0])
  308. self.assertEqual(u'two', message.repeated_string[1])
  309. def testParseRepeatedMessageShortFormat(self, message_module):
  310. message = message_module.TestAllTypes()
  311. text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n'
  312. 'repeated_nested_message: {bb: 300}\n'
  313. 'repeated_nested_message [{bb: 400}];\n')
  314. text_format.Parse(text, message)
  315. self.assertEqual(100, message.repeated_nested_message[0].bb)
  316. self.assertEqual(200, message.repeated_nested_message[1].bb)
  317. self.assertEqual(300, message.repeated_nested_message[2].bb)
  318. self.assertEqual(400, message.repeated_nested_message[3].bb)
  319. def testParseEmptyText(self, message_module):
  320. message = message_module.TestAllTypes()
  321. text = ''
  322. text_format.Parse(text, message)
  323. self.assertEqual(message_module.TestAllTypes(), message)
  324. def testParseInvalidUtf8(self, message_module):
  325. message = message_module.TestAllTypes()
  326. text = 'repeated_string: "\\xc3\\xc3"'
  327. self.assertRaises(text_format.ParseError, text_format.Parse, text, message)
  328. def testParseSingleWord(self, message_module):
  329. message = message_module.TestAllTypes()
  330. text = 'foo'
  331. six.assertRaisesRegex(self, text_format.ParseError, (
  332. r'1:1 : Message type "\w+.TestAllTypes" has no field named '
  333. r'"foo".'), text_format.Parse, text, message)
  334. def testParseUnknownField(self, message_module):
  335. message = message_module.TestAllTypes()
  336. text = 'unknown_field: 8\n'
  337. six.assertRaisesRegex(self, text_format.ParseError, (
  338. r'1:1 : Message type "\w+.TestAllTypes" has no field named '
  339. r'"unknown_field".'), text_format.Parse, text, message)
  340. def testParseBadEnumValue(self, message_module):
  341. message = message_module.TestAllTypes()
  342. text = 'optional_nested_enum: BARR'
  343. six.assertRaisesRegex(self, text_format.ParseError,
  344. (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
  345. r'has no value named BARR.'), text_format.Parse,
  346. text, message)
  347. message = message_module.TestAllTypes()
  348. text = 'optional_nested_enum: 100'
  349. six.assertRaisesRegex(self, text_format.ParseError,
  350. (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
  351. r'has no value with number 100.'), text_format.Parse,
  352. text, message)
  353. def testParseBadIntValue(self, message_module):
  354. message = message_module.TestAllTypes()
  355. text = 'optional_int32: bork'
  356. six.assertRaisesRegex(self, text_format.ParseError,
  357. ('1:17 : Couldn\'t parse integer: bork'),
  358. text_format.Parse, text, message)
  359. def testParseStringFieldUnescape(self, message_module):
  360. message = message_module.TestAllTypes()
  361. text = r'''repeated_string: "\xf\x62"
  362. repeated_string: "\\xf\\x62"
  363. repeated_string: "\\\xf\\\x62"
  364. repeated_string: "\\\\xf\\\\x62"
  365. repeated_string: "\\\\\xf\\\\\x62"
  366. repeated_string: "\x5cx20"'''
  367. text_format.Parse(text, message)
  368. SLASH = '\\'
  369. self.assertEqual('\x0fb', message.repeated_string[0])
  370. self.assertEqual(SLASH + 'xf' + SLASH + 'x62', message.repeated_string[1])
  371. self.assertEqual(SLASH + '\x0f' + SLASH + 'b', message.repeated_string[2])
  372. self.assertEqual(SLASH + SLASH + 'xf' + SLASH + SLASH + 'x62',
  373. message.repeated_string[3])
  374. self.assertEqual(SLASH + SLASH + '\x0f' + SLASH + SLASH + 'b',
  375. message.repeated_string[4])
  376. self.assertEqual(SLASH + 'x20', message.repeated_string[5])
  377. def testMergeDuplicateScalars(self, message_module):
  378. message = message_module.TestAllTypes()
  379. text = ('optional_int32: 42 ' 'optional_int32: 67')
  380. r = text_format.Merge(text, message)
  381. self.assertIs(r, message)
  382. self.assertEqual(67, message.optional_int32)
  383. def testMergeDuplicateNestedMessageScalars(self, message_module):
  384. message = message_module.TestAllTypes()
  385. text = ('optional_nested_message { bb: 1 } '
  386. 'optional_nested_message { bb: 2 }')
  387. r = text_format.Merge(text, message)
  388. self.assertTrue(r is message)
  389. self.assertEqual(2, message.optional_nested_message.bb)
  390. def testParseOneof(self, message_module):
  391. m = message_module.TestAllTypes()
  392. m.oneof_uint32 = 11
  393. m2 = message_module.TestAllTypes()
  394. text_format.Parse(text_format.MessageToString(m), m2)
  395. self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
  396. def testParseMultipleOneof(self, message_module):
  397. m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
  398. m2 = message_module.TestAllTypes()
  399. if message_module is unittest_pb2:
  400. with self.assertRaisesRegexp(text_format.ParseError,
  401. ' is specified along with field '):
  402. text_format.Parse(m_string, m2)
  403. else:
  404. text_format.Parse(m_string, m2)
  405. self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
  406. # These are tests that aren't fundamentally specific to proto2, but are at
  407. # the moment because of differences between the proto2 and proto3 test schemas.
  408. # Ideally the schemas would be made more similar so these tests could pass.
  409. class OnlyWorksWithProto2RightNowTests(TextFormatBase):
  410. def testPrintAllFieldsPointy(self):
  411. message = unittest_pb2.TestAllTypes()
  412. test_util.SetAllFields(message)
  413. self.CompareToGoldenFile(
  414. self.RemoveRedundantZeros(text_format.MessageToString(
  415. message, pointy_brackets=True)),
  416. 'text_format_unittest_data_pointy_oneof.txt')
  417. def testParseGolden(self):
  418. golden_text = '\n'.join(self.ReadGolden(
  419. 'text_format_unittest_data_oneof_implemented.txt'))
  420. parsed_message = unittest_pb2.TestAllTypes()
  421. r = text_format.Parse(golden_text, parsed_message)
  422. self.assertIs(r, parsed_message)
  423. message = unittest_pb2.TestAllTypes()
  424. test_util.SetAllFields(message)
  425. self.assertEqual(message, parsed_message)
  426. def testPrintAllFields(self):
  427. message = unittest_pb2.TestAllTypes()
  428. test_util.SetAllFields(message)
  429. self.CompareToGoldenFile(
  430. self.RemoveRedundantZeros(text_format.MessageToString(message)),
  431. 'text_format_unittest_data_oneof_implemented.txt')
  432. def testPrintInIndexOrder(self):
  433. message = unittest_pb2.TestFieldOrderings()
  434. message.my_string = '115'
  435. message.my_int = 101
  436. message.my_float = 111
  437. message.optional_nested_message.oo = 0
  438. message.optional_nested_message.bb = 1
  439. self.CompareToGoldenText(
  440. self.RemoveRedundantZeros(text_format.MessageToString(
  441. message, use_index_order=True)),
  442. 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n'
  443. 'optional_nested_message {\n oo: 0\n bb: 1\n}\n')
  444. self.CompareToGoldenText(
  445. self.RemoveRedundantZeros(text_format.MessageToString(message)),
  446. 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n'
  447. 'optional_nested_message {\n bb: 1\n oo: 0\n}\n')
  448. def testMergeLinesGolden(self):
  449. opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
  450. parsed_message = unittest_pb2.TestAllTypes()
  451. r = text_format.MergeLines(opened, parsed_message)
  452. self.assertIs(r, parsed_message)
  453. message = unittest_pb2.TestAllTypes()
  454. test_util.SetAllFields(message)
  455. self.assertEqual(message, parsed_message)
  456. def testParseLinesGolden(self):
  457. opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
  458. parsed_message = unittest_pb2.TestAllTypes()
  459. r = text_format.ParseLines(opened, parsed_message)
  460. self.assertIs(r, parsed_message)
  461. message = unittest_pb2.TestAllTypes()
  462. test_util.SetAllFields(message)
  463. self.assertEqual(message, parsed_message)
  464. def testPrintMap(self):
  465. message = map_unittest_pb2.TestMap()
  466. message.map_int32_int32[-123] = -456
  467. message.map_int64_int64[-2**33] = -2**34
  468. message.map_uint32_uint32[123] = 456
  469. message.map_uint64_uint64[2**33] = 2**34
  470. message.map_string_string['abc'] = '123'
  471. message.map_int32_foreign_message[111].c = 5
  472. # Maps are serialized to text format using their underlying repeated
  473. # representation.
  474. self.CompareToGoldenText(
  475. text_format.MessageToString(message), 'map_int32_int32 {\n'
  476. ' key: -123\n'
  477. ' value: -456\n'
  478. '}\n'
  479. 'map_int64_int64 {\n'
  480. ' key: -8589934592\n'
  481. ' value: -17179869184\n'
  482. '}\n'
  483. 'map_uint32_uint32 {\n'
  484. ' key: 123\n'
  485. ' value: 456\n'
  486. '}\n'
  487. 'map_uint64_uint64 {\n'
  488. ' key: 8589934592\n'
  489. ' value: 17179869184\n'
  490. '}\n'
  491. 'map_string_string {\n'
  492. ' key: "abc"\n'
  493. ' value: "123"\n'
  494. '}\n'
  495. 'map_int32_foreign_message {\n'
  496. ' key: 111\n'
  497. ' value {\n'
  498. ' c: 5\n'
  499. ' }\n'
  500. '}\n')
  501. def testMapOrderEnforcement(self):
  502. message = map_unittest_pb2.TestMap()
  503. for letter in string.ascii_uppercase[13:26]:
  504. message.map_string_string[letter] = 'dummy'
  505. for letter in reversed(string.ascii_uppercase[0:13]):
  506. message.map_string_string[letter] = 'dummy'
  507. golden = ''.join(('map_string_string {\n key: "%c"\n value: "dummy"\n}\n'
  508. % (letter,) for letter in string.ascii_uppercase))
  509. self.CompareToGoldenText(text_format.MessageToString(message), golden)
  510. def testMapOrderSemantics(self):
  511. golden_lines = self.ReadGolden('map_test_data.txt')
  512. # The C++ implementation emits defaulted-value fields, while the Python
  513. # implementation does not. Adjusting for this is awkward, but it is
  514. # valuable to test against a common golden file.
  515. line_blacklist = (' key: 0\n', ' value: 0\n', ' key: false\n',
  516. ' value: false\n')
  517. golden_lines = [line for line in golden_lines if line not in line_blacklist]
  518. message = map_unittest_pb2.TestMap()
  519. text_format.ParseLines(golden_lines, message)
  520. candidate = text_format.MessageToString(message)
  521. # The Python implementation emits "1.0" for the double value that the C++
  522. # implementation emits as "1".
  523. candidate = candidate.replace('1.0', '1', 2)
  524. self.assertMultiLineEqual(candidate, ''.join(golden_lines))
  525. # Tests of proto2-only features (MessageSet, extensions, etc.).
  526. class Proto2Tests(TextFormatBase):
  527. def testPrintMessageSet(self):
  528. message = unittest_mset_pb2.TestMessageSetContainer()
  529. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  530. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  531. message.message_set.Extensions[ext1].i = 23
  532. message.message_set.Extensions[ext2].str = 'foo'
  533. self.CompareToGoldenText(
  534. text_format.MessageToString(message), 'message_set {\n'
  535. ' [protobuf_unittest.TestMessageSetExtension1] {\n'
  536. ' i: 23\n'
  537. ' }\n'
  538. ' [protobuf_unittest.TestMessageSetExtension2] {\n'
  539. ' str: \"foo\"\n'
  540. ' }\n'
  541. '}\n')
  542. message = message_set_extensions_pb2.TestMessageSet()
  543. ext = message_set_extensions_pb2.message_set_extension3
  544. message.Extensions[ext].text = 'bar'
  545. self.CompareToGoldenText(
  546. text_format.MessageToString(message),
  547. '[google.protobuf.internal.TestMessageSetExtension3] {\n'
  548. ' text: \"bar\"\n'
  549. '}\n')
  550. def testPrintMessageSetByFieldNumber(self):
  551. out = text_format.TextWriter(False)
  552. message = unittest_mset_pb2.TestMessageSetContainer()
  553. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  554. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  555. message.message_set.Extensions[ext1].i = 23
  556. message.message_set.Extensions[ext2].str = 'foo'
  557. text_format.PrintMessage(message, out, use_field_number=True)
  558. self.CompareToGoldenText(out.getvalue(), '1 {\n'
  559. ' 1545008 {\n'
  560. ' 15: 23\n'
  561. ' }\n'
  562. ' 1547769 {\n'
  563. ' 25: \"foo\"\n'
  564. ' }\n'
  565. '}\n')
  566. out.close()
  567. def testPrintMessageSetAsOneLine(self):
  568. message = unittest_mset_pb2.TestMessageSetContainer()
  569. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  570. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  571. message.message_set.Extensions[ext1].i = 23
  572. message.message_set.Extensions[ext2].str = 'foo'
  573. self.CompareToGoldenText(
  574. text_format.MessageToString(message, as_one_line=True),
  575. 'message_set {'
  576. ' [protobuf_unittest.TestMessageSetExtension1] {'
  577. ' i: 23'
  578. ' }'
  579. ' [protobuf_unittest.TestMessageSetExtension2] {'
  580. ' str: \"foo\"'
  581. ' }'
  582. ' }')
  583. def testParseMessageSet(self):
  584. message = unittest_pb2.TestAllTypes()
  585. text = ('repeated_uint64: 1\n' 'repeated_uint64: 2\n')
  586. text_format.Parse(text, message)
  587. self.assertEqual(1, message.repeated_uint64[0])
  588. self.assertEqual(2, message.repeated_uint64[1])
  589. message = unittest_mset_pb2.TestMessageSetContainer()
  590. text = ('message_set {\n'
  591. ' [protobuf_unittest.TestMessageSetExtension1] {\n'
  592. ' i: 23\n'
  593. ' }\n'
  594. ' [protobuf_unittest.TestMessageSetExtension2] {\n'
  595. ' str: \"foo\"\n'
  596. ' }\n'
  597. '}\n')
  598. text_format.Parse(text, message)
  599. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  600. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  601. self.assertEqual(23, message.message_set.Extensions[ext1].i)
  602. self.assertEqual('foo', message.message_set.Extensions[ext2].str)
  603. def testParseMessageByFieldNumber(self):
  604. message = unittest_pb2.TestAllTypes()
  605. text = ('34: 1\n' 'repeated_uint64: 2\n')
  606. text_format.Parse(text, message, allow_field_number=True)
  607. self.assertEqual(1, message.repeated_uint64[0])
  608. self.assertEqual(2, message.repeated_uint64[1])
  609. message = unittest_mset_pb2.TestMessageSetContainer()
  610. text = ('1 {\n'
  611. ' 1545008 {\n'
  612. ' 15: 23\n'
  613. ' }\n'
  614. ' 1547769 {\n'
  615. ' 25: \"foo\"\n'
  616. ' }\n'
  617. '}\n')
  618. text_format.Parse(text, message, allow_field_number=True)
  619. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  620. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  621. self.assertEqual(23, message.message_set.Extensions[ext1].i)
  622. self.assertEqual('foo', message.message_set.Extensions[ext2].str)
  623. # Can't parse field number without set allow_field_number=True.
  624. message = unittest_pb2.TestAllTypes()
  625. text = '34:1\n'
  626. six.assertRaisesRegex(self, text_format.ParseError, (
  627. r'1:1 : Message type "\w+.TestAllTypes" has no field named '
  628. r'"34".'), text_format.Parse, text, message)
  629. # Can't parse if field number is not found.
  630. text = '1234:1\n'
  631. six.assertRaisesRegex(
  632. self,
  633. text_format.ParseError,
  634. (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
  635. r'"1234".'),
  636. text_format.Parse,
  637. text,
  638. message,
  639. allow_field_number=True)
  640. def testPrintAllExtensions(self):
  641. message = unittest_pb2.TestAllExtensions()
  642. test_util.SetAllExtensions(message)
  643. self.CompareToGoldenFile(
  644. self.RemoveRedundantZeros(text_format.MessageToString(message)),
  645. 'text_format_unittest_extensions_data.txt')
  646. def testPrintAllExtensionsPointy(self):
  647. message = unittest_pb2.TestAllExtensions()
  648. test_util.SetAllExtensions(message)
  649. self.CompareToGoldenFile(
  650. self.RemoveRedundantZeros(text_format.MessageToString(
  651. message, pointy_brackets=True)),
  652. 'text_format_unittest_extensions_data_pointy.txt')
  653. def testParseGoldenExtensions(self):
  654. golden_text = '\n'.join(self.ReadGolden(
  655. 'text_format_unittest_extensions_data.txt'))
  656. parsed_message = unittest_pb2.TestAllExtensions()
  657. text_format.Parse(golden_text, parsed_message)
  658. message = unittest_pb2.TestAllExtensions()
  659. test_util.SetAllExtensions(message)
  660. self.assertEqual(message, parsed_message)
  661. def testParseAllExtensions(self):
  662. message = unittest_pb2.TestAllExtensions()
  663. test_util.SetAllExtensions(message)
  664. ascii_text = text_format.MessageToString(message)
  665. parsed_message = unittest_pb2.TestAllExtensions()
  666. text_format.Parse(ascii_text, parsed_message)
  667. self.assertEqual(message, parsed_message)
  668. def testParseAllowedUnknownExtension(self):
  669. # Skip over unknown extension correctly.
  670. message = unittest_mset_pb2.TestMessageSetContainer()
  671. text = ('message_set {\n'
  672. ' [unknown_extension] {\n'
  673. ' i: 23\n'
  674. ' bin: "\xe0"'
  675. ' [nested_unknown_ext]: {\n'
  676. ' i: 23\n'
  677. ' test: "test_string"\n'
  678. ' floaty_float: -0.315\n'
  679. ' num: -inf\n'
  680. ' multiline_str: "abc"\n'
  681. ' "def"\n'
  682. ' "xyz."\n'
  683. ' [nested_unknown_ext]: <\n'
  684. ' i: 23\n'
  685. ' i: 24\n'
  686. ' pointfloat: .3\n'
  687. ' test: "test_string"\n'
  688. ' floaty_float: -0.315\n'
  689. ' num: -inf\n'
  690. ' long_string: "test" "test2" \n'
  691. ' >\n'
  692. ' }\n'
  693. ' }\n'
  694. ' [unknown_extension]: 5\n'
  695. '}\n')
  696. text_format.Parse(text, message, allow_unknown_extension=True)
  697. golden = 'message_set {\n}\n'
  698. self.CompareToGoldenText(text_format.MessageToString(message), golden)
  699. # Catch parse errors in unknown extension.
  700. message = unittest_mset_pb2.TestMessageSetContainer()
  701. malformed = ('message_set {\n'
  702. ' [unknown_extension] {\n'
  703. ' i:\n' # Missing value.
  704. ' }\n'
  705. '}\n')
  706. six.assertRaisesRegex(self,
  707. text_format.ParseError,
  708. 'Invalid field value: }',
  709. text_format.Parse,
  710. malformed,
  711. message,
  712. allow_unknown_extension=True)
  713. message = unittest_mset_pb2.TestMessageSetContainer()
  714. malformed = ('message_set {\n'
  715. ' [unknown_extension] {\n'
  716. ' str: "malformed string\n' # Missing closing quote.
  717. ' }\n'
  718. '}\n')
  719. six.assertRaisesRegex(self,
  720. text_format.ParseError,
  721. 'Invalid field value: "',
  722. text_format.Parse,
  723. malformed,
  724. message,
  725. allow_unknown_extension=True)
  726. message = unittest_mset_pb2.TestMessageSetContainer()
  727. malformed = ('message_set {\n'
  728. ' [unknown_extension] {\n'
  729. ' str: "malformed\n multiline\n string\n'
  730. ' }\n'
  731. '}\n')
  732. six.assertRaisesRegex(self,
  733. text_format.ParseError,
  734. 'Invalid field value: "',
  735. text_format.Parse,
  736. malformed,
  737. message,
  738. allow_unknown_extension=True)
  739. message = unittest_mset_pb2.TestMessageSetContainer()
  740. malformed = ('message_set {\n'
  741. ' [malformed_extension] <\n'
  742. ' i: -5\n'
  743. ' \n' # Missing '>' here.
  744. '}\n')
  745. six.assertRaisesRegex(self,
  746. text_format.ParseError,
  747. '5:1 : Expected ">".',
  748. text_format.Parse,
  749. malformed,
  750. message,
  751. allow_unknown_extension=True)
  752. # Don't allow unknown fields with allow_unknown_extension=True.
  753. message = unittest_mset_pb2.TestMessageSetContainer()
  754. malformed = ('message_set {\n'
  755. ' unknown_field: true\n'
  756. ' \n' # Missing '>' here.
  757. '}\n')
  758. six.assertRaisesRegex(self,
  759. text_format.ParseError,
  760. ('2:3 : Message type '
  761. '"proto2_wireformat_unittest.TestMessageSet" has no'
  762. ' field named "unknown_field".'),
  763. text_format.Parse,
  764. malformed,
  765. message,
  766. allow_unknown_extension=True)
  767. # Parse known extension correcty.
  768. message = unittest_mset_pb2.TestMessageSetContainer()
  769. text = ('message_set {\n'
  770. ' [protobuf_unittest.TestMessageSetExtension1] {\n'
  771. ' i: 23\n'
  772. ' }\n'
  773. ' [protobuf_unittest.TestMessageSetExtension2] {\n'
  774. ' str: \"foo\"\n'
  775. ' }\n'
  776. '}\n')
  777. text_format.Parse(text, message, allow_unknown_extension=True)
  778. ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
  779. ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
  780. self.assertEqual(23, message.message_set.Extensions[ext1].i)
  781. self.assertEqual('foo', message.message_set.Extensions[ext2].str)
  782. def testParseBadExtension(self):
  783. message = unittest_pb2.TestAllExtensions()
  784. text = '[unknown_extension]: 8\n'
  785. six.assertRaisesRegex(self, text_format.ParseError,
  786. '1:2 : Extension "unknown_extension" not registered.',
  787. text_format.Parse, text, message)
  788. message = unittest_pb2.TestAllTypes()
  789. six.assertRaisesRegex(self, text_format.ParseError, (
  790. '1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
  791. 'extensions.'), text_format.Parse, text, message)
  792. def testMergeDuplicateExtensionScalars(self):
  793. message = unittest_pb2.TestAllExtensions()
  794. text = ('[protobuf_unittest.optional_int32_extension]: 42 '
  795. '[protobuf_unittest.optional_int32_extension]: 67')
  796. text_format.Merge(text, message)
  797. self.assertEqual(67,
  798. message.Extensions[unittest_pb2.optional_int32_extension])
  799. def testParseDuplicateExtensionScalars(self):
  800. message = unittest_pb2.TestAllExtensions()
  801. text = ('[protobuf_unittest.optional_int32_extension]: 42 '
  802. '[protobuf_unittest.optional_int32_extension]: 67')
  803. six.assertRaisesRegex(self, text_format.ParseError, (
  804. '1:96 : Message type "protobuf_unittest.TestAllExtensions" '
  805. 'should not have multiple '
  806. '"protobuf_unittest.optional_int32_extension" extensions.'),
  807. text_format.Parse, text, message)
  808. def testParseDuplicateNestedMessageScalars(self):
  809. message = unittest_pb2.TestAllTypes()
  810. text = ('optional_nested_message { bb: 1 } '
  811. 'optional_nested_message { bb: 2 }')
  812. six.assertRaisesRegex(self, text_format.ParseError, (
  813. '1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
  814. 'should not have multiple "bb" fields.'), text_format.Parse, text,
  815. message)
  816. def testParseDuplicateScalars(self):
  817. message = unittest_pb2.TestAllTypes()
  818. text = ('optional_int32: 42 ' 'optional_int32: 67')
  819. six.assertRaisesRegex(self, text_format.ParseError, (
  820. '1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
  821. 'have multiple "optional_int32" fields.'), text_format.Parse, text,
  822. message)
  823. def testParseGroupNotClosed(self):
  824. message = unittest_pb2.TestAllTypes()
  825. text = 'RepeatedGroup: <'
  826. six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected ">".',
  827. text_format.Parse, text, message)
  828. text = 'RepeatedGroup: {'
  829. six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected "}".',
  830. text_format.Parse, text, message)
  831. def testParseEmptyGroup(self):
  832. message = unittest_pb2.TestAllTypes()
  833. text = 'OptionalGroup: {}'
  834. text_format.Parse(text, message)
  835. self.assertTrue(message.HasField('optionalgroup'))
  836. message.Clear()
  837. message = unittest_pb2.TestAllTypes()
  838. text = 'OptionalGroup: <>'
  839. text_format.Parse(text, message)
  840. self.assertTrue(message.HasField('optionalgroup'))
  841. # Maps aren't really proto2-only, but our test schema only has maps for
  842. # proto2.
  843. def testParseMap(self):
  844. text = ('map_int32_int32 {\n'
  845. ' key: -123\n'
  846. ' value: -456\n'
  847. '}\n'
  848. 'map_int64_int64 {\n'
  849. ' key: -8589934592\n'
  850. ' value: -17179869184\n'
  851. '}\n'
  852. 'map_uint32_uint32 {\n'
  853. ' key: 123\n'
  854. ' value: 456\n'
  855. '}\n'
  856. 'map_uint64_uint64 {\n'
  857. ' key: 8589934592\n'
  858. ' value: 17179869184\n'
  859. '}\n'
  860. 'map_string_string {\n'
  861. ' key: "abc"\n'
  862. ' value: "123"\n'
  863. '}\n'
  864. 'map_int32_foreign_message {\n'
  865. ' key: 111\n'
  866. ' value {\n'
  867. ' c: 5\n'
  868. ' }\n'
  869. '}\n')
  870. message = map_unittest_pb2.TestMap()
  871. text_format.Parse(text, message)
  872. self.assertEqual(-456, message.map_int32_int32[-123])
  873. self.assertEqual(-2**34, message.map_int64_int64[-2**33])
  874. self.assertEqual(456, message.map_uint32_uint32[123])
  875. self.assertEqual(2**34, message.map_uint64_uint64[2**33])
  876. self.assertEqual('123', message.map_string_string['abc'])
  877. self.assertEqual(5, message.map_int32_foreign_message[111].c)
  878. class Proto3Tests(unittest.TestCase):
  879. def testPrintMessageExpandAny(self):
  880. packed_message = unittest_pb2.OneString()
  881. packed_message.data = 'string'
  882. message = any_test_pb2.TestAny()
  883. message.any_value.Pack(packed_message)
  884. self.assertEqual(
  885. text_format.MessageToString(message,
  886. descriptor_pool=descriptor_pool.Default()),
  887. 'any_value {\n'
  888. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  889. ' data: "string"\n'
  890. ' }\n'
  891. '}\n')
  892. def testPrintMessageExpandAnyRepeated(self):
  893. packed_message = unittest_pb2.OneString()
  894. message = any_test_pb2.TestAny()
  895. packed_message.data = 'string0'
  896. message.repeated_any_value.add().Pack(packed_message)
  897. packed_message.data = 'string1'
  898. message.repeated_any_value.add().Pack(packed_message)
  899. self.assertEqual(
  900. text_format.MessageToString(message,
  901. descriptor_pool=descriptor_pool.Default()),
  902. 'repeated_any_value {\n'
  903. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  904. ' data: "string0"\n'
  905. ' }\n'
  906. '}\n'
  907. 'repeated_any_value {\n'
  908. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  909. ' data: "string1"\n'
  910. ' }\n'
  911. '}\n')
  912. def testPrintMessageExpandAnyNoDescriptorPool(self):
  913. packed_message = unittest_pb2.OneString()
  914. packed_message.data = 'string'
  915. message = any_test_pb2.TestAny()
  916. message.any_value.Pack(packed_message)
  917. self.assertEqual(
  918. text_format.MessageToString(message, descriptor_pool=None),
  919. 'any_value {\n'
  920. ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
  921. ' value: "\\n\\006string"\n'
  922. '}\n')
  923. def testPrintMessageExpandAnyDescriptorPoolMissingType(self):
  924. packed_message = unittest_pb2.OneString()
  925. packed_message.data = 'string'
  926. message = any_test_pb2.TestAny()
  927. message.any_value.Pack(packed_message)
  928. empty_pool = descriptor_pool.DescriptorPool()
  929. self.assertEqual(
  930. text_format.MessageToString(message, descriptor_pool=empty_pool),
  931. 'any_value {\n'
  932. ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
  933. ' value: "\\n\\006string"\n'
  934. '}\n')
  935. def testPrintMessageExpandAnyPointyBrackets(self):
  936. packed_message = unittest_pb2.OneString()
  937. packed_message.data = 'string'
  938. message = any_test_pb2.TestAny()
  939. message.any_value.Pack(packed_message)
  940. self.assertEqual(
  941. text_format.MessageToString(message,
  942. pointy_brackets=True,
  943. descriptor_pool=descriptor_pool.Default()),
  944. 'any_value <\n'
  945. ' [type.googleapis.com/protobuf_unittest.OneString] <\n'
  946. ' data: "string"\n'
  947. ' >\n'
  948. '>\n')
  949. def testPrintMessageExpandAnyAsOneLine(self):
  950. packed_message = unittest_pb2.OneString()
  951. packed_message.data = 'string'
  952. message = any_test_pb2.TestAny()
  953. message.any_value.Pack(packed_message)
  954. self.assertEqual(
  955. text_format.MessageToString(message,
  956. as_one_line=True,
  957. descriptor_pool=descriptor_pool.Default()),
  958. 'any_value {'
  959. ' [type.googleapis.com/protobuf_unittest.OneString]'
  960. ' { data: "string" } '
  961. '}')
  962. def testPrintMessageExpandAnyAsOneLinePointyBrackets(self):
  963. packed_message = unittest_pb2.OneString()
  964. packed_message.data = 'string'
  965. message = any_test_pb2.TestAny()
  966. message.any_value.Pack(packed_message)
  967. self.assertEqual(
  968. text_format.MessageToString(message,
  969. as_one_line=True,
  970. pointy_brackets=True,
  971. descriptor_pool=descriptor_pool.Default()),
  972. 'any_value <'
  973. ' [type.googleapis.com/protobuf_unittest.OneString]'
  974. ' < data: "string" > '
  975. '>')
  976. def testMergeExpandedAny(self):
  977. message = any_test_pb2.TestAny()
  978. text = ('any_value {\n'
  979. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  980. ' data: "string"\n'
  981. ' }\n'
  982. '}\n')
  983. text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
  984. packed_message = unittest_pb2.OneString()
  985. message.any_value.Unpack(packed_message)
  986. self.assertEqual('string', packed_message.data)
  987. def testMergeExpandedAnyRepeated(self):
  988. message = any_test_pb2.TestAny()
  989. text = ('repeated_any_value {\n'
  990. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  991. ' data: "string0"\n'
  992. ' }\n'
  993. '}\n'
  994. 'repeated_any_value {\n'
  995. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  996. ' data: "string1"\n'
  997. ' }\n'
  998. '}\n')
  999. text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
  1000. packed_message = unittest_pb2.OneString()
  1001. message.repeated_any_value[0].Unpack(packed_message)
  1002. self.assertEqual('string0', packed_message.data)
  1003. message.repeated_any_value[1].Unpack(packed_message)
  1004. self.assertEqual('string1', packed_message.data)
  1005. def testMergeExpandedAnyPointyBrackets(self):
  1006. message = any_test_pb2.TestAny()
  1007. text = ('any_value {\n'
  1008. ' [type.googleapis.com/protobuf_unittest.OneString] <\n'
  1009. ' data: "string"\n'
  1010. ' >\n'
  1011. '}\n')
  1012. text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
  1013. packed_message = unittest_pb2.OneString()
  1014. message.any_value.Unpack(packed_message)
  1015. self.assertEqual('string', packed_message.data)
  1016. def testMergeExpandedAnyNoDescriptorPool(self):
  1017. message = any_test_pb2.TestAny()
  1018. text = ('any_value {\n'
  1019. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  1020. ' data: "string"\n'
  1021. ' }\n'
  1022. '}\n')
  1023. with self.assertRaises(text_format.ParseError) as e:
  1024. text_format.Merge(text, message, descriptor_pool=None)
  1025. self.assertEqual(str(e.exception),
  1026. 'Descriptor pool required to parse expanded Any field')
  1027. def testMergeExpandedAnyDescriptorPoolMissingType(self):
  1028. message = any_test_pb2.TestAny()
  1029. text = ('any_value {\n'
  1030. ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
  1031. ' data: "string"\n'
  1032. ' }\n'
  1033. '}\n')
  1034. with self.assertRaises(text_format.ParseError) as e:
  1035. empty_pool = descriptor_pool.DescriptorPool()
  1036. text_format.Merge(text, message, descriptor_pool=empty_pool)
  1037. self.assertEqual(
  1038. str(e.exception),
  1039. 'Type protobuf_unittest.OneString not found in descriptor pool')
  1040. def testMergeUnexpandedAny(self):
  1041. text = ('any_value {\n'
  1042. ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
  1043. ' value: "\\n\\006string"\n'
  1044. '}\n')
  1045. message = any_test_pb2.TestAny()
  1046. text_format.Merge(text, message)
  1047. packed_message = unittest_pb2.OneString()
  1048. message.any_value.Unpack(packed_message)
  1049. self.assertEqual('string', packed_message.data)
  1050. class TokenizerTest(unittest.TestCase):
  1051. def testSimpleTokenCases(self):
  1052. text = ('identifier1:"string1"\n \n\n'
  1053. 'identifier2 : \n \n123 \n identifier3 :\'string\'\n'
  1054. 'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n'
  1055. 'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n'
  1056. 'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
  1057. 'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f '
  1058. 'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ')
  1059. tokenizer = text_format.Tokenizer(text.splitlines())
  1060. methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), ':',
  1061. (tokenizer.ConsumeString, 'string1'),
  1062. (tokenizer.ConsumeIdentifier, 'identifier2'), ':',
  1063. (tokenizer.ConsumeInteger, 123),
  1064. (tokenizer.ConsumeIdentifier, 'identifier3'), ':',
  1065. (tokenizer.ConsumeString, 'string'),
  1066. (tokenizer.ConsumeIdentifier, 'identifiER_4'), ':',
  1067. (tokenizer.ConsumeFloat, 1.1e+2),
  1068. (tokenizer.ConsumeIdentifier, 'ID5'), ':',
  1069. (tokenizer.ConsumeFloat, -0.23),
  1070. (tokenizer.ConsumeIdentifier, 'ID6'), ':',
  1071. (tokenizer.ConsumeString, 'aaaa\'bbbb'),
  1072. (tokenizer.ConsumeIdentifier, 'ID7'), ':',
  1073. (tokenizer.ConsumeString, 'aa\"bb'),
  1074. (tokenizer.ConsumeIdentifier, 'ID8'), ':', '{',
  1075. (tokenizer.ConsumeIdentifier, 'A'), ':',
  1076. (tokenizer.ConsumeFloat, float('inf')),
  1077. (tokenizer.ConsumeIdentifier, 'B'), ':',
  1078. (tokenizer.ConsumeFloat, -float('inf')),
  1079. (tokenizer.ConsumeIdentifier, 'C'), ':',
  1080. (tokenizer.ConsumeBool, True),
  1081. (tokenizer.ConsumeIdentifier, 'D'), ':',
  1082. (tokenizer.ConsumeBool, False), '}',
  1083. (tokenizer.ConsumeIdentifier, 'ID9'), ':',
  1084. (tokenizer.ConsumeInteger, 22),
  1085. (tokenizer.ConsumeIdentifier, 'ID10'), ':',
  1086. (tokenizer.ConsumeInteger, -111111111111111111),
  1087. (tokenizer.ConsumeIdentifier, 'ID11'), ':',
  1088. (tokenizer.ConsumeInteger, -22),
  1089. (tokenizer.ConsumeIdentifier, 'ID12'), ':',
  1090. (tokenizer.ConsumeInteger, 2222222222222222222),
  1091. (tokenizer.ConsumeIdentifier, 'ID13'), ':',
  1092. (tokenizer.ConsumeFloat, 1.23456),
  1093. (tokenizer.ConsumeIdentifier, 'ID14'), ':',
  1094. (tokenizer.ConsumeFloat, 1.2e+2),
  1095. (tokenizer.ConsumeIdentifier, 'false_bool'), ':',
  1096. (tokenizer.ConsumeBool, False),
  1097. (tokenizer.ConsumeIdentifier, 'true_BOOL'), ':',
  1098. (tokenizer.ConsumeBool, True),
  1099. (tokenizer.ConsumeIdentifier, 'true_bool1'), ':',
  1100. (tokenizer.ConsumeBool, True),
  1101. (tokenizer.ConsumeIdentifier, 'false_BOOL1'), ':',
  1102. (tokenizer.ConsumeBool, False)]
  1103. i = 0
  1104. while not tokenizer.AtEnd():
  1105. m = methods[i]
  1106. if isinstance(m, str):
  1107. token = tokenizer.token
  1108. self.assertEqual(token, m)
  1109. tokenizer.NextToken()
  1110. else:
  1111. self.assertEqual(m[1], m[0]())
  1112. i += 1
  1113. def testConsumeAbstractIntegers(self):
  1114. # This test only tests the failures in the integer parsing methods as well
  1115. # as the '0' special cases.
  1116. int64_max = (1 << 63) - 1
  1117. uint32_max = (1 << 32) - 1
  1118. text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
  1119. tokenizer = text_format.Tokenizer(text.splitlines())
  1120. self.assertEqual(-1, tokenizer.ConsumeInteger())
  1121. self.assertEqual(uint32_max + 1, tokenizer.ConsumeInteger())
  1122. self.assertEqual(int64_max + 1, tokenizer.ConsumeInteger())
  1123. self.assertTrue(tokenizer.AtEnd())
  1124. text = '-0 0'
  1125. tokenizer = text_format.Tokenizer(text.splitlines())
  1126. self.assertEqual(0, tokenizer.ConsumeInteger())
  1127. self.assertEqual(0, tokenizer.ConsumeInteger())
  1128. self.assertTrue(tokenizer.AtEnd())
  1129. def testConsumeIntegers(self):
  1130. # This test only tests the failures in the integer parsing methods as well
  1131. # as the '0' special cases.
  1132. int64_max = (1 << 63) - 1
  1133. uint32_max = (1 << 32) - 1
  1134. text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
  1135. tokenizer = text_format.Tokenizer(text.splitlines())
  1136. self.assertRaises(text_format.ParseError,
  1137. text_format._ConsumeUint32, tokenizer)
  1138. self.assertRaises(text_format.ParseError,
  1139. text_format._ConsumeUint64, tokenizer)
  1140. self.assertEqual(-1, text_format._ConsumeInt32(tokenizer))
  1141. self.assertRaises(text_format.ParseError,
  1142. text_format._ConsumeUint32, tokenizer)
  1143. self.assertRaises(text_format.ParseError,
  1144. text_format._ConsumeInt32, tokenizer)
  1145. self.assertEqual(uint32_max + 1, text_format._ConsumeInt64(tokenizer))
  1146. self.assertRaises(text_format.ParseError,
  1147. text_format._ConsumeInt64, tokenizer)
  1148. self.assertEqual(int64_max + 1, text_format._ConsumeUint64(tokenizer))
  1149. self.assertTrue(tokenizer.AtEnd())
  1150. text = '-0 -0 0 0'
  1151. tokenizer = text_format.Tokenizer(text.splitlines())
  1152. self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
  1153. self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
  1154. self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
  1155. self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
  1156. self.assertTrue(tokenizer.AtEnd())
  1157. def testConsumeByteString(self):
  1158. text = '"string1\''
  1159. tokenizer = text_format.Tokenizer(text.splitlines())
  1160. self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
  1161. text = 'string1"'
  1162. tokenizer = text_format.Tokenizer(text.splitlines())
  1163. self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
  1164. text = '\n"\\xt"'
  1165. tokenizer = text_format.Tokenizer(text.splitlines())
  1166. self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
  1167. text = '\n"\\"'
  1168. tokenizer = text_format.Tokenizer(text.splitlines())
  1169. self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
  1170. text = '\n"\\x"'
  1171. tokenizer = text_format.Tokenizer(text.splitlines())
  1172. self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
  1173. def testConsumeBool(self):
  1174. text = 'not-a-bool'
  1175. tokenizer = text_format.Tokenizer(text.splitlines())
  1176. self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
  1177. def testSkipComment(self):
  1178. tokenizer = text_format.Tokenizer('# some comment'.splitlines())
  1179. self.assertTrue(tokenizer.AtEnd())
  1180. self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
  1181. def testConsumeComment(self):
  1182. tokenizer = text_format.Tokenizer('# some comment'.splitlines(),
  1183. skip_comments=False)
  1184. self.assertFalse(tokenizer.AtEnd())
  1185. self.assertEqual('# some comment', tokenizer.ConsumeComment())
  1186. self.assertTrue(tokenizer.AtEnd())
  1187. def testConsumeTwoComments(self):
  1188. text = '# some comment\n# another comment'
  1189. tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
  1190. self.assertEqual('# some comment', tokenizer.ConsumeComment())
  1191. self.assertFalse(tokenizer.AtEnd())
  1192. self.assertEqual('# another comment', tokenizer.ConsumeComment())
  1193. self.assertTrue(tokenizer.AtEnd())
  1194. def testConsumeTrailingComment(self):
  1195. text = 'some_number: 4\n# some comment'
  1196. tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
  1197. self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
  1198. self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
  1199. self.assertEqual(tokenizer.token, ':')
  1200. tokenizer.NextToken()
  1201. self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
  1202. self.assertEqual(4, tokenizer.ConsumeInteger())
  1203. self.assertFalse(tokenizer.AtEnd())
  1204. self.assertEqual('# some comment', tokenizer.ConsumeComment())
  1205. self.assertTrue(tokenizer.AtEnd())
  1206. if __name__ == '__main__':
  1207. unittest.main()