TextFormatTest.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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 ParseCompatibility() {
  201. string original = "repeated_float: inf\n" +
  202. "repeated_float: -inf\n" +
  203. "repeated_float: nan\n" +
  204. "repeated_float: inff\n" +
  205. "repeated_float: -inff\n" +
  206. "repeated_float: nanf\n" +
  207. "repeated_float: 1.0f\n" +
  208. "repeated_float: infinityf\n" +
  209. "repeated_float: -Infinityf\n" +
  210. "repeated_double: infinity\n" +
  211. "repeated_double: -infinity\n" +
  212. "repeated_double: nan\n";
  213. string canonical = "repeated_float: Infinity\n" +
  214. "repeated_float: -Infinity\n" +
  215. "repeated_float: NaN\n" +
  216. "repeated_float: Infinity\n" +
  217. "repeated_float: -Infinity\n" +
  218. "repeated_float: NaN\n" +
  219. "repeated_float: 1\n" + // Java has 1.0; this is fine
  220. "repeated_float: Infinity\n" +
  221. "repeated_float: -Infinity\n" +
  222. "repeated_double: Infinity\n" +
  223. "repeated_double: -Infinity\n" +
  224. "repeated_double: NaN\n";
  225. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  226. TextFormat.Merge(original, builder);
  227. Assert.AreEqual(canonical, builder.Build().ToString());
  228. }
  229. [Test]
  230. public void ParseExotic() {
  231. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  232. TextFormat.Merge(ExoticText, builder);
  233. // Too lazy to check things individually. Don't try to debug this
  234. // if testPrintExotic() is Assert.Failing.
  235. Assert.AreEqual(ExoticText, builder.Build().ToString());
  236. }
  237. [Test]
  238. public void ParseMessageSet() {
  239. ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
  240. extensionRegistry.Add(TestMessageSetExtension1.MessageSetExtension);
  241. extensionRegistry.Add(TestMessageSetExtension2.MessageSetExtension);
  242. TestMessageSet.Builder builder = TestMessageSet.CreateBuilder();
  243. TextFormat.Merge(MessageSetText, extensionRegistry, builder);
  244. TestMessageSet messageSet = builder.Build();
  245. Assert.IsTrue(messageSet.HasExtension(TestMessageSetExtension1.MessageSetExtension));
  246. Assert.AreEqual(123, messageSet.GetExtension(TestMessageSetExtension1.MessageSetExtension).I);
  247. Assert.IsTrue(messageSet.HasExtension(TestMessageSetExtension2.MessageSetExtension));
  248. Assert.AreEqual("foo", messageSet.GetExtension(TestMessageSetExtension2.MessageSetExtension).Str);
  249. }
  250. [Test]
  251. public void ParseNumericEnum() {
  252. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  253. TextFormat.Merge("optional_nested_enum: 2", builder);
  254. Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR, builder.OptionalNestedEnum);
  255. }
  256. [Test]
  257. public void ParseAngleBrackets() {
  258. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  259. TextFormat.Merge("OptionalGroup: < a: 1 >", builder);
  260. Assert.IsTrue(builder.HasOptionalGroup);
  261. Assert.AreEqual(1, builder.OptionalGroup.A);
  262. }
  263. [Test]
  264. public void ParseComment() {
  265. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  266. TextFormat.Merge(
  267. "# this is a comment\n" +
  268. "optional_int32: 1 # another comment\n" +
  269. "optional_int64: 2\n" +
  270. "# EOF comment", builder);
  271. Assert.AreEqual(1, builder.OptionalInt32);
  272. Assert.AreEqual(2, builder.OptionalInt64);
  273. }
  274. private static void AssertParseError(string error, string text) {
  275. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  276. try {
  277. TextFormat.Merge(text, TestUtil.CreateExtensionRegistry(), builder);
  278. Assert.Fail("Expected parse exception.");
  279. } catch (FormatException e) {
  280. Assert.AreEqual(error, e.Message);
  281. }
  282. }
  283. [Test]
  284. public void ParseErrors() {
  285. AssertParseError(
  286. "1:16: Expected \":\".",
  287. "optional_int32 123");
  288. AssertParseError(
  289. "1:23: Expected identifier.",
  290. "optional_nested_enum: ?");
  291. AssertParseError(
  292. "1:18: Couldn't parse integer: Number must be positive: -1",
  293. "optional_uint32: -1");
  294. AssertParseError(
  295. "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
  296. "integer: 82301481290849012385230157",
  297. "optional_int32: 82301481290849012385230157");
  298. AssertParseError(
  299. "1:16: Expected \"true\" or \"false\".",
  300. "optional_bool: maybe");
  301. AssertParseError(
  302. "1:18: Expected string.",
  303. "optional_string: 123");
  304. AssertParseError(
  305. "1:18: String missing ending quote.",
  306. "optional_string: \"ueoauaoe");
  307. AssertParseError(
  308. "1:18: String missing ending quote.",
  309. "optional_string: \"ueoauaoe\n" +
  310. "optional_int32: 123");
  311. AssertParseError(
  312. "1:18: Invalid escape sequence: '\\z'",
  313. "optional_string: \"\\z\"");
  314. AssertParseError(
  315. "1:18: String missing ending quote.",
  316. "optional_string: \"ueoauaoe\n" +
  317. "optional_int32: 123");
  318. AssertParseError(
  319. "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
  320. "[nosuchext]: 123");
  321. AssertParseError(
  322. "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
  323. "not extend message type \"protobuf_unittest.TestAllTypes\".",
  324. "[protobuf_unittest.optional_int32_extension]: 123");
  325. AssertParseError(
  326. "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
  327. "named \"nosuchfield\".",
  328. "nosuchfield: 123");
  329. AssertParseError(
  330. "1:21: Expected \">\".",
  331. "OptionalGroup < a: 1");
  332. AssertParseError(
  333. "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
  334. "value named \"NO_SUCH_VALUE\".",
  335. "optional_nested_enum: NO_SUCH_VALUE");
  336. AssertParseError(
  337. "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
  338. "value with number 123.",
  339. "optional_nested_enum: 123");
  340. // Delimiters must match.
  341. AssertParseError(
  342. "1:22: Expected identifier.",
  343. "OptionalGroup < a: 1 }");
  344. AssertParseError(
  345. "1:22: Expected identifier.",
  346. "OptionalGroup { a: 1 >");
  347. }
  348. // =================================================================
  349. private static ByteString Bytes(params byte[] bytes) {
  350. return ByteString.CopyFrom(bytes);
  351. }
  352. private delegate void FormattingAction();
  353. private static void AssertFormatException(FormattingAction action) {
  354. try {
  355. action();
  356. Assert.Fail("Should have thrown an exception.");
  357. } catch (FormatException) {
  358. // success
  359. }
  360. }
  361. [Test]
  362. public void Escape() {
  363. // Escape sequences.
  364. Assert.AreEqual("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
  365. TextFormat.EscapeBytes(Bytes("\0\u0001\u0007\b\f\n\r\t\v\\\'\"")));
  366. Assert.AreEqual("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
  367. TextFormat.EscapeText("\0\u0001\u0007\b\f\n\r\t\v\\\'\""));
  368. Assert.AreEqual(Bytes("\0\u0001\u0007\b\f\n\r\t\v\\\'\""),
  369. TextFormat.UnescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
  370. Assert.AreEqual("\0\u0001\u0007\b\f\n\r\t\v\\\'\"",
  371. TextFormat.UnescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
  372. // Unicode handling.
  373. Assert.AreEqual("\\341\\210\\264", TextFormat.EscapeText("\u1234"));
  374. Assert.AreEqual("\\341\\210\\264", TextFormat.EscapeBytes(Bytes(0xe1, 0x88, 0xb4)));
  375. Assert.AreEqual("\u1234", TextFormat.UnescapeText("\\341\\210\\264"));
  376. Assert.AreEqual(Bytes(0xe1, 0x88, 0xb4), TextFormat.UnescapeBytes("\\341\\210\\264"));
  377. Assert.AreEqual("\u1234", TextFormat.UnescapeText("\\xe1\\x88\\xb4"));
  378. Assert.AreEqual(Bytes(0xe1, 0x88, 0xb4), TextFormat.UnescapeBytes("\\xe1\\x88\\xb4"));
  379. // Errors.
  380. AssertFormatException(() => TextFormat.UnescapeText("\\x"));
  381. AssertFormatException(() => TextFormat.UnescapeText("\\z"));
  382. AssertFormatException(() => TextFormat.UnescapeText("\\"));
  383. }
  384. [Test]
  385. public void ParseInteger() {
  386. Assert.AreEqual( 0, TextFormat.ParseInt32( "0"));
  387. Assert.AreEqual( 1, TextFormat.ParseInt32( "1"));
  388. Assert.AreEqual( -1, TextFormat.ParseInt32( "-1"));
  389. Assert.AreEqual( 12345, TextFormat.ParseInt32( "12345"));
  390. Assert.AreEqual( -12345, TextFormat.ParseInt32( "-12345"));
  391. Assert.AreEqual( 2147483647, TextFormat.ParseInt32( "2147483647"));
  392. Assert.AreEqual(-2147483648, TextFormat.ParseInt32("-2147483648"));
  393. Assert.AreEqual( 0, TextFormat.ParseUInt32( "0"));
  394. Assert.AreEqual( 1, TextFormat.ParseUInt32( "1"));
  395. Assert.AreEqual( 12345, TextFormat.ParseUInt32( "12345"));
  396. Assert.AreEqual( 2147483647, TextFormat.ParseUInt32("2147483647"));
  397. Assert.AreEqual(2147483648U, TextFormat.ParseUInt32("2147483648"));
  398. Assert.AreEqual(4294967295U, TextFormat.ParseUInt32("4294967295"));
  399. Assert.AreEqual( 0L, TextFormat.ParseInt64( "0"));
  400. Assert.AreEqual( 1L, TextFormat.ParseInt64( "1"));
  401. Assert.AreEqual( -1L, TextFormat.ParseInt64( "-1"));
  402. Assert.AreEqual( 12345L, TextFormat.ParseInt64( "12345"));
  403. Assert.AreEqual( -12345L, TextFormat.ParseInt64( "-12345"));
  404. Assert.AreEqual( 2147483647L, TextFormat.ParseInt64( "2147483647"));
  405. Assert.AreEqual(-2147483648L, TextFormat.ParseInt64("-2147483648"));
  406. Assert.AreEqual( 4294967295L, TextFormat.ParseInt64( "4294967295"));
  407. Assert.AreEqual( 4294967296L, TextFormat.ParseInt64( "4294967296"));
  408. Assert.AreEqual(9223372036854775807L, TextFormat.ParseInt64("9223372036854775807"));
  409. Assert.AreEqual(-9223372036854775808L, TextFormat.ParseInt64("-9223372036854775808"));
  410. Assert.AreEqual( 0L, TextFormat.ParseUInt64( "0"));
  411. Assert.AreEqual( 1L, TextFormat.ParseUInt64( "1"));
  412. Assert.AreEqual( 12345L, TextFormat.ParseUInt64( "12345"));
  413. Assert.AreEqual( 2147483647L, TextFormat.ParseUInt64( "2147483647"));
  414. Assert.AreEqual( 4294967295L, TextFormat.ParseUInt64( "4294967295"));
  415. Assert.AreEqual( 4294967296L, TextFormat.ParseUInt64( "4294967296"));
  416. Assert.AreEqual(9223372036854775807UL, TextFormat.ParseUInt64("9223372036854775807"));
  417. Assert.AreEqual(9223372036854775808UL, TextFormat.ParseUInt64("9223372036854775808"));
  418. Assert.AreEqual(18446744073709551615UL, TextFormat.ParseUInt64("18446744073709551615"));
  419. // Hex
  420. Assert.AreEqual(0x1234abcd, TextFormat.ParseInt32("0x1234abcd"));
  421. Assert.AreEqual(-0x1234abcd, TextFormat.ParseInt32("-0x1234abcd"));
  422. Assert.AreEqual(0xffffffffffffffffUL, TextFormat.ParseUInt64("0xffffffffffffffff"));
  423. Assert.AreEqual(0x7fffffffffffffffL,
  424. TextFormat.ParseInt64("0x7fffffffffffffff"));
  425. // Octal
  426. Assert.AreEqual(342391, TextFormat.ParseInt32("01234567"));
  427. // Out-of-range
  428. AssertFormatException(() => TextFormat.ParseInt32("2147483648"));
  429. AssertFormatException(() => TextFormat.ParseInt32("-2147483649"));
  430. AssertFormatException(() => TextFormat.ParseUInt32("4294967296"));
  431. AssertFormatException(() => TextFormat.ParseUInt32("-1"));
  432. AssertFormatException(() => TextFormat.ParseInt64("9223372036854775808"));
  433. AssertFormatException(() => TextFormat.ParseInt64("-9223372036854775809"));
  434. AssertFormatException(() => TextFormat.ParseUInt64("18446744073709551616"));
  435. AssertFormatException(() => TextFormat.ParseUInt64("-1"));
  436. AssertFormatException(() => TextFormat.ParseInt32("abcd"));
  437. }
  438. }
  439. }