using System.Linq;
using NUnit.Framework;
namespace System.Collections.Generic
{
///
/// A reusable test fixture base class for testing ICollection{T} types. This
/// helper class also implements the EnumerationTest{T} class to test
/// the IEnumeration{T} portion of the ICollection{T} being tested."
///
/// The type held by the collection.
public abstract class CollectionTests : EnumerationTests
{
///
/// Initializes a new instance of the
/// class.
///
/// True if the order of iteration by
/// the should be tested, false if otherwise.
/// If you specify true, be sure to implement the
/// property.
protected CollectionTests(bool testIterationOrder)
: this(testIterationOrder, null)
{ }
///
/// Initializes a new instance of the
/// class.
///
/// True if the order of iteration by
/// the should be tested, false if otherwise.
/// If you specify true, be sure to implement the
/// property.
/// The that
/// is used to compare values in the for
/// uniqueness or null if the default
/// specified by is to be used.
protected CollectionTests(bool testIterationOrder, IEqualityComparer comparer)
: base(testIterationOrder, comparer)
{ }
[Test]
[Description("Tests read-only classes. Checks if an NotSupportedException " +
"is thrown if an object is added. If the ICollection is not read " +
"only, then the test always passes.")]
public void NotSupportedExceptionWhenAddingToReadOnlyCollection()
{
ICollection collection = CreateReadOnlyCollection();
if (collection == null)
Assert.Ignore("The collection is NOT read only, so no testing " +
"needs to be done.");
CheckCollectionCount(collection);
var item = CreateItem();
Assert.Throws(() => collection.Add(item));
}
[Test]
[Description("Tests read-only classes. Checks if an NotSupportedException " +
"is thrown when Clear() is called on a collection. If the ICollection " +
"is not read only, then the test always passes.")]
public void NotSupportedExceptionWhenClearingAReadOnlyCollection()
{
ICollection collection = CreateReadOnlyCollection();
if (collection == null)
Assert.Ignore("The collection is NOT read only, so no testing " +
"needs to be done.");
CheckCollectionCount(collection);
Assert.Throws(() => collection.Clear());
}
[Test]
[Description("Tests read-only classes. Checks if an NotSupportedException " +
"is thrown when Remove() is called on a collection. If the ICollection " +
"is not read only, then the test always passes.")]
public void NotSupportedExceptionWhenRemovingFromAReadOnlyCollection()
{
ICollection collection = CreateReadOnlyCollection();
if (collection == null)
Assert.Ignore("The collection is NOT read only, so no testing " +
"needs to be done.");
CheckCollectionCount(collection);
var item = collection.First();
Assert.Throws(() => collection.Remove(item));
}
[Test]
[Description("Enumerates through the ICollection and checks if the " +
"Contains(T) method properly returns true for each item in the list.")]
public void ContainsWorksProperly()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
foreach (T item in collection)
{
Assert.True(collection.Contains(item), "The item \"" + item +
"\" is not in the collection even though that item was " +
"pulled from the collection.");
}
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection with a null " +
"array parameter to ensure the CopyTo(T[], int) method throws an " +
"ArgumentNullException.")]
public void ArgumentNullExceptionWhenCopyToArrayIsNull()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
Assert.Throws(() => collection.CopyTo(null, 0));
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection with a -1 " +
"arrayIndex parameter to ensure the CopyTo(T[], int) method throws an " +
"ArgumentOutOfRangeException.")]
public void ArgumentOutOfRangeExceptionWhenCopyToArrayIndexIsNegative()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[RequiredCollectionCount];
Assert.Throws(() => collection.CopyTo(array, -1));
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection with an array " +
"index parameter that is equal to the length of the array passed in " +
"to ensure an ArgumentException is thrown.")]
public void ArgumentExceptionWhenCopyToArrayIndexIsEqualToTheLengthOfTheArray()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[RequiredCollectionCount];
Assert.Throws(() => collection.CopyTo(array, RequiredCollectionCount));
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection with an array " +
"index parameter that is greater than the length of the array passed in " +
"to ensure an ArgumentException is thrown.")]
public void ArgumentExceptionWhenCopyToArrayIndexIsGreaterThanTheLengthOfTheArray()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[RequiredCollectionCount];
Assert.Throws(Is.AssignableTo(), () => collection.CopyTo(array, RequiredCollectionCount + 1));
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection with an array " +
"that is smaller than the number of elements from the array index " +
"passed in to the end of the ICollection to ensure an " +
"ArgumentException is thrown.")]
public void ArgumentExceptionWhenCopyToArrayIsSmallerThanTheNumberOfElementsFromArrayIndexToTheEndOfTheCollection()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[1];
Assert.Throws(() => collection.CopyTo(array, 0));
}
[Test]
[Description("Calls CopyTo(T[], int) on the ICollection and then checks " +
"the returned array to ensure it contains items that are in " +
"the ICollection.")]
public void CopyToContainsProperItems()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[RequiredCollectionCount];
collection.CopyTo(array, 0);
foreach (T item in array)
{
Assert.True(collection.Contains(item), "The item \"" + item + "\" " +
"copied from the array is not contained within the collection it " +
"was copied from.");
Assert.AreEqual(1, array.Count(otherItem => item.Equals(otherItem)),
"The item \"" + item + "\" is contained within the copied array " +
"more than once. Each item in the collection must be unique.");
}
}
[Test]
[Description("Removes() all items from the ICollection using Remove() " +
"method to ensure the Remove() method works properly")]
public void RemovesProperly()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
T[] array = new T[RequiredCollectionCount];
collection.CopyTo(array, 0);
foreach (T item in array)
{
Assert.True(collection.Remove(item), "Failed to remove one of " +
"the items from the list, even though it was contained " +
"within the list.");
}
Assert.AreEqual(0, collection.Count, "The collection is not empty even " +
"though all items were supposedly removed. ");
}
[Test]
[Description("Removes() an item from the list twice to ensure the " +
"Remove() method properly returns true the first time and false the " +
"second time.")]
public void RemoveMethodDoesNotRemoveTwice()
{
ICollection collection = CreateCollection();
CheckCollectionCount(collection);
// grab an item from the center of the list, just for kicks
T item = collection.Skip((int)(RequiredCollectionCount - (RequiredCollectionCount * 0.5f))).First();
Assert.True(collection.Remove(item), "Failed to remove an item that " +
"was supposed to be in the collection.");
Assert.False(collection.Remove(item), "The Remove() method returned " +
"true (i.e. it had properly removed an item from the collection) " +
"even though it had already been removed previously.");
}
[Test]
[Description("Counts the items in the ICollection using iteration and " +
"then checks that number against the Count property to ensure both " +
"are correct.")]
public void CountIsCorrect()
{
ICollection collection = CreateCollection();
Assert.AreEqual(collection.Count(), collection.Count, "The Count() " +
"LINQ method returned a different value from the ICollection's " +
"Count property.");
}
///
/// Checks the collection to see if it contains the required number of
/// items as specified by .
///
/// The collection to check.
void CheckCollectionCount(ICollection collection)
{
Assert.AreEqual(RequiredCollectionCount, collection.Count, "The collection " +
"does not contain the required number of items. It must contain " +
RequiredCollectionCount + " items.");
}
///
/// The number of items each collection is required to contain when it
/// was created by . The value of this
/// field is 7.
///
public const int RequiredCollectionCount = 7;
///
/// Creates an to test. Derived classes
/// should always create a new collection and never reuse the same
/// instance unless it makes sense for the class in question. The created
/// collection should contain the number of items specified by
/// . Each item in the list should
/// be unique so that a comparison of them does not yield duplicates.
/// This method should also create a collection that follows the rules
/// specified by the method
///
/// (see the comments on that method for details).
///
protected abstract ICollection CreateCollection();
///
/// Creates a read-only to test. This method
/// should behave exactly like the method
/// and follow the exact same rules (see the comments on
/// for details). If the collection can
/// never be read-only, then it should return the same exact thing as the
/// method.
///
protected abstract ICollection CreateReadOnlyCollection();
///
/// Creates an item that can be added to the class.
///
protected abstract T CreateItem();
///
/// This method should return a new that can
/// be iterated over exactly once. This method should create a new
/// every time it is invoked and not reuse
/// instances.
///
///
/// The containing a single item.
///
protected override IEnumerable CreateSingleItemEnumerable()
{
ICollection collection = CreateCollection();
// skip all of the items except one
T[] array = new T[collection.Count];
collection.CopyTo(array, 0);
IEnumerable itemsToRemove = array.Take(collection.Count - 1);
foreach (T item in itemsToRemove)
collection.Remove(item);
return collection;
}
///
/// This method should return a new that can
/// be iterated over five or more times. The items will be compared to
/// the items in but only
/// if the property
/// is set to true. This method should create a new
/// every time it is invoked and not reuse
/// instances. All instances returned through iteration of the
/// should be unique.
///
///
/// The containing many items.
///
protected override IEnumerable CreateManyItemEnumerable()
{
return CreateCollection();
}
}
///
/// A test fixture that is used to test the
/// and to provide an example of
/// how to create a proper
/// test fixture.
///
[TestFixture]
public class ListCollectionTestsFixture : CollectionTests
{
///
/// Initializes a new instance of the
/// class.
///
public ListCollectionTestsFixture() : base(true)
{ }
///
/// Creates an to test. Derived classes
/// should always create a new collection and never reuse the same
/// instance unless it makes sense for the class in question. The created
/// collection should contain the number of items specified by
/// . Each item in the list should
/// be unique so that a comparison of them does not yield duplicates.
///
/// The
protected override ICollection CreateCollection()
{
return new List(new[] { 0, 1, 2, 3, 4, 5, 6 });
}
///
/// Creates a read-only to test. This method
/// should behave exactly like the method
/// and follow the exact same rules (see the comments on
/// for details). If the collection can
/// never be read-only, then it should return the same exact thing as the
/// method.
///
///
protected override ICollection CreateReadOnlyCollection()
{
List list = new List(new[] { 0, 1, 2, 3, 4, 5, 6 });
return list.AsReadOnly();
}
///
/// Creates an item that can be added to the class.
///
/// The item that can be added to the list.
protected override int CreateItem()
{
return 1;
}
///
/// Returns the items created by
///
/// are expected to be in.
///
protected override IEnumerable OrderedItems
{
get { return _orderedItems; }
}
///
/// The backing field to .
///
readonly int[] _orderedItems = {0, 1, 2, 3, 4, 5, 6};
}
}