CodedOutputStreamTest.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. #endregion
  32. using System;
  33. using System.IO;
  34. using Google.Protobuf.TestProtos;
  35. using NUnit.Framework;
  36. namespace Google.Protobuf
  37. {
  38. public class CodedOutputStreamTest
  39. {
  40. /// <summary>
  41. /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and
  42. /// checks that the result matches the given bytes
  43. /// </summary>
  44. private static void AssertWriteVarint(byte[] data, ulong value)
  45. {
  46. // Only do 32-bit write if the value fits in 32 bits.
  47. if ((value >> 32) == 0)
  48. {
  49. MemoryStream rawOutput = new MemoryStream();
  50. CodedOutputStream output = new CodedOutputStream(rawOutput);
  51. output.WriteRawVarint32((uint) value);
  52. output.Flush();
  53. Assert.AreEqual(data, rawOutput.ToArray());
  54. // Also try computing size.
  55. Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value));
  56. }
  57. {
  58. MemoryStream rawOutput = new MemoryStream();
  59. CodedOutputStream output = new CodedOutputStream(rawOutput);
  60. output.WriteRawVarint64(value);
  61. output.Flush();
  62. Assert.AreEqual(data, rawOutput.ToArray());
  63. // Also try computing size.
  64. Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value));
  65. }
  66. // Try different buffer sizes.
  67. for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)
  68. {
  69. // Only do 32-bit write if the value fits in 32 bits.
  70. if ((value >> 32) == 0)
  71. {
  72. MemoryStream rawOutput = new MemoryStream();
  73. CodedOutputStream output =
  74. new CodedOutputStream(rawOutput, bufferSize);
  75. output.WriteRawVarint32((uint) value);
  76. output.Flush();
  77. Assert.AreEqual(data, rawOutput.ToArray());
  78. }
  79. {
  80. MemoryStream rawOutput = new MemoryStream();
  81. CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize);
  82. output.WriteRawVarint64(value);
  83. output.Flush();
  84. Assert.AreEqual(data, rawOutput.ToArray());
  85. }
  86. }
  87. }
  88. /// <summary>
  89. /// Tests WriteRawVarint32() and WriteRawVarint64()
  90. /// </summary>
  91. [Test]
  92. public void WriteVarint()
  93. {
  94. AssertWriteVarint(new byte[] {0x00}, 0);
  95. AssertWriteVarint(new byte[] {0x01}, 1);
  96. AssertWriteVarint(new byte[] {0x7f}, 127);
  97. // 14882
  98. AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7));
  99. // 2961488830
  100. AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b},
  101. (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
  102. (0x0bL << 28));
  103. // 64-bit
  104. // 7256456126
  105. AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b},
  106. (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
  107. (0x1bL << 28));
  108. // 41256202580718336
  109. AssertWriteVarint(
  110. new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49},
  111. (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
  112. (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49));
  113. // 11964378330978735131
  114. AssertWriteVarint(
  115. new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01},
  116. unchecked((ulong)
  117. ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
  118. (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
  119. (0x05L << 49) | (0x26L << 56) | (0x01L << 63))));
  120. }
  121. /// <summary>
  122. /// Parses the given bytes using WriteRawLittleEndian32() and checks
  123. /// that the result matches the given value.
  124. /// </summary>
  125. private static void AssertWriteLittleEndian32(byte[] data, uint value)
  126. {
  127. MemoryStream rawOutput = new MemoryStream();
  128. CodedOutputStream output = new CodedOutputStream(rawOutput);
  129. output.WriteRawLittleEndian32(value);
  130. output.Flush();
  131. Assert.AreEqual(data, rawOutput.ToArray());
  132. // Try different buffer sizes.
  133. for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)
  134. {
  135. rawOutput = new MemoryStream();
  136. output = new CodedOutputStream(rawOutput, bufferSize);
  137. output.WriteRawLittleEndian32(value);
  138. output.Flush();
  139. Assert.AreEqual(data, rawOutput.ToArray());
  140. }
  141. }
  142. /// <summary>
  143. /// Parses the given bytes using WriteRawLittleEndian64() and checks
  144. /// that the result matches the given value.
  145. /// </summary>
  146. private static void AssertWriteLittleEndian64(byte[] data, ulong value)
  147. {
  148. MemoryStream rawOutput = new MemoryStream();
  149. CodedOutputStream output = new CodedOutputStream(rawOutput);
  150. output.WriteRawLittleEndian64(value);
  151. output.Flush();
  152. Assert.AreEqual(data, rawOutput.ToArray());
  153. // Try different block sizes.
  154. for (int blockSize = 1; blockSize <= 16; blockSize *= 2)
  155. {
  156. rawOutput = new MemoryStream();
  157. output = new CodedOutputStream(rawOutput, blockSize);
  158. output.WriteRawLittleEndian64(value);
  159. output.Flush();
  160. Assert.AreEqual(data, rawOutput.ToArray());
  161. }
  162. }
  163. /// <summary>
  164. /// Tests writeRawLittleEndian32() and writeRawLittleEndian64().
  165. /// </summary>
  166. [Test]
  167. public void WriteLittleEndian()
  168. {
  169. AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678);
  170. AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0);
  171. AssertWriteLittleEndian64(
  172. new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12},
  173. 0x123456789abcdef0L);
  174. AssertWriteLittleEndian64(
  175. new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a},
  176. 0x9abcdef012345678UL);
  177. }
  178. [Test]
  179. public void WriteWholeMessage_VaryingBlockSizes()
  180. {
  181. TestAllTypes message = SampleMessages.CreateFullTestAllTypes();
  182. byte[] rawBytes = message.ToByteArray();
  183. // Try different block sizes.
  184. for (int blockSize = 1; blockSize < 256; blockSize *= 2)
  185. {
  186. MemoryStream rawOutput = new MemoryStream();
  187. CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize);
  188. message.WriteTo(output);
  189. output.Flush();
  190. Assert.AreEqual(rawBytes, rawOutput.ToArray());
  191. }
  192. }
  193. [Test]
  194. public void EncodeZigZag32()
  195. {
  196. Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag32(0));
  197. Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag32(-1));
  198. Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag32(1));
  199. Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag32(-2));
  200. Assert.AreEqual(0x7FFFFFFEu, CodedOutputStream.EncodeZigZag32(0x3FFFFFFF));
  201. Assert.AreEqual(0x7FFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0xC0000000)));
  202. Assert.AreEqual(0xFFFFFFFEu, CodedOutputStream.EncodeZigZag32(0x7FFFFFFF));
  203. Assert.AreEqual(0xFFFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0x80000000)));
  204. }
  205. [Test]
  206. public void EncodeZigZag64()
  207. {
  208. Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag64(0));
  209. Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag64(-1));
  210. Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag64(1));
  211. Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag64(-2));
  212. Assert.AreEqual(0x000000007FFFFFFEuL,
  213. CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL)));
  214. Assert.AreEqual(0x000000007FFFFFFFuL,
  215. CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL)));
  216. Assert.AreEqual(0x00000000FFFFFFFEuL,
  217. CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL)));
  218. Assert.AreEqual(0x00000000FFFFFFFFuL,
  219. CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL)));
  220. Assert.AreEqual(0xFFFFFFFFFFFFFFFEL,
  221. CodedOutputStream.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL)));
  222. Assert.AreEqual(0xFFFFFFFFFFFFFFFFL,
  223. CodedOutputStream.EncodeZigZag64(unchecked((long) 0x8000000000000000UL)));
  224. }
  225. [Test]
  226. public void RoundTripZigZag32()
  227. {
  228. // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1)
  229. // were chosen semi-randomly via keyboard bashing.
  230. Assert.AreEqual(0, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(0)));
  231. Assert.AreEqual(1, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(1)));
  232. Assert.AreEqual(-1, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-1)));
  233. Assert.AreEqual(14927, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(14927)));
  234. Assert.AreEqual(-3612, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-3612)));
  235. }
  236. [Test]
  237. public void RoundTripZigZag64()
  238. {
  239. Assert.AreEqual(0, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(0)));
  240. Assert.AreEqual(1, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(1)));
  241. Assert.AreEqual(-1, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-1)));
  242. Assert.AreEqual(14927, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(14927)));
  243. Assert.AreEqual(-3612, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-3612)));
  244. Assert.AreEqual(856912304801416L,
  245. CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(856912304801416L)));
  246. Assert.AreEqual(-75123905439571256L,
  247. CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-75123905439571256L)));
  248. }
  249. [Test]
  250. public void TestNegativeEnumNoTag()
  251. {
  252. Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2));
  253. Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue));
  254. byte[] bytes = new byte[10];
  255. CodedOutputStream output = new CodedOutputStream(bytes);
  256. output.WriteEnum((int) SampleEnum.NegativeValue);
  257. Assert.AreEqual(0, output.SpaceLeft);
  258. Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes));
  259. }
  260. [Test]
  261. public void TestCodedInputOutputPosition()
  262. {
  263. byte[] content = new byte[110];
  264. for (int i = 0; i < content.Length; i++)
  265. content[i] = (byte)i;
  266. byte[] child = new byte[120];
  267. {
  268. MemoryStream ms = new MemoryStream(child);
  269. CodedOutputStream cout = new CodedOutputStream(ms, 20);
  270. // Field 11: numeric value: 500
  271. cout.WriteTag(11, WireFormat.WireType.Varint);
  272. Assert.AreEqual(1, cout.Position);
  273. cout.WriteInt32(500);
  274. Assert.AreEqual(3, cout.Position);
  275. //Field 12: length delimited 120 bytes
  276. cout.WriteTag(12, WireFormat.WireType.LengthDelimited);
  277. Assert.AreEqual(4, cout.Position);
  278. cout.WriteBytes(ByteString.CopyFrom(content));
  279. Assert.AreEqual(115, cout.Position);
  280. // Field 13: fixed numeric value: 501
  281. cout.WriteTag(13, WireFormat.WireType.Fixed32);
  282. Assert.AreEqual(116, cout.Position);
  283. cout.WriteSFixed32(501);
  284. Assert.AreEqual(120, cout.Position);
  285. cout.Flush();
  286. }
  287. byte[] bytes = new byte[130];
  288. {
  289. CodedOutputStream cout = new CodedOutputStream(bytes);
  290. // Field 1: numeric value: 500
  291. cout.WriteTag(1, WireFormat.WireType.Varint);
  292. Assert.AreEqual(1, cout.Position);
  293. cout.WriteInt32(500);
  294. Assert.AreEqual(3, cout.Position);
  295. //Field 2: length delimited 120 bytes
  296. cout.WriteTag(2, WireFormat.WireType.LengthDelimited);
  297. Assert.AreEqual(4, cout.Position);
  298. cout.WriteBytes(ByteString.CopyFrom(child));
  299. Assert.AreEqual(125, cout.Position);
  300. // Field 3: fixed numeric value: 500
  301. cout.WriteTag(3, WireFormat.WireType.Fixed32);
  302. Assert.AreEqual(126, cout.Position);
  303. cout.WriteSFixed32(501);
  304. Assert.AreEqual(130, cout.Position);
  305. cout.Flush();
  306. }
  307. // Now test Input stream:
  308. {
  309. CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0, false);
  310. Assert.AreEqual(0, cin.Position);
  311. // Field 1:
  312. uint tag = cin.ReadTag();
  313. Assert.AreEqual(1, tag >> 3);
  314. Assert.AreEqual(1, cin.Position);
  315. Assert.AreEqual(500, cin.ReadInt32());
  316. Assert.AreEqual(3, cin.Position);
  317. //Field 2:
  318. tag = cin.ReadTag();
  319. Assert.AreEqual(2, tag >> 3);
  320. Assert.AreEqual(4, cin.Position);
  321. int childlen = cin.ReadLength();
  322. Assert.AreEqual(120, childlen);
  323. Assert.AreEqual(5, cin.Position);
  324. int oldlimit = cin.PushLimit((int)childlen);
  325. Assert.AreEqual(5, cin.Position);
  326. // Now we are reading child message
  327. {
  328. // Field 11: numeric value: 500
  329. tag = cin.ReadTag();
  330. Assert.AreEqual(11, tag >> 3);
  331. Assert.AreEqual(6, cin.Position);
  332. Assert.AreEqual(500, cin.ReadInt32());
  333. Assert.AreEqual(8, cin.Position);
  334. //Field 12: length delimited 120 bytes
  335. tag = cin.ReadTag();
  336. Assert.AreEqual(12, tag >> 3);
  337. Assert.AreEqual(9, cin.Position);
  338. ByteString bstr = cin.ReadBytes();
  339. Assert.AreEqual(110, bstr.Length);
  340. Assert.AreEqual((byte) 109, bstr[109]);
  341. Assert.AreEqual(120, cin.Position);
  342. // Field 13: fixed numeric value: 501
  343. tag = cin.ReadTag();
  344. Assert.AreEqual(13, tag >> 3);
  345. // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit
  346. Assert.AreEqual(121, cin.Position);
  347. Assert.AreEqual(501, cin.ReadSFixed32());
  348. Assert.AreEqual(125, cin.Position);
  349. Assert.IsTrue(cin.IsAtEnd);
  350. }
  351. cin.PopLimit(oldlimit);
  352. Assert.AreEqual(125, cin.Position);
  353. // Field 3: fixed numeric value: 501
  354. tag = cin.ReadTag();
  355. Assert.AreEqual(3, tag >> 3);
  356. Assert.AreEqual(126, cin.Position);
  357. Assert.AreEqual(501, cin.ReadSFixed32());
  358. Assert.AreEqual(130, cin.Position);
  359. Assert.IsTrue(cin.IsAtEnd);
  360. }
  361. }
  362. [Test]
  363. public void Dispose_DisposesUnderlyingStream()
  364. {
  365. var memoryStream = new MemoryStream();
  366. Assert.IsTrue(memoryStream.CanWrite);
  367. using (var cos = new CodedOutputStream(memoryStream))
  368. {
  369. cos.WriteRawByte(0);
  370. Assert.AreEqual(0, memoryStream.Position); // Not flushed yet
  371. }
  372. Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream
  373. Assert.IsFalse(memoryStream.CanWrite); // Disposed
  374. }
  375. [Test]
  376. public void Dispose_WithLeaveOpen()
  377. {
  378. var memoryStream = new MemoryStream();
  379. Assert.IsTrue(memoryStream.CanWrite);
  380. using (var cos = new CodedOutputStream(memoryStream, true))
  381. {
  382. cos.WriteRawByte(0);
  383. Assert.AreEqual(0, memoryStream.Position); // Not flushed yet
  384. }
  385. Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream
  386. Assert.IsTrue(memoryStream.CanWrite); // We left the stream open
  387. }
  388. [Test]
  389. public void Dispose_FromByteArray()
  390. {
  391. var stream = new CodedOutputStream(new byte[10]);
  392. stream.Dispose();
  393. }
  394. }
  395. }