#region CPL License /* Nuclex Framework Copyright (C) 2002-2010 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 #if UNITTEST using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; using NMock2; namespace Nuclex.Support.Collections { /// Unit Test for the observable dictionary wrapper [TestFixture] public class ObservableDictionaryTest { #region interface IObservableDictionarySubscriber /// Interface used to test the observable dictionary public interface IObservableDictionarySubscriber { /// Called when the dictionary is about to clear its contents /// Dictionary that is clearing its contents /// Not used void Clearing(object sender, EventArgs arguments); /// Called when the dictionary has been clear of its contents /// Dictionary that was cleared of its contents /// Not used void Cleared(object sender, EventArgs arguments); /// Called when an item is added to the dictionary /// Dictionary to which an item is being added /// Contains the item that is being added void ItemAdded(object sender, ItemEventArgs> arguments); /// Called when an item is removed from the dictionary /// Dictionary from which an item is being removed /// Contains the item that is being removed void ItemRemoved(object sender, ItemEventArgs> arguments); } #endregion // interface IObservableDictionarySubscriber /// Initialization routine executed before each test is run [SetUp] public void Setup() { this.mockery = new Mockery(); this.mockedSubscriber = this.mockery.NewMock(); this.observedDictionary = new ObservableDictionary(); this.observedDictionary.Add(1, "one"); this.observedDictionary.Add(2, "two"); this.observedDictionary.Add(3, "three"); this.observedDictionary.Add(42, "forty-two"); this.observedDictionary.Clearing += new EventHandler(this.mockedSubscriber.Clearing); this.observedDictionary.Cleared += new EventHandler(this.mockedSubscriber.Cleared); this.observedDictionary.ItemAdded += new EventHandler>>( this.mockedSubscriber.ItemAdded ); this.observedDictionary.ItemRemoved += new EventHandler>>( this.mockedSubscriber.ItemRemoved ); } /// /// Verifies that the default constructor of the observable dictionary works /// [Test] public void TestDefaultConstructor() { ObservableDictionary testDictionary = new ObservableDictionary(); Assert.AreEqual(0, testDictionary.Count); } /// /// Verifies that the copy constructor of the observable dictionary works /// [Test] public void TestCopyConstructor() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); CollectionAssert.AreEqual(numbers, testDictionary); } /// Verifies that the IsReadOnly property is working [Test] public void TestIsReadOnly() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); Assert.IsFalse(testDictionary.IsReadOnly); } /// /// Checks whether the Contains() method of the observable dictionary is able to /// determine if the dictionary contains an item /// [Test] public void TestContains() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); Assert.IsTrue( testDictionary.Contains(new KeyValuePair(42, "forty-two")) ); Assert.IsFalse( testDictionary.Contains(new KeyValuePair(24, "twenty-four")) ); } /// /// Checks whether the Contains() method of the observable dictionary is able to /// determine if the dictionary contains a key /// [Test] public void TestContainsKey() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); Assert.IsTrue(testDictionary.ContainsKey(42)); Assert.IsFalse(testDictionary.ContainsKey(24)); } /// /// Verifies that the CopyTo() of the observable dictionary works /// [Test] public void TestCopyToArray() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); KeyValuePair[] items = new KeyValuePair[numbers.Count]; testDictionary.CopyTo(items, 0); CollectionAssert.AreEqual(numbers, items); } /// /// Tests whether the typesafe enumerator of the observable dictionary is working /// [Test] public void TestTypesafeEnumerator() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); List> outputItems = new List>(); foreach(KeyValuePair item in testDictionary) { outputItems.Add(item); } CollectionAssert.AreEqual(numbers, outputItems); } /// /// Tests whether the keys collection of the observable dictionary can be queried /// [Test] public void TestGetKeysCollection() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); ICollection inputKeys = numbers.Keys; ICollection keys = testDictionary.Keys; CollectionAssert.AreEquivalent(inputKeys, keys); } /// /// Tests whether the values collection of the observable dictionary can be queried /// [Test] public void TestGetValuesCollection() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); ICollection inputValues = numbers.Values; ICollection values = testDictionary.Values; CollectionAssert.AreEquivalent(inputValues, values); } /// /// Tests whether the TryGetValue() method of the observable dictionary is working /// [Test] public void TestTryGetValue() { string value; Assert.IsTrue(this.observedDictionary.TryGetValue(42, out value)); Assert.AreEqual("forty-two", value); Assert.IsFalse(this.observedDictionary.TryGetValue(24, out value)); Assert.AreEqual(null, value); } /// /// Tests whether the retrieval of values using the indexer of the observable /// dictionary is working /// [Test] public void TestRetrieveValueByIndexer() { Assert.AreEqual("forty-two", this.observedDictionary[42]); } /// /// Tests whether an exception is thrown if the indexer of the observable dictionary /// is used to attempt to retrieve a non-existing value /// [Test] public void TestRetrieveNonExistingValueByIndexer() { Assert.Throws( delegate() { Console.WriteLine(this.observedDictionary[24]); } ); } /// /// Checks whether the Add() methods works via the generic /// IDictionary<> interface /// [Test] public void TestAddViaGenericIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments(); (this.observedDictionary as IDictionary).Add(10, "ten"); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.Contains( this.observedDictionary, new KeyValuePair(10, "ten") ); } /// /// Checks whether the Remove() method works via the generic /// IDictionary<> interface /// [Test] public void TestRemoveViaGenericIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments(); (this.observedDictionary as IDictionary).Remove(3); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.DoesNotContain(this.observedDictionary.Keys, 3); } /// /// Tests whether the TryGetValue() method of the observable dictionary is working /// [Test] public void TestRetrieveValueByIndexerViaGenericIDictionary() { Assert.AreEqual( "forty-two", (this.observedDictionary as IDictionary)[42] ); } /// /// Verifies that the indexer can be used to insert an item via the generic /// IDictionar<> interface /// [Test] public void TestReplaceByIndexerViaGenericIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments(); Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments(); (this.observedDictionary as IDictionary)[42] = "two and fourty"; this.mockery.VerifyAllExpectationsHaveBeenMet(); Assert.AreEqual("two and fourty", this.observedDictionary[42]); } /// /// Checks whether the Clear() method of observable dictionary is working /// [Test] public void TestClearViaIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments(); Expect.Once.On(this.mockedSubscriber).Method("Cleared").WithAnyArguments(); (this.observedDictionary as IDictionary).Clear(); this.mockery.VerifyAllExpectationsHaveBeenMet(); Assert.AreEqual(0, this.observedDictionary.Count); } /// /// Checks whether the Add() method works via the IDictionary interface /// [Test] public void TestAddViaIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments(); (this.observedDictionary as IDictionary).Add(24, "twenty-four"); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.Contains( this.observedDictionary, new KeyValuePair(24, "twenty-four") ); } /// /// Checks whether the Contains() method of the observable dictionary is able to /// determine if the dictionary contains an item via the IDictionary interface /// [Test] public void TestContainsViaIDictionary() { Assert.IsTrue((this.observedDictionary as IDictionary).Contains(42)); Assert.IsFalse((this.observedDictionary as IDictionary).Contains(24)); } /// /// Checks whether the GetEnumerator() method of the observable dictionary /// returns a working enumerator if accessed via the IDictionary interface /// [Test] public void TestEnumeratorViaIDictionary() { Dictionary outputNumbers = new Dictionary(); foreach(DictionaryEntry entry in (this.observedDictionary as IDictionary)) { (outputNumbers as IDictionary).Add(entry.Key, entry.Value); } CollectionAssert.AreEquivalent(this.observedDictionary, outputNumbers); } /// /// Checks whether the IsFixedSize property of the observable dictionary returns /// the expected result for a read only dictionary based on a dynamic dictionary /// [Test] public void TestIsFixedSizeViaIList() { Assert.IsFalse((this.observedDictionary as IDictionary).IsFixedSize); } /// /// Tests whether the keys collection of the observable dictionary can be queried /// via the IDictionary interface /// [Test] public void TestGetKeysCollectionViaIDictionary() { ICollection keys = (this.observedDictionary as IDictionary).Keys; Assert.AreEqual(this.observedDictionary.Count, keys.Count); } /// /// Tests whether the values collection of the observable dictionary can be queried /// via the IDictionary interface /// [Test] public void TestGetValuesCollectionViaIDictionary() { ICollection values = (this.observedDictionary as IDictionary).Values; Assert.AreEqual(this.observedDictionary.Count, values.Count); } /// /// Checks whether Remove() method works via the IDictionary interface /// [Test] public void TestRemoveViaIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments(); (this.observedDictionary as IDictionary).Remove(3); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.DoesNotContain(this.observedDictionary.Keys, 3); } /// /// Tests whether the retrieval of values using the indexer of the observable /// dictionary is working via the IDictionary interface /// [Test] public void TestRetrieveValueByIndexerViaIDictionary() { Assert.AreEqual("forty-two", (this.observedDictionary as IDictionary)[42]); } /// /// Verifies the indexer can be used to insert an item via the IDictionary interface /// [Test] public void TestReplaceByIndexerViaIDictionary() { Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments(); Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments(); (this.observedDictionary as IDictionary)[42] = "two and fourty"; this.mockery.VerifyAllExpectationsHaveBeenMet(); Assert.AreEqual("two and fourty", this.observedDictionary[42]); } /// /// Checks whether Add() method is working via the generic /// ICollection<> interface /// [Test] public void TestAddViaGenericICollection() { Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments(); (this.observedDictionary as ICollection>).Add( new KeyValuePair(24, "twenty-four") ); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.Contains( this.observedDictionary, new KeyValuePair(24, "twenty-four") ); } /// /// Checks whether the Clear() method is working via the generic /// ICollection<> interface /// [Test] public void TestClearViaGenericICollection() { Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments(); Expect.Once.On(this.mockedSubscriber).Method("Cleared").WithAnyArguments(); (this.observedDictionary as ICollection>).Clear(); this.mockery.VerifyAllExpectationsHaveBeenMet(); Assert.AreEqual(0, this.observedDictionary.Count); } /// /// Checks whether the Remove() method is working via the /// generic ICollection<> interface /// [Test] public void TestRemoveViaGenericICollection() { IEnumerator> enumerator = (this.observedDictionary as ICollection>).GetEnumerator(); enumerator.MoveNext(); Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments(); (this.observedDictionary as ICollection>).Remove( enumerator.Current ); this.mockery.VerifyAllExpectationsHaveBeenMet(); CollectionAssert.DoesNotContain(this.observedDictionary, enumerator.Current); } /// /// Verifies that the CopyTo() of the observable dictionary works when called /// via the the ICollection interface /// [Test] public void TestCopyToArrayViaICollection() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); DictionaryEntry[] entries = new DictionaryEntry[numbers.Count]; (testDictionary as ICollection).CopyTo(entries, 0); KeyValuePair[] items = new KeyValuePair[numbers.Count]; for(int index = 0; index < entries.Length; ++index) { items[index] = new KeyValuePair( (int)entries[index].Key, (string)entries[index].Value ); } CollectionAssert.AreEquivalent(numbers, items); } /// /// Verifies that the IsSynchronized property and the SyncRoot property are working /// [Test] public void TestSynchronization() { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary = makeObservable(numbers); if(!(testDictionary as ICollection).IsSynchronized) { lock((testDictionary as ICollection).SyncRoot) { Assert.AreEqual(numbers.Count, testDictionary.Count); } } } /// /// Test whether the observable dictionary can be serialized /// [Test] public void TestSerialization() { BinaryFormatter formatter = new BinaryFormatter(); using(MemoryStream memory = new MemoryStream()) { Dictionary numbers = createTestDictionary(); ObservableDictionary testDictionary1 = makeObservable(numbers); formatter.Serialize(memory, testDictionary1); memory.Position = 0; object testDictionary2 = formatter.Deserialize(memory); CollectionAssert.AreEquivalent(testDictionary1, (IEnumerable)testDictionary2); } } /// /// Creates a new observable dictionary filled with some values for testing /// /// The newly created observable dictionary private static Dictionary createTestDictionary() { Dictionary numbers = new Dictionary(); numbers.Add(1, "one"); numbers.Add(2, "two"); numbers.Add(3, "three"); numbers.Add(42, "forty-two"); return new Dictionary(numbers); } /// /// Creates a new observable dictionary filled with some values for testing /// /// The newly created observable dictionary private static ObservableDictionary makeObservable( IDictionary dictionary ) { return new ObservableDictionary(dictionary); } /// Mock object factory private Mockery mockery; /// The mocked observable collection subscriber private IObservableDictionarySubscriber mockedSubscriber; /// An observable dictionary to which a mock will be subscribed private ObservableDictionary observedDictionary; } } // namespace Nuclex.Support.Collections #endif // UNITTEST