From f4f0d52095cbf6eb8690f05b57b348a99611a17d Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Mon, 4 Mar 2019 16:09:03 -0500 Subject: [PATCH 01/19] Added Collection AddRange and InsertRange and added new XUnit tests to cover new APIs Added missing APIs from Collection; Added new unit tests for RemoveRange, ReplaceRange, InsertItemsRange and RemoveItemsRange Updated AddRange in Collection to add items to the end of the collection Added CollectionChanged tests for ObservableCollection for InsertRange, AddRange, RemoveRange and ReplaceRange Removing API changes as these will be mirrored from CoreCLR Updated array assertions to use Span to simplify logic Sorted order of new API methods Simplified CollectionTests Assertion to use Span instead of calling out each item in the array Added missing API ReplaceItemsRange and updated unit tests for check for overflow errors on RemoveItems Added overrides for ObservableCollection ItemsRange API to only fire CollectionChanged once per API call. Before this was firing for each item in the collection which is not the desired result. Updated unit tests to verify this logic Updated RemoveItemsRange to prevent int.MaxValue overflow errors Added int.MaxValue overflow tests for Collection and ObservableCollection when invoking RemoveItemsRange API Added additional RemoveRange unit tests to cover when Count is Less than 0 or when Count is 0 Updated RemoveRange overflow tests to check for ArgumentException for new business rules Updated ObservableCollection overflow test to assert ArgumentException Added try-finally block to ObservableCollection to certify that _skipCollectionChanged is always set to false after a collection manipulation in case an exception is thrown in a subclass. Added new test class to test the new rules on the example of a NonNullObservableCollection CollectionChanged events do not fire on RemoveRange if the count == 0 Updated ObservableCollection to only throw the 3 required events when ReplaceItemsRange is invoked. Updated OnChangedEvent methods to check for IList and cast as necessary. Added additional exception handling to reset _skipRaisingEvents bool. Added unit tests to verify event and event parameters are being passed correctly. Added Collection AddRange and InsertRange and added new XUnit tests to cover new APIs Simplified CollectionTests Assertion to use Span instead of calling out each item in the array Added additional RemoveRange unit tests to cover when Count is Less than 0 or when Count is 0 Updated ObservableCollection to only throw the 3 required events when ReplaceItemsRange is invoked. Updated OnChangedEvent methods to check for IList and cast as necessary. Added additional exception handling to reset _skipRaisingEvents bool. Added unit tests to verify event and event parameters are being passed correctly. Updated ReplaceRange event to pass in the OldItems and NewItems to match the event docs Simplified CollectionChanged 'NewItems for InsertItemsRange Updated removedItems to use an array instead of a List Added new OnCollectionChanged overloads to reduce need for additional if checks. Removed stale code Optimized ReplaceItemsRange by simplifying the itemsToReplace which is no an array instead of a List Removed (IList) cast in ReplaceItemsRange when raising CollectionChanged Removed temp array in RemoveRange which decreases memory allocation needed --- .../ObjectModel/ObservableCollection.cs | 147 ++++++- .../ObservableCollection_MethodsTest.cs | 275 ++++++++++++ ...leCollection_SkipCollectionChangedTests.cs | 118 +++++ .../tests/System.ObjectModel.Tests.csproj | 1 + src/System.Runtime/ref/System.Runtime.cs | 9 +- .../ObjectModel/CollectionTests.cs | 405 ++++++++++++++++++ 6 files changed, 950 insertions(+), 5 deletions(-) create mode 100644 src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs diff --git a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs index f74a2c8c7bef..0f96dd66bc37 100644 --- a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs +++ b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs @@ -27,6 +27,9 @@ public class ObservableCollection : Collection, INotifyCollectionChanged, [NonSerialized] private int _blockReentrancyCount; + [NonSerialized] + private bool _skipRaisingEvents; + /// /// Initializes a new instance of ObservableCollection that is empty and has default initial capacity. /// @@ -121,11 +124,92 @@ protected override void RemoveItem(int index) base.RemoveItem(index); + if (!_skipRaisingEvents) + { + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index); + } + } + + /// + /// Called by base class Collection<T> when a count of items is removed from the list; + /// raises a CollectionChanged event to any listeners. + /// + protected override void RemoveItemsRange(int index, int count) + { + CheckReentrancy(); + + T[] removedItems = null; + + bool ignore = _skipRaisingEvents; + if (!ignore) + { + _skipRaisingEvents = true; + + if (count > 0) + { + removedItems = new T[count]; + for (int i = 0; i < count; i++) + { + removedItems[i] = this[index + i]; + } + } + } + + try + { + base.RemoveItemsRange(index, count); + } + finally + { + if (!ignore) + { + _skipRaisingEvents = false; + } + } + + if (count > 0 && !_skipRaisingEvents) + { + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItems, index); + } + } + + /// + /// Called by base class Collection<T> when a collection of items is added to list; + /// raises a CollectionChanged event to any listeners. + /// + protected override void ReplaceItemsRange(int index, int count, IEnumerable collection) + { + CheckReentrancy(); + + _skipRaisingEvents = true; + + T[] itemsToReplace = new T[count - index]; + for (int i = index; i < count; i++) + { + itemsToReplace[i] = this[i]; + } + + try + { + base.ReplaceItemsRange(index, count, collection); + } + finally + { + _skipRaisingEvents = false; + } + + IList newItems = collection is IList list ? list : new List(collection); + OnCountPropertyChanged(); OnIndexerPropertyChanged(); - OnCollectionChanged(NotifyCollectionChangedAction.Remove, removedItem, index); + OnCollectionChanged(NotifyCollectionChangedAction.Replace, itemsToReplace, newItems, index); } + /// /// Called by base class Collection<T> when an item is added to list; /// raises a CollectionChanged event to any listeners. @@ -135,9 +219,48 @@ protected override void InsertItem(int index, T item) CheckReentrancy(); base.InsertItem(index, item); - OnCountPropertyChanged(); - OnIndexerPropertyChanged(); - OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); + if (!_skipRaisingEvents) + { + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); + } + } + + /// + /// Called by base class Collection<T> when a collection of items is added to list; + /// raises a CollectionChanged event to any listeners. + /// + protected override void InsertItemsRange(int index, IEnumerable collection) + { + CheckReentrancy(); + + bool ignore = _skipRaisingEvents; + if (!ignore) + { + _skipRaisingEvents = true; + } + + try + { + base.InsertItemsRange(index, collection); + } + finally + { + if (!ignore) + { + _skipRaisingEvents = false; + } + } + + if (!_skipRaisingEvents) + { + IList newItems = collection is IList list ? list : new List(collection); + + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Add, newItems, index); + } } /// @@ -265,6 +388,14 @@ private void OnCollectionChanged(NotifyCollectionChangedAction action, object it OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); } + /// + /// Helper to raise CollectionChanged event to any listeners + /// + private void OnCollectionChanged(NotifyCollectionChangedAction action, IList items, int index) + { + OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, items, index)); + } + /// /// Helper to raise CollectionChanged event to any listeners /// @@ -281,6 +412,14 @@ private void OnCollectionChanged(NotifyCollectionChangedAction action, object ol OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)); } + /// + /// Helper to raise CollectionChanged event to any listeners + /// + private void OnCollectionChanged(NotifyCollectionChangedAction action, IList oldItems, IList newItems, int index) + { + OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItems, oldItems, index)); + } + /// /// Helper to raise CollectionChanged event with action == Reset to any listeners /// diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs index 6f03a97cc190..d43045743140 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +using System.Linq; using Xunit; namespace System.Collections.ObjectModel.Tests @@ -454,6 +455,280 @@ public static void GetEnumeratorTest() Assert.Equal(col.Count, i); e.Dispose(); } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_Beginning_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(0, dataToInsert); + + Assert.NotNull(collection); + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(0, 5).ToArray()); + Assert.Equal(initialData, collectionAssertion.AsSpan(5).ToArray()); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_Middle_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(2, dataToInsert); + + Assert.NotNull(collection); + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(2, 5).ToArray()); + Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(7, 2).ToArray()); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_End_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(4, dataToInsert); + + Assert.NotNull(collection); + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); + } + + [Fact] + public static void AddRange_NotifyCollectionChanged_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.AddRange(dataToInsert); + + Assert.NotNull(collection); + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); + } + + [Fact] + public static void AddRange_NotifyCollectionChanged_EventArgs_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + + collection.AddRange(dataToAdd); + + Assert.NotNull(collection); + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + + collection.InsertRange(0, dataToAdd); + + Assert.NotNull(collection); + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_Middle_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < 4; i++) + { + collection.Add(i); + } + + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + collection.InsertRange(2, dataToAdd); + + Assert.NotNull(collection); + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_End_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < 4; i++) + { + collection.Add(i); + } + + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + collection.InsertRange(4, dataToAdd); + + Assert.NotNull(collection); + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_FirstTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(0, itemsToRemove); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collection.ToArray()); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_MiddleTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(1, itemsToRemove); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData[0], collection[0]); + Assert.Equal(initialData[3], collection[1]); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_LastTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(2, itemsToRemove); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collection.ToArray()); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_IntMaxValueOverflow_Test() + { + int eventCounter = 0; + int count = 500; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < count; i++) + { + collection.Add(i); + } + + collection.CollectionChanged += (o, e) => eventCounter++; + + Assert.Throws(() => collection.RemoveRange(collection.Count - 2, int.MaxValue)); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexOfZero_Test() + { + int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataRemoved = new int[0]; + int numberOfItemsToRemove = 4; + ObservableCollection collection = new ObservableCollection(); + foreach (int item in initialData) + { + collection.Add(item); + } + + collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); + collection.RemoveRange(0, numberOfItemsToRemove); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); + Assert.Equal(initialData.AsSpan(0, numberOfItemsToRemove).ToArray(), actualDataRemoved); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexMiddle_Test() + { + int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataRemoved = new int[0]; + int numberOfItemsToRemove = 4; + int startIndex = 3; + ObservableCollection collection = new ObservableCollection(); + foreach (int item in initialData) + { + collection.Add(item); + } + + collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); + collection.RemoveRange(startIndex, numberOfItemsToRemove); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); + Assert.Equal(initialData.AsSpan(startIndex, numberOfItemsToRemove).ToArray(), actualDataRemoved); + } + + [Fact] + public static void ReplaceRange_NotifyCollectionChanged_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int[] dataToReplace = new int[] { 3, 8 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.ReplaceRange(0, 2, dataToReplace); + + Assert.NotNull(collection); + Assert.Equal(initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(dataToReplace, collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(2, 2).ToArray()); + } } /// diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs new file mode 100644 index 000000000000..b8480702ad84 --- /dev/null +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Xunit; + +namespace System.ObjectModel.Tests.ObservableCollection +{ + public class ObservableCollection_SkipCollectionChangedTests + { + [Fact] + public void SkipCollectionChanged_AddRange_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + Assert.Throws(() => collection.AddRange(new string[1])); + Assert.Equal(0, collectionChangedCounter); + + collection.Add("4"); + Assert.Equal(1, collectionChangedCounter); + } + + [Fact] + public void SkipCollectionChanged_InsertRange_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + Assert.Throws(() => collection.InsertRange(0, new string[1])); + Assert.Equal(0, collectionChangedCounter); + + collection.Add("4"); + Assert.Equal(1, collectionChangedCounter); + } + + [Fact] + public void SkipCollectionChanged_RemoveRange_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + collection.RemoveRange(0, 2); + Assert.Equal(1, collectionChangedCounter); + + collection.Add("1"); + Assert.Equal(2, collectionChangedCounter); + } + + [Fact] + public void SkipCollectionChanged_RemoveRange_NoEventsRaised_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + collection.RemoveRange(0, 0); + + Assert.Equal(0, collectionChangedCounter); + } + + [Fact] + public void SkipCollectionChanged_ReplaceRange_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + Assert.Throws(() => collection.ReplaceRange(0, 2, new string[1])); + Assert.Equal(0, collectionChangedCounter); + + collection.Add("1"); + Assert.Equal(1, collectionChangedCounter); + } + + public class NonNullObservableCollection : ObservableCollection + { + + public NonNullObservableCollection() : base() { } + public NonNullObservableCollection(List list) : base(list) { } + + protected override void InsertItem(int index, T item) + { + if (item == null) + { + throw new ArgumentNullException(); + } + + base.InsertItem(index, item); + } + + protected override void SetItem(int index, T item) + { + if (item == null) + { + } + + base.SetItem(index, item); + } + } + } +} diff --git a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj index 7682226ac131..c9a873a29b9a 100644 --- a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj +++ b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj @@ -22,6 +22,7 @@ Common\System\CollectionsIDictionaryTest.cs + diff --git a/src/System.Runtime/ref/System.Runtime.cs b/src/System.Runtime/ref/System.Runtime.cs index 2646e062652b..694759465fd0 100644 --- a/src/System.Runtime/ref/System.Runtime.cs +++ b/src/System.Runtime/ref/System.Runtime.cs @@ -4034,6 +4034,7 @@ public Collection(System.Collections.Generic.IList list) { } bool System.Collections.IList.IsReadOnly { get { throw null; } } object System.Collections.IList.this[int index] { get { throw null; } set { } } public void Add(T item) { } + public void AddRange(System.Collections.Generic.IEnumerable collection) { } public void Clear() { } protected virtual void ClearItems() { } public bool Contains(T item) { throw null; } @@ -4042,9 +4043,15 @@ public void CopyTo(T[] array, int index) { } public int IndexOf(T item) { throw null; } public void Insert(int index, T item) { } protected virtual void InsertItem(int index, T item) { } - public bool Remove(T item) { throw null; } + protected virtual void InsertItemsRange(int index, System.Collections.Generic.IEnumerable collection) { } + public void InsertRange(int index, System.Collections.Generic.IEnumerable collection) { } + public bool Remove(T item) { throw null; } public void RemoveAt(int index) { } protected virtual void RemoveItem(int index) { } + protected virtual void RemoveItemsRange(int index, int count) { } + public void RemoveRange(int index, int count) { } + protected virtual void ReplaceItemsRange(int index, int count, System.Collections.Generic.IEnumerable collection) { } + public void ReplaceRange(int index, int count, System.Collections.Generic.IEnumerable collection) { } protected virtual void SetItem(int index, T item) { } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs index 4e1fb2f82eb0..0f7a5bca6bb6 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using Xunit; namespace System.Collections.ObjectModel.Tests @@ -325,6 +326,410 @@ public void ReadOnly_ModifyingCollection_ThrowsNotSupportedException() Assert.Throws(() => collection.RemoveAt(0)); } + [Fact] + public void Collection_AddRange_ToEmpty_Test() + { + int[] expected = new[] { 1, 2, 3, 4 }; + Collection collection = new Collection(); + + collection.AddRange(expected); + + Assert.NotNull(collection); + Assert.Equal(expected.Length, collection.Count); + Assert.Equal(expected, collection.ToArray()); + } + + [Fact] + public void Collection_AddRange_ToExisting_Test() + { + int[] initial = new int[] { 1, 2, 3, 4 }; + int[] dataToInsert = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(); + for (int i = 0; i < initial.Length; i++) + collection.Add(initial[i]); + + collection.AddRange(dataToInsert); + + Assert.NotNull(collection); + Assert.Equal(initial.Length + dataToInsert.Length, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initial, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4, 4).ToArray()); + } + + [Fact] + public void Collection_AddRange_Empty_Test() + { + int[] expected = new int[0]; + Collection collection = new Collection(); + + collection.AddRange(expected); + + Assert.NotNull(collection); + Assert.Equal(expected.Length, collection.Count); + } + + [Fact] + public void Collection_AddRange_Null_Test() + { + Collection collection = new Collection(); + Exception ex = Assert.Throws(() => collection.AddRange(null)); + } + + [Fact] + public void Collection_AddRange_ReadOnly_Test() + { + int[] expected = new int[] { 1, 2, 3, 4 }; + int[] baseCollection = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(baseCollection); + + Exception ex = Assert.Throws(() => collection.AddRange(expected)); + } + + [Fact] + public void Collection_InsertRange_Beginning_Test() + { + int[] expected = new int[] { 1, 2, 3, 4, 5 }; + int[] originalCollection = new int[] { 10, 11, 12, 13 }; + List baseCollection = new List(originalCollection); + + int expectedLength = expected.Length + originalCollection.Length; + Collection collection = new Collection(baseCollection); + + collection.InsertRange(0, expected); + + Assert.NotNull(collection); + Assert.Equal(expectedLength, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(expected, collectionAssertion.AsSpan(0, 5).ToArray()); + Assert.Equal(originalCollection, collectionAssertion.AsSpan(5, 4).ToArray()); + } + + [Fact] + public void Collection_InsertRange_End_Test() + { + int[] expected = new int[] { 1, 2, 3, 4, 5 }; + int[] originalCollection = new int[] { 10, 11, 12, 13 }; + List baseCollection = new List(originalCollection); + + int expectedLength = expected.Length + originalCollection.Length; + Collection collection = new Collection(baseCollection); + + collection.InsertRange(expected.Length - 1, expected); + + Assert.NotNull(collection); + Assert.Equal(expectedLength, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(originalCollection, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(expected, collectionAssertion.AsSpan(4, 5).ToArray()); + } + + [Fact] + public void Collection_InsertRange_Middle_Test() + { + int[] expected = new int[] { 1, 2, 3, 4, 5 }; + int[] originalCollection = new int[] { 10, 11, 12, 13 }; + List baseCollection = new List(originalCollection); + + int expectedLength = expected.Length + originalCollection.Length; + Collection collection = new Collection(baseCollection); + + collection.InsertRange(2, expected); + + Assert.NotNull(collection); + Assert.Equal(expectedLength, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(originalCollection.AsSpan(0, 2).ToArray(), collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(expected, collectionAssertion.AsSpan(2, 5).ToArray()); + Assert.Equal(originalCollection.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(7, 2).ToArray()); + } + + [Fact] + public void Collection_InsertRange_Empty_Test() + { + List baseCollection = new List(new[] { 10, 11, 12, 13 }); + Collection collection = new Collection(baseCollection); + + collection.InsertRange(0, new int[0]); + + Assert.NotNull(collection); + Assert.Equal(baseCollection.Count, collection.Count); + Assert.Equal(baseCollection, collection.ToArray()); + } + + [Fact] + public void Collection_InsertRange_Null_Test() + { + Collection collection = new Collection(); + Exception ex = Assert.Throws(() => collection.InsertRange(0, null)); + } + + [Fact] + public void Collection_InsertRange_ReadOnly_Test() + { + int[] expected = new int[] { 1, 2, 3, 4 }; + int[] baseCollection = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(baseCollection); + + Exception ex = Assert.Throws(() => collection.InsertRange(0, expected)); + } + + [Fact] + public void Collection_InsertRange_IndexLessThan0_Test() + { + int[] expected = new int[] { 1, 2, 3, 4 }; + Collection collection = new Collection(); + Exception ex = Assert.Throws(() => collection.InsertRange(-1, expected)); + } + + [Fact] + public void Collection_InsertRange_IndexGreaterThanCount_Test() + { + int[] expected = new int[] { 1, 2, 3, 4 }; + Collection collection = new Collection(); + Exception ex = Assert.Throws(() => collection.InsertRange(10, expected)); + } + + [Fact] + public void Collection_RemoveRange_Overflow_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + Assert.Throws(() => collection.RemoveRange(0, 4)); + } + + [Fact] + public void Collection_RemoveRange_IntMaxValueOverflow_Test() + { + var count = 500; + Collection collection = new Collection(); + for (int i = 0; i < count; i++) + { + collection.Add(i); + } + + Assert.Throws(() => collection.RemoveRange(collection.Count - 2, int.MaxValue)); + } + + [Fact] + public void Collection_RemoveRange_CountIsZero_Test() + { + int[] expected = new int[] { 1, 2, 3, 4, 5 }; + Collection collection = new Collection(); + for (int i = 0; i < expected.Length; i++) + { + collection.Add(expected[i]); + } + + collection.RemoveRange(0, 0); + + Assert.NotNull(collection); + Assert.Equal(expected.Length, collection.Count); + Assert.Equal(expected, collection.ToArray()); + } + + [Fact] + public void Collection_RemoveRange_CountIsLessThanZero_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + + Assert.Throws(() => collection.RemoveRange(0, -1)); + } + + [Fact] + public void Collection_RemoveRange_All_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + collection.RemoveRange(0, 3); + + Assert.NotNull(collection); + Assert.Equal(0, collection.Count); + } + + [Fact] + public void Collection_RemoveRange_FirstTwoItems_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + collection.RemoveRange(0, 2); + + Assert.NotNull(collection); + Assert.Equal(1, collection.Count); + Assert.Equal(3, collection[0]); + } + + [Fact] + public void Collection_RemoveRange_LastTwoItems_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + collection.RemoveRange(1, 2); + + Assert.NotNull(collection); + Assert.Equal(1, collection.Count); + Assert.Equal(1, collection[0]); + } + + [Fact] + public void Collection_RemoveRange_ZeroItems_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + collection.RemoveRange(0, 0); + + Assert.NotNull(collection); + Assert.Equal(3, collection.Count); + Assert.Equal(1, collection[0]); + Assert.Equal(2, collection[1]); + Assert.Equal(3, collection[2]); + } + + [Fact] + public void Collection_RemoveRange_IndexLessThanZero_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + AssertExtensions.Throws("index", () => collection.RemoveRange(-1, 3)); + } + + [Fact] + public void Collection_RemoveRange_IndexGreaterThanCollection_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + collection.Add(3); + + AssertExtensions.Throws("index", () => collection.RemoveRange(4, 3)); + } + + [Fact] + public void Collection_RemoveRange_ReadOnly_Test() + { + Collection collection = new Collection(new int[] { 1, 2, 3 }); + + Assert.Throws(() => collection.RemoveRange(0, 2)); + } + + [Fact] + public void Collection_ReplaceRange_FirstTwo_Test() + { + int[] initial = new int[] { 1, 2, 3, 4 }; + int[] replace = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(); + foreach (var item in initial) + collection.Add(item); + + collection.ReplaceRange(0, 2, replace); + + Assert.NotNull(collection); + Assert.Equal(initial.Length + 2, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(replace, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(initial.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(4, 2).ToArray()); + } + + [Fact] + public void Collection_ReplaceRange_LastTwo_Test() + { + int[] initial = new int[] { 1, 2, 3, 4 }; + int[] replace = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(); + foreach (var item in initial) + collection.Add(item); + + collection.ReplaceRange(2, 2, replace); + + Assert.NotNull(collection); + Assert.Equal(initial.Length + 2, collection.Count); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initial.AsSpan(0, 2).ToArray(), collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(replace.AsSpan(0, 4).ToArray(), collectionAssertion.AsSpan(2, 4).ToArray()); + } + + [Fact] + public void Collection_ReplaceRange_MiddleTwo_Test() + { + int[] initial = new int[] { 1, 2, 3, 4 }; + int[] replace = new int[] { 5, 6, 7, 8 }; + Collection collection = new Collection(); + foreach (var item in initial) + collection.Add(item); + + collection.ReplaceRange(1, 2, replace); + + Assert.NotNull(collection); + Assert.Equal(initial.Length + 2, collection.Count); + + Assert.Equal(initial[0], collection[0]); + Assert.Equal(replace, collection.ToArray().AsSpan(1, 4).ToArray()); + Assert.Equal(initial[3], collection[5]); + } + + [Fact] + public void Collection_ReplaceRange_NullCollection_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + + Assert.Throws(() => collection.ReplaceRange(0, 2, null)); + } + + [Fact] + public void Collection_ReplaceRange_ReadOnly_Test() + { + Collection collection = new Collection(new int[] { 1, 2, 3 }); + Assert.Throws(() => collection.ReplaceRange(0, 2, new int[] { 4, 5 })); + } + + [Fact] + public void Collection_ReplaceRange_IndexLessThanZero_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + + AssertExtensions.Throws("index", () => collection.ReplaceRange(-2, 2, new int[] { 1, 2 })); + } + + [Fact] + public void Collection_ReplaceRange_IndexGreaterThanCount_Test() + { + Collection collection = new Collection(); + collection.Add(1); + collection.Add(2); + + AssertExtensions.Throws("index", () => collection.ReplaceRange(4, 2, new int[] { 1, 2 })); + } + private class TestCollection : Collection { public TestCollection() From 17e62ef4294b8094b4fefa085f20382593bd2a9a Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Sun, 21 Apr 2019 20:51:20 -0400 Subject: [PATCH 02/19] Removed redudent AsSpan parameter in test code --- .../ObservableCollection/ObservableCollection_MethodsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs index d43045743140..2ddd43b7e084 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs @@ -615,7 +615,7 @@ public static void RemoveRange_NotifyCollectionChanged_FirstTwo_Test() Assert.NotNull(collection); Assert.Equal(initialData.Length - itemsToRemove, collection.Count); Assert.Equal(1, eventCounter); - Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collection.ToArray()); + Assert.Equal(initialData.AsSpan(2).ToArray(), collection.ToArray()); } [Fact] From 5e453ad1c69db259d656f3f588dee0651c481e55 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Sun, 21 Apr 2019 20:52:40 -0400 Subject: [PATCH 03/19] Removed stale code in test code --- .../ObservableCollection/ObservableCollection_MethodsTest.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs index 2ddd43b7e084..0efa36724137 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs @@ -656,7 +656,6 @@ public static void RemoveRange_NotifyCollectionChanged_LastTwo_Test() [Fact] public static void RemoveRange_NotifyCollectionChanged_IntMaxValueOverflow_Test() { - int eventCounter = 0; int count = 500; ObservableCollection collection = new ObservableCollection(); for (int i = 0; i < count; i++) @@ -664,8 +663,6 @@ public static void RemoveRange_NotifyCollectionChanged_IntMaxValueOverflow_Test( collection.Add(i); } - collection.CollectionChanged += (o, e) => eventCounter++; - Assert.Throws(() => collection.RemoveRange(collection.Count - 2, int.MaxValue)); } From 512c5177e2205d8e0be2fd3ced68c58d5b2c2090 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Sun, 21 Apr 2019 20:56:16 -0400 Subject: [PATCH 04/19] Removed redundent Assert.NotNull calls in several tests --- .../ObservableCollection_MethodsTest.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs index 0efa36724137..21df4624674d 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs @@ -467,7 +467,6 @@ public static void InsertRange_NotifyCollectionChanged_Beginning_Test() collection.InsertRange(0, dataToInsert); - Assert.NotNull(collection); Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); Assert.Equal(1, eventCounter); @@ -487,7 +486,6 @@ public static void InsertRange_NotifyCollectionChanged_Middle_Test() collection.InsertRange(2, dataToInsert); - Assert.NotNull(collection); Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); Assert.Equal(1, eventCounter); @@ -508,7 +506,6 @@ public static void InsertRange_NotifyCollectionChanged_End_Test() collection.InsertRange(4, dataToInsert); - Assert.NotNull(collection); Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); Assert.Equal(1, eventCounter); @@ -528,7 +525,6 @@ public static void AddRange_NotifyCollectionChanged_Test() collection.AddRange(dataToInsert); - Assert.NotNull(collection); Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); Assert.Equal(1, eventCounter); @@ -547,7 +543,6 @@ public static void AddRange_NotifyCollectionChanged_EventArgs_Test() collection.AddRange(dataToAdd); - Assert.NotNull(collection); Assert.Equal(dataToAdd, actualDataAdded); } @@ -561,7 +556,6 @@ public static void InsertRange_NotifyCollectionChanged_EventArgs_Test() collection.InsertRange(0, dataToAdd); - Assert.NotNull(collection); Assert.Equal(dataToAdd, actualDataAdded); } @@ -579,7 +573,6 @@ public static void InsertRange_NotifyCollectionChanged_EventArgs_Middle_Test() collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); collection.InsertRange(2, dataToAdd); - Assert.NotNull(collection); Assert.Equal(dataToAdd, actualDataAdded); } @@ -597,7 +590,6 @@ public static void InsertRange_NotifyCollectionChanged_EventArgs_End_Test() collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); collection.InsertRange(4, dataToAdd); - Assert.NotNull(collection); Assert.Equal(dataToAdd, actualDataAdded); } @@ -612,7 +604,6 @@ public static void RemoveRange_NotifyCollectionChanged_FirstTwo_Test() collection.RemoveRange(0, itemsToRemove); - Assert.NotNull(collection); Assert.Equal(initialData.Length - itemsToRemove, collection.Count); Assert.Equal(1, eventCounter); Assert.Equal(initialData.AsSpan(2).ToArray(), collection.ToArray()); @@ -629,7 +620,6 @@ public static void RemoveRange_NotifyCollectionChanged_MiddleTwo_Test() collection.RemoveRange(1, itemsToRemove); - Assert.NotNull(collection); Assert.Equal(initialData.Length - itemsToRemove, collection.Count); Assert.Equal(1, eventCounter); Assert.Equal(initialData[0], collection[0]); @@ -647,7 +637,6 @@ public static void RemoveRange_NotifyCollectionChanged_LastTwo_Test() collection.RemoveRange(2, itemsToRemove); - Assert.NotNull(collection); Assert.Equal(initialData.Length - itemsToRemove, collection.Count); Assert.Equal(1, eventCounter); Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collection.ToArray()); @@ -681,7 +670,6 @@ public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexOfZero_Tes collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); collection.RemoveRange(0, numberOfItemsToRemove); - Assert.NotNull(collection); Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); Assert.Equal(initialData.AsSpan(0, numberOfItemsToRemove).ToArray(), actualDataRemoved); } @@ -702,7 +690,6 @@ public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexMiddle_Tes collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); collection.RemoveRange(startIndex, numberOfItemsToRemove); - Assert.NotNull(collection); Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); Assert.Equal(initialData.AsSpan(startIndex, numberOfItemsToRemove).ToArray(), actualDataRemoved); } @@ -718,7 +705,6 @@ public static void ReplaceRange_NotifyCollectionChanged_Test() collection.ReplaceRange(0, 2, dataToReplace); - Assert.NotNull(collection); Assert.Equal(initialData.Length, collection.Count); Assert.Equal(1, eventCounter); From f4968c90abc2480be4a3c70efd5859b73e443dfe Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Sun, 21 Apr 2019 21:05:17 -0400 Subject: [PATCH 05/19] Added additional check in InsertRange to verify the input collection.Count is greater than 0 before raising the events --- .../Collections/ObjectModel/ObservableCollection.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs index 0f96dd66bc37..d711b6a0a0c2 100644 --- a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs +++ b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs @@ -257,9 +257,12 @@ protected override void InsertItemsRange(int index, IEnumerable collection) { IList newItems = collection is IList list ? list : new List(collection); - OnCountPropertyChanged(); - OnIndexerPropertyChanged(); - OnCollectionChanged(NotifyCollectionChangedAction.Add, newItems, index); + if (newItems.Count > 0) + { + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Add, newItems, index); + } } } From a50f5672be59f2e123f34732311e4f07bc1d7b6f Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Sun, 21 Apr 2019 21:06:36 -0400 Subject: [PATCH 06/19] Removed stale code from the `NonNullObservableCollection` test harness --- .../ObservableCollection_SkipCollectionChangedTests.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs index b8480702ad84..a3c94694444a 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs @@ -104,15 +104,6 @@ protected override void InsertItem(int index, T item) base.InsertItem(index, item); } - - protected override void SetItem(int index, T item) - { - if (item == null) - { - } - - base.SetItem(index, item); - } } } } From 781612b45aff356ceda54f979a37dff731b81429 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Mon, 22 Apr 2019 23:12:58 -0400 Subject: [PATCH 07/19] Removed unnecessary whitespace --- .../src/System/Collections/ObjectModel/ObservableCollection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs index d711b6a0a0c2..c9d5a82bdf39 100644 --- a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs +++ b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs @@ -209,7 +209,6 @@ protected override void ReplaceItemsRange(int index, int count, IEnumerable c OnCollectionChanged(NotifyCollectionChangedAction.Replace, itemsToReplace, newItems, index); } - /// /// Called by base class Collection<T> when an item is added to list; /// raises a CollectionChanged event to any listeners. From afb8909cc1b2cd071cd84cf230e7098a817e2390 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Tue, 23 Apr 2019 23:10:59 -0400 Subject: [PATCH 08/19] Renamed new API tests to include the .netcoreapp extension; Updated .Tests.csproj file to only run them when the project is built under .NET core as net standard is the default --- ...> ObservableCollection_MethodsTest.netcoreapp.cs} | 0 ...lection_SkipCollectionChangedTests.netcoreapp.cs} | 0 .../tests/System.ObjectModel.Tests.csproj | 12 ++++++------ 3 files changed, 6 insertions(+), 6 deletions(-) rename src/System.ObjectModel/tests/ObservableCollection/{ObservableCollection_MethodsTest.cs => ObservableCollection_MethodsTest.netcoreapp.cs} (100%) rename src/System.ObjectModel/tests/ObservableCollection/{ObservableCollection_SkipCollectionChangedTests.cs => ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs} (100%) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.netcoreapp.cs similarity index 100% rename from src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs rename to src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.netcoreapp.cs diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs similarity index 100% rename from src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.cs rename to src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs diff --git a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj index c9a873a29b9a..2434a8b95ca9 100644 --- a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj +++ b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj @@ -22,7 +22,9 @@ Common\System\CollectionsIDictionaryTest.cs - + + + @@ -33,9 +35,6 @@ - - - @@ -44,17 +43,18 @@ + + - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - \ No newline at end of file + From eb1d8027a8260a71d0fd600184707348a8e55c80 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Tue, 23 Apr 2019 23:26:08 -0400 Subject: [PATCH 09/19] Renamed CollectionTests -> CollectionTests.netcoreapp.cs and only run the test if it is a netcoreapp as the new APIs aren't in netstandard yet --- src/System.Runtime/tests/System.Runtime.Tests.csproj | 5 +++-- .../{CollectionTests.cs => CollectionTests.netcoreapp.cs} | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename src/System.Runtime/tests/System/Collections/ObjectModel/{CollectionTests.cs => CollectionTests.netcoreapp.cs} (100%) diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj index 812406b043d9..028ef06686d4 100644 --- a/src/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj @@ -155,7 +155,7 @@ - + @@ -234,6 +234,7 @@ + @@ -271,7 +272,7 @@ - + diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs similarity index 100% rename from src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs rename to src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs From 6403a789b825cf1349106c5759ebf121c9eeb853 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Tue, 23 Apr 2019 23:39:46 -0400 Subject: [PATCH 10/19] Added UAP and UAPAOT build configurations for System.ObjectModel tests --- src/System.ObjectModel/tests/Configurations.props | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/System.ObjectModel/tests/Configurations.props b/src/System.ObjectModel/tests/Configurations.props index 2bc19ff4170e..63b0f12fe5de 100644 --- a/src/System.ObjectModel/tests/Configurations.props +++ b/src/System.ObjectModel/tests/Configurations.props @@ -3,6 +3,8 @@ netstandard; netcoreapp; + uap; + uapaot; \ No newline at end of file From 9ee2e122b83414016022db5db8ff7cb6b22b94cb Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 24 Apr 2019 09:09:36 -0400 Subject: [PATCH 11/19] Updated ObservableCollection/Collection tests that use new APIs to be in a partial class with the .netcoreapp.cs extension and existings tests to be in the .cs file. --- ...rvableCollection_MethodTests.netcoreapp.cs | 269 +++++++++++++++ ...cs => ObservableCollection_MethodsTest.cs} | 260 +------------- .../tests/System.ObjectModel.Tests.csproj | 3 +- .../tests/System.Runtime.Tests.csproj | 1 + .../ObjectModel/CollectionTests.cs | 321 ++++++++++++++++++ .../ObjectModel/CollectionTests.netcoreapp.cs | 312 +---------------- 6 files changed, 595 insertions(+), 571 deletions(-) create mode 100644 src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodTests.netcoreapp.cs rename src/System.ObjectModel/tests/ObservableCollection/{ObservableCollection_MethodsTest.netcoreapp.cs => ObservableCollection_MethodsTest.cs} (76%) create mode 100644 src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodTests.netcoreapp.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodTests.netcoreapp.cs new file mode 100644 index 000000000000..f15d3c3c463f --- /dev/null +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodTests.netcoreapp.cs @@ -0,0 +1,269 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using Xunit; + +namespace System.Collections.ObjectModel.Tests +{ + public partial class ObservableCollection_MethodTests + { + [Fact] + public static void InsertRange_NotifyCollectionChanged_Beginning_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(0, dataToInsert); + + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(0, 5).ToArray()); + Assert.Equal(initialData, collectionAssertion.AsSpan(5).ToArray()); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_Middle_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(2, dataToInsert); + + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(2, 5).ToArray()); + Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(7, 2).ToArray()); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_End_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.InsertRange(4, dataToInsert); + + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); + } + + [Fact] + public static void AddRange_NotifyCollectionChanged_Test() + { + int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; + int[] initialData = new int[] { 10, 11, 12, 13 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.AddRange(dataToInsert); + + Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); + Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); + } + + [Fact] + public static void AddRange_NotifyCollectionChanged_EventArgs_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + + collection.AddRange(dataToAdd); + + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + + collection.InsertRange(0, dataToAdd); + + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_Middle_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < 4; i++) + { + collection.Add(i); + } + + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + collection.InsertRange(2, dataToAdd); + + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void InsertRange_NotifyCollectionChanged_EventArgs_End_Test() + { + int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataAdded = new int[0]; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < 4; i++) + { + collection.Add(i); + } + + collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); + collection.InsertRange(4, dataToAdd); + + Assert.Equal(dataToAdd, actualDataAdded); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_FirstTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(0, itemsToRemove); + + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData.AsSpan(2).ToArray(), collection.ToArray()); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_MiddleTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(1, itemsToRemove); + + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData[0], collection[0]); + Assert.Equal(initialData[3], collection[1]); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_LastTwo_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int itemsToRemove = 2; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.RemoveRange(2, itemsToRemove); + + Assert.Equal(initialData.Length - itemsToRemove, collection.Count); + Assert.Equal(1, eventCounter); + Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collection.ToArray()); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_IntMaxValueOverflow_Test() + { + int count = 500; + ObservableCollection collection = new ObservableCollection(); + for (int i = 0; i < count; i++) + { + collection.Add(i); + } + + Assert.Throws(() => collection.RemoveRange(collection.Count - 2, int.MaxValue)); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexOfZero_Test() + { + int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataRemoved = new int[0]; + int numberOfItemsToRemove = 4; + ObservableCollection collection = new ObservableCollection(); + foreach (int item in initialData) + { + collection.Add(item); + } + + collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); + collection.RemoveRange(0, numberOfItemsToRemove); + + Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); + Assert.Equal(initialData.AsSpan(0, numberOfItemsToRemove).ToArray(), actualDataRemoved); + } + + [Fact] + public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexMiddle_Test() + { + int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] actualDataRemoved = new int[0]; + int numberOfItemsToRemove = 4; + int startIndex = 3; + ObservableCollection collection = new ObservableCollection(); + foreach (int item in initialData) + { + collection.Add(item); + } + + collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); + collection.RemoveRange(startIndex, numberOfItemsToRemove); + + Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); + Assert.Equal(initialData.AsSpan(startIndex, numberOfItemsToRemove).ToArray(), actualDataRemoved); + } + + [Fact] + public static void ReplaceRange_NotifyCollectionChanged_Test() + { + int[] initialData = new int[] { 10, 11, 12, 13 }; + int[] dataToReplace = new int[] { 3, 8 }; + int eventCounter = 0; + ObservableCollection collection = new ObservableCollection(initialData); + collection.CollectionChanged += (o, e) => eventCounter++; + + collection.ReplaceRange(0, 2, dataToReplace); + + Assert.Equal(initialData.Length, collection.Count); + Assert.Equal(1, eventCounter); + + int[] collectionAssertion = collection.ToArray(); + Assert.Equal(dataToReplace, collectionAssertion.AsSpan(0, 2).ToArray()); + Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(2, 2).ToArray()); + } + } +} diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.netcoreapp.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs similarity index 76% rename from src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.netcoreapp.cs rename to src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs index 21df4624674d..bb291a98a3e4 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.netcoreapp.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_MethodsTest.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; -using System.Linq; using Xunit; namespace System.Collections.ObjectModel.Tests @@ -15,7 +14,7 @@ namespace System.Collections.ObjectModel.Tests /// that the CollectionChanged events and eventargs are fired and populated /// properly. /// - public static class PublicMethodsTest + public partial class PublicMethodsTest { /// /// Tests that is possible to Add an item to the collection. @@ -455,263 +454,6 @@ public static void GetEnumeratorTest() Assert.Equal(col.Count, i); e.Dispose(); } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_Beginning_Test() - { - int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; - int[] initialData = new int[] { 10, 11, 12, 13 }; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.InsertRange(0, dataToInsert); - - Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); - Assert.Equal(1, eventCounter); - - int[] collectionAssertion = collection.ToArray(); - Assert.Equal(dataToInsert, collectionAssertion.AsSpan(0, 5).ToArray()); - Assert.Equal(initialData, collectionAssertion.AsSpan(5).ToArray()); - } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_Middle_Test() - { - int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; - int[] initialData = new int[] { 10, 11, 12, 13 }; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.InsertRange(2, dataToInsert); - - Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); - Assert.Equal(1, eventCounter); - - int[] collectionAssertion = collection.ToArray(); - Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collectionAssertion.AsSpan(0, 2).ToArray()); - Assert.Equal(dataToInsert, collectionAssertion.AsSpan(2, 5).ToArray()); - Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(7, 2).ToArray()); - } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_End_Test() - { - int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; - int[] initialData = new int[] { 10, 11, 12, 13 }; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.InsertRange(4, dataToInsert); - - Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); - Assert.Equal(1, eventCounter); - - int[] collectionAssertion = collection.ToArray(); - Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); - Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); - } - - [Fact] - public static void AddRange_NotifyCollectionChanged_Test() - { - int[] dataToInsert = new int[] { 1, 2, 3, 4, 5 }; - int[] initialData = new int[] { 10, 11, 12, 13 }; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.AddRange(dataToInsert); - - Assert.Equal(dataToInsert.Length + initialData.Length, collection.Count); - Assert.Equal(1, eventCounter); - - int[] collectionAssertion = collection.ToArray(); - Assert.Equal(initialData, collectionAssertion.AsSpan(0, 4).ToArray()); - Assert.Equal(dataToInsert, collectionAssertion.AsSpan(4).ToArray()); - } - - [Fact] - public static void AddRange_NotifyCollectionChanged_EventArgs_Test() - { - int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataAdded = new int[0]; - ObservableCollection collection = new ObservableCollection(); - collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); - - collection.AddRange(dataToAdd); - - Assert.Equal(dataToAdd, actualDataAdded); - } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_EventArgs_Test() - { - int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataAdded = new int[0]; - ObservableCollection collection = new ObservableCollection(); - collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); - - collection.InsertRange(0, dataToAdd); - - Assert.Equal(dataToAdd, actualDataAdded); - } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_EventArgs_Middle_Test() - { - int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataAdded = new int[0]; - ObservableCollection collection = new ObservableCollection(); - for (int i = 0; i < 4; i++) - { - collection.Add(i); - } - - collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); - collection.InsertRange(2, dataToAdd); - - Assert.Equal(dataToAdd, actualDataAdded); - } - - [Fact] - public static void InsertRange_NotifyCollectionChanged_EventArgs_End_Test() - { - int[] dataToAdd = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataAdded = new int[0]; - ObservableCollection collection = new ObservableCollection(); - for (int i = 0; i < 4; i++) - { - collection.Add(i); - } - - collection.CollectionChanged += (o, e) => actualDataAdded = e.NewItems.Cast().ToArray(); - collection.InsertRange(4, dataToAdd); - - Assert.Equal(dataToAdd, actualDataAdded); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_FirstTwo_Test() - { - int[] initialData = new int[] { 10, 11, 12, 13 }; - int itemsToRemove = 2; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.RemoveRange(0, itemsToRemove); - - Assert.Equal(initialData.Length - itemsToRemove, collection.Count); - Assert.Equal(1, eventCounter); - Assert.Equal(initialData.AsSpan(2).ToArray(), collection.ToArray()); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_MiddleTwo_Test() - { - int[] initialData = new int[] { 10, 11, 12, 13 }; - int itemsToRemove = 2; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.RemoveRange(1, itemsToRemove); - - Assert.Equal(initialData.Length - itemsToRemove, collection.Count); - Assert.Equal(1, eventCounter); - Assert.Equal(initialData[0], collection[0]); - Assert.Equal(initialData[3], collection[1]); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_LastTwo_Test() - { - int[] initialData = new int[] { 10, 11, 12, 13 }; - int itemsToRemove = 2; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.RemoveRange(2, itemsToRemove); - - Assert.Equal(initialData.Length - itemsToRemove, collection.Count); - Assert.Equal(1, eventCounter); - Assert.Equal(initialData.AsSpan(0, 2).ToArray(), collection.ToArray()); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_IntMaxValueOverflow_Test() - { - int count = 500; - ObservableCollection collection = new ObservableCollection(); - for (int i = 0; i < count; i++) - { - collection.Add(i); - } - - Assert.Throws(() => collection.RemoveRange(collection.Count - 2, int.MaxValue)); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexOfZero_Test() - { - int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataRemoved = new int[0]; - int numberOfItemsToRemove = 4; - ObservableCollection collection = new ObservableCollection(); - foreach (int item in initialData) - { - collection.Add(item); - } - - collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); - collection.RemoveRange(0, numberOfItemsToRemove); - - Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); - Assert.Equal(initialData.AsSpan(0, numberOfItemsToRemove).ToArray(), actualDataRemoved); - } - - [Fact] - public static void RemoveRange_NotifyCollectionChanged_EventArgs_IndexMiddle_Test() - { - int[] initialData = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; - int[] actualDataRemoved = new int[0]; - int numberOfItemsToRemove = 4; - int startIndex = 3; - ObservableCollection collection = new ObservableCollection(); - foreach (int item in initialData) - { - collection.Add(item); - } - - collection.CollectionChanged += (o, e) => actualDataRemoved = e.OldItems.Cast().ToArray(); - collection.RemoveRange(startIndex, numberOfItemsToRemove); - - Assert.Equal(initialData.Length - numberOfItemsToRemove, collection.Count); - Assert.Equal(initialData.AsSpan(startIndex, numberOfItemsToRemove).ToArray(), actualDataRemoved); - } - - [Fact] - public static void ReplaceRange_NotifyCollectionChanged_Test() - { - int[] initialData = new int[] { 10, 11, 12, 13 }; - int[] dataToReplace = new int[] { 3, 8 }; - int eventCounter = 0; - ObservableCollection collection = new ObservableCollection(initialData); - collection.CollectionChanged += (o, e) => eventCounter++; - - collection.ReplaceRange(0, 2, dataToReplace); - - Assert.Equal(initialData.Length, collection.Count); - Assert.Equal(1, eventCounter); - - int[] collectionAssertion = collection.ToArray(); - Assert.Equal(dataToReplace, collectionAssertion.AsSpan(0, 2).ToArray()); - Assert.Equal(initialData.AsSpan(2, 2).ToArray(), collectionAssertion.AsSpan(2, 2).ToArray()); - } } /// diff --git a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj index 2434a8b95ca9..89419f88be3d 100644 --- a/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj +++ b/src/System.ObjectModel/tests/System.ObjectModel.Tests.csproj @@ -23,6 +23,7 @@ Common\System\CollectionsIDictionaryTest.cs + @@ -43,7 +44,7 @@ - + diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj index 028ef06686d4..4e998a688801 100644 --- a/src/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj @@ -72,6 +72,7 @@ + diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs new file mode 100644 index 000000000000..c8c7843f7641 --- /dev/null +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs @@ -0,0 +1,321 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace System.Collections.ObjectModel.Tests +{ + public partial class CollectionTests + { + private static readonly Collection s_empty = new Collection(); + + [Fact] + public static void Ctor_Empty() + { + Collection collection = new Collection(); + Assert.Empty(collection); + } + + [Fact] + public static void Ctor_NullList_ThrowsArgumentNullException() + { + AssertExtensions.Throws("list", () => new Collection(null)); + } + + [Fact] + public static void Ctor_IList() + { + var collection = new TestCollection(s_intArray); + Assert.Same(s_intArray, collection.GetItems()); + Assert.Equal(s_intArray.Length, collection.Count); + } + + [Fact] + public static void GetItems_CastableToList() + { + // + // Although MSDN only documents that Collection.Items returns an IList, + // apps have made it through the Windows Store that successfully cast the return value + // of Items to List. + // + // Thus, we must grumble and continue to honor this behavior. + // + + TestCollection c = new TestCollection(); + IList il = c.GetItems(); + + // Avoid using the List type so that we don't have to depend on the System.Collections contract + Type type = il.GetType(); + Assert.Equal(1, type.GenericTypeArguments.Length); + Assert.Equal(typeof(int), type.GenericTypeArguments[0]); + Assert.Equal("System.Collections.Generic.List`1", string.Format("{0}.{1}", type.Namespace, type.Name)); + } + + [Fact] + public static void Item_Get_Set() + { + var collection = new ModifiableCollection(s_intArray); + for (int i = 0; i < s_intArray.Length; i++) + { + collection[i] = i; + Assert.Equal(i, collection[i]); + } + } + + [Fact] + public static void Item_Get_Set_InvalidIndex_ThrowsArgumentOutOfRangeException() + { + var collection = new ModifiableCollection(s_intArray); + + AssertExtensions.Throws("index", () => collection[-1]); + AssertExtensions.Throws("index", () => collection[s_intArray.Length]); + AssertExtensions.Throws("index", () => s_empty[0]); + + AssertExtensions.Throws("index", () => collection[-1] = 0); + AssertExtensions.Throws("index", () => collection[s_intArray.Length] = 0); + } + + [Fact] + public static void Item_Set_InvalidType_ThrowsArgumentException() + { + var collection = new Collection(new Collection(s_intArray)); + AssertExtensions.Throws("value", () => ((IList)collection)[1] = "Two"); + } + + [Fact] + public static void IsReadOnly_ReturnsTrue() + { + var collection = new Collection(s_intArray); + Assert.True(((IList)collection).IsReadOnly); + Assert.True(((IList)collection).IsReadOnly); + } + + [Fact] + public static void Insert_ZeroIndex() + { + const int itemsToInsert = 5; + var collection = new ModifiableCollection(); + + for (int i = itemsToInsert - 1; i >= 0; i--) + { + collection.Insert(0, i); + } + + for (int i = 0; i < itemsToInsert; i++) + { + Assert.Equal(i, collection[i]); + } + } + + [Fact] + public static void Insert_MiddleIndex() + { + const int insertIndex = 3; + const int itemsToInsert = 5; + + var collection = new ModifiableCollection(s_intArray); + + for (int i = 0; i < itemsToInsert; i++) + { + collection.Insert(insertIndex + i, i); + } + + // Verify from the beginning of the collection up to insertIndex + for (int i = 0; i < insertIndex; i++) + { + Assert.Equal(s_intArray[i], collection[i]); + } + + // Verify itemsToInsert items starting from insertIndex + for (int i = 0; i < itemsToInsert; i++) + { + Assert.Equal(i, collection[insertIndex + i]); + } + + // Verify the rest of the items in the collection + for (int i = insertIndex; i < s_intArray.Length; i++) + { + Assert.Equal(s_intArray[i], collection[itemsToInsert + i]); + } + } + + [Fact] + public static void Insert_EndIndex() + { + const int itemsToInsert = 5; + + var collection = new ModifiableCollection(s_intArray); + + for (int i = 0; i < itemsToInsert; i++) + { + collection.Insert(collection.Count, i); + } + + for (int i = 0; i < itemsToInsert; i++) + { + Assert.Equal(i, collection[s_intArray.Length + i]); + } + } + + [Fact] + public static void Insert_InvalidIndex_ThrowsArgumentOutOfRangeException() + { + var collection = new ModifiableCollection(s_intArray); + AssertExtensions.Throws("index", () => collection.Insert(-1, 0)); + AssertExtensions.Throws("index", () => collection.Insert(s_intArray.Length + 1, 0)); + } + + [Fact] + public static void Clear() + { + var collection = new ModifiableCollection(s_intArray); + collection.Clear(); + Assert.Equal(0, collection.Count); + } + + [Fact] + public static void Contains() + { + var collection = new Collection(s_intArray); + for (int i = 0; i < s_intArray.Length; i++) + { + Assert.True(collection.Contains(s_intArray[i])); + } + + for (int i = 0; i < s_excludedFromIntArray.Length; i++) + { + Assert.False(collection.Contains(s_excludedFromIntArray[i])); + } + } + + [Fact] + public static void CopyTo() + { + var collection = new Collection(s_intArray); + const int targetIndex = 3; + int[] intArray = new int[s_intArray.Length + targetIndex]; + + Assert.Throws(() => collection.CopyTo(null, 0)); + AssertExtensions.Throws(null, () => ((ICollection)collection).CopyTo(new int[s_intArray.Length, s_intArray.Length], 0)); + Assert.Throws(() => collection.CopyTo(intArray, -1)); + AssertExtensions.Throws("destinationArray", "", () => collection.CopyTo(intArray, s_intArray.Length - 1)); + + collection.CopyTo(intArray, targetIndex); + for (int i = targetIndex; i < intArray.Length; i++) + { + Assert.Equal(collection[i - targetIndex], intArray[i]); + } + + object[] objectArray = new object[s_intArray.Length + targetIndex]; + ((ICollection)collection).CopyTo(intArray, targetIndex); + for (int i = targetIndex; i < intArray.Length; i++) + { + Assert.Equal(collection[i - targetIndex], intArray[i]); + } + } + + [Fact] + public static void IndexOf() + { + var collection = new Collection(s_intArray); + + for (int i = 0; i < s_intArray.Length; i++) + { + int item = s_intArray[i]; + Assert.Equal(Array.IndexOf(s_intArray, item), collection.IndexOf(item)); + } + + for (int i = 0; i < s_excludedFromIntArray.Length; i++) + { + Assert.Equal(-1, collection.IndexOf(s_excludedFromIntArray[i])); + } + } + + private static readonly int[] s_intSequence = new int[] { 0, 1, 2, 3, 4, 5 }; + + [Fact] + public static void RemoveAt() + { + VerifyRemoveAt(0, 1, new[] { 1, 2, 3, 4, 5 }); + VerifyRemoveAt(3, 2, new[] { 0, 1, 2, 5 }); + VerifyRemoveAt(4, 1, new[] { 0, 1, 2, 3, 5 }); + VerifyRemoveAt(5, 1, new[] { 0, 1, 2, 3, 4 }); + VerifyRemoveAt(0, 6, s_empty); + } + + private static void VerifyRemoveAt(int index, int count, IEnumerable expected) + { + var collection = new ModifiableCollection(s_intSequence); + + for (int i = 0; i < count; i++) + { + collection.RemoveAt(index); + } + + Assert.Equal(expected, collection); + } + + [Fact] + public static void RemoveAt_InvalidIndex_ThrowsArgumentOutOfRangeException() + { + var collection = new ModifiableCollection(s_intSequence); + AssertExtensions.Throws("index", () => collection.RemoveAt(-1)); + AssertExtensions.Throws("index", () => collection.RemoveAt(s_intArray.Length)); + } + + [Fact] + public static void MembersForwardedToUnderlyingIList() + { + var expectedApiCalls = + IListApi.Count | + IListApi.IsReadOnly | + IListApi.IndexerGet | + IListApi.IndexerSet | + IListApi.Insert | + IListApi.Clear | + IListApi.Contains | + IListApi.CopyTo | + IListApi.GetEnumeratorGeneric | + IListApi.IndexOf | + IListApi.RemoveAt | + IListApi.GetEnumerator; + + var list = new CallTrackingIList(expectedApiCalls); + var collection = new Collection(list); + + int count = collection.Count; + bool readOnly = ((IList)collection).IsReadOnly; + int x = collection[0]; + collection[0] = 22; + collection.Add(x); + collection.Clear(); + collection.Contains(x); + collection.CopyTo(s_intArray, 0); + collection.GetEnumerator(); + collection.IndexOf(x); + collection.Insert(0, x); + collection.Remove(x); + collection.RemoveAt(0); + ((IEnumerable)collection).GetEnumerator(); + + list.AssertAllMembersCalled(); + } + + [Fact] + public void ReadOnly_ModifyingCollection_ThrowsNotSupportedException() + { + var collection = new Collection(s_intArray); + + Assert.Throws(() => collection[0] = 0); + Assert.Throws(() => collection.Add(0)); + Assert.Throws(() => collection.Clear()); + Assert.Throws(() => collection.Insert(0, 0)); + Assert.Throws(() => collection.Remove(0)); + Assert.Throws(() => collection.RemoveAt(0)); + } + } +} diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs index 0f7a5bca6bb6..280c402c05eb 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using Xunit; @@ -17,315 +14,8 @@ namespace System.Collections.ObjectModel.Tests /// we expect are forwarded to the underlying list, and verify that the exceptions we expect /// are thrown. /// - public class CollectionTests : CollectionTestBase + public partial class CollectionTests : CollectionTestBase { - private static readonly Collection s_empty = new Collection(); - - [Fact] - public static void Ctor_Empty() - { - Collection collection = new Collection(); - Assert.Empty(collection); - } - - [Fact] - public static void Ctor_NullList_ThrowsArgumentNullException() - { - AssertExtensions.Throws("list", () => new Collection(null)); - } - - [Fact] - public static void Ctor_IList() - { - var collection = new TestCollection(s_intArray); - Assert.Same(s_intArray, collection.GetItems()); - Assert.Equal(s_intArray.Length, collection.Count); - } - - [Fact] - public static void GetItems_CastableToList() - { - // - // Although MSDN only documents that Collection.Items returns an IList, - // apps have made it through the Windows Store that successfully cast the return value - // of Items to List. - // - // Thus, we must grumble and continue to honor this behavior. - // - - TestCollection c = new TestCollection(); - IList il = c.GetItems(); - - // Avoid using the List type so that we don't have to depend on the System.Collections contract - Type type = il.GetType(); - Assert.Equal(1, type.GenericTypeArguments.Length); - Assert.Equal(typeof(int), type.GenericTypeArguments[0]); - Assert.Equal("System.Collections.Generic.List`1", string.Format("{0}.{1}", type.Namespace, type.Name)); - } - - [Fact] - public static void Item_Get_Set() - { - var collection = new ModifiableCollection(s_intArray); - for (int i = 0; i < s_intArray.Length; i++) - { - collection[i] = i; - Assert.Equal(i, collection[i]); - } - } - - [Fact] - public static void Item_Get_Set_InvalidIndex_ThrowsArgumentOutOfRangeException() - { - var collection = new ModifiableCollection(s_intArray); - - AssertExtensions.Throws("index", () => collection[-1]); - AssertExtensions.Throws("index", () => collection[s_intArray.Length]); - AssertExtensions.Throws("index", () => s_empty[0]); - - AssertExtensions.Throws("index", () => collection[-1] = 0); - AssertExtensions.Throws("index", () => collection[s_intArray.Length] = 0); - } - - [Fact] - public static void Item_Set_InvalidType_ThrowsArgumentException() - { - var collection = new Collection(new Collection(s_intArray)); - AssertExtensions.Throws("value", () => ((IList)collection)[1] = "Two"); - } - - [Fact] - public static void IsReadOnly_ReturnsTrue() - { - var collection = new Collection(s_intArray); - Assert.True(((IList)collection).IsReadOnly); - Assert.True(((IList)collection).IsReadOnly); - } - - [Fact] - public static void Insert_ZeroIndex() - { - const int itemsToInsert = 5; - var collection = new ModifiableCollection(); - - for (int i = itemsToInsert - 1; i >= 0; i--) - { - collection.Insert(0, i); - } - - for (int i = 0; i < itemsToInsert; i++) - { - Assert.Equal(i, collection[i]); - } - } - - [Fact] - public static void Insert_MiddleIndex() - { - const int insertIndex = 3; - const int itemsToInsert = 5; - - var collection = new ModifiableCollection(s_intArray); - - for (int i = 0; i < itemsToInsert; i++) - { - collection.Insert(insertIndex + i, i); - } - - // Verify from the beginning of the collection up to insertIndex - for (int i = 0; i < insertIndex; i++) - { - Assert.Equal(s_intArray[i], collection[i]); - } - - // Verify itemsToInsert items starting from insertIndex - for (int i = 0; i < itemsToInsert; i++) - { - Assert.Equal(i, collection[insertIndex + i]); - } - - // Verify the rest of the items in the collection - for (int i = insertIndex; i < s_intArray.Length; i++) - { - Assert.Equal(s_intArray[i], collection[itemsToInsert + i]); - } - } - - [Fact] - public static void Insert_EndIndex() - { - const int itemsToInsert = 5; - - var collection = new ModifiableCollection(s_intArray); - - for (int i = 0; i < itemsToInsert; i++) - { - collection.Insert(collection.Count, i); - } - - for (int i = 0; i < itemsToInsert; i++) - { - Assert.Equal(i, collection[s_intArray.Length + i]); - } - } - - [Fact] - public static void Insert_InvalidIndex_ThrowsArgumentOutOfRangeException() - { - var collection = new ModifiableCollection(s_intArray); - AssertExtensions.Throws("index", () => collection.Insert(-1, 0)); - AssertExtensions.Throws("index", () => collection.Insert(s_intArray.Length + 1, 0)); - } - - [Fact] - public static void Clear() - { - var collection = new ModifiableCollection(s_intArray); - collection.Clear(); - Assert.Equal(0, collection.Count); - } - - [Fact] - public static void Contains() - { - var collection = new Collection(s_intArray); - for (int i = 0; i < s_intArray.Length; i++) - { - Assert.True(collection.Contains(s_intArray[i])); - } - - for (int i = 0; i < s_excludedFromIntArray.Length; i++) - { - Assert.False(collection.Contains(s_excludedFromIntArray[i])); - } - } - - [Fact] - public static void CopyTo() - { - var collection = new Collection(s_intArray); - const int targetIndex = 3; - int[] intArray = new int[s_intArray.Length + targetIndex]; - - Assert.Throws(() => collection.CopyTo(null, 0)); - AssertExtensions.Throws(null, () => ((ICollection)collection).CopyTo(new int[s_intArray.Length, s_intArray.Length], 0)); - Assert.Throws(() => collection.CopyTo(intArray, -1)); - AssertExtensions.Throws("destinationArray", "", () => collection.CopyTo(intArray, s_intArray.Length - 1)); - - collection.CopyTo(intArray, targetIndex); - for (int i = targetIndex; i < intArray.Length; i++) - { - Assert.Equal(collection[i - targetIndex], intArray[i]); - } - - object[] objectArray = new object[s_intArray.Length + targetIndex]; - ((ICollection)collection).CopyTo(intArray, targetIndex); - for (int i = targetIndex; i < intArray.Length; i++) - { - Assert.Equal(collection[i - targetIndex], intArray[i]); - } - } - - [Fact] - public static void IndexOf() - { - var collection = new Collection(s_intArray); - - for (int i = 0; i < s_intArray.Length; i++) - { - int item = s_intArray[i]; - Assert.Equal(Array.IndexOf(s_intArray, item), collection.IndexOf(item)); - } - - for (int i = 0; i < s_excludedFromIntArray.Length; i++) - { - Assert.Equal(-1, collection.IndexOf(s_excludedFromIntArray[i])); - } - } - - private static readonly int[] s_intSequence = new int[] { 0, 1, 2, 3, 4, 5 }; - - [Fact] - public static void RemoveAt() - { - VerifyRemoveAt(0, 1, new[] { 1, 2, 3, 4, 5 }); - VerifyRemoveAt(3, 2, new[] { 0, 1, 2, 5 }); - VerifyRemoveAt(4, 1, new[] { 0, 1, 2, 3, 5 }); - VerifyRemoveAt(5, 1, new[] { 0, 1, 2, 3, 4 }); - VerifyRemoveAt(0, 6, s_empty); - } - - private static void VerifyRemoveAt(int index, int count, IEnumerable expected) - { - var collection = new ModifiableCollection(s_intSequence); - - for (int i = 0; i < count; i++) - { - collection.RemoveAt(index); - } - - Assert.Equal(expected, collection); - } - - [Fact] - public static void RemoveAt_InvalidIndex_ThrowsArgumentOutOfRangeException() - { - var collection = new ModifiableCollection(s_intSequence); - AssertExtensions.Throws("index", () => collection.RemoveAt(-1)); - AssertExtensions.Throws("index", () => collection.RemoveAt(s_intArray.Length)); - } - - [Fact] - public static void MembersForwardedToUnderlyingIList() - { - var expectedApiCalls = - IListApi.Count | - IListApi.IsReadOnly | - IListApi.IndexerGet | - IListApi.IndexerSet | - IListApi.Insert | - IListApi.Clear | - IListApi.Contains | - IListApi.CopyTo | - IListApi.GetEnumeratorGeneric | - IListApi.IndexOf | - IListApi.RemoveAt | - IListApi.GetEnumerator; - - var list = new CallTrackingIList(expectedApiCalls); - var collection = new Collection(list); - - int count = collection.Count; - bool readOnly = ((IList)collection).IsReadOnly; - int x = collection[0]; - collection[0] = 22; - collection.Add(x); - collection.Clear(); - collection.Contains(x); - collection.CopyTo(s_intArray, 0); - collection.GetEnumerator(); - collection.IndexOf(x); - collection.Insert(0, x); - collection.Remove(x); - collection.RemoveAt(0); - ((IEnumerable)collection).GetEnumerator(); - - list.AssertAllMembersCalled(); - } - - [Fact] - public void ReadOnly_ModifyingCollection_ThrowsNotSupportedException() - { - var collection = new Collection(s_intArray); - - Assert.Throws(() => collection[0] = 0); - Assert.Throws(() => collection.Add(0)); - Assert.Throws(() => collection.Clear()); - Assert.Throws(() => collection.Insert(0, 0)); - Assert.Throws(() => collection.Remove(0)); - Assert.Throws(() => collection.RemoveAt(0)); - } - [Fact] public void Collection_AddRange_ToEmpty_Test() { From d948ef54f92765780be4daeb6ba3e1bea70e0baf Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 24 Apr 2019 09:32:44 -0400 Subject: [PATCH 12/19] Added CollectionTestBase as parent class for CollectionTests for the use case where the other tests are ignored in netstandard builds --- .../tests/System/Collections/ObjectModel/CollectionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs index c8c7843f7641..516066580042 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs @@ -9,7 +9,7 @@ namespace System.Collections.ObjectModel.Tests { - public partial class CollectionTests + public partial class CollectionTests : CollectionTestBase { private static readonly Collection s_empty = new Collection(); From 8b527afdf2baf07fcc8efe5dc5a46d6968b724da Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 24 Apr 2019 09:57:35 -0400 Subject: [PATCH 13/19] Adding using statements back in which were failing the build --- .../tests/System/Collections/ObjectModel/CollectionTests.cs | 3 ++- .../Collections/ObjectModel/CollectionTests.netcoreapp.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs index 516066580042..a77a97d5958b 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs @@ -3,8 +3,9 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Generic; -using System.Text; +using System.Collections.ObjectModel; using Xunit; namespace System.Collections.ObjectModel.Tests diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs index 280c402c05eb..5ca1338e1e1c 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; +using System.Collections.ObjectModel; using Xunit; namespace System.Collections.ObjectModel.Tests From fa550f48609ac8bac15867436f89a288a15337d1 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 24 Apr 2019 10:15:46 -0400 Subject: [PATCH 14/19] Moving private classes from the netcoreapp tests to the regular CollectionTests as they were not available in the netstandard CI test run --- .../ObjectModel/CollectionTests.cs | 31 +++++++++++++++++-- .../ObjectModel/CollectionTests.netcoreapp.cs | 30 ------------------ 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs index a77a97d5958b..0961f2b8812f 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using Xunit; namespace System.Collections.ObjectModel.Tests @@ -318,5 +315,33 @@ public void ReadOnly_ModifyingCollection_ThrowsNotSupportedException() Assert.Throws(() => collection.Remove(0)); Assert.Throws(() => collection.RemoveAt(0)); } + + private class TestCollection : Collection + { + public TestCollection() + { + } + + public TestCollection(IList items) : base(items) + { + } + + public IList GetItems() => Items; + } + + private class ModifiableCollection : Collection + { + public ModifiableCollection() + { + } + + public ModifiableCollection(IList items) + { + foreach (var item in items) + { + Items.Add(item); + } + } + } } } diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs index 5ca1338e1e1c..91c097088130 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs @@ -3,9 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using Xunit; namespace System.Collections.ObjectModel.Tests @@ -421,33 +419,5 @@ public void Collection_ReplaceRange_IndexGreaterThanCount_Test() AssertExtensions.Throws("index", () => collection.ReplaceRange(4, 2, new int[] { 1, 2 })); } - - private class TestCollection : Collection - { - public TestCollection() - { - } - - public TestCollection(IList items) : base(items) - { - } - - public IList GetItems() => Items; - } - - private class ModifiableCollection : Collection - { - public ModifiableCollection() - { - } - - public ModifiableCollection(IList items) - { - foreach (var item in items) - { - Items.Add(item); - } - } - } } } From d36ec1e0c511cbb97bf8bfd70874422aa9cd445e Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 24 Apr 2019 10:59:28 -0400 Subject: [PATCH 15/19] Added missing using statement for colleciton tests --- .../System/Collections/ObjectModel/CollectionTests.netcoreapp.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs index 91c097088130..940af6773626 100644 --- a/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Collections/ObjectModel/CollectionTests.netcoreapp.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Xunit; namespace System.Collections.ObjectModel.Tests From e019416100e45601b7194348db722ac77c0345d5 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 1 May 2019 21:17:38 -0400 Subject: [PATCH 16/19] Added if-block that certifies we have replaced items before raising the Replace Event on ReplaceItemsRange --- .../ObjectModel/ObservableCollection.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs index c9d5a82bdf39..7dac6ec2f3f7 100644 --- a/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs +++ b/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs @@ -202,11 +202,17 @@ protected override void ReplaceItemsRange(int index, int count, IEnumerable c _skipRaisingEvents = false; } - IList newItems = collection is IList list ? list : new List(collection); + if (!_skipRaisingEvents) + { + IList newItems = collection is IList list ? list : new List(collection); - OnCountPropertyChanged(); - OnIndexerPropertyChanged(); - OnCollectionChanged(NotifyCollectionChangedAction.Replace, itemsToReplace, newItems, index); + if (newItems.Count > 0) + { + OnCountPropertyChanged(); + OnIndexerPropertyChanged(); + OnCollectionChanged(NotifyCollectionChangedAction.Replace, itemsToReplace, newItems, index); + } + } } /// From 01b9496d7fb88824d38db8bd45c48873445fbd70 Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 1 May 2019 21:19:25 -0400 Subject: [PATCH 17/19] Removed whitespace in System.Runtime.Tests.csproj --- src/System.Runtime/tests/System.Runtime.Tests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj index 4e998a688801..53a45b1ba1de 100644 --- a/src/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj @@ -156,7 +156,6 @@ - From 33bcaa0f062564d46f05b84314314a3ac393197b Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 1 May 2019 22:21:46 -0400 Subject: [PATCH 18/19] Added negative test case for ReplaceRange when no items are replaced --- ...ion_SkipCollectionChangedTests.netcoreapp.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs index a3c94694444a..4c0569b3a24c 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs @@ -89,6 +89,23 @@ public void SkipCollectionChanged_ReplaceRange_Test() Assert.Equal(1, collectionChangedCounter); } + [Fact] + public void SkipCollectionChanged_ReplaceRange_Empty_Test() + { + int collectionChangedCounter = 0; + NonNullObservableCollection collection = new NonNullObservableCollection(); + collection.Add("1"); + collection.Add("2"); + collection.Add("3"); + collection.CollectionChanged += (s, e) => collectionChangedCounter++; + + Assert.Throws(() => collection.ReplaceRange(0, 0, new string[0])); + Assert.Equal(0, collectionChangedCounter); + + collection.Add("1"); + Assert.Equal(1, collectionChangedCounter); + } + public class NonNullObservableCollection : ObservableCollection { From bbf807cdbc4058e9ef07c88a5c972d0caebee30d Mon Sep 17 00:00:00 2001 From: Andrew Hoefling Date: Wed, 1 May 2019 22:31:26 -0400 Subject: [PATCH 19/19] Fixed issue with failing test --- ...bservableCollection_SkipCollectionChangedTests.netcoreapp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs index 4c0569b3a24c..9a9b1c6f2120 100644 --- a/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs +++ b/src/System.ObjectModel/tests/ObservableCollection/ObservableCollection_SkipCollectionChangedTests.netcoreapp.cs @@ -99,7 +99,7 @@ public void SkipCollectionChanged_ReplaceRange_Empty_Test() collection.Add("3"); collection.CollectionChanged += (s, e) => collectionChangedCounter++; - Assert.Throws(() => collection.ReplaceRange(0, 0, new string[0])); + collection.ReplaceRange(0, 0, new string[0]); Assert.Equal(0, collectionChangedCounter); collection.Add("1");