TextFormatTest.cs 17 KB

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