#region Apache License 2.0 /* Nuclex .NET Framework Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #endregion // Apache License 2.0 using System; using System.Collections.Generic; using NUnit.Framework; namespace Nuclex.Support.Collections { /// Unit tests for the multi dictionary [TestFixture] internal class MultiDictionaryTest { /// /// Verifies that new instances of the multi dictionary can be created /// [Test] public void CanConstructNewDictionary() { var dictionary = new MultiDictionary(); Assert.IsNotNull(dictionary); // nonsense, prevents compiler warning } /// /// Verifies that the count is initialized correctly when building /// a multi dictionary from a dictionary of value collections. /// [Test] public void CountIsCalculatedIfInitializedFromDictionary() { var contents = new Dictionary>(); contents.Add(1, new List(new string[] { "one", "eins" })); contents.Add(2, new List(new string[] { "two", "zwei" })); var multiDictionary = new MultiDictionary(contents); Assert.AreEqual(4, multiDictionary.Count); } /// /// Verifies that a new multi dictionary based on a read-only dictionary is /// also read-only /// [Test] public void IsReadOnlyWhenBasedOnReadOnlyContainer() { var readOnly = new ReadOnlyDictionary>( new Dictionary>() ); var dictionary = new MultiDictionary(readOnly); Assert.IsTrue(dictionary.IsReadOnly); } /// /// Ensures that the multi dictionary can contain the same key multiple times /// (or in other words, multiple values on the same key) /// [Test] public void CanContainKeyMultipleTimes() { var dictionary = new MultiDictionary(); dictionary.Add(123, "one two three"); dictionary.Add(123, "eins zwei drei"); Assert.AreEqual(2, dictionary.Count); CollectionAssert.AreEquivalent( new KeyValuePair[] { new KeyValuePair(123, "one two three"), new KeyValuePair(123, "eins zwei drei") }, dictionary ); } /// /// Verifies that adding values through the indexer still updates the item count /// [Test] public void AddingValuesFromIndexerUpdatesCount() { var dictionary = new MultiDictionary(); dictionary.Add(42, "the answer to everything"); dictionary[42].Add("21x2"); Assert.AreEqual(2, dictionary.Count); CollectionAssert.AreEquivalent( new KeyValuePair[] { new KeyValuePair(42, "the answer to everything"), new KeyValuePair(42, "21x2") }, dictionary ); } /// /// Tests whether the collection can count the number of values stored /// under a key /// [Test] public void ValuesWithSameKeyCanBeCounted() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(20, "twenty"); dictionary.Add(30, "thirty"); dictionary.Add(10, "zehn"); dictionary.Add(20, "zwanzig"); dictionary.Add(10, "dix"); Assert.AreEqual(6, dictionary.Count); Assert.AreEqual(3, dictionary.CountValues(10)); Assert.AreEqual(2, dictionary.CountValues(20)); Assert.AreEqual(1, dictionary.CountValues(30)); } /// /// Verifies that counting the values of a non-existing key returns 0 /// [Test] public void CountingValuesOfNonExistentKeyReturnsNull() { var dictionary = new MultiDictionary(); Assert.AreEqual(0, dictionary.CountValues(1)); } /// /// Ensures that its possible to remove values individually without affecting /// other values stored under the same key /// [Test] public void ValuesCanBeRemovedIndividually() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); dictionary.Add(10, "dix"); dictionary.Remove(10, "zehn"); Assert.AreEqual(2, dictionary.Count); CollectionAssert.AreEquivalent( new KeyValuePair[] { new KeyValuePair(10, "ten"), new KeyValuePair(10, "dix") }, dictionary ); } /// /// Verifies that the Count property returns the number of unique keys if it is called /// on the collection-of-collections interface implemented by the multi dictionary /// [Test] public void CollectionOfCollectionCountIsUniqueKeyCount() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); Assert.AreEqual(2, dictionary.Count); var collectionOfCollections = (ICollection>>)dictionary; Assert.AreEqual(1, collectionOfCollections.Count); } /// /// Verifies that the multi dictionary can be tested for containment of a specific value /// [Test] public void ContainmentCanBeTested() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); Assert.IsTrue(dictionary.Contains(new KeyValuePair(10, "ten"))); Assert.IsTrue(dictionary.Contains(new KeyValuePair(10, "zehn"))); Assert.IsFalse(dictionary.Contains(new KeyValuePair(10, "dix"))); Assert.IsFalse(dictionary.Contains(new KeyValuePair(20, "ten"))); } /// /// Verifies that the multi dictionary can be tested for containment of a specific key /// [Test] public void KeyContainmentCanBeTested() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); Assert.IsTrue(dictionary.ContainsKey(10)); Assert.IsFalse(dictionary.ContainsKey(20)); } /// /// Verifies that the key collection can be retrieved from the dictionary /// [Test] public void KeyCollectionCanBeRetrieved() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); ICollection keys = dictionary.Keys; Assert.IsNotNull(keys); Assert.AreEqual(1, keys.Count); } /// /// Verifies that the key collection can be retrieved from the dictionary /// [Test] public void ValueCollectionCanBeRetrieved() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); dictionary.Add(20, "twenty"); ICollection values = dictionary.Values; Assert.IsNotNull(values); Assert.AreEqual(3, values.Count); } /// /// Verifies that TryGetValue() returns false and doesn't throw if a key /// is not found in the collection /// [Test] public void TryGetValueReturnsFalseOnMissingKey() { var dictionary = new MultiDictionary(); ICollection values; Assert.IsFalse(dictionary.TryGetValue(123, out values)); } /// Verifies that keys can be looked up via TryGetValue() [Test] public void TryGetValueCanLookUpValues() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); ICollection values; Assert.IsTrue(dictionary.TryGetValue(10, out values)); Assert.AreEqual(2, values.Count); } /// /// Verifies that assigning null to a key deletes all the values stored /// under it /// [Test] public void AssigningNullToKeyRemovesAllValues() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); dictionary.Add(20, "twenty"); Assert.AreEqual(3, dictionary.Count); dictionary[10] = null; Assert.AreEqual(1, dictionary.Count); Assert.IsFalse(dictionary.ContainsKey(10)); } /// /// Verifies that assigning null to a key deletes all the values stored /// under it /// [Test] public void ValueListCanBeAssignedToNewKey() { var dictionary = new MultiDictionary(); dictionary[3] = new List() { "three", "drei" }; Assert.AreEqual(2, dictionary.Count); Assert.IsTrue(dictionary.Contains(new KeyValuePair(3, "three"))); } /// /// Verifies that assigning null to a key deletes all the values stored /// under it /// [Test] public void ValueListCanOverwriteExistingKey() { var dictionary = new MultiDictionary(); dictionary.Add(10, "dix"); Assert.AreEqual(1, dictionary.Count); dictionary[10] = new List() { "ten", "zehn" }; Assert.AreEqual(2, dictionary.Count); Assert.IsFalse(dictionary.Contains(new KeyValuePair(10, "dix"))); Assert.IsTrue(dictionary.Contains(new KeyValuePair(10, "ten"))); } /// /// Verifies that nothing bad happens when a key is removed from the dictionary /// that it doesn't contain /// [Test] public void NonExistingKeyCanBeRemoved() { var dictionary = new MultiDictionary(); Assert.AreEqual(0, dictionary.RemoveKey(123)); } /// /// Verifies that the remove method returns the number of values that have /// been removed from the dictionary /// [Test] public void RemoveReturnsNumberOfValuesRemoved() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); Assert.AreEqual(2, dictionary.RemoveKey(10)); } /// /// Verifies that the dictionary becomes empty after clearing it /// [Test] public void DictionaryIsEmptyAfterClear() { var dictionary = new MultiDictionary(); dictionary.Add(10, "ten"); dictionary.Add(10, "zehn"); dictionary.Add(20, "twenty"); Assert.AreEqual(3, dictionary.Count); dictionary.Clear(); Assert.AreEqual(0, dictionary.Count); } /// /// Verifies that non-existing values can be removed from the dictionary /// [Test] public void NonExistingValueCanBeRemoved() { var dictionary = new MultiDictionary(); Assert.IsFalse(dictionary.Remove(123, "test")); } /// /// Verifies that nothing bad happens when the last value under a key is removed /// [Test] public void LastValueOfKeyCanBeRemoved() { var dictionary = new MultiDictionary(); dictionary.Add(123, "test"); dictionary.Remove(123, "test"); Assert.AreEqual(0, dictionary.CountValues(123)); } /// /// Verifies that the dictionary can be copied into an array /// [Test] public void DictionaryCanBeCopiedIntoArray() { var expected = new List>() { new KeyValuePair(1, "one"), new KeyValuePair(1, "eins"), new KeyValuePair(2, "two"), new KeyValuePair(2, "zwei") }; var dictionary = new MultiDictionary(); foreach(KeyValuePair entry in expected) { dictionary.Add(entry.Key, entry.Value); } var actual = new KeyValuePair[4]; dictionary.CopyTo(actual, 0); CollectionAssert.AreEquivalent(expected, actual); } } } // namespace Nuclex.Support.Collections