using System.Linq; using System.Utility; using NUnit.Framework; namespace System.Collections.Generic { /// /// Tests for the type. /// /// The type of the key. /// The type of the value. public abstract class DictionaryTests : CollectionTests> { /// /// Initializes a new instance of the /// class. /// /// True if the order of iteration by /// the should be tested, false if otherwise. /// If you specify true, be sure to implement the /// property. protected DictionaryTests(bool testIterationOrder) : this(testIterationOrder, EqualityComparer>.Default) {} /// /// Initializes a new instance of the /// class. /// /// True if the order of iteration by /// the should be tested, false if otherwise. /// If you specify true, be sure to implement the /// property. /// The that /// is used to compare values in the for /// uniqueness or null if the default /// specified by is to be used. protected DictionaryTests(bool testIterationOrder, IEqualityComparer> comparer) : base(testIterationOrder, comparer) {} //////////////////////////////////////////////////////////////////////// #region IDictionary.Add(TKey, TValue) Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.Add(TKey, TValue) " + "throws an exception if the key is null. Note that this " + "test assumes TKey can be null. If it cannot be override " + "this test and have it ignored.")] public virtual void AddArgumentNullException() { IDictionary dictionary = CreateDictionary(); Assert.Throws(() => dictionary.Add(default(TKey), default(TValue))); } [Test, Description("Ensures that IDictionary.Add(TKey, TValue) " + "throws an exception if an element with the same key " + "already exists in the dictionary.")] public void ExceptionThrownWhenKeyAlreadyExists() { IDictionary dictionary = CreateDictionary(); var keyValue = CreateItem(); dictionary.Add(keyValue.Key, keyValue.Value); Assert.Throws(() => dictionary.Add(keyValue.Key, keyValue.Value)); } [Test, Description("Ensures that IDictionary.Add(TKey, TValue) " + "throws an exception if it is called when the test is " + "read only. Note that this test assumes the dictionary " + "can be null. If it cannot be, override this test and " + "have it ignored.")] public virtual void AddNotSupportedExceptionWhenReadOnly() { IDictionary readOnlyDictionary = CreateReadOnlyDictionary(); if (readOnlyDictionary == null) Assert.Ignore("IDictionary cannot be read-only."); var keyValue = CreateItem(); Assert.Throws(() => readOnlyDictionary.Add(keyValue.Key, keyValue.Value)); } [Test, Description("Ensures that IDictionary.Add(TKey, TValue) " + "adds an item.")] public void ItemIsAdded() { IDictionary dictionary = CreateDictionary(); var keyValue = CreateItem(); dictionary.Add(keyValue.Key, keyValue.Value); TValue value = dictionary[keyValue.Key]; value.IsEqualTo(keyValue.Value, "dictionary value"); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.ContainsKey(TKey) Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.ContainsKey(TKey) " + "throws an exception if the key is null. Note that this " + "test assumes TKey can be null. If it cannot be override " + "this test and have it ignored.")] public virtual void ContainsKeyArgumentNullException() { IDictionary dictionary = CreateDictionary(); Assert.Throws(() => dictionary.ContainsKey(default(TKey))); } [Test, Description("Ensures that IDictionary.ContainsKey(TKey) " + "returns false when a key is not in the dictionary and" + "true when it is.")] public virtual void ContainsKeyReturnsTrueAndFalse() { IDictionary dictionary = CreateDictionary(); var keyValue = CreateItem(); Assert.False(dictionary.ContainsKey(keyValue.Key)); dictionary.Add(keyValue); Assert.True(dictionary.ContainsKey(keyValue.Key)); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.Remove(TKey) Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.Remove(TKey) " + "throws an exception if the key is null. Note that this " + "test assumes TKey can be null. If it cannot be override " + "this test and have it ignored.")] public virtual void RemoveArgumentNullException() { IDictionary dictionary = CreateDictionary(); Assert.Throws(() => dictionary.Remove(default(TKey))); } [Test, Description("Ensures that IDictionary.Remove(TKey) " + "throws a NotSupportedException if the IDictionary " + "is read only. If the IDictionary cannot be read then " + "this test is ignored.")] public virtual void RemoveThrowsNotSupportedExceptionWhenDictionaryIsReadOnly() { IDictionary readOnlyDictionary = CreateReadOnlyDictionary(); if (readOnlyDictionary == null) Assert.Ignore("IDictionary cannot be read-only."); var item = readOnlyDictionary.First(); Assert.Throws(() => readOnlyDictionary.Remove(item.Key)); } [Test, Description("Ensures that IDictionary.Remove(TKey) " + "doesn't remove the item when it is not in the " + "IDictionary and removes the item when " + "it is.")] public virtual void ItemRemovedAndNotRemoved() { IDictionary dictionary = CreateDictionary(); var item = CreateItem(); int countBeforeRemove = dictionary.Count; Assert.False(dictionary.Remove(item.Key), "Item should not have been removed."); dictionary.Count.IsEqualTo(countBeforeRemove, "IDictionary.Count"); dictionary.Add(item); countBeforeRemove = dictionary.Count; Assert.True(dictionary.Remove(item.Key)); dictionary.Count.IsNotEqualTo(countBeforeRemove, "IDictionary.Count"); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.TryGetValue(TKey, TValue) Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.TryGetValue(TKey, TValue) " + "throws an exception if the key is null. Note that this " + "test assumes TKey can be null. If it cannot be override " + "this test and have it ignored.")] public virtual void TryGetValueArgumentNullException() { IDictionary dictionary = CreateDictionary(); TValue value; Assert.Throws(() => dictionary.TryGetValue(default(TKey), out value)); } [Test, Description("Ensures that IDictionary.TryGetValue(TKey, TValue) " + "returns true if a value is in the IDictionary, false" + "if otherwise.")] public virtual void ItemRetrievedAndNotRetrieved() { IDictionary dictionary = CreateDictionary(); var item = CreateItem(); TValue retrievedItem; Assert.False(dictionary.TryGetValue(item.Key, out retrievedItem), "Item should not have been retrieved."); // If the value could not be retrieved, then the item should have // been set to the default value. retrievedItem.IsEqualTo(default(TValue), "IDictionary.TryGetValue(TKey, TValue)"); dictionary.Add(item); Assert.True(dictionary.TryGetValue(item.Key, out retrievedItem)); retrievedItem.IsEqualTo(item.Value, "IDictionary.TryGetValue(TKey, TValue)"); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.Keys Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.Keys " + "contains the proper keys.")] public virtual void KeysExpected() { IDictionary dictionary = CreateDictionary(); // Keys must exist for this test to work. dictionary.Keys.Count.IsNotEqualTo(0, "IDictionary.Keys"); var keys = dictionary.Select(pair => pair.Key); dictionary.Keys.IsEqualTo(keys, "IDictionary.Keys"); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.this[TKey] Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.this[TKey] " + "throws an exception if the key is null. Note that this " + "test assumes TKey can be null. If it cannot be override " + "this test and have it ignored.")] public virtual void IndexerArgumentNullException() { IDictionary dictionary = CreateDictionary(); Assert.Throws(() => dictionary[default(TKey)] = default (TValue)); } [Test, Description("Ensures that IDictionary.this[TKey] " + "throws a KeyNotFoundException if the key cannot be " + "found.")] public virtual void KeyNotFoundException() { IDictionary dictionary = CreateDictionary(); var item = CreateItem(); Assert.Throws(() => Console.WriteLine(dictionary[item.Key])); } [Test, Description("Ensures that IDictionary.this[TKey] " + "throws a NotSupportedException when the " + "IDictionary is read only. If the " + "IDictionary cannot be read then this " + "test is ignored.")] public virtual void IndexerThrowsNotSupportedExceptionWhenDictionaryIsReadOnly() { IDictionary readOnlyDictionary = CreateReadOnlyDictionary(); if (readOnlyDictionary == null) Assert.Ignore("IDictionary cannot be read-only."); var item = readOnlyDictionary.First(); Assert.Throws(() => Console.WriteLine(readOnlyDictionary[item.Key])); } [Test, Description("Ensures that IDictionary.this[TKey] " + "returns the expected value.")] public virtual void ItemRetrieved() { IDictionary dictionary = CreateDictionary(); var item = CreateItem(); dictionary.Add(item); TValue retrievedItem = dictionary[item.Key]; retrievedItem.IsEqualTo(item.Value, "IDictionary.this[TKey]"); } #endregion //////////////////////////////////////////////////////////////////////// #region IDictionary.Values Tests //////////////////////////////////////////////////////////////////////// [Test, Description("Ensures that IDictionary.Values " + "contains the proper keys.")] public virtual void ValuesExpected() { IDictionary dictionary = CreateDictionary(); // Keys must exist for this test to work. dictionary.Values.Count.IsNotEqualTo(0, "IDictionary.Values"); var values = dictionary.Select(pair => pair.Value); dictionary.Values.IsEqualTo(values, "IDictionary.Values"); } #endregion //////////////////////////////////////////////////////////////////////// #region Overridables //////////////////////////////////////////////////////////////////////// /// /// Creates an to test. The created /// collection should contain the number of items specified by /// . Each item /// in the list should be unique so that a comparison of them does not /// yield duplicates. This method should also create a collection that /// follows the rules specified by the method /// /// (see the comments on that method for details). /// /// The instance to be tested. protected abstract IDictionary CreateDictionary(); /// /// Creates a read-only to test. /// This method should behave exactly like the /// method and follow the exact same rules (see the comments on /// for details). If the collection can /// never be read-only, then this method should return null. /// protected abstract IDictionary CreateReadOnlyDictionary(); protected override ICollection> CreateCollection() { return CreateDictionary(); } protected override ICollection> CreateReadOnlyCollection() { return CreateReadOnlyDictionary(); } #endregion } /// /// A test fixture that is used to test the /// and to provide an example of /// how to create a proper /// test fixture. /// [TestFixture] public class DictionaryTestsFixture : DictionaryTests { public DictionaryTestsFixture() : base(false) { } #region Overridables protected override IDictionary CreateDictionary() { IDictionary dictionary = new Dictionary(); for (int i = 0; i < RequiredCollectionCount; i++) { string indexStr = i.ToString(); dictionary.Add(indexStr, "Value " + indexStr); } return dictionary; } protected override IDictionary CreateReadOnlyDictionary() { // DictionaryTests cannot be read-only. return null; } protected override KeyValuePair CreateItem() { string indexStr = (RequiredCollectionCount + 1).ToString(); return new KeyValuePair(indexStr, "Value " + indexStr); } #endregion } }