text_format_test.py 30 KB

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