From 5c906463278b2d5e8701e12b99ca9aea8c0d388b Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Thu, 27 Nov 2008 19:40:43 +0000 Subject: [PATCH] Achieved 100% test coverage for the TransformingReadOnlyCollection and ReadOnlyList classes git-svn-id: file:///srv/devel/repo-conversion/nusu@97 d2e56fa2-650e-0410-a79f-9358c0239efd --- Nuclex.Support.csproj | 9 + Source/Collections/ReadOnlyDictionary.Test.cs | 39 ++ Source/Collections/ReadOnlyList.Test.cs | 357 +++++++++++++ Source/Collections/ReadOnlyList.cs | 2 +- ...ansformingReadOnlyCollection.Interfaces.cs | 89 ---- .../TransformingReadOnlyCollection.Test.cs | 471 ++++++++++++++++++ .../TransformingReadOnlyCollection.cs | 13 +- 7 files changed, 886 insertions(+), 94 deletions(-) create mode 100644 Source/Collections/ReadOnlyDictionary.Test.cs create mode 100644 Source/Collections/ReadOnlyList.Test.cs create mode 100644 Source/Collections/TransformingReadOnlyCollection.Test.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index 3400830..84b333b 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -80,7 +80,13 @@ ReadOnlyCollection.cs + + ReadOnlyDictionary.cs + + + ReadOnlyList.cs + ReverseComparer.cs @@ -93,6 +99,9 @@ TransformingReadOnlyCollection.cs + + TransformingReadOnlyCollection.cs + FloatHelper.cs diff --git a/Source/Collections/ReadOnlyDictionary.Test.cs b/Source/Collections/ReadOnlyDictionary.Test.cs new file mode 100644 index 0000000..0c0894a --- /dev/null +++ b/Source/Collections/ReadOnlyDictionary.Test.cs @@ -0,0 +1,39 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +#if UNITTEST + +using NUnit.Framework; + +namespace Nuclex.Support.Collections { + + /// Unit Test for the read only dictionary wrapper + [TestFixture] + public class ReadOnlyDictionaryTest { + + } + +} // namespace Nuclex.Support.Collections + +#endif // UNITTEST diff --git a/Source/Collections/ReadOnlyList.Test.cs b/Source/Collections/ReadOnlyList.Test.cs new file mode 100644 index 0000000..ed623e9 --- /dev/null +++ b/Source/Collections/ReadOnlyList.Test.cs @@ -0,0 +1,357 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +#if UNITTEST + +using NUnit.Framework; + +namespace Nuclex.Support.Collections { + + /// Unit Test for the read only list wrapper + [TestFixture] + public class ReadOnlyListTest { + + /// + /// Verifies that the copy constructor of the read only list works + /// + [Test] + public void TestCopyConstructor() { + int[] integers = new int[] { 12, 34, 56, 78 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + CollectionAssert.AreEqual(integers, testList); + } + + /// Verifies that the IsReadOnly property returns true + [Test] + public void TestIsReadOnly() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + + Assert.IsTrue(testList.IsReadOnly); + } + + /// + /// Verifies that the CopyTo() of the read only list works + /// + [Test] + public void TestCopyToArray() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + ReadOnlyList testList = new ReadOnlyList(inputIntegers); + + int[] outputIntegers = new int[testList.Count]; + testList.CopyTo(outputIntegers, 0); + + CollectionAssert.AreEqual(inputIntegers, outputIntegers); + } + + /// + /// Checks whether the Contains() method of the read only list is able to + /// determine if the list contains an item + /// + [Test] + public void TestContains() { + int[] integers = new int[] { 1234, 6789 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.IsTrue(testList.Contains(1234)); + Assert.IsFalse(testList.Contains(4321)); + } + + /// + /// Checks whether the IndexOf() method of the read only list is able to + /// determine if the index of an item in the list + /// + [Test] + public void TestIndexOf() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.AreEqual(0, testList.IndexOf(12)); + Assert.AreEqual(1, testList.IndexOf(34)); + Assert.AreEqual(2, testList.IndexOf(67)); + Assert.AreEqual(3, testList.IndexOf(89)); + } + + /// + /// Checks whether the indexer method of the read only list is able to + /// retrieve items from the list + /// + [Test] + public void TestRetrieveByIndexer() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.AreEqual(12, testList[0]); + Assert.AreEqual(34, testList[1]); + Assert.AreEqual(67, testList[2]); + Assert.AreEqual(89, testList[3]); + } + + /// + /// Checks whether the read only list will throw an exception if its Insert() method + /// is called via the generic IList<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnInsertViaGenericIList() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + (testList as IList).Insert(0, 12345); + } + + /// + /// Checks whether the read only list will throw an exception if its RemoveAt() method + /// is called via the generic IList<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaGenericIList() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + (testList as IList).RemoveAt(0); + } + + /// + /// Checks whether the indexer method of the read only list will throw an exception + /// if it is attempted to be used for replacing an item + /// + [Test] + public void TestRetrieveByIndexerViaGenericIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.AreEqual(12, (testList as IList)[0]); + Assert.AreEqual(34, (testList as IList)[1]); + Assert.AreEqual(67, (testList as IList)[2]); + Assert.AreEqual(89, (testList as IList)[3]); + } + + /// + /// Checks whether the indexer method of the read only list will throw an exception + /// if it is attempted to be used for replacing an item + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnReplaceByIndexerViaGenericIList() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + + (testList as IList)[0] = 12345; + } + + /// + /// Checks whether the read only list will throw an exception if its Add() method + /// is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnAddViaGenericICollection() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + (testList as ICollection).Add(12345); + } + + /// + /// Checks whether the read only list will throw an exception if its Clear() method + /// is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnClearViaGenericICollection() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + (testList as ICollection).Clear(); + } + + /// + /// Checks whether the read only list will throw an exception if its Remove() method + /// is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaGenericICollection() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + (testList as ICollection).Remove(89); + } + + /// + /// Tests whether the typesafe enumerator of the read only collection is working + /// + [Test] + public void TestTypesafeEnumerator() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + ReadOnlyList testList = new ReadOnlyList(inputIntegers); + + List outputIntegers = new List(); + foreach(int value in testList) { + outputIntegers.Add(value); + } + + CollectionAssert.AreEqual(inputIntegers, outputIntegers); + } + + /// + /// Checks whether the read only list will throw an exception if its Clear() method + /// is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnClearViaIList() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + (testList as IList).Clear(); + } + + /// + /// Checks whether the read only list will throw an exception if its Add() method + /// is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnAddViaIList() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + (testList as IList).Add(12345); + } + + /// + /// Checks whether the Contains() method of the read only list is able to + /// determine if the list contains an item + /// + [Test] + public void TestContainsViaIList() { + int[] integers = new int[] { 1234, 6789 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.IsTrue((testList as IList).Contains(1234)); + Assert.IsFalse((testList as IList).Contains(4321)); + } + + /// + /// Checks whether the IndexOf() method of the read only list is able to + /// determine if the index of an item in the list + /// + [Test] + public void TestIndexOfViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.AreEqual(0, (testList as IList).IndexOf(12)); + Assert.AreEqual(1, (testList as IList).IndexOf(34)); + Assert.AreEqual(2, (testList as IList).IndexOf(67)); + Assert.AreEqual(3, (testList as IList).IndexOf(89)); + } + + /// + /// Checks whether the read only list will throw an exception if its Insert() method + /// is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnInsertViaIList() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + (testList as IList).Insert(0, 12345); + } + + /// + /// Checks whether the IsFixedSize property of the read only list returns the + /// expected result for a read only list based on a fixed array + /// + [Test] + public void TestIsFixedSizeViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.IsTrue((testList as IList).IsFixedSize); + } + + /// + /// Checks whether the read only list will throw an exception if its Remove() method + /// is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaIList() { + int[] integers = new int[] { 1234, 6789 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + (testList as IList).Remove(6789); + } + + /// + /// Checks whether the read only list will throw an exception if its Remove() method + /// is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveAtViaIList() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + + (testList as IList).RemoveAt(0); + } + + /// + /// Checks whether the indexer method of the read only list will throw an exception + /// if it is attempted to be used for replacing an item + /// + [Test] + public void TestRetrieveByIndexerViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + ReadOnlyList testList = new ReadOnlyList(integers); + + Assert.AreEqual(12, (testList as IList)[0]); + Assert.AreEqual(34, (testList as IList)[1]); + Assert.AreEqual(67, (testList as IList)[2]); + Assert.AreEqual(89, (testList as IList)[3]); + } + + /// + /// Checks whether the indexer method of the read only list will throw an exception + /// if it is attempted to be used for replacing an item + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnReplaceByIndexerViaIList() { + ReadOnlyList testList = new ReadOnlyList(new int[1]); + + (testList as IList)[0] = 12345; + } + + /// + /// Verifies that the CopyTo() of the read only list works if invoked via + /// the ICollection interface + /// + [Test] + public void TestCopyToArrayViaICollection() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + ReadOnlyList testList = new ReadOnlyList(inputIntegers); + + int[] outputIntegers = new int[testList.Count]; + (testList as ICollection).CopyTo(outputIntegers, 0); + + CollectionAssert.AreEqual(inputIntegers, outputIntegers); + } + + /// + /// Verifies that the IsSynchronized property and the SyncRoot property are working + /// + [Test] + public void TestSynchronization() { + ReadOnlyList testList = new ReadOnlyList(new int[0]); + + if(!(testList as ICollection).IsSynchronized) { + lock((testList as ICollection).SyncRoot) { + int count = testList.Count; + } + } + } + + } + +} // namespace Nuclex.Support.Collections + +#endif // UNITTEST diff --git a/Source/Collections/ReadOnlyList.cs b/Source/Collections/ReadOnlyList.cs index 3a72cd1..7201470 100644 --- a/Source/Collections/ReadOnlyList.cs +++ b/Source/Collections/ReadOnlyList.cs @@ -194,7 +194,7 @@ namespace Nuclex.Support.Collections { /// Whether the size of the List is fixed bool IList.IsFixedSize { - get { throw new NotImplementedException(); } + get { return this.objectList.IsFixedSize; } } /// Removes the specified item from the List diff --git a/Source/Collections/TransformingReadOnlyCollection.Interfaces.cs b/Source/Collections/TransformingReadOnlyCollection.Interfaces.cs index f3685ba..54d3a85 100644 --- a/Source/Collections/TransformingReadOnlyCollection.Interfaces.cs +++ b/Source/Collections/TransformingReadOnlyCollection.Interfaces.cs @@ -35,19 +35,6 @@ namespace Nuclex.Support.Collections { #region IList Members - /// - /// Determines the index of a specific item in the TransformingReadOnlyCollection. - /// - /// - /// The object to locate in the TransformingReadOnlyCollection. - /// - /// - /// The index of item if found in the list; otherwise, -1. - /// - int IList.IndexOf(ExposedItemType item) { - return IndexOf(item); - } - /// /// Inserts an item to the TransformingReadOnlyCollection at the specified index. /// @@ -120,48 +107,6 @@ namespace Nuclex.Support.Collections { throw new NotSupportedException("The collection is ready-only"); } - /// - /// Determines whether the TransformingReadOnlyCollection contains a specific value. - /// - /// - /// The object to locate in the TransformingReadOnlyCollection. - /// - /// - /// True if item is found in the TransformingReadOnlyCollection; otherwise, false. - /// - bool ICollection.Contains(ExposedItemType item) { - return Contains(item); - } - - /// - /// Copies the elements of the TransformingReadOnlyCollection to an System.Array, - /// starting at a particular System.Array index. - /// - /// - /// The one-dimensional System.Array that is the destination of the elements - /// copied from TransformingReadOnlyCollection. The System.Array must have - /// zero-based indexing. - /// - /// - /// The zero-based index in array at which copying begins - /// - /// - /// ArrayIndex is less than 0. - /// - /// - /// Array is null. - /// - /// - /// Array is multidimensional or arrayIndex is equal to or greater than the - /// length of array or the number of elements in the source - /// TransformingReadOnlyCollection is greater than the available - /// space from arrayIndex to the end of the destination array or type T cannot - /// be cast automatically to the type of the destination array. - /// - void ICollection.CopyTo(ExposedItemType[] array, int arrayIndex) { - CopyTo(array, arrayIndex); - } - /// /// Removes the first occurrence of a specific object from the /// TransformingReadOnlyCollection. @@ -181,33 +126,6 @@ namespace Nuclex.Support.Collections { throw new NotSupportedException("The collection is ready-only"); } - /// - /// The number of elements contained in the TransformingReadOnlyCollection. - /// - int ICollection.Count { - get { return Count; } - } - - /// - /// A value indicating whether the TransformingReadOnlyCollection is read-only. - /// - bool ICollection.IsReadOnly { - get { return true; } - } - - #endregion - - #region IEnumerable Members - - /// Returns an enumerator that iterates through the collection. - /// - /// A System.Collections.Generic.IEnumerator<ExposedItemType> that can be used - /// to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() { - return GetEnumerator(); - } - #endregion #region IEnumerable Members @@ -304,13 +222,6 @@ namespace Nuclex.Support.Collections { get { return true; } } - /// - /// A value indicating whether the index is not a valid index in the is read-only. - /// - bool IList.IsReadOnly { - get { return true; } - } - /// /// Removes the first occurrence of a specific object from the /// TransformingReadOnlyCollection. diff --git a/Source/Collections/TransformingReadOnlyCollection.Test.cs b/Source/Collections/TransformingReadOnlyCollection.Test.cs new file mode 100644 index 0000000..9f6a8c1 --- /dev/null +++ b/Source/Collections/TransformingReadOnlyCollection.Test.cs @@ -0,0 +1,471 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +#if UNITTEST + +using NUnit.Framework; +using NMock2; + +namespace Nuclex.Support.Collections { + + /// Unit Test for the transforming read only collection wrapper + [TestFixture] + public class TransformingReadOnlyCollectionTest { + + #region class StringTransformer + + /// Test implementation of a transforming collection + private class StringTransformer : TransformingReadOnlyCollection { + + /// Initializes a new int-to-string transforming collection + /// Items the transforming collection will contain + public StringTransformer(IList items) : base(items) { } + + /// Transforms an item into the exposed type + /// Item to be transformed + /// The transformed item + /// + /// This method is used to transform an item in the wrapped collection into + /// the exposed item type whenever the user accesses an item. Expect it to + /// be called frequently, because the TransformingReadOnlyCollection does + /// not cache or otherwise store the transformed items. + /// + protected override string Transform(int item) { + if(item == 42) { + return null; + } + + return item.ToString(); + } + + } + + #endregion // class StringTransformer + + /// + /// Verifies that the copy constructor of the transforming read only collection works + /// + [Test] + public void TestCopyConstructor() { + int[] integers = new int[] { 12, 34, 56, 78 }; + StringTransformer testCollection = new StringTransformer(integers); + + string[] strings = new string[] { "12", "34", "56", "78" }; + CollectionAssert.AreEqual(strings, testCollection); + } + + /// Verifies that the IsReadOnly property returns true + [Test] + public void TestIsReadOnly() { + StringTransformer testCollection = new StringTransformer(new int[0]); + + Assert.IsTrue(testCollection.IsReadOnly); + } + + /// + /// Verifies that the CopyTo() of the transforming read only collection works + /// + [Test] + public void TestCopyToArray() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + StringTransformer testCollection = new StringTransformer(inputIntegers); + + string[] inputStrings = new string[] { "12", "34", "56", "78" }; + string[] outputStrings = new string[testCollection.Count]; + testCollection.CopyTo(outputStrings, 0); + + CollectionAssert.AreEqual(inputStrings, outputStrings); + } + + /// + /// Verifies that the CopyTo() of the transforming read only collection throws + /// an exception if the target array is too small to hold the collection's contents + /// + [Test, ExpectedException(typeof(ArgumentException))] + public void TestThrowOnCopyToTooSmallArray() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + StringTransformer testCollection = new StringTransformer(inputIntegers); + + string[] outputStrings = new string[testCollection.Count - 1]; + testCollection.CopyTo(outputStrings, 0); + } + + /// + /// Checks whether the Contains() method of the transforming read only collection + /// is able to determine if the collection contains an item + /// + [Test] + public void TestContains() { + int[] integers = new int[] { 1234, 6789 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.IsTrue(testCollection.Contains("1234")); + Assert.IsFalse(testCollection.Contains("4321")); + } + + /// + /// Checks whether the IndexOf() method of the transforming read only collection + /// is able to determine if the index of an item in the collection + /// + [Test] + public void TestIndexOf() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual(0, testCollection.IndexOf("12")); + Assert.AreEqual(1, testCollection.IndexOf("34")); + Assert.AreEqual(2, testCollection.IndexOf("67")); + Assert.AreEqual(3, testCollection.IndexOf("89")); + } + + /// + /// Checks whether the IndexOf() method of the transforming read only collection + /// can cope with queries for 'null' when no 'null' item is contained on it + /// + [Test] + public void TestIndexOfWithNullItemNotContained() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual(-1, testCollection.IndexOf(null)); + } + + /// + /// Checks whether the IndexOf() method of the transforming read only collection + /// can cope with queries for 'null' when a 'null' item is contained on it + /// + [Test] + public void TestIndexOfWithNullItemContained() { + int[] integers = new int[] { 12, 34, 67, 89, 42 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual(4, testCollection.IndexOf(null)); + } + + /// + /// Verifies that the Enumerator of the transforming read only collection correctly + /// implements the Reset() method + /// + [Test] + public void TestEnumeratorReset() { + int[] integers = new int[] { 1234, 6789 }; + StringTransformer testCollection = new StringTransformer(integers); + + IEnumerator stringEnumerator = testCollection.GetEnumerator(); + Assert.IsTrue(stringEnumerator.MoveNext()); + Assert.IsTrue(stringEnumerator.MoveNext()); + Assert.IsFalse(stringEnumerator.MoveNext()); + + stringEnumerator.Reset(); + + Assert.IsTrue(stringEnumerator.MoveNext()); + Assert.IsTrue(stringEnumerator.MoveNext()); + Assert.IsFalse(stringEnumerator.MoveNext()); + } + + /// + /// Checks whether the indexer method of the transforming read only collection + /// is able to retrieve items from the collection + /// + [Test] + public void TestRetrieveByIndexer() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual("12", testCollection[0]); + Assert.AreEqual("34", testCollection[1]); + Assert.AreEqual("67", testCollection[2]); + Assert.AreEqual("89", testCollection[3]); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Insert() method is called via the generic IList<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnInsertViaGenericIList() { + StringTransformer testCollection = new StringTransformer(new int[0]); + (testCollection as IList).Insert(0, "12345"); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its RemoveAt() method is called via the generic IList<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaGenericIList() { + StringTransformer testCollection = new StringTransformer(new int[1]); + (testCollection as IList).RemoveAt(0); + } + + /// + /// Checks whether the indexer method of the transforming read only collection will + /// throw an exception if it is attempted to be used for replacing an item + /// + [Test] + public void TestRetrieveByIndexerViaGenericIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual("12", (testCollection as IList)[0]); + Assert.AreEqual("34", (testCollection as IList)[1]); + Assert.AreEqual("67", (testCollection as IList)[2]); + Assert.AreEqual("89", (testCollection as IList)[3]); + } + + /// + /// Checks whether the indexer method of the transforming read only collection + /// will throw an exception if it is attempted to be used for replacing an item + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnReplaceByIndexerViaGenericIList() { + StringTransformer testCollection = new StringTransformer(new int[1]); + + (testCollection as IList)[0] = "12345"; + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Add() method is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnAddViaGenericICollection() { + StringTransformer testCollection = new StringTransformer(new int[0]); + (testCollection as ICollection).Add("12345"); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Clear() method is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnClearViaGenericICollection() { + StringTransformer testCollection = new StringTransformer(new int[1]); + (testCollection as ICollection).Clear(); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Remove() method is called via the generic ICollection<> interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaGenericICollection() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + (testCollection as ICollection).Remove("89"); + } + + /// + /// Tests whether the typesafe enumerator of the read only collection is working + /// + [Test] + public void TestTypesafeEnumerator() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + StringTransformer testCollection = new StringTransformer(inputIntegers); + + List outputStrings = new List(); + foreach(string value in testCollection) { + outputStrings.Add(value); + } + + string[] inputStrings = new string[] { "12", "34", "56", "78" }; + CollectionAssert.AreEqual(inputStrings, outputStrings); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Clear() method is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnClearViaIList() { + StringTransformer testCollection = new StringTransformer(new int[1]); + (testCollection as IList).Clear(); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Add() method is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnAddViaIList() { + StringTransformer testCollection = new StringTransformer(new int[0]); + (testCollection as IList).Add("12345"); + } + + /// + /// Checks whether the Contains() method of the transforming read only collection + /// is able to determine if the collection contains an item + /// + [Test] + public void TestContainsViaIList() { + int[] integers = new int[] { 1234, 6789 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.IsTrue((testCollection as IList).Contains("1234")); + Assert.IsFalse((testCollection as IList).Contains("4321")); + } + + /// + /// Checks whether the IndexOf() method of the transforming read only collection + /// is able to determine if the index of an item in the collection + /// + [Test] + public void TestIndexOfViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual(0, (testCollection as IList).IndexOf("12")); + Assert.AreEqual(1, (testCollection as IList).IndexOf("34")); + Assert.AreEqual(2, (testCollection as IList).IndexOf("67")); + Assert.AreEqual(3, (testCollection as IList).IndexOf("89")); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Insert() method is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnInsertViaIList() { + StringTransformer testCollection = new StringTransformer(new int[0]); + (testCollection as IList).Insert(0, "12345"); + } + + /// + /// Checks whether the IsFixedSize property of the transforming read only collection + /// returns the expected result for a transforming read only collection based on + /// a fixed array + /// + [Test] + public void TestIsFixedSizeViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.IsTrue((testCollection as IList).IsFixedSize); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Remove() method is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveViaIList() { + int[] integers = new int[] { 1234, 6789 }; + StringTransformer testCollection = new StringTransformer(integers); + + (testCollection as IList).Remove("6789"); + } + + /// + /// Checks whether the transforming read only collection will throw an exception + /// if its Remove() method is called via the IList interface + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnRemoveAtViaIList() { + StringTransformer testCollection = new StringTransformer(new int[1]); + + (testCollection as IList).RemoveAt(0); + } + + /// + /// Checks whether the indexer method of the transforming read only collection + /// will throw an exception if it is attempted to be used for replacing an item + /// + [Test] + public void TestRetrieveByIndexerViaIList() { + int[] integers = new int[] { 12, 34, 67, 89 }; + StringTransformer testCollection = new StringTransformer(integers); + + Assert.AreEqual("12", (testCollection as IList)[0]); + Assert.AreEqual("34", (testCollection as IList)[1]); + Assert.AreEqual("67", (testCollection as IList)[2]); + Assert.AreEqual("89", (testCollection as IList)[3]); + } + + /// + /// Checks whether the indexer method of the transforming read only collection + /// will throw an exception if it is attempted to be used for replacing an item + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnReplaceByIndexerViaIList() { + StringTransformer testCollection = new StringTransformer(new int[1]); + + (testCollection as IList)[0] = "12345"; + } + + /// + /// Verifies that the CopyTo() of the transforming read only collection works + /// if invoked via the ICollection interface + /// + [Test] + public void TestCopyToArrayViaICollection() { + int[] inputIntegers = new int[] { 12, 34, 56, 78 }; + StringTransformer testCollection = new StringTransformer(inputIntegers); + + string[] outputStrings = new string[testCollection.Count]; + (testCollection as ICollection).CopyTo(outputStrings, 0); + + string[] inputStrings = new string[] { "12", "34", "56", "78" }; + CollectionAssert.AreEqual(inputStrings, outputStrings); + } + + /// + /// Verifies that the IsSynchronized property and the SyncRoot property are working + /// + [Test] + public void TestSynchronization() { + StringTransformer testCollection = new StringTransformer(new int[0]); + + if(!(testCollection as ICollection).IsSynchronized) { + lock((testCollection as ICollection).SyncRoot) { + int count = testCollection.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() { + Mockery mockery = new Mockery(); + IList mockedIList = mockery.NewMock>(); + StringTransformer testCollection = new StringTransformer(mockedIList); + + if(!(testCollection as ICollection).IsSynchronized) { + lock((testCollection as ICollection).SyncRoot) { + Expect.Once.On(mockedIList).GetProperty("Count").Will(Return.Value(12345)); + int count = testCollection.Count; + Assert.AreEqual(12345, count); // ;-) + } + } + } + + } + +} // namespace Nuclex.Support.Collections + +#endif // UNITTEST diff --git a/Source/Collections/TransformingReadOnlyCollection.cs b/Source/Collections/TransformingReadOnlyCollection.cs index 6170381..240599b 100644 --- a/Source/Collections/TransformingReadOnlyCollection.cs +++ b/Source/Collections/TransformingReadOnlyCollection.cs @@ -181,15 +181,15 @@ namespace Nuclex.Support.Collections { /// Array is null. /// public void CopyTo(ExposedItemType[] array, int index) { - - if(this.items.Count > (array.Length - index)) + if(this.items.Count > (array.Length - index)) { throw new ArgumentException( "Array too small to fit the collection items starting at the specified index" ); + } - for(int itemIndex = 0; itemIndex < this.items.Count; ++itemIndex) + for(int itemIndex = 0; itemIndex < this.items.Count; ++itemIndex) { array[itemIndex + index] = Transform(this.items[itemIndex]); - + } } /// @@ -266,6 +266,11 @@ namespace Nuclex.Support.Collections { get { return Transform(this.items[index]); } } + /// Whether the List is write-protected + public bool IsReadOnly { + get { return true; } + } + /// Transforms an item into the exposed type /// Item to be transformed /// The transformed item