text_format_test.py 30 KB

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