RepeatedFieldTest.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2015 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.Collections;
  34. using System.Collections.Generic;
  35. using System.Collections.ObjectModel;
  36. using System.IO;
  37. using System.Linq;
  38. using System.Text;
  39. using Google.Protobuf.TestProtos;
  40. using Google.Protobuf.WellKnownTypes;
  41. using NUnit.Framework;
  42. namespace Google.Protobuf.Collections
  43. {
  44. public class RepeatedFieldTest
  45. {
  46. [Test]
  47. public void NullValuesRejected()
  48. {
  49. var list = new RepeatedField<string>();
  50. Assert.Throws<ArgumentNullException>(() => list.Add((string)null));
  51. Assert.Throws<ArgumentNullException>(() => list.Add((IEnumerable<string>)null));
  52. Assert.Throws<ArgumentNullException>(() => list.Add((RepeatedField<string>)null));
  53. Assert.Throws<ArgumentNullException>(() => list.Contains(null));
  54. Assert.Throws<ArgumentNullException>(() => list.IndexOf(null));
  55. }
  56. [Test]
  57. public void Add_SingleItem()
  58. {
  59. var list = new RepeatedField<string>();
  60. list.Add("foo");
  61. Assert.AreEqual(1, list.Count);
  62. Assert.AreEqual("foo", list[0]);
  63. }
  64. [Test]
  65. public void Add_Sequence()
  66. {
  67. var list = new RepeatedField<string>();
  68. list.Add(new[] { "foo", "bar" });
  69. Assert.AreEqual(2, list.Count);
  70. Assert.AreEqual("foo", list[0]);
  71. Assert.AreEqual("bar", list[1]);
  72. }
  73. [Test]
  74. public void AddRange_SlowPath()
  75. {
  76. var list = new RepeatedField<string>();
  77. list.AddRange(new[] { "foo", "bar" }.Select(x => x));
  78. Assert.AreEqual(2, list.Count);
  79. Assert.AreEqual("foo", list[0]);
  80. Assert.AreEqual("bar", list[1]);
  81. }
  82. [Test]
  83. public void AddRange_SlowPath_NullsProhibited_ReferenceType()
  84. {
  85. var list = new RepeatedField<string>();
  86. // It's okay for this to throw ArgumentNullException if necessary.
  87. // It's not ideal, but not awful.
  88. Assert.Catch<ArgumentException>(() => list.AddRange(new[] { "foo", null }.Select(x => x)));
  89. }
  90. [Test]
  91. public void AddRange_SlowPath_NullsProhibited_NullableValueType()
  92. {
  93. var list = new RepeatedField<int?>();
  94. // It's okay for this to throw ArgumentNullException if necessary.
  95. // It's not ideal, but not awful.
  96. Assert.Catch<ArgumentException>(() => list.AddRange(new[] { 20, (int?)null }.Select(x => x)));
  97. }
  98. [Test]
  99. public void AddRange_Optimized_NonNullableValueType()
  100. {
  101. var list = new RepeatedField<int>();
  102. list.AddRange(new List<int> { 20, 30 });
  103. Assert.AreEqual(2, list.Count);
  104. Assert.AreEqual(20, list[0]);
  105. Assert.AreEqual(30, list[1]);
  106. }
  107. [Test]
  108. public void AddRange_Optimized_ReferenceType()
  109. {
  110. var list = new RepeatedField<string>();
  111. list.AddRange(new List<string> { "foo", "bar" });
  112. Assert.AreEqual(2, list.Count);
  113. Assert.AreEqual("foo", list[0]);
  114. Assert.AreEqual("bar", list[1]);
  115. }
  116. [Test]
  117. public void AddRange_Optimized_NullableValueType()
  118. {
  119. var list = new RepeatedField<int?>();
  120. list.AddRange(new List<int?> { 20, 30 });
  121. Assert.AreEqual(2, list.Count);
  122. Assert.AreEqual((int?) 20, list[0]);
  123. Assert.AreEqual((int?) 30, list[1]);
  124. }
  125. [Test]
  126. public void AddRange_Optimized_NullsProhibited_ReferenceType()
  127. {
  128. // We don't just trust that a collection with a nullable element type doesn't contain nulls
  129. var list = new RepeatedField<string>();
  130. // It's okay for this to throw ArgumentNullException if necessary.
  131. // It's not ideal, but not awful.
  132. Assert.Catch<ArgumentException>(() => list.AddRange(new List<string> { "foo", null }));
  133. }
  134. [Test]
  135. public void AddRange_Optimized_NullsProhibited_NullableValueType()
  136. {
  137. // We don't just trust that a collection with a nullable element type doesn't contain nulls
  138. var list = new RepeatedField<int?>();
  139. // It's okay for this to throw ArgumentNullException if necessary.
  140. // It's not ideal, but not awful.
  141. Assert.Catch<ArgumentException>(() => list.AddRange(new List<int?> { 20, null }));
  142. }
  143. [Test]
  144. public void AddRange_AlreadyNotEmpty()
  145. {
  146. var list = new RepeatedField<int> { 1, 2, 3 };
  147. list.AddRange(new List<int> { 4, 5, 6 });
  148. CollectionAssert.AreEqual(new[] { 1, 2, 3, 4, 5, 6 }, list);
  149. }
  150. [Test]
  151. public void AddRange_RepeatedField()
  152. {
  153. var list = new RepeatedField<string> { "original" };
  154. list.AddRange(new RepeatedField<string> { "foo", "bar" });
  155. Assert.AreEqual(3, list.Count);
  156. Assert.AreEqual("original", list[0]);
  157. Assert.AreEqual("foo", list[1]);
  158. Assert.AreEqual("bar", list[2]);
  159. }
  160. [Test]
  161. public void RemoveAt_Valid()
  162. {
  163. var list = new RepeatedField<string> { "first", "second", "third" };
  164. list.RemoveAt(1);
  165. CollectionAssert.AreEqual(new[] { "first", "third" }, list);
  166. // Just check that these don't throw...
  167. list.RemoveAt(list.Count - 1); // Now the count will be 1...
  168. list.RemoveAt(0);
  169. Assert.AreEqual(0, list.Count);
  170. }
  171. [Test]
  172. public void RemoveAt_Invalid()
  173. {
  174. var list = new RepeatedField<string> { "first", "second", "third" };
  175. Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(-1));
  176. Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(3));
  177. }
  178. [Test]
  179. public void Insert_Valid()
  180. {
  181. var list = new RepeatedField<string> { "first", "second" };
  182. list.Insert(1, "middle");
  183. CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
  184. list.Insert(3, "end");
  185. CollectionAssert.AreEqual(new[] { "first", "middle", "second", "end" }, list);
  186. list.Insert(0, "start");
  187. CollectionAssert.AreEqual(new[] { "start", "first", "middle", "second", "end" }, list);
  188. }
  189. [Test]
  190. public void Insert_Invalid()
  191. {
  192. var list = new RepeatedField<string> { "first", "second" };
  193. Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(-1, "foo"));
  194. Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(3, "foo"));
  195. Assert.Throws<ArgumentNullException>(() => list.Insert(0, null));
  196. }
  197. [Test]
  198. public void Equals_RepeatedField()
  199. {
  200. var list = new RepeatedField<string> { "first", "second" };
  201. Assert.IsFalse(list.Equals((RepeatedField<string>) null));
  202. Assert.IsTrue(list.Equals(list));
  203. Assert.IsFalse(list.Equals(new RepeatedField<string> { "first", "third" }));
  204. Assert.IsFalse(list.Equals(new RepeatedField<string> { "first" }));
  205. Assert.IsTrue(list.Equals(new RepeatedField<string> { "first", "second" }));
  206. }
  207. [Test]
  208. public void Equals_Object()
  209. {
  210. var list = new RepeatedField<string> { "first", "second" };
  211. Assert.IsFalse(list.Equals((object) null));
  212. Assert.IsTrue(list.Equals((object) list));
  213. Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first", "third" }));
  214. Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first" }));
  215. Assert.IsTrue(list.Equals((object) new RepeatedField<string> { "first", "second" }));
  216. Assert.IsFalse(list.Equals(new object()));
  217. }
  218. [Test]
  219. public void GetEnumerator_GenericInterface()
  220. {
  221. IEnumerable<string> list = new RepeatedField<string> { "first", "second" };
  222. // Select gets rid of the optimizations in ToList...
  223. CollectionAssert.AreEqual(new[] { "first", "second" }, list.Select(x => x).ToList());
  224. }
  225. [Test]
  226. public void GetEnumerator_NonGenericInterface()
  227. {
  228. IEnumerable list = new RepeatedField<string> { "first", "second" };
  229. CollectionAssert.AreEqual(new[] { "first", "second" }, list.Cast<object>().ToList());
  230. }
  231. [Test]
  232. public void CopyTo()
  233. {
  234. var list = new RepeatedField<string> { "first", "second" };
  235. string[] stringArray = new string[4];
  236. list.CopyTo(stringArray, 1);
  237. CollectionAssert.AreEqual(new[] { null, "first", "second", null }, stringArray);
  238. }
  239. [Test]
  240. public void Indexer_Get()
  241. {
  242. var list = new RepeatedField<string> { "first", "second" };
  243. Assert.AreEqual("first", list[0]);
  244. Assert.AreEqual("second", list[1]);
  245. Assert.Throws<ArgumentOutOfRangeException>(() => list[-1].GetHashCode());
  246. Assert.Throws<ArgumentOutOfRangeException>(() => list[2].GetHashCode());
  247. }
  248. [Test]
  249. public void Indexer_Set()
  250. {
  251. var list = new RepeatedField<string> { "first", "second" };
  252. list[0] = "changed";
  253. Assert.AreEqual("changed", list[0]);
  254. Assert.Throws<ArgumentNullException>(() => list[0] = null);
  255. Assert.Throws<ArgumentOutOfRangeException>(() => list[-1] = "bad");
  256. Assert.Throws<ArgumentOutOfRangeException>(() => list[2] = "bad");
  257. }
  258. [Test]
  259. public void Clone_ReturnsMutable()
  260. {
  261. var list = new RepeatedField<int> { 0 };
  262. var clone = list.Clone();
  263. clone[0] = 1;
  264. }
  265. [Test]
  266. public void Enumerator()
  267. {
  268. var list = new RepeatedField<string> { "first", "second" };
  269. using (var enumerator = list.GetEnumerator())
  270. {
  271. Assert.IsTrue(enumerator.MoveNext());
  272. Assert.AreEqual("first", enumerator.Current);
  273. Assert.IsTrue(enumerator.MoveNext());
  274. Assert.AreEqual("second", enumerator.Current);
  275. Assert.IsFalse(enumerator.MoveNext());
  276. Assert.IsFalse(enumerator.MoveNext());
  277. }
  278. }
  279. [Test]
  280. public void AddEntriesFrom_PackedInt32()
  281. {
  282. uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  283. var stream = new MemoryStream();
  284. var output = new CodedOutputStream(stream);
  285. var length = CodedOutputStream.ComputeInt32Size(10)
  286. + CodedOutputStream.ComputeInt32Size(999)
  287. + CodedOutputStream.ComputeInt32Size(-1000);
  288. output.WriteTag(packedTag);
  289. output.WriteRawVarint32((uint) length);
  290. output.WriteInt32(10);
  291. output.WriteInt32(999);
  292. output.WriteInt32(-1000);
  293. output.Flush();
  294. stream.Position = 0;
  295. // Deliberately "expecting" a non-packed tag, but we detect that the data is
  296. // actually packed.
  297. uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  298. var field = new RepeatedField<int>();
  299. var input = new CodedInputStream(stream);
  300. input.AssertNextTag(packedTag);
  301. field.AddEntriesFrom(input, FieldCodec.ForInt32(nonPackedTag));
  302. CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
  303. Assert.IsTrue(input.IsAtEnd);
  304. }
  305. [Test]
  306. public void AddEntriesFrom_NonPackedInt32()
  307. {
  308. uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
  309. var stream = new MemoryStream();
  310. var output = new CodedOutputStream(stream);
  311. output.WriteTag(nonPackedTag);
  312. output.WriteInt32(10);
  313. output.WriteTag(nonPackedTag);
  314. output.WriteInt32(999);
  315. output.WriteTag(nonPackedTag);
  316. output.WriteInt32(-1000); // Just for variety...
  317. output.Flush();
  318. stream.Position = 0;
  319. // Deliberately "expecting" a packed tag, but we detect that the data is
  320. // actually not packed.
  321. uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  322. var field = new RepeatedField<int>();
  323. var input = new CodedInputStream(stream);
  324. input.AssertNextTag(nonPackedTag);
  325. field.AddEntriesFrom(input, FieldCodec.ForInt32(packedTag));
  326. CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
  327. Assert.IsTrue(input.IsAtEnd);
  328. }
  329. [Test]
  330. public void AddEntriesFrom_String()
  331. {
  332. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  333. var stream = new MemoryStream();
  334. var output = new CodedOutputStream(stream);
  335. output.WriteTag(tag);
  336. output.WriteString("Foo");
  337. output.WriteTag(tag);
  338. output.WriteString("");
  339. output.WriteTag(tag);
  340. output.WriteString("Bar");
  341. output.Flush();
  342. stream.Position = 0;
  343. var field = new RepeatedField<string>();
  344. var input = new CodedInputStream(stream);
  345. input.AssertNextTag(tag);
  346. field.AddEntriesFrom(input, FieldCodec.ForString(tag));
  347. CollectionAssert.AreEqual(new[] { "Foo", "", "Bar" }, field);
  348. Assert.IsTrue(input.IsAtEnd);
  349. }
  350. [Test]
  351. public void AddEntriesFrom_Message()
  352. {
  353. var message1 = new ForeignMessage { C = 2000 };
  354. var message2 = new ForeignMessage { C = -250 };
  355. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  356. var stream = new MemoryStream();
  357. var output = new CodedOutputStream(stream);
  358. output.WriteTag(tag);
  359. output.WriteMessage(message1);
  360. output.WriteTag(tag);
  361. output.WriteMessage(message2);
  362. output.Flush();
  363. stream.Position = 0;
  364. var field = new RepeatedField<ForeignMessage>();
  365. var input = new CodedInputStream(stream);
  366. input.AssertNextTag(tag);
  367. field.AddEntriesFrom(input, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
  368. CollectionAssert.AreEqual(new[] { message1, message2}, field);
  369. Assert.IsTrue(input.IsAtEnd);
  370. }
  371. [Test]
  372. public void WriteTo_PackedInt32()
  373. {
  374. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  375. var field = new RepeatedField<int> { 10, 1000, 1000000 };
  376. var stream = new MemoryStream();
  377. var output = new CodedOutputStream(stream);
  378. field.WriteTo(output, FieldCodec.ForInt32(tag));
  379. output.Flush();
  380. stream.Position = 0;
  381. var input = new CodedInputStream(stream);
  382. input.AssertNextTag(tag);
  383. var length = input.ReadLength();
  384. Assert.AreEqual(10, input.ReadInt32());
  385. Assert.AreEqual(1000, input.ReadInt32());
  386. Assert.AreEqual(1000000, input.ReadInt32());
  387. Assert.IsTrue(input.IsAtEnd);
  388. Assert.AreEqual(1 + CodedOutputStream.ComputeLengthSize(length) + length, stream.Length);
  389. }
  390. [Test]
  391. public void WriteTo_NonPackedInt32()
  392. {
  393. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
  394. var field = new RepeatedField<int> { 10, 1000, 1000000};
  395. var stream = new MemoryStream();
  396. var output = new CodedOutputStream(stream);
  397. field.WriteTo(output, FieldCodec.ForInt32(tag));
  398. output.Flush();
  399. stream.Position = 0;
  400. var input = new CodedInputStream(stream);
  401. input.AssertNextTag(tag);
  402. Assert.AreEqual(10, input.ReadInt32());
  403. input.AssertNextTag(tag);
  404. Assert.AreEqual(1000, input.ReadInt32());
  405. input.AssertNextTag(tag);
  406. Assert.AreEqual(1000000, input.ReadInt32());
  407. Assert.IsTrue(input.IsAtEnd);
  408. }
  409. [Test]
  410. public void WriteTo_String()
  411. {
  412. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  413. var field = new RepeatedField<string> { "Foo", "", "Bar" };
  414. var stream = new MemoryStream();
  415. var output = new CodedOutputStream(stream);
  416. field.WriteTo(output, FieldCodec.ForString(tag));
  417. output.Flush();
  418. stream.Position = 0;
  419. var input = new CodedInputStream(stream);
  420. input.AssertNextTag(tag);
  421. Assert.AreEqual("Foo", input.ReadString());
  422. input.AssertNextTag(tag);
  423. Assert.AreEqual("", input.ReadString());
  424. input.AssertNextTag(tag);
  425. Assert.AreEqual("Bar", input.ReadString());
  426. Assert.IsTrue(input.IsAtEnd);
  427. }
  428. [Test]
  429. public void WriteTo_Message()
  430. {
  431. var message1 = new ForeignMessage { C = 20 };
  432. var message2 = new ForeignMessage { C = 25 };
  433. uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
  434. var field = new RepeatedField<ForeignMessage> { message1, message2 };
  435. var stream = new MemoryStream();
  436. var output = new CodedOutputStream(stream);
  437. field.WriteTo(output, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
  438. output.Flush();
  439. stream.Position = 0;
  440. var input = new CodedInputStream(stream);
  441. input.AssertNextTag(tag);
  442. Assert.AreEqual(message1, input.ReadMessage(ForeignMessage.Parser));
  443. input.AssertNextTag(tag);
  444. Assert.AreEqual(message2, input.ReadMessage(ForeignMessage.Parser));
  445. Assert.IsTrue(input.IsAtEnd);
  446. }
  447. [Test]
  448. public void CalculateSize_VariableSizeNonPacked()
  449. {
  450. var list = new RepeatedField<int> { 1, 500, 1 };
  451. var tag = WireFormat.MakeTag(1, WireFormat.WireType.Varint);
  452. // 2 bytes for the first entry, 3 bytes for the second, 2 bytes for the third
  453. Assert.AreEqual(7, list.CalculateSize(FieldCodec.ForInt32(tag)));
  454. }
  455. [Test]
  456. public void CalculateSize_FixedSizeNonPacked()
  457. {
  458. var list = new RepeatedField<int> { 1, 500, 1 };
  459. var tag = WireFormat.MakeTag(1, WireFormat.WireType.Fixed32);
  460. // 5 bytes for the each entry
  461. Assert.AreEqual(15, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
  462. }
  463. [Test]
  464. public void CalculateSize_VariableSizePacked()
  465. {
  466. var list = new RepeatedField<int> { 1, 500, 1};
  467. var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
  468. // 1 byte for the tag, 1 byte for the length,
  469. // 1 byte for the first entry, 2 bytes for the second, 1 byte for the third
  470. Assert.AreEqual(6, list.CalculateSize(FieldCodec.ForInt32(tag)));
  471. }
  472. [Test]
  473. public void CalculateSize_FixedSizePacked()
  474. {
  475. var list = new RepeatedField<int> { 1, 500, 1 };
  476. var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
  477. // 1 byte for the tag, 1 byte for the length, 4 bytes per entry
  478. Assert.AreEqual(14, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
  479. }
  480. [Test]
  481. public void TestNegativeEnumArray()
  482. {
  483. int arraySize = 1 + 1 + (11 * 5);
  484. int msgSize = arraySize;
  485. byte[] bytes = new byte[msgSize];
  486. CodedOutputStream output = new CodedOutputStream(bytes);
  487. uint tag = WireFormat.MakeTag(8, WireFormat.WireType.Varint);
  488. for (int i = 0; i >= -5; i--)
  489. {
  490. output.WriteTag(tag);
  491. output.WriteEnum(i);
  492. }
  493. Assert.AreEqual(0, output.SpaceLeft);
  494. CodedInputStream input = new CodedInputStream(bytes);
  495. tag = input.ReadTag();
  496. RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
  497. values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
  498. Assert.AreEqual(6, values.Count);
  499. Assert.AreEqual(SampleEnum.None, values[0]);
  500. Assert.AreEqual(((SampleEnum)(-1)), values[1]);
  501. Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
  502. Assert.AreEqual(((SampleEnum)(-3)), values[3]);
  503. Assert.AreEqual(((SampleEnum)(-4)), values[4]);
  504. Assert.AreEqual(((SampleEnum)(-5)), values[5]);
  505. }
  506. [Test]
  507. public void TestNegativeEnumPackedArray()
  508. {
  509. int arraySize = 1 + (10 * 5);
  510. int msgSize = 1 + 1 + arraySize;
  511. byte[] bytes = new byte[msgSize];
  512. CodedOutputStream output = new CodedOutputStream(bytes);
  513. // Length-delimited to show we want the packed representation
  514. uint tag = WireFormat.MakeTag(8, WireFormat.WireType.LengthDelimited);
  515. output.WriteTag(tag);
  516. int size = 0;
  517. for (int i = 0; i >= -5; i--)
  518. {
  519. size += CodedOutputStream.ComputeEnumSize(i);
  520. }
  521. output.WriteRawVarint32((uint)size);
  522. for (int i = 0; i >= -5; i--)
  523. {
  524. output.WriteEnum(i);
  525. }
  526. Assert.AreEqual(0, output.SpaceLeft);
  527. CodedInputStream input = new CodedInputStream(bytes);
  528. tag = input.ReadTag();
  529. RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
  530. values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
  531. Assert.AreEqual(6, values.Count);
  532. Assert.AreEqual(SampleEnum.None, values[0]);
  533. Assert.AreEqual(((SampleEnum)(-1)), values[1]);
  534. Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
  535. Assert.AreEqual(((SampleEnum)(-3)), values[3]);
  536. Assert.AreEqual(((SampleEnum)(-4)), values[4]);
  537. Assert.AreEqual(((SampleEnum)(-5)), values[5]);
  538. }
  539. // Fairly perfunctory tests for the non-generic IList implementation
  540. [Test]
  541. public void IList_Indexer()
  542. {
  543. var field = new RepeatedField<string> { "first", "second" };
  544. IList list = field;
  545. Assert.AreEqual("first", list[0]);
  546. list[1] = "changed";
  547. Assert.AreEqual("changed", field[1]);
  548. }
  549. [Test]
  550. public void IList_Contains()
  551. {
  552. IList list = new RepeatedField<string> { "first", "second" };
  553. Assert.IsTrue(list.Contains("second"));
  554. Assert.IsFalse(list.Contains("third"));
  555. Assert.IsFalse(list.Contains(new object()));
  556. }
  557. [Test]
  558. public void IList_Add()
  559. {
  560. IList list = new RepeatedField<string> { "first", "second" };
  561. list.Add("third");
  562. CollectionAssert.AreEqual(new[] { "first", "second", "third" }, list);
  563. }
  564. [Test]
  565. public void IList_Remove()
  566. {
  567. IList list = new RepeatedField<string> { "first", "second" };
  568. list.Remove("third"); // No-op, no exception
  569. list.Remove(new object()); // No-op, no exception
  570. list.Remove("first");
  571. CollectionAssert.AreEqual(new[] { "second" }, list);
  572. }
  573. [Test]
  574. public void IList_IsFixedSize()
  575. {
  576. var field = new RepeatedField<string> { "first", "second" };
  577. IList list = field;
  578. Assert.IsFalse(list.IsFixedSize);
  579. }
  580. [Test]
  581. public void IList_IndexOf()
  582. {
  583. IList list = new RepeatedField<string> { "first", "second" };
  584. Assert.AreEqual(1, list.IndexOf("second"));
  585. Assert.AreEqual(-1, list.IndexOf("third"));
  586. Assert.AreEqual(-1, list.IndexOf(new object()));
  587. }
  588. [Test]
  589. public void IList_SyncRoot()
  590. {
  591. IList list = new RepeatedField<string> { "first", "second" };
  592. Assert.AreSame(list, list.SyncRoot);
  593. }
  594. [Test]
  595. public void IList_CopyTo()
  596. {
  597. IList list = new RepeatedField<string> { "first", "second" };
  598. string[] stringArray = new string[4];
  599. list.CopyTo(stringArray, 1);
  600. CollectionAssert.AreEqual(new[] { null, "first", "second", null }, stringArray);
  601. object[] objectArray = new object[4];
  602. list.CopyTo(objectArray, 1);
  603. CollectionAssert.AreEqual(new[] { null, "first", "second", null }, objectArray);
  604. Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new StringBuilder[4], 1));
  605. Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new int[4], 1));
  606. }
  607. [Test]
  608. public void IList_IsSynchronized()
  609. {
  610. IList list = new RepeatedField<string> { "first", "second" };
  611. Assert.IsFalse(list.IsSynchronized);
  612. }
  613. [Test]
  614. public void IList_Insert()
  615. {
  616. IList list = new RepeatedField<string> { "first", "second" };
  617. list.Insert(1, "middle");
  618. CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
  619. }
  620. [Test]
  621. public void ToString_Integers()
  622. {
  623. var list = new RepeatedField<int> { 5, 10, 20 };
  624. var text = list.ToString();
  625. Assert.AreEqual("[ 5, 10, 20 ]", text);
  626. }
  627. [Test]
  628. public void ToString_Strings()
  629. {
  630. var list = new RepeatedField<string> { "x", "y", "z" };
  631. var text = list.ToString();
  632. Assert.AreEqual("[ \"x\", \"y\", \"z\" ]", text);
  633. }
  634. [Test]
  635. public void ToString_Messages()
  636. {
  637. var list = new RepeatedField<TestAllTypes> { new TestAllTypes { SingleDouble = 1.5 }, new TestAllTypes { SingleInt32 = 10 } };
  638. var text = list.ToString();
  639. Assert.AreEqual("[ { \"singleDouble\": 1.5 }, { \"singleInt32\": 10 } ]", text);
  640. }
  641. [Test]
  642. public void ToString_Empty()
  643. {
  644. var list = new RepeatedField<TestAllTypes> { };
  645. var text = list.ToString();
  646. Assert.AreEqual("[ ]", text);
  647. }
  648. [Test]
  649. public void ToString_InvalidElementType()
  650. {
  651. var list = new RepeatedField<decimal> { 15m };
  652. Assert.Throws<ArgumentException>(() => list.ToString());
  653. }
  654. [Test]
  655. public void ToString_Timestamp()
  656. {
  657. var list = new RepeatedField<Timestamp> { Timestamp.FromDateTime(new DateTime(2015, 10, 1, 12, 34, 56, DateTimeKind.Utc)) };
  658. var text = list.ToString();
  659. Assert.AreEqual("[ \"2015-10-01T12:34:56Z\" ]", text);
  660. }
  661. [Test]
  662. public void ToString_Struct()
  663. {
  664. var message = new Struct { Fields = { { "foo", new Value { NumberValue = 20 } } } };
  665. var list = new RepeatedField<Struct> { message };
  666. var text = list.ToString();
  667. Assert.AreEqual(text, "[ { \"foo\": 20 } ]", message.ToString());
  668. }
  669. [Test]
  670. public void NaNValuesComparedBitwise()
  671. {
  672. var list1 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.SignallingFlipped };
  673. var list2 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.PayloadFlipped };
  674. var list3 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.SignallingFlipped };
  675. // All SampleNaNs have the same hashcode under certain targets (e.g. netcoreapp2.1)
  676. EqualityTester.AssertInequality(list1, list2, checkHashcode: false);
  677. EqualityTester.AssertEquality(list1, list3);
  678. Assert.True(list1.Contains(SampleNaNs.SignallingFlipped));
  679. Assert.False(list2.Contains(SampleNaNs.SignallingFlipped));
  680. }
  681. [Test]
  682. public void Capacity_Increase()
  683. {
  684. // Unfortunately this case tests implementation details of RepeatedField. This is necessary
  685. var list = new RepeatedField<int>() { 1, 2, 3 };
  686. Assert.AreEqual(8, list.Capacity);
  687. Assert.AreEqual(3, list.Count);
  688. list.Capacity = 10; // Set capacity to a larger value to trigger growth
  689. Assert.AreEqual(10, list.Capacity, "Capacity increased");
  690. Assert.AreEqual(3, list.Count);
  691. CollectionAssert.AreEqual(new int[] {1, 2, 3}, list.ToArray(), "We didn't lose our data in the resize");
  692. }
  693. [Test]
  694. public void Capacity_Decrease()
  695. {
  696. var list = new RepeatedField<int>() { 1, 2, 3 };
  697. Assert.AreEqual(8, list.Capacity);
  698. Assert.DoesNotThrow(() => list.Capacity = 5, "Can decrease capacity if new capacity is greater than list.Count");
  699. Assert.AreEqual(5, list.Capacity);
  700. Assert.DoesNotThrow(() => list.Capacity = 3, "Can set capacity exactly to list.Count" );
  701. Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = 2, "Can't set the capacity smaller than list.Count" );
  702. Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = 0, "Can't set the capacity to zero" );
  703. Assert.Throws<ArgumentOutOfRangeException>(() => list.Capacity = -1, "Can't set the capacity to negative" );
  704. }
  705. [Test]
  706. public void Capacity_Zero()
  707. {
  708. var list = new RepeatedField<int>() { 1 };
  709. list.RemoveAt(0);
  710. Assert.AreEqual(0, list.Count);
  711. Assert.AreEqual(8, list.Capacity);
  712. Assert.DoesNotThrow(() => list.Capacity = 0, "Can set Capacity to 0");
  713. Assert.AreEqual(0, list.Capacity);
  714. }
  715. }
  716. }