PageRenderTime 181ms CodeModel.GetById 81ms app.highlight 60ms RepoModel.GetById 30ms app.codeStats 1ms

/Utilities/Collections/CollectionBase.cs

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