PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/Utilities/Collections/CollectionBase.cs

#
C# | 1303 lines | 908 code | 114 blank | 281 comment | 70 complexity | a89a7dedbf477df6bbad60bc812c8075 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Text;
  6. using Delta.Utilities.Helpers;
  7. using NUnit.Framework;
  8. namespace Delta.Utilities.Collections
  9. {
  10. /// <summary>
  11. /// CollectionBase is a base class that can be used to more easily implement
  12. /// the generic ICollection&lt;T&gt; and non-generic ICollection interfaces.
  13. /// </summary>
  14. /// <typeparam name="T">Data type</typeparam>
  15. [DebuggerDisplay("{DebuggerToString()}")]
  16. public abstract class CollectionBase<T> : ICollection<T>, ICollection
  17. {
  18. #region Count (Public)
  19. /// <summary>
  20. /// Must be overridden to provide the number of items in the collection.
  21. /// </summary>
  22. /// <value>The number of items in the collection.</value>
  23. /// <typeparam name="T">T</typeparam>
  24. public abstract int Count
  25. {
  26. get;
  27. }
  28. #endregion
  29. #region Private
  30. #region IsReadOnly (Private)
  31. /// <summary>
  32. /// Indicates whether the collection is read-only. Always returns false.
  33. /// </summary>
  34. /// <value>Always returns false.</value>
  35. /// <typeparam name="T">T</typeparam>
  36. bool ICollection<T>.IsReadOnly
  37. {
  38. get
  39. {
  40. return false;
  41. } // get
  42. }
  43. #endregion
  44. #region IsSynchronized (Private)
  45. /// <summary>
  46. /// Indicates whether the collection is synchronized.
  47. /// </summary>
  48. /// <value>Always returns false, indicating that the collection is not
  49. /// synchronized.</value>
  50. /// <typeparam name="T">T</typeparam>
  51. bool ICollection.IsSynchronized
  52. {
  53. get
  54. {
  55. return false;
  56. } // get
  57. }
  58. #endregion
  59. #region SyncRoot (Private)
  60. /// <summary>
  61. /// Indicates the synchronization object for this collection.
  62. /// </summary>
  63. /// <value>Always returns this.</value>
  64. /// <typeparam name="T">T</typeparam>
  65. object ICollection.SyncRoot
  66. {
  67. get
  68. {
  69. return this;
  70. } // get
  71. }
  72. #endregion
  73. #endregion
  74. #region ICollection Members
  75. /// <summary>
  76. /// Copies all the items in the collection into an array. Implemented by
  77. /// using the enumerator returned from GetEnumerator to get all the items
  78. /// and copy them to the provided array.
  79. /// </summary>
  80. /// <param name="array">Array to copy to.</param>
  81. /// <param name="index">Starting index in <paramref name="array"/> to
  82. /// copy to.</param>
  83. void ICollection.CopyTo(Array array, int index)
  84. {
  85. int count = Count;
  86. if (count == 0)
  87. {
  88. return;
  89. }
  90. if (array == null)
  91. {
  92. throw new ArgumentNullException("array");
  93. }
  94. if (index < 0)
  95. {
  96. throw new ArgumentOutOfRangeException(
  97. "index", "The argument may not be less than zero: " + index);
  98. }
  99. if (index >= array.Length ||
  100. count > array.Length - index)
  101. {
  102. throw new ArgumentException(
  103. "index", "The array is too small to hold all of the items.");
  104. }
  105. int i = 0;
  106. foreach (object o in (ICollection)this)
  107. {
  108. if (i >= count)
  109. {
  110. break;
  111. }
  112. array.SetValue(o, index);
  113. ++index;
  114. ++i;
  115. }
  116. }
  117. #endregion
  118. #region ICollection<T> Members
  119. /// <summary>
  120. /// Must be overridden to allow adding items to this collection.
  121. /// </summary>
  122. /// <remarks>
  123. /// This method is not abstract, although derived classes should always
  124. /// override it. It is not abstract because some derived classes may wish
  125. /// to reimplement Add with a different return type (typically bool).
  126. /// In C#, this can be accomplished with code like the following:
  127. /// <code>
  128. /// public class MyCollection&lt;T&gt;
  129. /// : CollectionBase&lt;T&gt;, ICollection&lt;T&gt;
  130. /// {
  131. /// public new bool Add(T item)
  132. /// {
  133. /// /* Add the item */
  134. /// }
  135. ///
  136. /// void ICollection&lt;T&gt;.Add(T item)
  137. /// {
  138. /// Add(item);
  139. /// }
  140. /// }
  141. /// </code>
  142. /// </remarks>
  143. /// <param name="item">Item to be added to the collection.</param>
  144. /// <exception cref="NotImplementedException">Always throws this exception
  145. /// to indicated that the method must be overridden or re-implemented in
  146. /// the derived class.</exception>
  147. public virtual void Add(T item)
  148. {
  149. throw new NotSupportedException(
  150. "This method must be overridden in the derived class.");
  151. }
  152. /// <summary>
  153. /// Must be overridden to allow clearing this collection.
  154. /// </summary>
  155. public abstract void Clear();
  156. /// <summary>
  157. /// Determines if the collection contains a particular item. This default
  158. /// implementation iterates all of the items in the collection via
  159. /// GetEnumerator, testing each item against <paramref name="item"/> using
  160. /// IComparable&lt;T&gt;.Equals or Object.Equals.
  161. /// </summary>
  162. /// <remarks>You should strongly consider overriding this method to provide
  163. /// a more efficient implementation, or if the default equality comparison
  164. /// is inappropriate.</remarks>
  165. /// <param name="item">The item to check for in the collection.</param>
  166. /// <returns>True if the collection contains <paramref name="item"/>,
  167. /// false otherwise.</returns>
  168. public virtual bool Contains(T item)
  169. {
  170. IEqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
  171. foreach (T i in this)
  172. {
  173. if (equalityComparer.Equals(i, item))
  174. {
  175. return true;
  176. }
  177. }
  178. return false;
  179. }
  180. /// <summary>
  181. /// Copies all the items in the collection into an array. Implemented by
  182. /// using the enumerator returned from GetEnumerator to get all the items
  183. /// and copy them to the provided array.
  184. /// </summary>
  185. /// <param name="array">Array to copy to.</param>
  186. /// <param name="arrayIndex">Starting index in <paramref name="array"/>
  187. /// to copy to.</param>
  188. public virtual void CopyTo(T[] array, int arrayIndex)
  189. {
  190. int count = Count;
  191. if (count == 0)
  192. {
  193. return;
  194. }
  195. if (array == null)
  196. {
  197. throw new ArgumentNullException("array");
  198. }
  199. if (count < 0)
  200. {
  201. throw new IndexOutOfRangeException(
  202. "The count may not be less than zero: " + count);
  203. }
  204. if (arrayIndex < 0)
  205. {
  206. throw new ArgumentOutOfRangeException(
  207. "arrayIndex", "The argument may not be less than zero: " +
  208. arrayIndex);
  209. }
  210. if (arrayIndex >= array.Length ||
  211. count > array.Length - arrayIndex)
  212. {
  213. throw new ArgumentException(
  214. "The array is too small to hold all of the items.", "arrayIndex");
  215. }
  216. int index = arrayIndex, i = 0;
  217. foreach (T item in (ICollection<T>)this)
  218. {
  219. if (i >= count)
  220. {
  221. break;
  222. }
  223. array[index] = item;
  224. ++index;
  225. ++i;
  226. }
  227. }
  228. /// <summary>
  229. /// Must be overridden to allow removing items from this collection.
  230. /// </summary>
  231. /// <returns>
  232. /// True if <paramref name="item"/> existed in the collection and was
  233. /// removed. False if <paramref name="item"/> did not exist in the
  234. /// collection.
  235. /// </returns>
  236. public abstract bool Remove(T item);
  237. #endregion
  238. #region IEnumerable Members
  239. /// <summary>
  240. /// Provides an IEnumerator that can be used to iterate all the members of
  241. /// the collection. This implementation uses the IEnumerator&lt;T&gt; that
  242. /// was overridden by the derived classes to enumerate the members of the
  243. /// collection.
  244. /// </summary>
  245. /// <returns>An IEnumerator that can be used to iterate the collection.
  246. /// </returns>
  247. IEnumerator IEnumerable.GetEnumerator()
  248. {
  249. foreach (T item in this)
  250. {
  251. yield return item;
  252. }
  253. }
  254. #endregion
  255. #region IEnumerable<T> Members
  256. /// <summary>
  257. /// Must be overridden to enumerate all the members of the collection.
  258. /// </summary>
  259. /// <returns>A generic IEnumerator&lt;T&gt; that can be used
  260. /// to enumerate all the items in the collection.</returns>
  261. public abstract IEnumerator<T> GetEnumerator();
  262. #endregion
  263. #region ToArray (Public)
  264. /// <summary>
  265. /// Creates an array of the correct size, and copies all the items in the
  266. /// collection into the array, by calling CopyTo.
  267. /// </summary>
  268. /// <returns>An array containing all the elements in the collection,
  269. /// in order.</returns>
  270. public virtual T[] ToArray()
  271. {
  272. int count = Count;
  273. T[] array = new T[count];
  274. CopyTo(array, 0);
  275. return array;
  276. }
  277. #endregion
  278. #region Exists (Public)
  279. /// <summary>
  280. /// Determines if the collection contains any item that satisfies the
  281. /// condition defined by <paramref name="predicate"/>.
  282. /// </summary>
  283. /// <param name="predicate">A delegate that defines the condition to check
  284. /// for.</param>
  285. /// <returns>True if the collection contains one or more items that satisfy
  286. /// the condition defined by <paramref name="predicate"/>. False if the
  287. /// collection does not contain an item that satisfies
  288. /// <paramref name="predicate"/>.</returns>
  289. public virtual bool Exists(Predicate<T> predicate)
  290. {
  291. if (predicate == null)
  292. {
  293. throw new ArgumentNullException("predicate");
  294. }
  295. foreach (T item in this)
  296. {
  297. if (predicate(item))
  298. {
  299. return true;
  300. }
  301. }
  302. return false;
  303. }
  304. #endregion
  305. #region TrueForAll (Public)
  306. /// <summary>
  307. /// Determines if all of the items in the collection satisfy the condition
  308. /// defined by <paramref name="predicate"/>.
  309. /// </summary>
  310. /// <param name="predicate">A delegate that defines the condition to check
  311. /// for.</param>
  312. /// <returns>True if all of the items in the collection satisfy the
  313. /// condition defined by <paramref name="predicate"/>, or if the collection
  314. /// is empty. False if one or more items in the collection do not satisfy
  315. /// <paramref name="predicate"/>.</returns>
  316. public virtual bool TrueForAll(Predicate<T> predicate)
  317. {
  318. if (predicate == null)
  319. {
  320. throw new ArgumentNullException("predicate");
  321. }
  322. foreach (T item in this)
  323. {
  324. if (!predicate(item))
  325. {
  326. return false;
  327. }
  328. }
  329. return true;
  330. }
  331. #endregion
  332. #region CountWhere (Public)
  333. /// <summary>
  334. /// Counts the number of items in the collection that satisfy the condition
  335. /// defined by <paramref name="predicate"/>.
  336. /// </summary>
  337. /// <param name="predicate">A delegate that defines the condition to check
  338. /// for.</param>
  339. /// <returns>The number of items in the collection that satisfy
  340. /// <paramref name="predicate"/>.</returns>
  341. public virtual int CountWhere(Predicate<T> predicate)
  342. {
  343. if (predicate == null)
  344. {
  345. throw new ArgumentNullException("predicate");
  346. }
  347. int count = 0;
  348. foreach (T item in this)
  349. {
  350. if (predicate(item))
  351. {
  352. ++count;
  353. }
  354. }
  355. return count;
  356. }
  357. #endregion
  358. #region FindAll (Public)
  359. /// <summary>
  360. /// Enumerates the items in the collection that satisfy the condition
  361. /// defined by <paramref name="predicate"/>.
  362. /// </summary>
  363. /// <param name="predicate">
  364. /// A delegate that defines the condition to check for.
  365. /// </param>
  366. /// <returns>An IEnumerable&lt;T&gt; that enumerates the items that
  367. /// satisfy the condition.</returns>
  368. public virtual IEnumerable<T> FindAll(Predicate<T> predicate)
  369. {
  370. if (predicate == null)
  371. {
  372. throw new ArgumentNullException("predicate");
  373. }
  374. foreach (T item in this)
  375. {
  376. if (predicate(item))
  377. {
  378. yield return item;
  379. }
  380. }
  381. }
  382. #endregion
  383. #region RemoveAll (Public)
  384. /// <summary>
  385. /// Removes all the items in the collection that satisfy the condition
  386. /// defined by <paramref name="predicate"/>.
  387. /// </summary>
  388. /// <param name="predicate">A delegate that defines the condition to check
  389. /// for.</param>
  390. /// <returns>Returns a collection of the items that were removed, in sorted
  391. /// order.</returns>
  392. public virtual ICollection<T> RemoveAll(Predicate<T> predicate)
  393. {
  394. if (predicate == null)
  395. {
  396. throw new ArgumentNullException("predicate");
  397. }
  398. /*unused
  399. if (collection is T[])
  400. collection = new ArrayWrapper<T>((T[])collection);
  401. if (collection.IsReadOnly)
  402. throw new ArgumentException(Strings.ListIsReadOnly, "collection");
  403. */
  404. IList<T> list = this as IList<T>;
  405. if (list != null)
  406. {
  407. T item;
  408. int i = -1, j = 0;
  409. int listCount = list.Count;
  410. List<T> removed = new List<T>();
  411. // Remove item where predicate is true, compressing items to lower in
  412. // the list. This is much more efficient than the naive algorithm that
  413. // uses IList<T>.Remove().
  414. while (j < listCount)
  415. {
  416. item = list[j];
  417. if (predicate(item))
  418. {
  419. removed.Add(item);
  420. }
  421. else
  422. {
  423. ++i;
  424. if (i != j)
  425. {
  426. list[i] = item;
  427. }
  428. }
  429. ++j;
  430. }
  431. ++i;
  432. if (i < listCount)
  433. {
  434. // remove items from the end.
  435. IList fixedList = list as IList;
  436. if (fixedList != null &&
  437. fixedList.IsFixedSize)
  438. {
  439. // An array or similar. Null out the last elements.
  440. while (i < listCount)
  441. {
  442. list[i++] = default(T);
  443. }
  444. }
  445. else
  446. {
  447. // Normal list.
  448. while (i < listCount)
  449. {
  450. list.RemoveAt(listCount - 1);
  451. --listCount;
  452. }
  453. }
  454. }
  455. return removed;
  456. }
  457. else
  458. {
  459. // We have to copy all the items to remove to a List, because
  460. // collections can't be modifed during an enumeration.
  461. List<T> removed = new List<T>();
  462. foreach (T item in this)
  463. {
  464. if (predicate(item))
  465. {
  466. removed.Add(item);
  467. }
  468. }
  469. foreach (T item in removed)
  470. {
  471. Remove(item);
  472. }
  473. return removed;
  474. }
  475. }
  476. #endregion
  477. #region ForEach (Public)
  478. /// <summary>
  479. /// Performs the specified action on each item in this collection.
  480. /// </summary>
  481. /// <param name="action">An Action delegate which is invoked for each item
  482. /// in this collection.</param>
  483. public virtual void ForEach(Action<T> action)
  484. {
  485. if (action == null)
  486. {
  487. throw new ArgumentNullException("action");
  488. }
  489. foreach (T item in this)
  490. {
  491. action(item);
  492. }
  493. }
  494. #endregion
  495. #region ConvertAll (Public)
  496. /// <summary>
  497. /// Convert this collection of items by applying a delegate to each item
  498. /// in the collection. The resulting enumeration contains the result of
  499. /// applying <paramref name="converter"/> to each item in this collection,
  500. /// in order.
  501. /// </summary>
  502. /// <typeparam name="TOutput">The type each item is being converted to.
  503. /// </typeparam>
  504. /// <param name="converter">A delegate to the method to call, passing each
  505. /// item in this collection.</param>
  506. /// <returns>An IEnumerable&lt;TOutput^gt; that enumerates the resulting
  507. /// collection from applying <paramref name="converter"/> to each item in
  508. /// this collection in order.</returns>
  509. /// <exception cref="ArgumentNullException"><paramref name="converter"/>
  510. /// is null.</exception>
  511. public virtual IEnumerable<TOutput> ConvertAll<TOutput>(
  512. Converter<T, TOutput> converter)
  513. {
  514. if (converter == null)
  515. {
  516. throw new ArgumentNullException("converter");
  517. }
  518. foreach (T sourceItem in this)
  519. {
  520. yield return converter(sourceItem);
  521. }
  522. }
  523. #endregion
  524. #region ToString (Public)
  525. /// <summary>
  526. /// Shows the string representation of the collection. The string
  527. /// representation contains a list of the items in the collection.
  528. /// Contained collections (except string) are expanded recursively.
  529. /// </summary>
  530. /// <returns>The string representation of the collection.</returns>
  531. public override string ToString()
  532. {
  533. return this.Write();
  534. }
  535. #endregion
  536. #region Methods (Private)
  537. #region DebuggerToString
  538. /// <summary>
  539. /// Display the contents of the collection in the debugger. This is
  540. /// intentionally private, it is called only from the debugger due to the
  541. /// presence of the DebuggerDisplay attribute. It is similar format to
  542. /// ToString(), but is limited to 250-300 characters or so, so as not to
  543. /// overload the debugger.
  544. /// </summary>
  545. /// <returns>The string representation of the items in the collection,
  546. /// similar in format to ToString().</returns>
  547. internal string DebuggerToString()
  548. {
  549. const int MAXLENGTH = 250;
  550. StringBuilder builder = new StringBuilder();
  551. builder.Append('{');
  552. // Call ToString on each item and put it in.
  553. bool firstItem = true;
  554. foreach (T item in this)
  555. {
  556. if (builder.Length >= MAXLENGTH)
  557. {
  558. builder.Append(",...");
  559. break;
  560. }
  561. if (!firstItem)
  562. {
  563. builder.Append(',');
  564. }
  565. if (item == null)
  566. {
  567. builder.Append("null");
  568. }
  569. else
  570. {
  571. builder.Append(item.ToString());
  572. }
  573. firstItem = false;
  574. }
  575. builder.Append('}');
  576. return builder.ToString();
  577. }
  578. #endregion
  579. #endregion
  580. }
  581. /// <summary>
  582. /// Collection base tests, must be declared outside of a generic class.
  583. /// </summary>
  584. internal class CollectionBaseTests
  585. {
  586. #region Helpers
  587. #region DerivedCollectionBase
  588. /// <summary>
  589. /// Derived collection base
  590. /// </summary>
  591. private class DerivedCollectionBase<T> : CollectionBase<T>
  592. {
  593. #region Count (Public)
  594. /// <summary>
  595. /// Count
  596. /// </summary>
  597. /// <returns>Int</returns>
  598. public override int Count
  599. {
  600. get
  601. {
  602. return items.Count;
  603. } // get
  604. }
  605. #endregion
  606. #region Private
  607. #region items (Private)
  608. /// <summary>
  609. /// Items
  610. /// </summary>
  611. private readonly List<T> items;
  612. #endregion
  613. #endregion
  614. #region Constructors
  615. /// <summary>
  616. /// Create derived collection base
  617. /// </summary>
  618. /// <param name="setItems">Set items</param>
  619. public DerivedCollectionBase(T[] setItems)
  620. {
  621. items = new List<T>(setItems);
  622. }
  623. /// <summary>
  624. /// Create derived collection base
  625. /// </summary>
  626. /// <param name="setItems">Set items</param>
  627. public DerivedCollectionBase(IEnumerable<T> setItems)
  628. {
  629. items = new List<T>(setItems);
  630. }
  631. #endregion
  632. #region Clear (Public)
  633. /// <summary>
  634. /// Clear
  635. /// </summary>
  636. public override void Clear()
  637. {
  638. items.Clear();
  639. }
  640. #endregion
  641. #region Remove (Public)
  642. /// <summary>
  643. /// Remove item from the collection.
  644. /// </summary>
  645. /// <param name="item">Item</param>
  646. /// <returns>True if the item was removed</returns>
  647. public override bool Remove(T item)
  648. {
  649. return items.Remove(item);
  650. }
  651. #endregion
  652. #region GetEnumerator (Public)
  653. /// <summary>
  654. /// Get enumerator
  655. /// </summary>
  656. /// <returns>IEnumerator</returns>
  657. public override IEnumerator<T> GetEnumerator()
  658. {
  659. return items.GetEnumerator();
  660. }
  661. #endregion
  662. }
  663. #endregion
  664. #endregion
  665. #region CheckEnumerableElementsAnyOrder (Static)
  666. /// <summary>
  667. /// Test an IEnumerable should contain the given values in any order.
  668. /// </summary>
  669. /// <param name="e">E</param>
  670. /// <param name="expected">Expected</param>
  671. [Test]
  672. internal static void CheckEnumerableElementsAnyOrder<T>(
  673. IEnumerable<T> e, T[] expected)
  674. {
  675. bool[] found = new bool[expected.Length];
  676. int i = 0;
  677. foreach (T item in e)
  678. {
  679. int index;
  680. for (index = 0; index < expected.Length; ++index)
  681. {
  682. if (!found[index] &&
  683. Equals(expected[index], item))
  684. {
  685. break;
  686. }
  687. }
  688. Assert.True(index < expected.Length);
  689. Assert.True(Equals(expected[index], item));
  690. found[index] = true;
  691. ++i;
  692. }
  693. Assert.Equal(expected.Length, i);
  694. }
  695. #endregion
  696. #region TestCollectionBase (Static)
  697. /// <summary>
  698. /// Test collection base. Note: Too slow for a dynamic unit test.
  699. /// </summary>
  700. [Test]
  701. public static void TestCollectionBase()
  702. {
  703. string[] testStrings =
  704. new[]
  705. {
  706. "Omg", "what", "the", "f", "is", "up"
  707. };
  708. DerivedCollectionBase<string> testCollection =
  709. new DerivedCollectionBase<string>(testStrings);
  710. Assert.Equal("what", testCollection.ToArray()[1]);
  711. Assert.Equal("the", testCollection.ToArray()[2]);
  712. Assert.Equal("Omg", testCollection.ToArray()[0]);
  713. Assert.Equal("Omg, what, the, f, is, up", testCollection.ToString());
  714. }
  715. #endregion
  716. #region TestExists (Static)
  717. /// <summary>
  718. /// Test exists. Note: Too slow for a dynamic unit test.
  719. /// </summary>
  720. [Test]
  721. public static void TestExists()
  722. {
  723. DerivedCollectionBase<double> coll1 =
  724. new DerivedCollectionBase<double>(
  725. new[]
  726. {
  727. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  728. });
  729. Assert.True(coll1.Exists(
  730. delegate(double d)
  731. {
  732. return d > 100;
  733. }));
  734. Assert.True(coll1.Exists(
  735. delegate(double d)
  736. {
  737. return Math.Abs(d) == 0.04;
  738. }));
  739. Assert.False(coll1.Exists(
  740. delegate(double d)
  741. {
  742. return d < -10.0;
  743. }));
  744. coll1.Clear();
  745. Assert.False(coll1.Exists(
  746. delegate(double d)
  747. {
  748. return Math.Abs(d) == 0.04;
  749. }));
  750. DerivedCollectionBase<double> coll2 =
  751. new DerivedCollectionBase<double>(
  752. new[]
  753. {
  754. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  755. });
  756. Assert.True(coll2.Exists(
  757. delegate(double d)
  758. {
  759. return d > 100;
  760. }));
  761. Assert.True(coll2.Exists(
  762. delegate(double d)
  763. {
  764. return Math.Abs(d) == 0.04;
  765. }));
  766. Assert.False(coll2.Exists(
  767. delegate(double d)
  768. {
  769. return d < -10.0;
  770. }));
  771. coll2 = new DerivedCollectionBase<double>(new double[]
  772. {
  773. });
  774. Assert.False(coll2.Exists(
  775. delegate(double d)
  776. {
  777. return Math.Abs(d) == 0.04;
  778. }));
  779. }
  780. #endregion
  781. #region TestTrueForAll (Static)
  782. /// <summary>
  783. /// Test true for all. Note: Too slow for a dynamic unit test.
  784. /// </summary>
  785. [Test]
  786. public static void TestTrueForAll()
  787. {
  788. DerivedCollectionBase<double> coll1 =
  789. new DerivedCollectionBase<double>(
  790. new[]
  791. {
  792. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  793. });
  794. Assert.False(coll1.TrueForAll(
  795. delegate(double d)
  796. {
  797. return d > 100;
  798. }));
  799. Assert.False(coll1.TrueForAll(
  800. delegate(double d)
  801. {
  802. return Math.Abs(d) < 10;
  803. }));
  804. Assert.True(coll1.TrueForAll(
  805. delegate(double d)
  806. {
  807. return d > -10;
  808. }));
  809. Assert.True(coll1.TrueForAll(
  810. delegate(double d)
  811. {
  812. return Math.Abs(d) < 200;
  813. }));
  814. coll1.Clear();
  815. Assert.True(coll1.TrueForAll(
  816. delegate(double d)
  817. {
  818. return Math.Abs(d) == 0.04;
  819. }));
  820. DerivedCollectionBase<double> coll2 =
  821. new DerivedCollectionBase<double>(
  822. new[]
  823. {
  824. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  825. });
  826. Assert.False(coll2.TrueForAll(
  827. delegate(double d)
  828. {
  829. return d > 100;
  830. }));
  831. Assert.False(coll2.TrueForAll(
  832. delegate(double d)
  833. {
  834. return Math.Abs(d) < 10;
  835. }));
  836. Assert.True(coll2.TrueForAll(
  837. delegate(double d)
  838. {
  839. return d > -10;
  840. }));
  841. Assert.True(coll2.TrueForAll(
  842. delegate(double d)
  843. {
  844. return Math.Abs(d) < 200;
  845. }));
  846. coll2 = new DerivedCollectionBase<double>(new double[]
  847. {
  848. });
  849. Assert.True(coll2.TrueForAll(
  850. delegate(double d)
  851. {
  852. return Math.Abs(d) == 0.04;
  853. }));
  854. }
  855. #endregion
  856. #region TestCountWhere (Static)
  857. /// <summary>
  858. /// Test count where. Note: Too slow for a dynamic unit test.
  859. /// </summary>
  860. [Test]
  861. public static void TestCountWhere()
  862. {
  863. DerivedCollectionBase<double> coll1 =
  864. new DerivedCollectionBase<double>(
  865. new[]
  866. {
  867. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  868. });
  869. Assert.Equal(0, coll1.CountWhere(
  870. delegate(double d)
  871. {
  872. return d > 200;
  873. }));
  874. Assert.Equal(6, coll1.CountWhere(
  875. delegate(double d)
  876. {
  877. return Math.Abs(d) < 10;
  878. }));
  879. Assert.Equal(8, coll1.CountWhere(
  880. delegate(double d)
  881. {
  882. return d > -10;
  883. }));
  884. Assert.Equal(4, coll1.CountWhere(
  885. delegate(double d)
  886. {
  887. return Math.Abs(d) > 5;
  888. }));
  889. coll1.Clear();
  890. Assert.Equal(0, coll1.CountWhere(
  891. delegate(double d)
  892. {
  893. return Math.Abs(d) < 10;
  894. }));
  895. DerivedCollectionBase<double> coll2 =
  896. new DerivedCollectionBase<double>(
  897. new[]
  898. {
  899. 4.5, 1.2, 7.6, -7.6, -0.04, 1.78, 10.11, 187.4
  900. });
  901. Assert.Equal(0, coll2.CountWhere(
  902. delegate(double d)
  903. {
  904. return d > 200;
  905. }));
  906. Assert.Equal(6, coll2.CountWhere(
  907. delegate(double d)
  908. {
  909. return Math.Abs(d) < 10;
  910. }));
  911. Assert.Equal(8, coll2.CountWhere(
  912. delegate(double d)
  913. {
  914. return d > -10;
  915. }));
  916. Assert.Equal(4, coll2.CountWhere(
  917. delegate(double d)
  918. {
  919. return Math.Abs(d) > 5;
  920. }));
  921. coll2 = new DerivedCollectionBase<double>(new double[]
  922. {
  923. });
  924. Assert.Equal(0, coll2.CountWhere(
  925. delegate(double d)
  926. {
  927. return Math.Abs(d) < 10;
  928. }));
  929. }
  930. #endregion
  931. #region TestFindAll (Static)
  932. /// <summary>
  933. /// Test find all. Note: Too slow for a dynamic unit test.
  934. /// </summary>
  935. [Test]
  936. public static void TestFindAll()
  937. {
  938. DerivedCollectionBase<double> coll1 =
  939. new DerivedCollectionBase<double>(
  940. new[]
  941. {
  942. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  943. });
  944. double[] expected = {
  945. 7.6, -7.6, 10.11, 187.4
  946. };
  947. int i;
  948. i = 0;
  949. foreach (double x in coll1.FindAll(
  950. delegate(double d)
  951. {
  952. return Math.Abs(d) > 5;
  953. }))
  954. {
  955. Assert.Equal(expected[i], x);
  956. ++i;
  957. }
  958. Assert.Equal(expected.Length, i);
  959. DerivedCollectionBase<double> coll2 =
  960. new DerivedCollectionBase<double>(
  961. new[]
  962. {
  963. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  964. });
  965. expected = new[]
  966. {
  967. 7.6, -7.6, 10.11, 187.4
  968. };
  969. i = 0;
  970. foreach (double x in coll2.FindAll(
  971. delegate(double d)
  972. {
  973. return Math.Abs(d) > 5;
  974. }))
  975. {
  976. Assert.Equal(expected[i], x);
  977. ++i;
  978. }
  979. Assert.Equal(expected.Length, i);
  980. }
  981. #endregion
  982. #region TestRemoveAll (Static)
  983. /// <summary>
  984. /// Test remove all. Note: Too slow for a dynamic unit test.
  985. /// </summary>
  986. [Test]
  987. public static void TestRemoveAll()
  988. {
  989. DerivedCollectionBase<double> coll1 =
  990. new DerivedCollectionBase<double>(
  991. new[]
  992. {
  993. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  994. });
  995. coll1.RemoveAll(delegate(double d)
  996. {
  997. return Math.Abs(d) > 5;
  998. });
  999. CompareCollections(coll1, new[]
  1000. {
  1001. 4.5, 1.2, -0.04, 1.78
  1002. }, true);
  1003. coll1 = new DerivedCollectionBase<double>(
  1004. new[]
  1005. {
  1006. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  1007. });
  1008. coll1.RemoveAll(delegate(double d)
  1009. {
  1010. return d == 0;
  1011. });
  1012. CompareCollections(coll1,
  1013. new[]
  1014. {
  1015. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  1016. }, true);
  1017. coll1 = new DerivedCollectionBase<double>(
  1018. new[]
  1019. {
  1020. 4.5, 1.2, 7.6, -0.04, -7.6, 1.78, 10.11, 187.4
  1021. });
  1022. coll1.RemoveAll(delegate(double d)
  1023. {
  1024. return d < 200;
  1025. });
  1026. Assert.Equal(0, coll1.Count);
  1027. }
  1028. #endregion
  1029. #region TestForEach (Static)
  1030. /// <summary>
  1031. /// Test for each. Note: Too slow for a dynamic unit test.
  1032. /// </summary>
  1033. [Test]
  1034. public static void TestForEach()
  1035. {
  1036. DerivedCollectionBase<string> coll1 =
  1037. new DerivedCollectionBase<string>(
  1038. new[]
  1039. {
  1040. "foo", "bar", "hello", "sailor"
  1041. });
  1042. string s = "";
  1043. coll1.ForEach(delegate(string x)
  1044. {
  1045. s += "!" + x;
  1046. });
  1047. Assert.Equal(s, "!foo!bar!hello!sailor");
  1048. DerivedCollectionBase<string> coll2 =
  1049. new DerivedCollectionBase<string>(
  1050. new[]
  1051. {
  1052. "foo", "bar", "hello", "sailor"
  1053. });
  1054. s = "";
  1055. coll2.ForEach(delegate(string x)
  1056. {
  1057. s += "!" + x;
  1058. });
  1059. Assert.Equal(s, "!foo!bar!hello!sailor");
  1060. coll1 = new DerivedCollectionBase<string>(new string[]
  1061. {
  1062. });
  1063. s = "";
  1064. coll1.ForEach(delegate(string x)
  1065. {
  1066. s += "!" + x;
  1067. });
  1068. Assert.Equal(s, "");
  1069. coll2 = new DerivedCollectionBase<string>(new string[]
  1070. {
  1071. });
  1072. s = "";
  1073. coll2.ForEach(delegate(string x)
  1074. {
  1075. s += "!" + x;
  1076. });
  1077. Assert.Equal(s, "");
  1078. }
  1079. #endregion
  1080. #region CompareCollections (LongRunning)
  1081. /// <summary>
  1082. /// Test an ICollection&lt;string&gt; that should contain the given values,
  1083. /// possibly in order. Checks only the following items: GetEnumerator,
  1084. /// CopyTo, Count, Contains.
  1085. /// </summary>
  1086. /// <param name="coll">ICollection to test. </param>
  1087. /// <param name="values">The elements that should be in the collection.
  1088. /// </param>
  1089. /// <param name="mustBeInOrder">Must the elements be in order?</param>
  1090. [Test, Category("LongRunning")]
  1091. public static void CompareCollections<T>(
  1092. ICollection<T> coll, T[] values, bool mustBeInOrder)
  1093. {
  1094. bool[] used = new bool[values.Length];
  1095. // Check ICollection.Count.
  1096. Assert.Equal(values.Length, coll.Count);
  1097. // Check ICollection.GetEnumerator().
  1098. int i = 0, j;
  1099. foreach (T s in coll)
  1100. {
  1101. if (mustBeInOrder)
  1102. {
  1103. Assert.True(Equals(values[i], s));
  1104. } // if (mustBeInOrder)
  1105. else
  1106. {
  1107. bool found = false;
  1108. for (j = 0; j < values.Length; ++j)
  1109. {
  1110. if (!used[j] && Equals(values[j], s))
  1111. {
  1112. found = true;
  1113. used[j] = true;
  1114. break;
  1115. } // if ()
  1116. } // for (j)
  1117. Assert.True(found);
  1118. } // else
  1119. ++i;
  1120. } // foreach
  1121. // Check Contains
  1122. foreach (T s in values)
  1123. {
  1124. Assert.True(coll.Contains(s));
  1125. } // foreach
  1126. // Check CopyTo.
  1127. used = new bool[values.Length];
  1128. T[] newKeys = new T[coll.Count + 2];
  1129. coll.CopyTo(newKeys, 1);
  1130. for (i = 0, j = 1; i < coll.Count; ++i, ++j)
  1131. {
  1132. if (mustBeInOrder)
  1133. {
  1134. Assert.True(Equals(values[i], newKeys[j]));
  1135. } // if (mustBeInOrder)
  1136. else
  1137. {
  1138. bool found = false;
  1139. for (int k = 0; k < values.Length; ++k)
  1140. {
  1141. if (!used[k] && Equals(values[k], newKeys[j]))
  1142. {
  1143. found = true;
  1144. used[k] = true;
  1145. break;
  1146. } // if ()
  1147. } // for (int)
  1148. Assert.True(found);
  1149. } // else
  1150. } // for (i)
  1151. // Shouldn't have distubed the values around what was filled in.
  1152. Assert.True(Equals(default(T), newKeys[0]));
  1153. Assert.True(Equals(default(T), newKeys[coll.Count + 1]));
  1154. if (coll.Count != 0)
  1155. {
  1156. // Check CopyTo exceptions.
  1157. try
  1158. {
  1159. coll.CopyTo(null, 0);
  1160. throw new Exception("Copy to null should throw exception");
  1161. } // try
  1162. catch (Exception e)
  1163. {
  1164. Assert.True(e is ArgumentNullException);
  1165. } // catch
  1166. try
  1167. {
  1168. coll.CopyTo(newKeys, 3);
  1169. throw new Exception("CopyTo should throw argument exception");
  1170. } // try
  1171. catch (Exception e)
  1172. {
  1173. Assert.True(e is ArgumentException);
  1174. } // catch
  1175. try
  1176. {
  1177. coll.CopyTo(newKeys, -1);
  1178. throw new Exception(
  1179. "CopyTo should throw argument out of range exception");
  1180. } // try
  1181. catch (Exception e)
  1182. {
  1183. Assert.True(e is ArgumentOutOfRangeException);
  1184. } // catch
  1185. } // if (coll.Count)
  1186. }
  1187. #endregion
  1188. }
  1189. }