TextFormatTest.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. using System;
  17. using System.IO;
  18. using System.Text;
  19. using Google.ProtocolBuffers.TestProtos;
  20. using NUnit.Framework;
  21. namespace Google.ProtocolBuffers {
  22. [TestFixture]
  23. public class TextFormatTest {
  24. private static readonly string AllFieldsSetText = TestUtil.ReadTextFromFile("text_format_unittest_data.txt");
  25. private static readonly string AllExtensionsSetText = TestUtil.ReadTextFromFile("text_format_unittest_extensions_data.txt");
  26. /// <summary>
  27. /// Note that this is slightly different to the Java - 123.0 becomes 123, and 1.23E17 becomes 1.23E+17.
  28. /// Both of these differences can be parsed by the Java and the C++, and we can parse their output too.
  29. /// </summary>
  30. private const string ExoticText =
  31. "repeated_int32: -1\n" +
  32. "repeated_int32: -2147483648\n" +
  33. "repeated_int64: -1\n" +
  34. "repeated_int64: -9223372036854775808\n" +
  35. "repeated_uint32: 4294967295\n" +
  36. "repeated_uint32: 2147483648\n" +
  37. "repeated_uint64: 18446744073709551615\n" +
  38. "repeated_uint64: 9223372036854775808\n" +
  39. "repeated_double: 123\n" +
  40. "repeated_double: 123.5\n" +
  41. "repeated_double: 0.125\n" +
  42. "repeated_double: 1.23E+17\n" +
  43. "repeated_double: 1.235E+22\n" +
  44. "repeated_double: 1.235E-18\n" +
  45. "repeated_double: 123.456789\n" +
  46. "repeated_double: Infinity\n" +
  47. "repeated_double: -Infinity\n" +
  48. "repeated_double: NaN\n" +
  49. "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
  50. "\\341\\210\\264\"\n" +
  51. "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
  52. private const string MessageSetText =
  53. "[protobuf_unittest.TestMessageSetExtension1] {\n" +
  54. " i: 123\n" +
  55. "}\n" +
  56. "[protobuf_unittest.TestMessageSetExtension2] {\n" +
  57. " str: \"foo\"\n" +
  58. "}\n";
  59. /// <summary>
  60. /// Print TestAllTypes and compare with golden file.
  61. /// </summary>
  62. [Test]
  63. public void PrintMessage() {
  64. string text = TextFormat.PrintToString(TestUtil.GetAllSet());
  65. Assert.AreEqual(AllFieldsSetText.Replace("\r\n", "\n"), text.Replace("\r\n", "\n"));
  66. }
  67. /// <summary>
  68. /// Print TestAllExtensions and compare with golden file.
  69. /// </summary>
  70. [Test]
  71. public void PrintExtensions() {
  72. string text = TextFormat.PrintToString(TestUtil.GetAllExtensionsSet());
  73. Assert.AreEqual(AllExtensionsSetText.Replace("\r\n", "\n"), text.Replace("\r\n", "\n"));
  74. }
  75. /// <summary>
  76. /// Test printing of unknown fields in a message.
  77. /// </summary>
  78. [Test]
  79. public void PrintUnknownFields() {
  80. TestEmptyMessage message =
  81. TestEmptyMessage.CreateBuilder()
  82. .SetUnknownFields(
  83. UnknownFieldSet.CreateBuilder()
  84. .AddField(5,
  85. UnknownField.CreateBuilder()
  86. .AddVarint(1)
  87. .AddFixed32(2)
  88. .AddFixed64(3)
  89. .AddLengthDelimited(ByteString.CopyFromUtf8("4"))
  90. .AddGroup(
  91. UnknownFieldSet.CreateBuilder()
  92. .AddField(10,
  93. UnknownField.CreateBuilder()
  94. .AddVarint(5)
  95. .Build())
  96. .Build())
  97. .Build())
  98. .AddField(8,
  99. UnknownField.CreateBuilder()
  100. .AddVarint(1)
  101. .AddVarint(2)
  102. .AddVarint(3)
  103. .Build())
  104. .AddField(15,
  105. UnknownField.CreateBuilder()
  106. .AddVarint(0xABCDEF1234567890L)
  107. .AddFixed32(0xABCD1234)
  108. .AddFixed64(0xABCDEF1234567890L)
  109. .Build())
  110. .Build())
  111. .Build();
  112. Assert.AreEqual(
  113. "5: 1\n" +
  114. "5: 0x00000002\n" +
  115. "5: 0x0000000000000003\n" +
  116. "5: \"4\"\n" +
  117. "5 {\n" +
  118. " 10: 5\n" +
  119. "}\n" +
  120. "8: 1\n" +
  121. "8: 2\n" +
  122. "8: 3\n" +
  123. "15: 12379813812177893520\n" +
  124. "15: 0xabcd1234\n" +
  125. "15: 0xabcdef1234567890\n",
  126. TextFormat.PrintToString(message));
  127. }
  128. /// <summary>
  129. /// Helper to construct a ByteString from a string containing only 8-bit
  130. /// characters. The characters are converted directly to bytes, *not*
  131. /// encoded using UTF-8.
  132. /// </summary>
  133. private static ByteString Bytes(string str) {
  134. return ByteString.CopyFrom(Encoding.GetEncoding(28591).GetBytes(str));
  135. }
  136. [Test]
  137. public void PrintExotic() {
  138. IMessage message = TestAllTypes.CreateBuilder()
  139. // Signed vs. unsigned numbers.
  140. .AddRepeatedInt32 (-1)
  141. .AddRepeatedUint32(uint.MaxValue)
  142. .AddRepeatedInt64 (-1)
  143. .AddRepeatedUint64(ulong.MaxValue)
  144. .AddRepeatedInt32 (1 << 31)
  145. .AddRepeatedUint32(1U << 31)
  146. .AddRepeatedInt64 (1L << 63)
  147. .AddRepeatedUint64(1UL << 63)
  148. // Floats of various precisions and exponents.
  149. .AddRepeatedDouble(123)
  150. .AddRepeatedDouble(123.5)
  151. .AddRepeatedDouble(0.125)
  152. .AddRepeatedDouble(123e15)
  153. .AddRepeatedDouble(123.5e20)
  154. .AddRepeatedDouble(123.5e-20)
  155. .AddRepeatedDouble(123.456789)
  156. .AddRepeatedDouble(Double.PositiveInfinity)
  157. .AddRepeatedDouble(Double.NegativeInfinity)
  158. .AddRepeatedDouble(Double.NaN)
  159. // Strings and bytes that needing escaping.
  160. .AddRepeatedString("\0\u0001\u0007\b\f\n\r\t\v\\\'\"\u1234")
  161. .AddRepeatedBytes(Bytes("\0\u0001\u0007\b\f\n\r\t\v\\\'\"\u00fe"))
  162. .Build();
  163. Assert.AreEqual(ExoticText, message.ToString());
  164. }
  165. [Test]
  166. public void PrintMessageSet() {
  167. TestMessageSet messageSet =
  168. TestMessageSet.CreateBuilder()
  169. .SetExtension(
  170. TestMessageSetExtension1.MessageSetExtension,
  171. TestMessageSetExtension1.CreateBuilder().SetI(123).Build())
  172. .SetExtension(
  173. TestMessageSetExtension2.MessageSetExtension,
  174. TestMessageSetExtension2.CreateBuilder().SetStr("foo").Build())
  175. .Build();
  176. Assert.AreEqual(MessageSetText, messageSet.ToString());
  177. }
  178. // =================================================================
  179. [Test]
  180. public void Parse() {
  181. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  182. TextFormat.Merge(AllFieldsSetText, builder);
  183. TestUtil.AssertAllFieldsSet(builder.Build());
  184. }
  185. [Test]
  186. public void ParseReader() {
  187. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  188. TextFormat.Merge(new StringReader(AllFieldsSetText), builder);
  189. TestUtil.AssertAllFieldsSet(builder.Build());
  190. }
  191. [Test]
  192. public void ParseExtensions() {
  193. TestAllExtensions.Builder builder = TestAllExtensions.CreateBuilder();
  194. TextFormat.Merge(AllExtensionsSetText,
  195. TestUtil.CreateExtensionRegistry(),
  196. builder);
  197. TestUtil.AssertAllExtensionsSet(builder.Build());
  198. }
  199. [Test]
  200. public void ParseExotic() {
  201. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  202. TextFormat.Merge(ExoticText, builder);
  203. // Too lazy to check things individually. Don't try to debug this
  204. // if testPrintExotic() is Assert.Failing.
  205. Assert.AreEqual(ExoticText, builder.Build().ToString());
  206. }
  207. [Test]
  208. public void ParseMessageSet() {
  209. ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
  210. extensionRegistry.Add(TestMessageSetExtension1.MessageSetExtension);
  211. extensionRegistry.Add(TestMessageSetExtension2.MessageSetExtension);
  212. TestMessageSet.Builder builder = TestMessageSet.CreateBuilder();
  213. TextFormat.Merge(MessageSetText, extensionRegistry, builder);
  214. TestMessageSet messageSet = builder.Build();
  215. Assert.IsTrue(messageSet.HasExtension(TestMessageSetExtension1.MessageSetExtension));
  216. Assert.AreEqual(123, messageSet.GetExtension(TestMessageSetExtension1.MessageSetExtension).I);
  217. Assert.IsTrue(messageSet.HasExtension(TestMessageSetExtension2.MessageSetExtension));
  218. Assert.AreEqual("foo", messageSet.GetExtension(TestMessageSetExtension2.MessageSetExtension).Str);
  219. }
  220. [Test]
  221. public void ParseNumericEnum() {
  222. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  223. TextFormat.Merge("optional_nested_enum: 2", builder);
  224. Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR, builder.OptionalNestedEnum);
  225. }
  226. [Test]
  227. public void ParseAngleBrackets() {
  228. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  229. TextFormat.Merge("OptionalGroup: < a: 1 >", builder);
  230. Assert.IsTrue(builder.HasOptionalGroup);
  231. Assert.AreEqual(1, builder.OptionalGroup.A);
  232. }
  233. private static void AssertParseError(string error, string text) {
  234. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  235. try {
  236. TextFormat.Merge(text, TestUtil.CreateExtensionRegistry(), builder);
  237. Assert.Fail("Expected parse exception.");
  238. } catch (FormatException e) {
  239. Assert.AreEqual(error, e.Message);
  240. }
  241. }
  242. [Test]
  243. public void ParseErrors() {
  244. AssertParseError(
  245. "1:16: Expected \":\".",
  246. "optional_int32 123");
  247. AssertParseError(
  248. "1:23: Expected identifier.",
  249. "optional_nested_enum: ?");
  250. AssertParseError(
  251. "1:18: Couldn't parse integer: Number must be positive: -1",
  252. "optional_uint32: -1");
  253. AssertParseError(
  254. "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
  255. "integer: 82301481290849012385230157",
  256. "optional_int32: 82301481290849012385230157");
  257. AssertParseError(
  258. "1:16: Expected \"true\" or \"false\".",
  259. "optional_bool: maybe");
  260. AssertParseError(
  261. "1:18: Expected string.",
  262. "optional_string: 123");
  263. AssertParseError(
  264. "1:18: String missing ending quote.",
  265. "optional_string: \"ueoauaoe");
  266. AssertParseError(
  267. "1:18: String missing ending quote.",
  268. "optional_string: \"ueoauaoe\n" +
  269. "optional_int32: 123");
  270. AssertParseError(
  271. "1:18: Invalid escape sequence: '\\z'",
  272. "optional_string: \"\\z\"");
  273. AssertParseError(
  274. "1:18: String missing ending quote.",
  275. "optional_string: \"ueoauaoe\n" +
  276. "optional_int32: 123");
  277. AssertParseError(
  278. "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
  279. "[nosuchext]: 123");
  280. AssertParseError(
  281. "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
  282. "not extend message type \"protobuf_unittest.TestAllTypes\".",
  283. "[protobuf_unittest.optional_int32_extension]: 123");
  284. AssertParseError(
  285. "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
  286. "named \"nosuchfield\".",
  287. "nosuchfield: 123");
  288. AssertParseError(
  289. "1:21: Expected \">\".",
  290. "OptionalGroup < a: 1");
  291. AssertParseError(
  292. "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
  293. "value named \"NO_SUCH_VALUE\".",
  294. "optional_nested_enum: NO_SUCH_VALUE");
  295. AssertParseError(
  296. "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
  297. "value with number 123.",
  298. "optional_nested_enum: 123");
  299. // Delimiters must match.
  300. AssertParseError(
  301. "1:22: Expected identifier.",
  302. "OptionalGroup < a: 1 }");
  303. AssertParseError(
  304. "1:22: Expected identifier.",
  305. "OptionalGroup { a: 1 >");
  306. }
  307. // =================================================================
  308. private static ByteString Bytes(params byte[] bytes) {
  309. return ByteString.CopyFrom(bytes);
  310. }
  311. private delegate void FormattingAction();
  312. private static void AssertFormatException(FormattingAction action) {
  313. try {
  314. action();
  315. Assert.Fail("Should have thrown an exception.");
  316. } catch (FormatException) {
  317. // success
  318. }
  319. }
  320. [Test]
  321. public void Escape() {
  322. // Escape sequences.
  323. Assert.AreEqual("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
  324. TextFormat.EscapeBytes(Bytes("\0\u0001\u0007\b\f\n\r\t\v\\\'\"")));
  325. Assert.AreEqual("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
  326. TextFormat.EscapeText("\0\u0001\u0007\b\f\n\r\t\v\\\'\""));
  327. Assert.AreEqual(Bytes("\0\u0001\u0007\b\f\n\r\t\v\\\'\""),
  328. TextFormat.UnescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
  329. Assert.AreEqual("\0\u0001\u0007\b\f\n\r\t\v\\\'\"",
  330. TextFormat.UnescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
  331. // Unicode handling.
  332. Assert.AreEqual("\\341\\210\\264", TextFormat.EscapeText("\u1234"));
  333. Assert.AreEqual("\\341\\210\\264", TextFormat.EscapeBytes(Bytes(0xe1, 0x88, 0xb4)));
  334. Assert.AreEqual("\u1234", TextFormat.UnescapeText("\\341\\210\\264"));
  335. Assert.AreEqual(Bytes(0xe1, 0x88, 0xb4), TextFormat.UnescapeBytes("\\341\\210\\264"));
  336. Assert.AreEqual("\u1234", TextFormat.UnescapeText("\\xe1\\x88\\xb4"));
  337. Assert.AreEqual(Bytes(0xe1, 0x88, 0xb4), TextFormat.UnescapeBytes("\\xe1\\x88\\xb4"));
  338. // Errors.
  339. AssertFormatException(() => TextFormat.UnescapeText("\\x"));
  340. AssertFormatException(() => TextFormat.UnescapeText("\\z"));
  341. AssertFormatException(() => TextFormat.UnescapeText("\\"));
  342. }
  343. [Test]
  344. public void ParseInteger() {
  345. Assert.AreEqual( 0, TextFormat.ParseInt32( "0"));
  346. Assert.AreEqual( 1, TextFormat.ParseInt32( "1"));
  347. Assert.AreEqual( -1, TextFormat.ParseInt32( "-1"));
  348. Assert.AreEqual( 12345, TextFormat.ParseInt32( "12345"));
  349. Assert.AreEqual( -12345, TextFormat.ParseInt32( "-12345"));
  350. Assert.AreEqual( 2147483647, TextFormat.ParseInt32( "2147483647"));
  351. Assert.AreEqual(-2147483648, TextFormat.ParseInt32("-2147483648"));
  352. Assert.AreEqual( 0, TextFormat.ParseUInt32( "0"));
  353. Assert.AreEqual( 1, TextFormat.ParseUInt32( "1"));
  354. Assert.AreEqual( 12345, TextFormat.ParseUInt32( "12345"));
  355. Assert.AreEqual( 2147483647, TextFormat.ParseUInt32("2147483647"));
  356. Assert.AreEqual(2147483648U, TextFormat.ParseUInt32("2147483648"));
  357. Assert.AreEqual(4294967295U, TextFormat.ParseUInt32("4294967295"));
  358. Assert.AreEqual( 0L, TextFormat.ParseInt64( "0"));
  359. Assert.AreEqual( 1L, TextFormat.ParseInt64( "1"));
  360. Assert.AreEqual( -1L, TextFormat.ParseInt64( "-1"));
  361. Assert.AreEqual( 12345L, TextFormat.ParseInt64( "12345"));
  362. Assert.AreEqual( -12345L, TextFormat.ParseInt64( "-12345"));
  363. Assert.AreEqual( 2147483647L, TextFormat.ParseInt64( "2147483647"));
  364. Assert.AreEqual(-2147483648L, TextFormat.ParseInt64("-2147483648"));
  365. Assert.AreEqual( 4294967295L, TextFormat.ParseInt64( "4294967295"));
  366. Assert.AreEqual( 4294967296L, TextFormat.ParseInt64( "4294967296"));
  367. Assert.AreEqual(9223372036854775807L, TextFormat.ParseInt64("9223372036854775807"));
  368. Assert.AreEqual(-9223372036854775808L, TextFormat.ParseInt64("-9223372036854775808"));
  369. Assert.AreEqual( 0L, TextFormat.ParseUInt64( "0"));
  370. Assert.AreEqual( 1L, TextFormat.ParseUInt64( "1"));
  371. Assert.AreEqual( 12345L, TextFormat.ParseUInt64( "12345"));
  372. Assert.AreEqual( 2147483647L, TextFormat.ParseUInt64( "2147483647"));
  373. Assert.AreEqual( 4294967295L, TextFormat.ParseUInt64( "4294967295"));
  374. Assert.AreEqual( 4294967296L, TextFormat.ParseUInt64( "4294967296"));
  375. Assert.AreEqual(9223372036854775807UL, TextFormat.ParseUInt64("9223372036854775807"));
  376. Assert.AreEqual(9223372036854775808UL, TextFormat.ParseUInt64("9223372036854775808"));
  377. Assert.AreEqual(18446744073709551615UL, TextFormat.ParseUInt64("18446744073709551615"));
  378. // Hex
  379. Assert.AreEqual(0x1234abcd, TextFormat.ParseInt32("0x1234abcd"));
  380. Assert.AreEqual(-0x1234abcd, TextFormat.ParseInt32("-0x1234abcd"));
  381. Assert.AreEqual(0xffffffffffffffffUL, TextFormat.ParseUInt64("0xffffffffffffffff"));
  382. Assert.AreEqual(0x7fffffffffffffffL,
  383. TextFormat.ParseInt64("0x7fffffffffffffff"));
  384. // Octal
  385. Assert.AreEqual(342391, TextFormat.ParseInt32("01234567"));
  386. // Out-of-range
  387. AssertFormatException(() => TextFormat.ParseInt32("2147483648"));
  388. AssertFormatException(() => TextFormat.ParseInt32("-2147483649"));
  389. AssertFormatException(() => TextFormat.ParseUInt32("4294967296"));
  390. AssertFormatException(() => TextFormat.ParseUInt32("-1"));
  391. AssertFormatException(() => TextFormat.ParseInt64("9223372036854775808"));
  392. AssertFormatException(() => TextFormat.ParseInt64("-9223372036854775809"));
  393. AssertFormatException(() => TextFormat.ParseUInt64("18446744073709551616"));
  394. AssertFormatException(() => TextFormat.ParseUInt64("-1"));
  395. AssertFormatException(() => TextFormat.ParseInt32("abcd"));
  396. }
  397. }
  398. }