#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using System.Collections;
using System.Collections.Generic;
#if UNITTEST
using NUnit.Framework;
namespace Nuclex.Support.Collections {
/// Unit Test for the weak collection wrapper
[TestFixture]
internal class WeakCollectionTest {
#region class Dummy
/// Dummy class used to test the weakly referencing collection
private class Dummy {
/// Initializes a new dummy
/// Value that will be stored by the dummy
public Dummy(int value) {
this.Value = value;
}
///
/// Determines whether the specified System.Object is equal to
/// the current Dummy object.
///
///
/// The System.Object to compare with the current Dummy object
///
///
/// True if the specified System.Object is equal to the current Dummy object;
/// otherwise, false.
///
public override bool Equals(object otherAsObject) {
Dummy other = otherAsObject as Dummy;
if(other == null) {
return false;
}
return this.Value.Equals(other.Value);
}
/// Serves as a hash function for a particular type.
/// A hash code for the current System.Object.
public override int GetHashCode() {
return this.Value.GetHashCode();
}
/// Some value that can be used for testing
public int Value;
}
#endregion // class Dummy
#region class ListWithoutICollection
private class ListWithoutICollection : IList> {
public int IndexOf(WeakReference item) { throw new NotImplementedException(); }
public void Insert(int index, WeakReference item) {
throw new NotImplementedException();
}
public void RemoveAt(int index) { throw new NotImplementedException(); }
public WeakReference this[int index] {
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public void Add(WeakReference item) { throw new NotImplementedException(); }
public void Clear() { throw new NotImplementedException(); }
public bool Contains(WeakReference item) { throw new NotImplementedException(); }
public void CopyTo(WeakReference[] array, int arrayIndex) {
throw new NotImplementedException();
}
public int Count { get { return 12345; } }
public bool IsReadOnly { get { throw new NotImplementedException(); } }
public bool Remove(WeakReference item) { throw new NotImplementedException(); }
public IEnumerator> GetEnumerator() {
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}
#endregion // class ListWithoutICollection
/// Verifies that the constructor of the weak collection is working
[Test]
public void TestConstructor() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.IsNotNull(dummies);
}
///
/// Test whether the non-typesafe Add() method of the weak collection works
///
[Test]
public void TestAddAsObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(12345);
(dummies as IList).Add((object)oneTwoThreeDummy);
CollectionAssert.Contains(dummies, oneTwoThreeDummy);
}
///
/// Test whether the non-typesafe Add() method throws an exception if an object is
/// added that is not compatible to the collection's item type
///
[Test]
public void TestThrowOnAddIncompatibleObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.Throws(
delegate() { (dummies as IList).Add(new object()); }
);
}
///
/// Test whether the generic Add() method of the weak collection works
///
[Test]
public void TestAdd() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(12345);
dummies.Add(oneTwoThreeDummy);
CollectionAssert.Contains(dummies, oneTwoThreeDummy);
}
/// Tests whether the Clear() method works
[Test]
public void TestClear() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(12345);
dummies.Add(oneTwoThreeDummy);
Dummy threeTwoOneDummy = new Dummy(54321);
dummies.Add(threeTwoOneDummy);
Assert.AreEqual(2, dummies.Count);
dummies.Clear();
Assert.AreEqual(0, dummies.Count);
}
/// Tests whether the Contains() method works
[Test]
public void TestContains() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(12345);
dummies.Add(oneTwoThreeDummy);
Dummy threeTwoOneDummy = new Dummy(54321);
Assert.IsTrue(dummies.Contains(oneTwoThreeDummy));
Assert.IsFalse(dummies.Contains(threeTwoOneDummy));
}
/// Tests whether the non-typesafe Contains() method works
[Test]
public void TestContainsWithObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(12345);
dummies.Add(oneTwoThreeDummy);
Dummy threeTwoOneDummy = new Dummy(54321);
Assert.IsTrue((dummies as IList).Contains((object)oneTwoThreeDummy));
Assert.IsFalse((dummies as IList).Contains((object)threeTwoOneDummy));
}
///
/// Verifies that the Enumerator of the dummy collection correctly
/// implements the Reset() method
///
[Test]
public void TestEnumeratorReset() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
IEnumerator dummyEnumerator = dummies.GetEnumerator();
Assert.IsTrue(dummyEnumerator.MoveNext());
Assert.IsTrue(dummyEnumerator.MoveNext());
Assert.IsFalse(dummyEnumerator.MoveNext());
dummyEnumerator.Reset();
Assert.IsTrue(dummyEnumerator.MoveNext());
Assert.IsTrue(dummyEnumerator.MoveNext());
Assert.IsFalse(dummyEnumerator.MoveNext());
}
/// Verifies that the IndexOf() method is working as intended
[Test]
public void TestIndexOf() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Dummy sevenEightNineDummy = new Dummy(789);
Assert.AreEqual(0, dummies.IndexOf(oneTwoThreeDummy));
Assert.AreEqual(1, dummies.IndexOf(fourFiveSixDummy));
Assert.AreEqual(-1, dummies.IndexOf(sevenEightNineDummy));
}
///
/// Verifies that the non-typesafe IndexOf() method is working as intended
///
[Test]
public void TestIndexOfWithObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Dummy sevenEightNineDummy = new Dummy(789);
Assert.AreEqual(0, (dummies as IList).IndexOf((object)oneTwoThreeDummy));
Assert.AreEqual(1, (dummies as IList).IndexOf((object)fourFiveSixDummy));
Assert.AreEqual(-1, (dummies as IList).IndexOf((object)sevenEightNineDummy));
}
///
/// Verifies that an exception is thrown if an incompatible object is passed to
/// the non-typesafe variant of the IndexOf() method
///
[Test]
public void TestThrowOnIndexOfWithIncompatibleObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.Throws(
delegate() { Assert.IsNull((dummies as IList).IndexOf(new object())); }
);
}
/// Test whether the IndexOf() method can cope with null references
[Test]
public void TestIndexOfNull() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.AreEqual(-1, dummies.IndexOf(null));
dummies.Add(null);
Assert.AreEqual(0, dummies.IndexOf(null));
}
///
/// Verifies that the CopyTo() method of the weak collection works
///
[Test]
public void TestCopyToArray() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Dummy[] inputDummies = new Dummy[] { oneTwoThreeDummy, fourFiveSixDummy };
Dummy[] outputDummies = new Dummy[dummies.Count];
dummies.CopyTo(outputDummies, 0);
CollectionAssert.AreEqual(inputDummies, outputDummies);
}
///
/// Verifies that the CopyTo() method of the weak collection throws an exception
/// if the target array is too small to hold the collection's contents
///
[Test]
public void TestThrowOnCopyToTooSmallArray() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Dummy[] outputStrings = new Dummy[dummies.Count - 1];
Assert.Throws(
delegate() { dummies.CopyTo(outputStrings, 0); }
);
}
///
/// Verifies that the CopyTo() method of the transforming read only collection
/// works if invoked via the ICollection interface
///
[Test]
public void TestCopyToArrayViaICollection() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Dummy[] inputDummies = new Dummy[] { oneTwoThreeDummy, fourFiveSixDummy };
Dummy[] outputDummies = new Dummy[dummies.Count];
(dummies as ICollection).CopyTo(outputDummies, 0);
CollectionAssert.AreEqual(inputDummies, outputDummies);
}
///
/// Verifies that the Insert() method correctly shifts items in the collection
///
[Test]
public void TestInsert() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Insert(0, fourFiveSixDummy);
Assert.AreEqual(2, dummies.Count);
Assert.AreSame(fourFiveSixDummy, dummies[0]);
Assert.AreSame(oneTwoThreeDummy, dummies[1]);
}
///
/// Verifies that the non-typesafe Insert() method correctly shifts items in
/// the collection
///
[Test]
public void TestInsertObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
(dummies as IList).Insert(0, (object)fourFiveSixDummy);
Assert.AreEqual(2, dummies.Count);
Assert.AreSame(fourFiveSixDummy, dummies[0]);
Assert.AreSame(oneTwoThreeDummy, dummies[1]);
}
///
/// Verifies that the non-typesafe Insert() method correctly shifts items in
/// the collection
///
[Test]
public void TestThrowOnInsertIncompatibleObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Assert.Throws(
delegate() { (dummies as IList).Insert(0, new object()); }
);
}
///
/// Checks whether the IsFixedSize property of the weak collection returns
/// the expected result for a weak collection based on a fixed array
///
[Test]
public void TestIsFixedSizeViaIList() {
Dummy oneTwoThreeDummy = new Dummy(123);
Dummy fourFiveSixDummy = new Dummy(456);
WeakReference[] dummyReferences = new WeakReference[] {
new WeakReference(oneTwoThreeDummy),
new WeakReference(fourFiveSixDummy)
};
WeakCollection dummies = new WeakCollection(dummyReferences);
Assert.IsTrue((dummies as IList).IsFixedSize);
}
///
/// Tests whether the IsReadOnly property of the weak collection works
///
[Test]
public void TestIsReadOnly() {
Dummy oneTwoThreeDummy = new Dummy(123);
Dummy fourFiveSixDummy = new Dummy(456);
List> dummyReferences = new List>();
dummyReferences.Add(new WeakReference(oneTwoThreeDummy));
dummyReferences.Add(new WeakReference(fourFiveSixDummy));
ReadOnlyList> readOnlyDummyReferences =
new ReadOnlyList>(dummyReferences);
WeakCollection dummies = new WeakCollection(dummyReferences);
WeakCollection readOnlydummies = new WeakCollection(
readOnlyDummyReferences
);
Assert.IsFalse(dummies.IsReadOnly);
Assert.IsTrue(readOnlydummies.IsReadOnly);
}
///
/// Tests whether the IsSynchronized property of the weak collection works
///
[Test]
public void TestIsSynchronized() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.IsFalse((dummies as IList).IsSynchronized);
}
/// Tests the indexer of the weak collection
[Test]
public void TestIndexer() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Assert.AreSame(oneTwoThreeDummy, dummies[0]);
Assert.AreSame(fourFiveSixDummy, dummies[1]);
dummies[0] = fourFiveSixDummy;
Assert.AreSame(fourFiveSixDummy, dummies[0]);
}
/// Tests the non-typesafe indexer of the weak collection
[Test]
public void TestIndexerWithObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Assert.AreSame((object)oneTwoThreeDummy, (dummies as IList)[0]);
Assert.AreSame((object)fourFiveSixDummy, (dummies as IList)[1]);
(dummies as IList)[0] = (object)fourFiveSixDummy;
Assert.AreSame((object)fourFiveSixDummy, (dummies as IList)[0]);
}
///
/// Tests whether the non-typesafe indexer of the weak collection throws
/// the correct exception if an incompatible object is assigned
///
[Test]
public void TestThrowOnIndexerWithIncompatibleObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Assert.Throws(
delegate() { (dummies as IList)[0] = new object(); }
);
}
/// Tests the Remove() method of the weak collection
[Test]
public void TestRemove() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Assert.AreEqual(2, dummies.Count);
Assert.IsTrue(dummies.Remove(oneTwoThreeDummy));
Assert.AreEqual(1, dummies.Count);
Assert.IsFalse(dummies.Remove(oneTwoThreeDummy));
}
/// Tests the non-typesafe Remove() method of the weak collection
[Test]
public void TestRemoveObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Assert.AreEqual(2, dummies.Count);
(dummies as IList).Remove((object)oneTwoThreeDummy);
Assert.AreEqual(1, dummies.Count);
}
///
/// Tests whether a null object can be managed by and removed from the weak collection
///
[Test]
public void TestRemoveNull() {
WeakCollection dummies = new WeakCollection(
new List>()
);
dummies.Add(null);
Assert.AreEqual(1, dummies.Count);
Assert.IsTrue(dummies.Remove(null));
Assert.AreEqual(0, dummies.Count);
}
///
/// Tests whether the non-typesafe Remove() method of the weak collection throws
/// an exception if an object is tried to be removed that is incompatible with
/// the collection's item type
///
[Test]
public void TestThrowOnRemoveIncompatibleObject() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Assert.Throws(
delegate() { (dummies as IList).Remove(new object()); }
);
}
/// Tests the RemoveAt() method of the weak collection
[Test]
public void TestRemoveAt() {
WeakCollection dummies = new WeakCollection(
new List>()
);
Dummy oneTwoThreeDummy = new Dummy(123);
dummies.Add(oneTwoThreeDummy);
Dummy fourFiveSixDummy = new Dummy(456);
dummies.Add(fourFiveSixDummy);
Assert.AreSame(oneTwoThreeDummy, dummies[0]);
dummies.RemoveAt(0);
Assert.AreSame(fourFiveSixDummy, dummies[0]);
}
///
/// Verifies that the IsSynchronized property and the SyncRoot property are working
///
[Test]
public void TestSynchronization() {
WeakCollection dummies = new WeakCollection(
new List>()
);
if(!(dummies as ICollection).IsSynchronized) {
lock((dummies as ICollection).SyncRoot) {
Assert.AreEqual(0, dummies.Count);
}
}
}
///
/// Verifies that the IsSynchronized property and the SyncRoot property are working
/// on transforming read only collections based on IList<>s that do not
/// implement the ICollection interface
///
[Test]
public void TestSynchronizationOfIListWithoutICollection() {
WeakCollection dummies = new WeakCollection(
new ListWithoutICollection()
);
if(!(dummies as ICollection).IsSynchronized) {
lock((dummies as ICollection).SyncRoot) {
int count = dummies.Count;
Assert.AreEqual(12345, count); // ;-)
}
}
}
/// Tests the RemoveDeadItems() method
[Test]
public void TestRemoveDeadItems() {
List> dummyReferences = new List>();
Dummy oneTwoThreeDummy = new Dummy(123);
dummyReferences.Add(new WeakReference(oneTwoThreeDummy));
dummyReferences.Add(new WeakReference(null));
Dummy fourFiveSixDummy = new Dummy(456);
dummyReferences.Add(new WeakReference(fourFiveSixDummy));
WeakCollection dummies = new WeakCollection(dummyReferences);
Assert.AreEqual(3, dummies.Count);
dummies.RemoveDeadItems();
Assert.AreEqual(2, dummies.Count);
Assert.AreSame(oneTwoThreeDummy, dummies[0]);
Assert.AreSame(fourFiveSixDummy, dummies[1]);
}
}
} // namespace Nuclex.Support.Collections
#endif // UNITTEST