diff --git a/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs new file mode 100644 index 0000000..de42c0b --- /dev/null +++ b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs @@ -0,0 +1,192 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Swordfish.NET.Collections; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; + +namespace Swordfish.NET.UnitTestV3 +{ + /// + /// Tests that the following methods fire the correct event in ConcurrentObservableCollection: + /// + /// - AddRange + /// - InsertRange + /// - RemoveRange + /// - Reset + /// - Clear + /// + /// Test the following collection classes: + /// + /// - ConcurrentObservableCollection - done (this class) + /// - ConcurrentObservableDictionary + /// - ConcurrentObservableHashSet + /// - ConcurrentObservableSortedCollection + /// - ConcurrentObservableSortedDictionary + /// - ConcurrentObservableSortedSet + /// + [TestClass] + public class ConcurrentObservableCollection_INotifyCollectionChangedTests + { + [TestMethod] + public void Test_ConcurrentObservableCollection_AddRange() + { + var toAdd = Enumerable.Range(0, 100).ToList(); + var collection = new ConcurrentObservableCollection(); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.AddRange(toAdd); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add); + Assert.IsNotNull(returnedArgs.NewItems); + Assert.IsNull(returnedArgs.OldItems); + Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType(), (a, b) => a == b).All(c => c)); + + } + + [TestMethod] + public void Test_ConcurrentObservableCollection_InsertRange() + { + var initial = Enumerable.Range(0, 100).ToList(); + var toAdd = Enumerable.Range(100, 100).ToList(); + var startIndex = 50; + var collection = new ConcurrentObservableCollection(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.InsertRange(startIndex, toAdd); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Add, returnedArgs.Action); + Assert.AreEqual(startIndex, returnedArgs.NewStartingIndex); + Assert.IsNotNull(returnedArgs.NewItems); + Assert.IsNull(returnedArgs.OldItems); + Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType(), (a, b) => a == b).All(c => c)); + } + + [TestMethod] + public void Test_ConcurrentObservableCollection_RemoveRange() + { + var initial = Enumerable.Range(0, 100).ToList(); + var startIndex = 50; + var removeCount = 40; + var collection = new ConcurrentObservableCollection(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.RemoveRange(startIndex, removeCount); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.IsNotNull(returnedObject); + Assert.IsNotNull(returnedArgs); + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action); + Assert.AreEqual(startIndex, returnedArgs.OldStartingIndex); + Assert.IsNull(returnedArgs.NewItems); + Assert.IsNotNull(returnedArgs.OldItems); + Assert.AreEqual(removeCount, returnedArgs.OldItems.Count); + } + + [TestMethod] + public void Test_ConcurrentObservableCollection_Reset() + { + var initial = Enumerable.Range(0, 100).ToList(); + var toAdd = Enumerable.Range(100, 100).ToList(); + var collection = new ConcurrentObservableCollection(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.Reset(toAdd); + + // Check two collection changed events were fired + Assert.AreEqual(2, returnedList.Count); + (var returnedObject0, var returnedArgs0) = returnedList[0]; + (var returnedObject1, var returnedArgs1) = returnedList[1]; + + Assert.IsNotNull(returnedObject0); + Assert.IsNotNull(returnedArgs0); + Assert.IsNotNull(returnedObject1); + Assert.IsNotNull(returnedArgs1); + + Assert.AreEqual(returnedObject0, collection); + Assert.AreEqual(returnedObject1, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs0.Action); + Assert.AreEqual(NotifyCollectionChangedAction.Add, returnedArgs1.Action); + + Assert.IsNull(returnedArgs0.NewItems); + Assert.IsNotNull(returnedArgs0.OldItems); + Assert.AreEqual(initial.Count(), returnedArgs0.OldItems.Count); + Assert.IsTrue(initial.Zip(returnedArgs0.OldItems.OfType(), (a, b) => a == b).All(c => c)); + + Assert.IsNull(returnedArgs1.OldItems); + Assert.IsNotNull(returnedArgs1.NewItems); + Assert.AreEqual(toAdd.Count(), returnedArgs1.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs1.NewItems.OfType(), (a, b) => a == b).All(c => c)); + } + + [TestMethod] + public void Test_ConcurrentObservableCollection_Clear() + { + var initial = Enumerable.Range(0, 100).ToList(); + var collection = new ConcurrentObservableCollection(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.Clear(); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.IsNotNull(returnedObject); + Assert.IsNotNull(returnedArgs); + + Assert.AreEqual(0, collection.Count); + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action); + + Assert.IsNull(returnedArgs.NewItems); + + Assert.IsNotNull(returnedArgs.OldItems); + Assert.AreEqual(initial.Count(), returnedArgs.OldItems.Count); + Assert.IsTrue(initial.Zip(returnedArgs.OldItems.OfType(), (a, b) => a == b).All(c => c)); + } + + } +} diff --git a/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs new file mode 100644 index 0000000..dbaba28 --- /dev/null +++ b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs @@ -0,0 +1,165 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Swordfish.NET.Collections; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Swordfish.NET.UnitTestV3 +{ + /// + /// Tests that the following methods fire the correct event in ConcurrentObservableDictionary: + /// + /// - AddRange + /// - RemoveRange + /// - Clear + /// + /// Test the following collection classes: + /// + /// - ConcurrentObservableCollection - done (other class) + /// - ConcurrentObservableDictionary + /// - ConcurrentObservableHashSet + /// - ConcurrentObservableSortedCollection + /// - ConcurrentObservableSortedDictionary + /// - ConcurrentObservableSortedSet + /// + [TestClass] + public class ConcurrentObservableDictionary_INotifyCollectionChangedTests + { + [TestMethod] + public void Test_ConcurrentObservableDictionary_AddRange_IEnumerable() + { + var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)); + var collection = new ConcurrentObservableDictionary(); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.AddRange(toAdd); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add); + Assert.IsNotNull(returnedArgs.NewItems); + Assert.IsNull(returnedArgs.OldItems); + Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c)); + } + + [TestMethod] + public void Test_ConcurrentObservableDictionary_AddRange_List() + { + var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)).ToList(); + var collection = new ConcurrentObservableDictionary(); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.AddRange(toAdd); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add); + Assert.IsNotNull(returnedArgs.NewItems); + Assert.IsNull(returnedArgs.OldItems); + Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c)); + } + + [TestMethod] + public void Test_ConcurrentObservableDictionary_AddRange_Dictionary() + { + var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)).ToDictionary(x => x.Key, x => x.Value); + var collection = new ConcurrentObservableDictionary(); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.AddRange(toAdd); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add); + Assert.IsNotNull(returnedArgs.NewItems); + Assert.IsNull(returnedArgs.OldItems); + Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count); + Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c)); + } + + [TestMethod] + public void Test_ConcurrentObservableCollection_RemoveRange_ByIndex() + { + var initial = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)); + var startIndex = 50; + var removeCount = 40; + var collection = new ConcurrentObservableDictionary(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.RemoveRange(startIndex, removeCount); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.IsNotNull(returnedObject); + Assert.IsNotNull(returnedArgs); + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action); + Assert.AreEqual(startIndex, returnedArgs.OldStartingIndex); + Assert.IsNull(returnedArgs.NewItems); + Assert.IsNotNull(returnedArgs.OldItems); + Assert.AreEqual(removeCount, returnedArgs.OldItems.Count); + } + + [TestMethod] + public void Test_ConcurrentObservableDictionary_Clear() + { + var initial = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)); + var collection = new ConcurrentObservableDictionary(); + collection.AddRange(initial); + Assert.AreEqual(100, collection.Count); + + // Record all the collection changed events + List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>(); + collection.CollectionChanged += (s, e) => returnedList.Add((s, e)); + + collection.Clear(); + + // Check just one collection changed event was fired + Assert.AreEqual(1, returnedList.Count); + (var returnedObject, var returnedArgs) = returnedList[0]; + + Assert.AreEqual(0, collection.Count); + + Assert.AreEqual(returnedObject, collection); + Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action); + + Assert.IsNull(returnedArgs.NewItems); + + Assert.IsNotNull(returnedArgs.OldItems); + Assert.AreEqual(initial.Count(), returnedArgs.OldItems.Count); + Assert.IsTrue(initial.Zip(returnedArgs.OldItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c)); + + } + } +} diff --git a/Swordfish.NET.CollectionsV3/ListSelect.cs b/Swordfish.NET.CollectionsV3/ListSelect.cs index 0163671..2fcacd4 100644 --- a/Swordfish.NET.CollectionsV3/ListSelect.cs +++ b/Swordfish.NET.CollectionsV3/ListSelect.cs @@ -18,7 +18,7 @@ public static ListSelect Create(IList /// Provides an IList interface that lets you use a list with a select to type convert a list as its being accessed /// - public class ListSelect : IList + public class ListSelect : IList, IList { private IList _sourceList; private Func _select; @@ -51,13 +51,19 @@ int ICollection.Count } } - bool ICollection.IsReadOnly - { - get - { - return true; - } - } + bool ICollection.IsReadOnly => true; + + bool IList.IsFixedSize => true; + + bool IList.IsReadOnly => true; + + int ICollection.Count => _sourceList.Count; + + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => null; + + object IList.this[int index] { get => _sourceList[index]; set => throw new NotImplementedException(); } public void Add(TResult item) { @@ -122,5 +128,34 @@ void IList.RemoveAt(int index) { throw new NotImplementedException(); } + + int IList.Add(object value) + { + throw new NotImplementedException(); + } + + bool IList.Contains(object value) => Contains((TResult)value); + + int IList.IndexOf(object value) => IndexOf((TResult)value); + + void IList.Insert(int index, object value) + { + throw new NotImplementedException(); + } + + void IList.Remove(object value) + { + throw new NotImplementedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotImplementedException(); + } + + void ICollection.CopyTo(Array array, int index) + { + throw new NotImplementedException(); + } } }