#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2009 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() method 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() method 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() method 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) {
          Assert.AreEqual(0, 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