From b37c4a757ce095e6cc5218ae26b411af1dd7723a Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Fri, 2 Mar 2012 21:05:05 +0000 Subject: [PATCH] MultiDictionary wasn't firing 'removed' events when an entire set of values is replaced - fixed, but not unit-tested yet; added more unit tests to the ObservableSet class; ObservableSet was not firing the 'added' event - fixed git-svn-id: file:///srv/devel/repo-conversion/nusu@260 d2e56fa2-650e-0410-a79f-9358c0239efd --- Source/Collections/MultiDictionary.Test.cs | 54 +++++++++++++++++++++- Source/Collections/MultiDictionary.cs | 41 ++++++++++++++-- Source/Collections/ObservableSet.Test.cs | 32 ++++++++++++- Source/Collections/ObservableSet.cs | 6 ++- 4 files changed, 124 insertions(+), 9 deletions(-) diff --git a/Source/Collections/MultiDictionary.Test.cs b/Source/Collections/MultiDictionary.Test.cs index 19310bc..f950252 100644 --- a/Source/Collections/MultiDictionary.Test.cs +++ b/Source/Collections/MultiDictionary.Test.cs @@ -41,6 +41,20 @@ namespace Nuclex.Support.Collections { 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 @@ -116,6 +130,15 @@ namespace Nuclex.Support.Collections { 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 @@ -150,10 +173,39 @@ namespace Nuclex.Support.Collections { dictionary.Add(10, "zehn"); Assert.AreEqual(2, dictionary.Count); - var collectionOfCollections = (ICollection>>)dictionary; + 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)); + } + } } // namespace Nuclex.Support.Collections diff --git a/Source/Collections/MultiDictionary.cs b/Source/Collections/MultiDictionary.cs index 5d335b3..9674990 100644 --- a/Source/Collections/MultiDictionary.cs +++ b/Source/Collections/MultiDictionary.cs @@ -333,15 +333,39 @@ namespace Nuclex.Support.Collections { ICollection currentValues; if(this.typedDictionary.TryGetValue(key, out currentValues)) { - currentValues.Clear(); + ValueList currentValueList = (ValueList)currentValues; + + int index = 0; + foreach(TValue addedValue in value) { + if(index < currentValueList.Count) { + TValue original = currentValueList[index]; + currentValueList[index] = addedValue; + OnReplaced( + new KeyValuePair(key, original), + new KeyValuePair(key, addedValue) + ); + } else { + currentValueList.Add(addedValue); + OnAdded(new KeyValuePair(key, addedValue)); + } + ++index; + } + + int count = currentValueList.Count; + while(count > index) { + --count; + TValue removedValue = currentValueList[count]; + currentValueList.RemoveAt(count); + OnRemoved(new KeyValuePair(key, removedValue)); + } } else { currentValues = new ValueList(this); this.typedDictionary.Add(key, currentValues); - } - foreach(TValue addedValue in value) { - currentValues.Add(addedValue); - OnAdded(new KeyValuePair(key, addedValue)); + foreach(TValue addedValue in value) { + currentValues.Add(addedValue); + OnAdded(new KeyValuePair(key, addedValue)); + } } } } @@ -420,6 +444,13 @@ namespace Nuclex.Support.Collections { /// Item that has been removed from the collection protected virtual void OnRemoved(KeyValuePair item) { } + /// Fires the 'ItemReplaced' event + /// Item that was replaced in the collection + /// Item that the original was replaced by + protected virtual void OnReplaced( + KeyValuePair oldItem, KeyValuePair newItem + ) { } + /// Fires the 'Clearing' event protected virtual void OnClearing() { } diff --git a/Source/Collections/ObservableSet.Test.cs b/Source/Collections/ObservableSet.Test.cs index ddcaf36..a2954d1 100644 --- a/Source/Collections/ObservableSet.Test.cs +++ b/Source/Collections/ObservableSet.Test.cs @@ -31,12 +31,40 @@ using NMock; namespace Nuclex.Support.Collections { -#if false /// Unit Test for the observable set wrapper [TestFixture] internal class ObservableSetTest { + + #region interface IObservableCollectionSubscriber + + public interface IObservableCollectionSubscriber { + + /// Raised when an item has been added to the collection + event EventHandler> ItemAdded; + /// Raised when an item is removed from the collection + event EventHandler> ItemRemoved; + /// Raised when an item is replaced in the collection + event EventHandler> ItemReplaced; + /// Raised when the collection is about to be cleared + event EventHandler Clearing; + /// Raised when the collection has been cleared + event EventHandler Cleared; + + } + + #endregion // interface IObservableCollectionSubscriber + + + + /// + /// Verifies that the observable set has a default constructor + /// + [Test] + public void HasDefaultConstructor() { + Assert.IsNotNull(new ObservableSet()); + } + } -#endif } // namespace Nuclex.Support.Collections diff --git a/Source/Collections/ObservableSet.cs b/Source/Collections/ObservableSet.cs index f142888..76ad175 100644 --- a/Source/Collections/ObservableSet.cs +++ b/Source/Collections/ObservableSet.cs @@ -82,7 +82,11 @@ namespace Nuclex.Support.Collections { /// True if the element was added, false if it was already contained in the set /// public bool Add(TItem item) { - return this.set.Add(item); + bool wasAdded = this.set.Add(item); + if(wasAdded) { + OnAdded(item); + } + return wasAdded; } /// Removes all elements that are contained in the collection