#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