text_format_test.py 94 KB

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