TextFormatTest.cs 18 KB

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