From 9f3d8486fea505158034085939b56ca063aea8ee Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Fri, 8 Dec 2023 15:43:38 -0600 Subject: [PATCH 01/15] Make mutable generic collection interfaces implement read-only collection interfaces --- .../Collections/ICollection.Generic.Tests.cs | 2 + .../Collections/IDictionary.Generic.Tests.cs | 84 +++++++++++++++++++ .../System/Collections/IList.Generic.Tests.cs | 8 ++ .../System/Collections/ISet.Generic.Tests.cs | 27 ++++++ .../System/Collections/Generic/ICollection.cs | 6 +- .../System/Collections/Generic/IDictionary.cs | 22 +++-- .../src/System/Collections/Generic/IList.cs | 6 +- .../src/System/Collections/Generic/ISet.cs | 30 +++++-- 8 files changed, 168 insertions(+), 17 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs index a94a9308b99ab4..282f42f88a190b 100644 --- a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs @@ -130,7 +130,9 @@ public void ICollection_Generic_IsReadOnly_Validity(int count) public void ICollection_Generic_Count_Validity(int count) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } #endregion diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index df92ab206f6686..6b37e5c0cc3a7d 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -263,15 +263,18 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)]); + Assert.Throws(() => readOnlyDictionary[default(TKey)]); } else { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; Assert.Equal(value, dictionary[default(TKey)]); + Assert.Equal(value, readOnlyDictionary[default(TKey)]); } } } @@ -281,8 +284,10 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) public void IDictionary_Generic_ItemGet_MissingNonDefaultKey_ThrowsKeyNotFoundException(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); Assert.Throws(() => dictionary[missingKey]); + Assert.Throws(() => readOnlyDictionary[missingKey]); } [Theory] @@ -292,10 +297,12 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.Throws(() => dictionary[missingKey]); + Assert.Throws(() => readOnlyDictionary[missingKey]); } } @@ -304,9 +311,11 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; foreach (KeyValuePair pair in dictionary) { Assert.Equal(pair.Value, dictionary[pair.Key]); + Assert.Equal(pair.Value, readOnlyDictionary[pair.Key]); } } @@ -384,8 +393,10 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable expected = dictionary.Select((pair) => pair.Key); Assert.True(expected.SequenceEqual(dictionary.Keys)); + Assert.True(expected.SequenceEqual(readOnlyDictionary.Keys)); } [Theory] @@ -395,7 +406,9 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; int previousCount = keys.Count; if (count > 0) Assert.NotEmpty(keys); @@ -403,10 +416,12 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(keys); + Assert.Empty(readOnlyKeys); } else { Assert.Equal(previousCount, keys.Count); + Assert.Equal(previousCount, readOnlyKeys.Count); } } } @@ -418,13 +433,18 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; + IEnumerator readOnlyKeys = readOnlyDictionary.Keys; IEnumerator keysEnum = keys.GetEnumerator(); + IEnumerator readOnlyKeysEnum = readOnlyKeys.GetEnumerator(); dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => keysEnum.MoveNext()); Assert.Throws(() => keysEnum.Reset()); + Assert.Throws(() => readOnlyKeysEnum.MoveNext()); + Assert.Throws(() => readOnlyKeysEnum.Reset()); } else { @@ -433,6 +453,11 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid _ = keysEnum.Current; } keysEnum.Reset(); + if (readOnlyKeysEnum.MoveNext()) + { + _ = readOnlyKeysEnum.Current; + } + readOnlyKeysEnum.Reset(); } } } @@ -454,12 +479,21 @@ public void IDictionary_Generic_Keys_IsReadOnly(int count) public void IDictionary_Generic_Keys_Enumeration_Reset(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator enumerator = keys.GetEnumerator(); + IEnumerator readOnlyEnumerator = readOnlyKeys.GetEnumerator(); if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) + { enumerator.Reset(); + readOnlyEnumerator.Reset(); + } else + { Assert.Throws(() => enumerator.Reset()); + Assert.Throws(() => readOnlyEnumerator.Reset()); + } } #endregion @@ -471,8 +505,10 @@ public void IDictionary_Generic_Keys_Enumeration_Reset(int count) public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable expected = dictionary.Select((pair) => pair.Value); Assert.True(expected.SequenceEqual(dictionary.Values)); + Assert.True(expected.SequenceEqual(readOnlyDictionary.Values)); } [Theory] @@ -482,6 +518,7 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; int seed = 431; foreach (KeyValuePair pair in dictionary.ToList()) { @@ -491,6 +528,7 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) dictionary.Add(missingKey, pair.Value); } Assert.Equal(count * 2, dictionary.Values.Count); + Assert.Equal(count * 2, readOnlyDictionary.Values.Count()); } } @@ -499,10 +537,15 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollection(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; + IEnumerable readOnlyValues = readOnlyDictionary.Values; int previousCount = values.Count; if (count > 0) + { Assert.NotEmpty(values); + Assert.NotEmpty(readOnlyValues); + } if (!IsReadOnly) { @@ -510,10 +553,12 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(values); + Assert.Empty(readOnlyValues); } else { Assert.Equal(previousCount, values.Count); + Assert.Equal(previousCount, readOnlyValues.Count()); } } } @@ -525,13 +570,18 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; + IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator valuesEnum = values.GetEnumerator(); + IEnumerator readOnlyValuesEnum = readOnlyValues.GetEnumerator(); dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => valuesEnum.MoveNext()); Assert.Throws(() => valuesEnum.Reset()); + Assert.Throws(() => readOnlyValuesEnum.MoveNext()); + Assert.Throws(() => readOnlyValuesEnum.Reset()); } else { @@ -540,6 +590,11 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval _ = valuesEnum.Current; } valuesEnum.Reset(); + if (readOnlyValuesEnum.MoveNext()) + { + _ = readOnlyValuesEnum.Current; + } + readOnlyValuesEnum.Reset(); } } } @@ -561,12 +616,21 @@ public void IDictionary_Generic_Values_IsReadOnly(int count) public void IDictionary_Generic_Values_Enumeration_Reset(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; + IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator enumerator = values.GetEnumerator(); + IEnumerator readOnlyEnumerator = readOnlyValues.GetEnumerator(); if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) + { enumerator.Reset(); + readOnlyEnumerator.Reset(); + } else + { Assert.Throws(() => enumerator.Reset()); + Assert.Throws(() => readOnlyEnumerator.Reset()); + } } #endregion @@ -708,8 +772,10 @@ public void IDictionary_Generic_ContainsKey_ValidKeyNotContainedInDictionary(int if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.ContainsKey(missingKey)); + Assert.False(readOnlyDictionary.ContainsKey(missingKey)); } } @@ -720,9 +786,11 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.ContainsKey(missingKey)); + Assert.True(readOnlyDictionary.ContainsKey(missingKey)); } } @@ -731,6 +799,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; if (DefaultValueAllowed) { if (!IsReadOnly) @@ -740,12 +809,14 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(i while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.False(dictionary.ContainsKey(missingKey)); + Assert.False(readOnlyDictionary.ContainsKey(missingKey)); } } else { // throws ArgumentNullException Assert.Throws(() => dictionary.ContainsKey(default(TKey))); + Assert.Throws(() => readOnlyDictionary.ContainsKey(default(TKey))); } } @@ -756,10 +827,12 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyContainedInDictionary(int if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); if (!dictionary.ContainsKey(missingKey)) dictionary.Add(missingKey, CreateTValue(5341)); Assert.True(dictionary.ContainsKey(missingKey)); + Assert.True(readOnlyDictionary.ContainsKey(missingKey)); } } @@ -907,10 +980,12 @@ KeyValuePair, WeakReference> PopulateAndRemove(IDi public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); TValue outValue; Assert.False(dictionary.TryGetValue(missingKey, out outValue)); + Assert.False(readOnlyDictionary.TryGetValue(missingKey, out outValue)); } [Theory] @@ -920,12 +995,15 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); TValue outValue; dictionary.TryAdd(missingKey, value); Assert.True(dictionary.TryGetValue(missingKey, out outValue)); Assert.Equal(value, outValue); + Assert.True(readOnlyDictionary.TryGetValue(missingKey, out outValue)); + Assert.Equal(value, outValue); } } @@ -934,6 +1012,7 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TValue outValue; if (DefaultValueAllowed) { @@ -943,11 +1022,13 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(i while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.False(dictionary.TryGetValue(missingKey, out outValue)); + Assert.False(readOnlyDictionary.TryGetValue(missingKey, out outValue)); } } else { Assert.Throws(() => dictionary.TryGetValue(default(TKey), out outValue)); + Assert.Throws(() => readOnlyDictionary.TryGetValue(default(TKey), out outValue)); } } @@ -958,12 +1039,15 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyContainedInDictionary(int if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); TValue value = CreateTValue(5123); TValue outValue; dictionary.TryAdd(missingKey, value); Assert.True(dictionary.TryGetValue(missingKey, out outValue)); Assert.Equal(value, outValue); + Assert.True(readOnlyDictionary.TryGetValue(missingKey, out outValue)); + Assert.Equal(value, outValue); } } diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 44f67e0ca24f83..8266a4219f8c3e 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -103,8 +103,11 @@ protected override IEnumerable GetModifyEnumerables(ModifyOper public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[-1]); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[int.MinValue]); } [Theory] @@ -112,8 +115,11 @@ public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[count]); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[count + 1]); } [Theory] @@ -121,8 +127,10 @@ public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T result; Assert.All(Enumerable.Range(0, count), index => result = list[index]); + Assert.All(Enumerable.Range(0, count), index => result = readOnlyList[index]); } #endregion diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 303001e8bd1443..3ac893ea1834fe 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -77,6 +77,7 @@ public void ICollection_Generic_Add_ReturnValue(int count) if (!IsReadOnly) { ISet set = GenericISetFactory(count); + IReadOnlySet readOnlySet = set; int seed = 92834; T newValue = CreateT(seed++); while (set.Contains(newValue)) @@ -85,7 +86,9 @@ public void ICollection_Generic_Add_ReturnValue(int count) if (!DuplicateValuesAllowed) Assert.False(set.Add(newValue)); Assert.Equal(count + 1, set.Count); + Assert.Equal(count + 1, readOnlySet.Count); Assert.True(set.Contains(newValue)); + Assert.True(readOnlySet.Contains(newValue)); } } @@ -159,6 +162,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; bool setContainsValueNotInEnumerable = false; bool enumerableContainsValueNotInSet = false; IEqualityComparer comparer = GetIEqualityComparer(); @@ -179,10 +183,12 @@ private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) } } Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, set.IsProperSubsetOf(enumerable)); + Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, readOnlySet.IsProperSubsetOf(enumerable)); } private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; bool isProperSuperset = true; bool setContainsElementsNotInEnumerable = false; IEqualityComparer comparer = GetIEqualityComparer(); @@ -204,54 +210,66 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) } isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; Assert.Equal(isProperSuperset, set.IsProperSupersetOf(enumerable)); + Assert.Equal(isProperSuperset, readOnlySet.IsProperSupersetOf(enumerable)); } private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in set) if (!enumerable.Contains(value, comparer)) { Assert.False(set.IsSubsetOf(enumerable)); + Assert.False(readOnlySet.IsSubsetOf(enumerable)); return; } Assert.True(set.IsSubsetOf(enumerable)); + Assert.True(readOnlySet.IsSubsetOf(enumerable)); } private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in enumerable) if (!set.Contains(value, comparer)) { Assert.False(set.IsSupersetOf(enumerable)); + Assert.False(readOnlySet.IsSupersetOf(enumerable)); return; } Assert.True(set.IsSupersetOf(enumerable)); + Assert.True(readOnlySet.IsSupersetOf(enumerable)); } private void Validate_Overlaps(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in enumerable) { if (set.Contains(value, comparer)) { Assert.True(set.Overlaps(enumerable)); + Assert.True(readOnlySet.Overlaps(enumerable)); return; } } Assert.False(set.Overlaps(enumerable)); + Assert.False(readOnlySet.Overlaps(enumerable)); } private void Validate_SetEquals(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in set) { if (!enumerable.Contains(value, comparer)) { Assert.False(set.SetEquals(enumerable)); + Assert.False(readOnlySet.SetEquals(enumerable)); return; } } @@ -260,10 +278,12 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) if (!set.Contains(value, comparer)) { Assert.False(set.SetEquals(enumerable)); + Assert.False(readOnlySet.SetEquals(enumerable)); return; } } Assert.True(set.SetEquals(enumerable)); + Assert.True(readOnlySet.SetEquals(enumerable)); } private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) @@ -302,12 +322,19 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) public void ISet_Generic_NullEnumerableArgument(int count) { ISet set = GenericISetFactory(count); + IReadOnlySet readOnlySet = set; Assert.Throws(() => set.IsProperSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsProperSubsetOf(null)); Assert.Throws(() => set.IsProperSupersetOf(null)); + Assert.Throws(() => readOnlySet.IsProperSupersetOf(null)); Assert.Throws(() => set.IsSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsSubsetOf(null)); Assert.Throws(() => set.IsSupersetOf(null)); + Assert.Throws(() => readOnlySet.IsSupersetOf(null)); Assert.Throws(() => set.Overlaps(null)); + Assert.Throws(() => readOnlySet.Overlaps(null)); Assert.Throws(() => set.SetEquals(null)); + Assert.Throws(() => readOnlySet.SetEquals(null)); if (!IsReadOnly) { Assert.Throws(() => set.ExceptWith(null)); diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs index 1c1095f8a5cf75..3eadb223acdb34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs @@ -9,9 +9,9 @@ namespace System.Collections.Generic { // Base interface for all collections, defining enumerators, size, and // synchronization methods. - public interface ICollection : IEnumerable + public interface ICollection : IReadOnlyCollection { - int Count + new int Count { #if MONO [DynamicDependency(nameof(Array.InternalArray__ICollection_get_Count), typeof(Array))] @@ -19,6 +19,8 @@ int Count get; } + int IReadOnlyCollection.Count => Count; + bool IsReadOnly { #if MONO diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs index 56a03106c205b6..1610ee0851d762 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs @@ -9,32 +9,40 @@ namespace System.Collections.Generic // Keys can be any non-null object. Values can be any object. // You can look up a value in an IDictionary via the default indexed // property, Items. - public interface IDictionary : ICollection> + public interface IDictionary : ICollection>, IReadOnlyDictionary { // Interfaces are not serializable // The Item property provides methods to read and edit entries // in the Dictionary. - TValue this[TKey key] + new TValue this[TKey key] { get; set; } + TValue IReadOnlyDictionary.this[TKey key] => this[key]; + // Returns a collections of the keys in this dictionary. - ICollection Keys + new ICollection Keys { get; } + IEnumerable IReadOnlyDictionary.Keys => Keys; + // Returns a collections of the values in this dictionary. - ICollection Values + new ICollection Values { get; } + IEnumerable IReadOnlyDictionary.Values => Values; + // Returns whether this dictionary contains a particular key. // - bool ContainsKey(TKey key); + new bool ContainsKey(TKey key); + + bool IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); // Adds a key-value pair to the dictionary. // @@ -44,6 +52,8 @@ ICollection Values // bool Remove(TKey key); - bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); + new bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); + + bool IReadOnlyDictionary.TryGetValue(TKey key, out TValue value) => TryGetValue(key, out value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs index f45ae823daf650..6785fed5bb24dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs @@ -10,10 +10,10 @@ namespace System.Collections.Generic // An IList is an ordered collection of objects. The exact ordering // is up to the implementation of the list, ranging from a sorted // order to insertion order. - public interface IList : ICollection + public interface IList : ICollection, IReadOnlyList { // The Item property provides methods to read and edit entries in the List. - T this[int index] + new T this[int index] { #if MONO [DynamicDependency(nameof(Array.InternalArray__get_Item) + "``1", typeof(Array))] @@ -25,6 +25,8 @@ T this[int index] set; } + T IReadOnlyList.this[int index] => this[index]; + // Returns the index of a particular item, if it is in the list. // Returns -1 if the item isn't in the list. #if MONO diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs index cee05d198cda07..23d395a025212e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs @@ -8,7 +8,7 @@ namespace System.Collections.Generic /// by some comparer. It also supports basic set operations such as Union, Intersection, /// Complement and Exclusive Complement. /// - public interface ISet : ICollection + public interface ISet : ICollection, IReadOnlySet { //Add ITEM to the set, return true if added, false if duplicate new bool Add(T item); @@ -26,21 +26,37 @@ public interface ISet : ICollection void SymmetricExceptWith(IEnumerable other); //Check if this set is a subset of other - bool IsSubsetOf(IEnumerable other); + new bool IsSubsetOf(IEnumerable other); + + bool IReadOnlySet.IsSubsetOf(IEnumerable other) => IsSubsetOf(other); //Check if this set is a superset of other - bool IsSupersetOf(IEnumerable other); + new bool IsSupersetOf(IEnumerable other); + + bool IReadOnlySet.IsSupersetOf(IEnumerable other) => IsSupersetOf(other); //Check if this set is a subset of other, but not the same as it - bool IsProperSupersetOf(IEnumerable other); + new bool IsProperSupersetOf(IEnumerable other); + + bool IReadOnlySet.IsProperSupersetOf(IEnumerable other) => IsProperSupersetOf(other); //Check if this set is a superset of other, but not the same as it - bool IsProperSubsetOf(IEnumerable other); + new bool IsProperSubsetOf(IEnumerable other); + + bool IReadOnlySet.IsProperSubsetOf(IEnumerable other) => IsProperSubsetOf(other); //Check if this set has any elements in common with other - bool Overlaps(IEnumerable other); + new bool Overlaps(IEnumerable other); + + bool IReadOnlySet.Overlaps(IEnumerable other) => Overlaps(other); //Check if this set contains the same and only the same elements as other - bool SetEquals(IEnumerable other); + new bool SetEquals(IEnumerable other); + + bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); + + new bool Contains(T item) => ((ICollection)this).Contains(item); + + bool IReadOnlySet.Contains(T value) => ((ICollection)this).Contains(value); } } From df31e3b9ba2ab9728cd209bf067ecf6a2131a793 Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Sat, 9 Dec 2023 14:31:52 -0600 Subject: [PATCH 02/15] More updates --- .../System/Collections/CollectionAsserts.cs | 4 +- .../Collections/ICollection.Generic.Tests.cs | 40 ++++++++++++++ .../Collections/IDictionary.Generic.Tests.cs | 29 ++++++++++ .../System/Collections/IList.Generic.Tests.cs | 53 +++++++++++++++++++ .../System/Collections/ISet.Generic.Tests.cs | 22 ++++++++ .../Generic/CollectionExtensionsTests.cs | 6 +++ .../src/System/Collections/Generic/ISet.cs | 5 ++ 7 files changed, 157 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index 2de26be1737fdc..91706ed78f9212 100644 --- a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs +++ b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs @@ -35,7 +35,7 @@ public static void Equal(ICollection expected, ICollection actual) Assert.False(a.MoveNext(), "actual has more elements"); } - public static void Equal(ICollection expected, ICollection actual) + public static void Equal(IReadOnlyCollection expected, IReadOnlyCollection actual) { Assert.Equal(expected == null, actual == null); if (expected == null) @@ -80,7 +80,7 @@ public static void EqualUnordered(ICollection expected, ICollection actual) Assert.Equal(e[null].Count(), a[null].Count()); } - public static void EqualUnordered(ICollection expected, ICollection actual) + public static void EqualUnordered(IReadOnlyCollection expected, IReadOnlyCollection actual) { Assert.Equal(expected == null, actual == null); if (expected == null) diff --git a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs index 282f42f88a190b..65449f7a38dd10 100644 --- a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs @@ -146,8 +146,10 @@ public virtual void ICollection_Generic_Add_DefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; collection.Add(default(T)); Assert.Equal(count + 1, collection.Count); + Assert.Equal(count + 1, readOnlyCollection.Count); } } @@ -160,10 +162,12 @@ public void ICollection_Generic_Add_InvalidValueToMiddleOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); Assert.Equal(count * 2, collection.Count); + Assert.Equal(count * 2, readOnlyCollection.Count); }); } } @@ -177,10 +181,12 @@ public void ICollection_Generic_Add_InvalidValueToBeginningOfCollection(int coun Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(0); + IReadOnlyCollection readOnlyCollection = collection; collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); }); } } @@ -194,8 +200,10 @@ public void ICollection_Generic_Add_InvalidValueToEndOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; collection.Add(invalidValue); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); }); } } @@ -207,10 +215,12 @@ public void ICollection_Generic_Add_DuplicateValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DuplicateValuesAllowed) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T duplicateValue = CreateT(700); collection.Add(duplicateValue); collection.Add(duplicateValue); Assert.Equal(count + 2, collection.Count); + Assert.Equal(count + 2, readOnlyCollection.Count); } } @@ -221,9 +231,11 @@ public void ICollection_Generic_Add_AfterCallingClear(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; collection.Clear(); AddToCollection(collection, 5); Assert.Equal(5, collection.Count); + Assert.Equal(5, readOnlyCollection.Count); } } @@ -235,6 +247,7 @@ public void ICollection_Generic_Add_AfterRemovingAnyValue(int count) { int seed = 840; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; List items = collection.ToList(); T toAdd = CreateT(seed++); while (collection.Contains(toAdd)) @@ -249,6 +262,7 @@ public void ICollection_Generic_Add_AfterRemovingAnyValue(int count) collection.Add(toAdd); items.Add(toAdd); CollectionAsserts.EqualUnordered(items, collection); + CollectionAsserts.EqualUnordered(items, readOnlyCollection); } } @@ -259,11 +273,13 @@ public void ICollection_Generic_Add_AfterRemovingAllItems(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; List itemsToRemove = collection.ToList(); for (int i = 0; i < count; i++) collection.Remove(collection.ElementAt(0)); collection.Add(CreateT(254)); Assert.Equal(1, collection.Count); + Assert.Equal(1, readOnlyCollection.Count); } } @@ -274,8 +290,10 @@ public void ICollection_Generic_Add_ToReadOnlyCollection(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; Assert.Throws(() => collection.Add(CreateT(0))); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } } @@ -305,15 +323,18 @@ public void ICollection_Generic_Add_AfterRemoving(int count) public void ICollection_Generic_Clear(int count) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } else { collection.Clear(); Assert.Equal(0, collection.Count); + Assert.Equal(0, readOnlyCollection.Count); } } @@ -322,12 +343,14 @@ public void ICollection_Generic_Clear(int count) public void ICollection_Generic_Clear_Repeatedly(int count) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } else { @@ -335,6 +358,7 @@ public void ICollection_Generic_Clear_Repeatedly(int count) collection.Clear(); collection.Clear(); Assert.Equal(0, collection.Count); + Assert.Equal(0, readOnlyCollection.Count); } } @@ -433,10 +457,12 @@ public void ICollection_Generic_Contains_ValidValueThatExistsTwiceInTheCollectio if (DuplicateValuesAllowed && !IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T item = CreateT(12); collection.Add(item); collection.Add(item); Assert.Equal(count + 2, collection.Count); + Assert.Equal(count + 2, readOnlyCollection.Count); } } @@ -562,6 +588,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int { int seed = count * 21; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T value = default(T); while (collection.Contains(value)) { @@ -570,6 +597,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int } Assert.False(collection.Remove(value)); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } } @@ -581,11 +609,13 @@ public void ICollection_Generic_Remove_NonDefaultValueNotContainedInCollection(i { int seed = count * 251; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); while (collection.Contains(value) || Enumerable.Contains(InvalidValues, value)) value = CreateT(seed++); Assert.False(collection.Remove(value)); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } } @@ -597,6 +627,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection { int seed = count * 21; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T value = default(T); if (!collection.Contains(value)) { @@ -605,6 +636,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection } Assert.True(collection.Remove(value)); Assert.Equal(count - 1, collection.Count); + Assert.Equal(count - 1, readOnlyCollection.Count); } } @@ -616,6 +648,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int { int seed = count * 251; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); if (!collection.Contains(value)) { @@ -624,6 +657,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int } Assert.True(collection.Remove(value)); Assert.Equal(count - 1, collection.Count); + Assert.Equal(count - 1, readOnlyCollection.Count); } } @@ -635,6 +669,7 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun { int seed = count * 90; ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); collection.Add(value); collection.Add(value); @@ -642,6 +677,7 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun Assert.True(collection.Remove(value)); Assert.True(collection.Contains(value)); Assert.Equal(count - 1, collection.Count); + Assert.Equal(count - 1, readOnlyCollection.Count); } } @@ -652,11 +688,13 @@ public void ICollection_Generic_Remove_EveryValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; Assert.All(collection.ToList(), value => { Assert.True(collection.Remove(value)); }); Assert.Empty(collection); + Assert.Empty(readOnlyCollection); } } @@ -665,11 +703,13 @@ public void ICollection_Generic_Remove_EveryValue(int count) public void ICollection_Generic_Remove_InvalidValue_ThrowsArgumentException(int count) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; Assert.All(InvalidValues, value => { Assert.Throws(() => collection.Remove(value)); }); Assert.Equal(count, collection.Count); + Assert.Equal(count, readOnlyCollection.Count); } [Theory] diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index 6b37e5c0cc3a7d..7818212af60ddf 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -330,6 +330,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)] = CreateTValue(3)); @@ -339,6 +340,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; Assert.Equal(value, dictionary[default(TKey)]); + Assert.Equal(value, readOnlyDictionary[default(TKey)]); } } } @@ -362,9 +364,11 @@ public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary[missingKey] = CreateTValue(543); Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); } } @@ -375,12 +379,15 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey existingKey = GetNewKey(dictionary); dictionary.Add(existingKey, CreateTValue(5342)); TValue newValue = CreateTValue(1234); dictionary[existingKey] = newValue; Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); Assert.Equal(newValue, dictionary[existingKey]); + Assert.Equal(newValue, readOnlyDictionary[existingKey]); } } @@ -657,9 +664,12 @@ public void IDictionary_Generic_Add_DefaultKey_DefaultValue(int count) TValue value = default(TValue); if (DefaultValueAllowed && !IsReadOnly) { + IReadOnlyDictionary readOnlyDictionary = dictionary; dictionary.Add(missingKey, value); Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); Assert.Equal(value, dictionary[missingKey]); + Assert.Equal(value, readOnlyDictionary[missingKey]); } else if (!IsReadOnly) { @@ -676,9 +686,12 @@ public void IDictionary_Generic_Add_DefaultKey_NonDefaultValue(int count) TValue value = CreateTValue(1456); if (DefaultValueAllowed && !IsReadOnly) { + IReadOnlyDictionary readOnlyDictionary = dictionary; dictionary.Add(missingKey, value); Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); Assert.Equal(value, dictionary[missingKey]); + Assert.Equal(value, readOnlyDictionary[missingKey]); } else if (!IsReadOnly) { @@ -693,11 +706,14 @@ public void IDictionary_Generic_Add_NonDefaultKey_DefaultValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = default(TValue); dictionary.Add(missingKey, value); Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); Assert.Equal(value, dictionary[missingKey]); + Assert.Equal(value, readOnlyDictionary[missingKey]); } } @@ -708,11 +724,14 @@ public void IDictionary_Generic_Add_NonDefaultKey_NonDefaultValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(1342); dictionary.Add(missingKey, value); Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(count + 1, readOnlyDictionary.Count); Assert.Equal(value, dictionary[missingKey]); + Assert.Equal(value, readOnlyDictionary[missingKey]); } } @@ -723,6 +742,7 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; int seed = 321; TValue duplicate = CreateTValue(seed++); while (dictionary.Values.Contains(duplicate)) @@ -730,6 +750,7 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) dictionary.Add(GetNewKey(dictionary), duplicate); dictionary.Add(GetNewKey(dictionary), duplicate); Assert.Equal(2, dictionary.Values.Count((value) => value.Equals(duplicate))); + Assert.Equal(2, readOnlyDictionary.Values.Count((value) => value.Equals(duplicate))); } } @@ -755,8 +776,10 @@ public void IDictionary_Generic_Add_DistinctValuesWithHashCollisions(int count) IDictionary dictionary = GenericIDictionaryFactory(new EqualityComparerConstantHashCode(EqualityComparer.Default)); if (dictionary != null) { + IReadOnlyDictionary readOnlyDictionary = dictionary; AddToCollection(dictionary, count); Assert.Equal(count, dictionary.Count); + Assert.Equal(count, readOnlyDictionary.Count); } } } @@ -858,11 +881,13 @@ public void IDictionary_Generic_RemoveKey_EveryKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.All(dictionary.Keys.ToList(), key => { Assert.True(dictionary.Remove(key)); }); Assert.Empty(dictionary); + Assert.Empty(readOnlyDictionary); } } @@ -873,9 +898,11 @@ public void IDictionary_Generic_RemoveKey_ValidKeyNotContainedInDictionary(int c if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.Remove(missingKey)); Assert.Equal(count, dictionary.Count); + Assert.Equal(count, readOnlyDictionary.Count); } } @@ -886,10 +913,12 @@ public void IDictionary_Generic_RemoveKey_ValidKeyContainedInDictionary(int coun if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); + IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.Remove(missingKey)); Assert.Equal(count, dictionary.Count); + Assert.Equal(count, readOnlyDictionary.Count); } } diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 8266a4219f8c3e..3d80b00cca9e87 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -144,10 +144,12 @@ public void IList_Generic_ItemSet_NegativeIndex_ThrowsException(int count) if (!IsReadOnly) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue] = validAdd); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -158,10 +160,12 @@ public void IList_Generic_ItemSet_IndexGreaterThanListCount_ThrowsException(int if (!IsReadOnly) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1] = validAdd); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -172,9 +176,11 @@ public void IList_Generic_ItemSet_OnReadOnlyList(int count) if (IsReadOnly && count > 0) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T before = list[count / 2]; Assert.Throws(() => list[count / 2] = CreateT(321432)); Assert.Equal(before, list[count / 2]); + Assert.Equal(before, readOnlyList[count / 2]); } } @@ -185,9 +191,11 @@ public void IList_Generic_ItemSet_FirstItemToNonDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = CreateT(123452); list[0] = value; Assert.Equal(value, list[0]); + Assert.Equal(value, readOnlyList[0]); } } @@ -198,15 +206,18 @@ public void IList_Generic_ItemSet_FirstItemToDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; if (DefaultValueAllowed) { list[0] = default(T); Assert.Equal(default(T), list[0]); + Assert.Equal(default(T), readOnlyList[0]); } else { Assert.Throws(() => list[0] = default(T)); Assert.NotEqual(default(T), list[0]); + Assert.NotEqual(default(T), readOnlyList[0]); } } } @@ -218,10 +229,12 @@ public void IList_Generic_ItemSet_LastItemToNonDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list[lastIndex] = value; Assert.Equal(value, list[lastIndex]); + Assert.Equal(value, readOnlyList[lastIndex]); } } @@ -232,16 +245,19 @@ public void IList_Generic_ItemSet_LastItemToDefaultValue(int count) if (count > 0 && !IsReadOnly && DefaultValueAllowed) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; int lastIndex = count > 0 ? count - 1 : 0; if (DefaultValueAllowed) { list[lastIndex] = default(T); Assert.Equal(default(T), list[lastIndex]); + Assert.Equal(default(T), readOnlyList[lastIndex]); } else { Assert.Throws(() => list[lastIndex] = default(T)); Assert.NotEqual(default(T), list[lastIndex]); + Assert.NotEqual(default(T), readOnlyList[lastIndex]); } } } @@ -253,11 +269,14 @@ public void IList_Generic_ItemSet_DuplicateValues(int count) if (count >= 2 && !IsReadOnly && DuplicateValuesAllowed) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = CreateT(123452); list[0] = value; list[1] = value; Assert.Equal(value, list[0]); + Assert.Equal(value, readOnlyList[0]); Assert.Equal(value, list[1]); + Assert.Equal(value, readOnlyList[1]); } } @@ -401,10 +420,12 @@ public void IList_Generic_Insert_NegativeIndex_ThrowsArgumentOutOfRangeException if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.Insert(-1, validAdd)); Assert.Throws(() => list.Insert(int.MinValue, validAdd)); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -415,10 +436,13 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(12350); list.Insert(count, validAdd); Assert.Equal(count + 1, list.Count); + Assert.Equal(count + 1, readOnlyList.Count); Assert.Equal(validAdd, list[count]); + Assert.Equal(validAdd, readOnlyList[count]); } } @@ -429,8 +453,10 @@ public void IList_Generic_Insert_ToReadOnlyList(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.Throws(() => list.Insert(count / 2, CreateT(321432))); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -441,10 +467,13 @@ public void IList_Generic_Insert_FirstItemToNonDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = CreateT(123452); list.Insert(0, value); Assert.Equal(value, list[0]); + Assert.Equal(value, readOnlyList[0]); Assert.Equal(count + 1, list.Count); + Assert.Equal(count + 1, readOnlyList.Count); } } @@ -455,10 +484,13 @@ public void IList_Generic_Insert_FirstItemToDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DefaultValueAllowed) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = default(T); list.Insert(0, value); Assert.Equal(value, list[0]); + Assert.Equal(value, readOnlyList[0]); Assert.Equal(count + 1, list.Count); + Assert.Equal(count + 1, readOnlyList.Count); } } @@ -469,11 +501,14 @@ public void IList_Generic_Insert_LastItemToNonDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); Assert.Equal(value, list[lastIndex]); + Assert.Equal(value, readOnlyList[lastIndex]); Assert.Equal(count + 1, list.Count); + Assert.Equal(count + 1, readOnlyList.Count); } } @@ -484,11 +519,14 @@ public void IList_Generic_Insert_LastItemToDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DefaultValueAllowed) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T value = default(T); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); Assert.Equal(value, list[lastIndex]); + Assert.Equal(value, readOnlyList[lastIndex]); Assert.Equal(count + 1, list.Count); + Assert.Equal(count + 1, readOnlyList.Count); } } @@ -506,11 +544,15 @@ public void IList_Generic_Insert_DuplicateValues(int count) } else { + IReadOnlyList readOnlyList = list; list.Insert(0, value); list.Insert(1, value); Assert.Equal(value, list[0]); + Assert.Equal(value, readOnlyList[0]); Assert.Equal(value, list[1]); + Assert.Equal(value, readOnlyList[1]); Assert.Equal(count + 2, list.Count); + Assert.Equal(count + 2, readOnlyList.Count); } } } @@ -540,10 +582,12 @@ public void IList_Generic_RemoveAt_NegativeIndex_ThrowsArgumentOutOfRangeExcepti if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(-1)); Assert.Throws(() => list.RemoveAt(int.MinValue)); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -554,10 +598,12 @@ public void IList_Generic_RemoveAt_IndexGreaterThanListCount_ThrowsArgumentOutOf if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(count)); Assert.Throws(() => list.RemoveAt(count + 1)); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -568,8 +614,10 @@ public void IList_Generic_RemoveAt_OnReadOnlyList(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.Throws(() => list.RemoveAt(count / 2)); Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); } } @@ -580,11 +628,14 @@ public void IList_Generic_RemoveAt_AllValidIndices(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.Equal(count, list.Count); + Assert.Equal(count, readOnlyList.Count); Assert.All(Enumerable.Range(0, count).Reverse(), index => { list.RemoveAt(index); Assert.Equal(index, list.Count); + Assert.Equal(index, readOnlyList.Count); }); } } @@ -596,10 +647,12 @@ public void IList_Generic_RemoveAt_ZeroMultipleTimes(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); + IReadOnlyList readOnlyList = list; Assert.All(Enumerable.Range(0, count), index => { list.RemoveAt(0); Assert.Equal(count - index - 1, list.Count); + Assert.Equal(count - index - 1, readOnlyList.Count); }); } } diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 3ac893ea1834fe..32386672503342 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -101,6 +101,7 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) if (!DuplicateValuesAllowed) { ICollection collection = GenericICollectionFactory(count); + IReadOnlyCollection readOnlyCollection = collection; int seed = 800; T duplicateValue = CreateT(seed++); while (collection.Contains(duplicateValue)) @@ -108,6 +109,7 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) collection.Add(duplicateValue); collection.Add(duplicateValue); Assert.Equal(count + 1, collection.Count); + Assert.Equal(count + 1, readOnlyCollection.Count); } } } @@ -118,10 +120,12 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) private void Validate_ExceptWith(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; if (set.Count == 0 || enumerable == set) { set.ExceptWith(enumerable); Assert.Equal(0, set.Count); + Assert.Equal(0, readOnlySet.Count); } else { @@ -130,22 +134,27 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) expected.Remove(element); set.ExceptWith(enumerable); Assert.Equal(expected.Count, set.Count); + Assert.Equal(expected.Count, readOnlySet.Count); Assert.True(expected.SetEquals(set)); + Assert.True(expected.SetEquals(readOnlySet)); } } private void Validate_IntersectWith(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; if (set.Count == 0 || Enumerable.Count(enumerable) == 0) { set.IntersectWith(enumerable); Assert.Equal(0, set.Count); + Assert.Equal(0, readOnlySet.Count); } else if (set == enumerable) { HashSet beforeOperation = new HashSet(set, GetIEqualityComparer()); set.IntersectWith(enumerable); Assert.True(beforeOperation.SetEquals(set)); + Assert.True(beforeOperation.SetEquals(readOnlySet)); } else { @@ -156,7 +165,9 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) expected.Add(value); set.IntersectWith(enumerable); Assert.Equal(expected.Count, set.Count); + Assert.Equal(expected.Count, readOnlySet.Count); Assert.True(expected.SetEquals(set)); + Assert.True(expected.SetEquals(readOnlySet)); } } @@ -288,6 +299,7 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); HashSet expected = new HashSet(comparer); foreach (T element in enumerable) @@ -298,11 +310,14 @@ private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable expected.Add(element); set.SymmetricExceptWith(enumerable); Assert.Equal(expected.Count, set.Count); + Assert.Equal(expected.Count, readOnlySet.Count); Assert.True(expected.SetEquals(set)); + Assert.True(expected.SetEquals(readOnlySet)); } private void Validate_UnionWith(ISet set, IEnumerable enumerable) { + IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); HashSet expected = new HashSet(set, comparer); foreach (T element in enumerable) @@ -310,7 +325,9 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) expected.Add(element); set.UnionWith(enumerable); Assert.Equal(expected.Count, set.Count); + Assert.Equal(expected.Count, readOnlySet.Count); Assert.True(expected.SetEquals(set)); + Assert.True(expected.SetEquals(readOnlySet)); } #endregion @@ -529,7 +546,9 @@ public void ISet_Generic_Overlaps_Itself(int setLength) public void ISet_Generic_SetEquals_Itself(int setLength) { ISet set = GenericISetFactory(setLength); + IReadOnlySet readOnlySet = set; Assert.True(set.SetEquals(set)); + Assert.True(readOnlySet.SetEquals(readOnlySet)); } [Theory] @@ -671,6 +690,7 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!IsReadOnly) { ISet set = GenericISetFactory(setLength); + IReadOnlySet readOnlySet = set; T value = CreateT(532); if (!set.Contains(value)) set.Add(value); @@ -688,7 +708,9 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp expected.Add(element); set.SymmetricExceptWith(enumerable); Assert.Equal(expected.Count, set.Count); + Assert.Equal(expected.Count, readOnlySet.Count); Assert.True(expected.SetEquals(set)); + Assert.True(expected.SetEquals(readOnlySet)); } } diff --git a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs index 213d9d6faca996..f46358e572ca0f 100644 --- a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs +++ b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs @@ -59,16 +59,20 @@ public void TryAdd_NullKeyIDictionary_ThrowsArgumentNullException() public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue() { IDictionary dictionary = new SortedDictionary(); + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(dictionary.TryAdd("key", "value")); Assert.Equal("value", dictionary["key"]); + Assert.Equal("value", readOnlyDictionary["key"]); } [Fact] public void TryAdd_KeyExistsInIDictionary_ReturnsFalse() { IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.False(dictionary.TryAdd("key", "value2")); Assert.Equal("value", dictionary["key"]); + Assert.Equal("value", readOnlyDictionary["key"]); } [Fact] @@ -93,9 +97,11 @@ public void Remove_NullKeyIDictionary_ThrowsArgumentNullException() public void Remove_KeyExistsInIDictionary_ReturnsTrue() { IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(dictionary.Remove("key", out var value)); Assert.Equal("value", value); Assert.Throws(() => dictionary["key"]); + Assert.Throws(() => readOnlyDictionary["key"]); } [Fact] diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs index 23d395a025212e..0951aab79f653a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs @@ -55,6 +55,11 @@ public interface ISet : ICollection, IReadOnlySet bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); + /// + /// Determines if the set contains a specific item + /// + /// The item to check if the set contains. + /// if found; otherwise . new bool Contains(T item) => ((ICollection)this).Contains(item); bool IReadOnlySet.Contains(T value) => ((ICollection)this).Contains(value); From e2c9b7c67f37370c5cff178496bdd6e2486c96ea Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Sat, 9 Dec 2023 15:40:56 -0600 Subject: [PATCH 03/15] Fix build --- .../src/System/Collections/Generic/IDictionary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs index 1610ee0851d762..8d8702d5b8cf92 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs @@ -54,6 +54,6 @@ public interface IDictionary : ICollection.TryGetValue(TKey key, out TValue value) => TryGetValue(key, out value); + bool IReadOnlyDictionary.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => TryGetValue(key, out value); } } From 4e81afc6ab43967480f8869351cd7e29cc91059d Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Sun, 10 Dec 2023 13:34:23 -0600 Subject: [PATCH 04/15] Update refs --- .../System.Runtime/ref/System.Runtime.cs | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 78482d61ea3f84..b7d68934b13136 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7761,9 +7761,9 @@ public partial interface IAsyncEnumerator : System.IAsyncDisposable T Current { get; } System.Threading.Tasks.ValueTask MoveNextAsync(); } - public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection { - int Count { get; } + new int Count { get; } bool IsReadOnly { get; } void Add(T item); void Clear(); @@ -7775,15 +7775,15 @@ public partial interface IComparer { int Compare(T? x, T? y); } - public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable + public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection> { - TValue this[TKey key] { get; set; } - System.Collections.Generic.ICollection Keys { get; } - System.Collections.Generic.ICollection Values { get; } + new TValue this[TKey key] { get; set; } + new System.Collections.Generic.ICollection Keys { get; } + new System.Collections.Generic.ICollection Values { get; } void Add(TKey key, TValue value); - bool ContainsKey(TKey key); + new bool ContainsKey(TKey key); bool Remove(TKey key); - bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); + new bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); } public partial interface IEnumerable : System.Collections.IEnumerable { @@ -7798,9 +7798,9 @@ public partial interface IEqualityComparer bool Equals(T? x, T? y); int GetHashCode([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T obj); } - public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection { - T this[int index] { get; set; } + new T this[int index] { get; set; } int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); @@ -7831,17 +7831,18 @@ public partial interface IReadOnlySet : System.Collections.Generic.IEnumerabl bool Overlaps(System.Collections.Generic.IEnumerable other); bool SetEquals(System.Collections.Generic.IEnumerable other); } - public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection { new bool Add(T item); + new bool Contains(T item); void ExceptWith(System.Collections.Generic.IEnumerable other); void IntersectWith(System.Collections.Generic.IEnumerable other); - bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); - bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); - bool IsSubsetOf(System.Collections.Generic.IEnumerable other); - bool IsSupersetOf(System.Collections.Generic.IEnumerable other); - bool Overlaps(System.Collections.Generic.IEnumerable other); - bool SetEquals(System.Collections.Generic.IEnumerable other); + new bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); + new bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); + new bool IsSubsetOf(System.Collections.Generic.IEnumerable other); + new bool IsSupersetOf(System.Collections.Generic.IEnumerable other); + new bool Overlaps(System.Collections.Generic.IEnumerable other); + new bool SetEquals(System.Collections.Generic.IEnumerable other); void SymmetricExceptWith(System.Collections.Generic.IEnumerable other); void UnionWith(System.Collections.Generic.IEnumerable other); } From 2a873e50f3715498182650c57abd8dafff7717f9 Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Sun, 10 Dec 2023 13:58:50 -0600 Subject: [PATCH 05/15] Add DIM's to ref also --- .../System.Runtime/ref/System.Runtime.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index b7d68934b13136..9675671f4faac1 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7764,6 +7764,7 @@ public partial interface IAsyncEnumerator : System.IAsyncDisposable public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection { new int Count { get; } + int System.Collections.Generic.IReadOnlyCollection.Count => Count; bool IsReadOnly { get; } void Add(T item); void Clear(); @@ -7778,12 +7779,17 @@ public partial interface IComparer public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection> { new TValue this[TKey key] { get; set; } + TValue System.Collections.Generic.IReadOnlyDictionary.this[TKey key] => this[key]; new System.Collections.Generic.ICollection Keys { get; } + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys => Keys; new System.Collections.Generic.ICollection Values { get; } + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values => Values; void Add(TKey key, TValue value); new bool ContainsKey(TKey key); + bool System.Collections.Generic.IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); bool Remove(TKey key); new bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); + bool System.Collections.Generic.IReadOnlyDictionary.TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value) => TryGetValue(key, out value); } public partial interface IEnumerable : System.Collections.IEnumerable { @@ -7801,6 +7807,7 @@ public partial interface IEqualityComparer public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection { new T this[int index] { get; set; } + T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); @@ -7834,15 +7841,22 @@ public partial interface IReadOnlySet : System.Collections.Generic.IEnumerabl public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection { new bool Add(T item); - new bool Contains(T item); + new bool Contains(T item) => ((ICollection)this).Contains(item); + bool System.Collections.Generic.IReadOnlySet.Contains(T item) => ((ICollection)this).Contains(item); void ExceptWith(System.Collections.Generic.IEnumerable other); void IntersectWith(System.Collections.Generic.IEnumerable other); new bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => IsProperSubsetOf(other); new bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => IsProperSupersetOf(other); new bool IsSubsetOf(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.IsSubsetOf(System.Collections.Generic.IEnumerable other) => IsSubsetOf(other); new bool IsSupersetOf(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.IsSupersetOf(System.Collections.Generic.IEnumerable other) => IsSupersetOf(other); new bool Overlaps(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.Overlaps(System.Collections.Generic.IEnumerable other) => Overlaps(other); new bool SetEquals(System.Collections.Generic.IEnumerable other); + bool System.Collections.Generic.IReadOnlySet.SetEquals(System.Collections.Generic.IEnumerable other) => SetEquals(other); void SymmetricExceptWith(System.Collections.Generic.IEnumerable other); void UnionWith(System.Collections.Generic.IEnumerable other); } From a7d4cbfd8ce0b325ba90b553f06247ae8970578b Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Sun, 10 Dec 2023 14:30:19 -0600 Subject: [PATCH 06/15] fixes --- .../tests/System/Collections/IDictionary.Generic.Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index 7818212af60ddf..d9206edea98af6 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -428,7 +428,7 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( else { Assert.Equal(previousCount, keys.Count); - Assert.Equal(previousCount, readOnlyKeys.Count); + Assert.Equal(previousCount, readOnlyKeys.Count()); } } } @@ -442,7 +442,7 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid IDictionary dictionary = GenericIDictionaryFactory(count); IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; - IEnumerator readOnlyKeys = readOnlyDictionary.Keys; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator keysEnum = keys.GetEnumerator(); IEnumerator readOnlyKeysEnum = readOnlyKeys.GetEnumerator(); dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); From 5089b365ce6fe3da62bc6ef79999797e9e15cc30 Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Mon, 11 Dec 2023 13:13:48 -0600 Subject: [PATCH 07/15] Try to fix arrays --- .../src/System/Array.CoreCLR.cs | 2 +- src/coreclr/vm/array.cpp | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index d18caf9a39410a..c8a4ac6bc53904 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -399,7 +399,7 @@ public ArrayInitializeCache(RuntimeType arrayType) // it for type and executes it. // // The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be - // array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly + // array that is castable to "T[]" (i.e. for primitives and valuetypes, it will be exactly // "T[]" - for orefs, it may be a "U[]" where U derives from T.) //---------------------------------------------------------------------------------------- internal sealed class SZArrayHelper diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index 46ea5958f61513..5558fd26f2bd00 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -1235,29 +1235,14 @@ MethodDesc* GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod(Met } CONTRACTL_END - int slot = pItfcMeth->GetSlot(); - - // We need to pick the right starting method depending on the depth of the inheritance chain - static const BinderMethodID startingMethod[] = { - METHOD__SZARRAYHELPER__GETENUMERATOR, // First method of IEnumerable`1 - METHOD__SZARRAYHELPER__GET_COUNT, // First method of ICollection`1/IReadOnlyCollection`1 - METHOD__SZARRAYHELPER__GET_ITEM // First method of IList`1/IReadOnlyList`1 - }; - // Subtract one for the non-generic IEnumerable that the generic enumerable inherits from unsigned int inheritanceDepth = pItfcMeth->GetMethodTable()->GetNumInterfaces() - 1; - PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < ARRAY_SIZE(startingMethod)); - - MethodDesc *pGenericImplementor = CoreLibBinder::GetMethod((BinderMethodID)(startingMethod[inheritanceDepth] + slot)); - // The most common reason for this assert is that the order of the SZArrayHelper methods in - // corelib.h does not match the order they are implemented on the generic interfaces. - _ASSERTE(pGenericImplementor == MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName())); + MethodDesc *pGenericImplementor = MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName()); // OPTIMIZATION: For any method other than GetEnumerator(), we can safely substitute // "Object" for reference-type theT's. This causes fewer methods to be instantiated. - if (startingMethod[inheritanceDepth] != METHOD__SZARRAYHELPER__GETENUMERATOR && - !theT.IsValueType()) + if (inheritanceDepth != 1 && !theT.IsValueType()) { theT = TypeHandle(g_pObjectClass); } From 27c9fe6bd9839410860672990f29851e37665b51 Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 09:49:12 -0600 Subject: [PATCH 08/15] Moved dim's to the end of the interfaces. Made the tests support .NET Framework 4.8. --- .../System/Collections/CollectionAsserts.cs | 156 +++++++++++++- .../Collections/ICollection.Generic.Tests.cs | 85 ++------ .../Collections/IDictionary.Generic.Tests.cs | 194 +++++++++--------- .../System/Collections/IList.Generic.Tests.cs | 136 ++++-------- .../System/Collections/ISet.Generic.Tests.cs | 97 +++------ .../Generic/CollectionExtensionsTests.cs | 12 +- .../System/Collections/Generic/ICollection.cs | 4 +- .../System/Collections/Generic/IDictionary.cs | 16 +- .../src/System/Collections/Generic/IList.cs | 4 +- .../src/System/Collections/Generic/ISet.cs | 24 +-- .../System.Runtime/ref/System.Runtime.cs | 28 +-- 11 files changed, 390 insertions(+), 366 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index 91706ed78f9212..c207236a3df8c7 100644 --- a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs +++ b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using Xunit; @@ -9,6 +10,151 @@ namespace System.Collections.Tests { internal static class CollectionAsserts { + public static void HasCount(ICollection collection, int count) + { + Assert.Equal(count, collection.Count); +#if !NETFRAMEWORK + IReadOnlyCollection readOnlyCollection = collection; + Assert.Equal(count, readOnlyCollection.Count); +#endif + } + + public static void EqualAt(IList list, int index, T expected) + { + Assert.Equal(expected, list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Equal(expected, readOnlyList[index]); +#endif + } + + public static void NotEqualAt(IList list, int index, T expected) + { + Assert.NotEqual(expected, list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.NotEqual(expected, readOnlyList[index]); +#endif + } + + public static void ThrowsElementAt(IList list, int index, Type exceptionType) + { + Assert.Throws(exceptionType, () => list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Throws(exceptionType, () => readOnlyList[index]); +#endif + } + + public static void ElementAtSucceeds(IList list, int index) + { + T result = list[index]; +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Equal(result, readOnlyList[index]); +#endif + } + + public static void EqualAt(IDictionary dictionary, TKey key, TValue expected) + { + Assert.Equal(expected, dictionary[key]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary[key]); +#endif + } + + public static void ContainsKey(IDictionary dictionary, TKey key, bool expected) + { + Assert.Equal(expected, dictionary.ContainsKey(key)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary.ContainsKey(key)); +#endif + } + + public static void TryGetValue(IDictionary dictionary, TKey key, bool expected, TValue expectedValue = default) + { + Assert.Equal(expected, dictionary.TryGetValue(key, out TValue value)); + if (expected) + { + Assert.Equal(expectedValue, value); + } +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary.TryGetValue(key, out value)); + if (expected) + { + Assert.Equal(expectedValue, value); + } +#endif + } + + public static void Contains(ISet set, T expected) + { + Assert.True(set.Contains(expected)); +#if !NETFRAMEWORK + ICollection collection = set; + Assert.True(collection.Contains(expected)); + IReadOnlySet readOnlySet = set; + Assert.True(readOnlySet.Contains(expected)); +#endif + } + + public static void IsProperSubsetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsProperSubsetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsProperSubsetOf(enumerable)); +#endif + } + + public static void IsProperSupersetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsProperSupersetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsProperSupersetOf(enumerable)); +#endif + } + + public static void IsSubsetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsSubsetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsSubsetOf(enumerable)); +#endif + } + + public static void IsSupersetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsSupersetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsSupersetOf(enumerable)); +#endif + } + + public static void Overlaps(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.Overlaps(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.Overlaps(enumerable)); +#endif + } + + public static void SetEquals(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.SetEquals(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.SetEquals(enumerable)); +#endif + } + public static void Equal(ICollection expected, ICollection actual) { Assert.Equal(expected == null, actual == null); @@ -35,7 +181,7 @@ public static void Equal(ICollection expected, ICollection actual) Assert.False(a.MoveNext(), "actual has more elements"); } - public static void Equal(IReadOnlyCollection expected, IReadOnlyCollection actual) + public static void Equal(ICollection expected, ICollection actual) { Assert.Equal(expected == null, actual == null); if (expected == null) @@ -43,6 +189,12 @@ public static void Equal(IReadOnlyCollection expected, IReadOnlyCollection return; } Assert.Equal(expected.Count, actual.Count); +#if !NETFRAMEWORK + IReadOnlyCollection readOnlyExpected = expected; + Assert.Equal(expected.Count, readOnlyExpected.Count); + IReadOnlyCollection readOnlyActual = actual; + Assert.Equal(actual.Count, readOnlyActual.Count); +#endif IEnumerator e = expected.GetEnumerator(); IEnumerator a = actual.GetEnumerator(); while (e.MoveNext()) @@ -80,7 +232,7 @@ public static void EqualUnordered(ICollection expected, ICollection actual) Assert.Equal(e[null].Count(), a[null].Count()); } - public static void EqualUnordered(IReadOnlyCollection expected, IReadOnlyCollection actual) + public static void EqualUnordered(ICollection expected, ICollection actual) { Assert.Equal(expected == null, actual == null); if (expected == null) diff --git a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs index 65449f7a38dd10..8ae72dea074ab0 100644 --- a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs @@ -130,9 +130,7 @@ public void ICollection_Generic_IsReadOnly_Validity(int count) public void ICollection_Generic_Count_Validity(int count) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } #endregion @@ -146,10 +144,8 @@ public virtual void ICollection_Generic_Add_DefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; collection.Add(default(T)); - Assert.Equal(count + 1, collection.Count); - Assert.Equal(count + 1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } @@ -162,12 +158,10 @@ public void ICollection_Generic_Add_InvalidValueToMiddleOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count * 2, collection.Count); - Assert.Equal(count * 2, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count * 2); }); } } @@ -181,12 +175,10 @@ public void ICollection_Generic_Add_InvalidValueToBeginningOfCollection(int coun Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(0); - IReadOnlyCollection readOnlyCollection = collection; collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -200,10 +192,9 @@ public void ICollection_Generic_Add_InvalidValueToEndOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; + collection.Add(invalidValue); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -215,12 +206,10 @@ public void ICollection_Generic_Add_DuplicateValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DuplicateValuesAllowed) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T duplicateValue = CreateT(700); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 2, collection.Count); - Assert.Equal(count + 2, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -231,11 +220,9 @@ public void ICollection_Generic_Add_AfterCallingClear(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; collection.Clear(); AddToCollection(collection, 5); - Assert.Equal(5, collection.Count); - Assert.Equal(5, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, 5); } } @@ -247,7 +234,6 @@ public void ICollection_Generic_Add_AfterRemovingAnyValue(int count) { int seed = 840; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; List items = collection.ToList(); T toAdd = CreateT(seed++); while (collection.Contains(toAdd)) @@ -262,7 +248,6 @@ public void ICollection_Generic_Add_AfterRemovingAnyValue(int count) collection.Add(toAdd); items.Add(toAdd); CollectionAsserts.EqualUnordered(items, collection); - CollectionAsserts.EqualUnordered(items, readOnlyCollection); } } @@ -273,13 +258,11 @@ public void ICollection_Generic_Add_AfterRemovingAllItems(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; List itemsToRemove = collection.ToList(); for (int i = 0; i < count; i++) collection.Remove(collection.ElementAt(0)); collection.Add(CreateT(254)); - Assert.Equal(1, collection.Count); - Assert.Equal(1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, 1); } } @@ -290,10 +273,8 @@ public void ICollection_Generic_Add_ToReadOnlyCollection(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; Assert.Throws(() => collection.Add(CreateT(0))); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -323,18 +304,15 @@ public void ICollection_Generic_Add_AfterRemoving(int count) public void ICollection_Generic_Clear(int count) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); - Assert.Equal(0, collection.Count); - Assert.Equal(0, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -343,22 +321,19 @@ public void ICollection_Generic_Clear(int count) public void ICollection_Generic_Clear_Repeatedly(int count) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); collection.Clear(); collection.Clear(); - Assert.Equal(0, collection.Count); - Assert.Equal(0, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -457,12 +432,10 @@ public void ICollection_Generic_Contains_ValidValueThatExistsTwiceInTheCollectio if (DuplicateValuesAllowed && !IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T item = CreateT(12); collection.Add(item); collection.Add(item); - Assert.Equal(count + 2, collection.Count); - Assert.Equal(count + 2, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -588,7 +561,6 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int { int seed = count * 21; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T value = default(T); while (collection.Contains(value)) { @@ -596,8 +568,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int count--; } Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -609,13 +580,11 @@ public void ICollection_Generic_Remove_NonDefaultValueNotContainedInCollection(i { int seed = count * 251; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); while (collection.Contains(value) || Enumerable.Contains(InvalidValues, value)) value = CreateT(seed++); Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -627,7 +596,6 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection { int seed = count * 21; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T value = default(T); if (!collection.Contains(value)) { @@ -635,8 +603,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); - Assert.Equal(count - 1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -648,7 +615,6 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int { int seed = count * 251; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); if (!collection.Contains(value)) { @@ -656,8 +622,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); - Assert.Equal(count - 1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -669,15 +634,13 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun { int seed = count * 90; ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; T value = CreateT(seed++); collection.Add(value); collection.Add(value); count += 2; Assert.True(collection.Remove(value)); Assert.True(collection.Contains(value)); - Assert.Equal(count - 1, collection.Count); - Assert.Equal(count - 1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -688,13 +651,11 @@ public void ICollection_Generic_Remove_EveryValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; Assert.All(collection.ToList(), value => { Assert.True(collection.Remove(value)); }); - Assert.Empty(collection); - Assert.Empty(readOnlyCollection); + CollectionAsserts.HasCount(collection, 0); } } @@ -703,13 +664,11 @@ public void ICollection_Generic_Remove_EveryValue(int count) public void ICollection_Generic_Remove_InvalidValue_ThrowsArgumentException(int count) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; Assert.All(InvalidValues, value => { Assert.Throws(() => collection.Remove(value)); }); - Assert.Equal(count, collection.Count); - Assert.Equal(count, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count); } [Theory] diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index d9206edea98af6..a44de75b265a0e 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -263,18 +263,19 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary[default(TKey)]); +#endif } else { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - Assert.Equal(value, dictionary[default(TKey)]); - Assert.Equal(value, readOnlyDictionary[default(TKey)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -284,10 +285,12 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) public void IDictionary_Generic_ItemGet_MissingNonDefaultKey_ThrowsKeyNotFoundException(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } [Theory] @@ -297,12 +300,14 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } } @@ -311,11 +316,9 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; foreach (KeyValuePair pair in dictionary) { - Assert.Equal(pair.Value, dictionary[pair.Key]); - Assert.Equal(pair.Value, readOnlyDictionary[pair.Key]); + CollectionAsserts.EqualAt(dictionary, pair.Key, pair.Value); } } @@ -330,7 +333,6 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)] = CreateTValue(3)); @@ -339,8 +341,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - Assert.Equal(value, dictionary[default(TKey)]); - Assert.Equal(value, readOnlyDictionary[default(TKey)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -364,11 +365,9 @@ public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary[missingKey] = CreateTValue(543); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); + CollectionAsserts.HasCount(dictionary, count + 1); } } @@ -379,15 +378,12 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey existingKey = GetNewKey(dictionary); dictionary.Add(existingKey, CreateTValue(5342)); TValue newValue = CreateTValue(1234); dictionary[existingKey] = newValue; - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); - Assert.Equal(newValue, dictionary[existingKey]); - Assert.Equal(newValue, readOnlyDictionary[existingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, existingKey, newValue); } } @@ -400,10 +396,12 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable expected = dictionary.Select((pair) => pair.Key); Assert.True(expected.SequenceEqual(dictionary.Keys)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(expected.SequenceEqual(readOnlyDictionary.Keys)); +#endif } [Theory] @@ -413,9 +411,11 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable readOnlyKeys = readOnlyDictionary.Keys; +#endif int previousCount = keys.Count; if (count > 0) Assert.NotEmpty(keys); @@ -423,12 +423,16 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(keys); +#if !NETFRAMEWORK Assert.Empty(readOnlyKeys); +#endif } else { Assert.Equal(previousCount, keys.Count); +#if !NETFRAMEWORK Assert.Equal(previousCount, readOnlyKeys.Count()); +#endif } } } @@ -440,18 +444,22 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; - IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator keysEnum = keys.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator readOnlyKeysEnum = readOnlyKeys.GetEnumerator(); +#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => keysEnum.MoveNext()); Assert.Throws(() => keysEnum.Reset()); +#if !NETFRAMEWORK Assert.Throws(() => readOnlyKeysEnum.MoveNext()); Assert.Throws(() => readOnlyKeysEnum.Reset()); +#endif } else { @@ -460,11 +468,13 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid _ = keysEnum.Current; } keysEnum.Reset(); +#if !NETFRAMEWORK if (readOnlyKeysEnum.MoveNext()) { _ = readOnlyKeysEnum.Current; } readOnlyKeysEnum.Reset(); +#endif } } } @@ -486,20 +496,26 @@ public void IDictionary_Generic_Keys_IsReadOnly(int count) public void IDictionary_Generic_Keys_Enumeration_Reset(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection keys = dictionary.Keys; - IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator enumerator = keys.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; IEnumerator readOnlyEnumerator = readOnlyKeys.GetEnumerator(); +#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) { enumerator.Reset(); +#if !NETFRAMEWORK readOnlyEnumerator.Reset(); +#endif } else { Assert.Throws(() => enumerator.Reset()); +#if !NETFRAMEWORK Assert.Throws(() => readOnlyEnumerator.Reset()); +#endif } } @@ -512,10 +528,12 @@ public void IDictionary_Generic_Keys_Enumeration_Reset(int count) public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable expected = dictionary.Select((pair) => pair.Value); Assert.True(expected.SequenceEqual(dictionary.Values)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(expected.SequenceEqual(readOnlyDictionary.Values)); +#endif } [Theory] @@ -525,7 +543,6 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; int seed = 431; foreach (KeyValuePair pair in dictionary.ToList()) { @@ -535,7 +552,10 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) dictionary.Add(missingKey, pair.Value); } Assert.Equal(count * 2, dictionary.Values.Count); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Equal(count * 2, readOnlyDictionary.Values.Count()); +#endif } } @@ -544,14 +564,18 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollection(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; IEnumerable readOnlyValues = readOnlyDictionary.Values; +#endif int previousCount = values.Count; if (count > 0) { Assert.NotEmpty(values); +#if !NETFRAMEWORK Assert.NotEmpty(readOnlyValues); +#endif } if (!IsReadOnly) @@ -560,12 +584,16 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(values); +#if !NETFRAMEWORK Assert.Empty(readOnlyValues); +#endif } else { Assert.Equal(previousCount, values.Count); +#if !NETFRAMEWORK Assert.Equal(previousCount, readOnlyValues.Count()); +#endif } } } @@ -577,18 +605,22 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; - IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator valuesEnum = values.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator readOnlyValuesEnum = readOnlyValues.GetEnumerator(); +#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => valuesEnum.MoveNext()); Assert.Throws(() => valuesEnum.Reset()); +#if !NETFRAMEWORK Assert.Throws(() => readOnlyValuesEnum.MoveNext()); Assert.Throws(() => readOnlyValuesEnum.Reset()); +#endif } else { @@ -597,11 +629,13 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval _ = valuesEnum.Current; } valuesEnum.Reset(); +#if !NETFRAMEWORK if (readOnlyValuesEnum.MoveNext()) { _ = readOnlyValuesEnum.Current; } readOnlyValuesEnum.Reset(); +#endif } } } @@ -623,20 +657,26 @@ public void IDictionary_Generic_Values_IsReadOnly(int count) public void IDictionary_Generic_Values_Enumeration_Reset(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; ICollection values = dictionary.Values; - IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator enumerator = values.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyValues = readOnlyDictionary.Values; IEnumerator readOnlyEnumerator = readOnlyValues.GetEnumerator(); +#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) { enumerator.Reset(); +#if !NETFRAMEWORK readOnlyEnumerator.Reset(); +#endif } else { Assert.Throws(() => enumerator.Reset()); +#if !NETFRAMEWORK Assert.Throws(() => readOnlyEnumerator.Reset()); +#endif } } @@ -664,12 +704,9 @@ public void IDictionary_Generic_Add_DefaultKey_DefaultValue(int count) TValue value = default(TValue); if (DefaultValueAllowed && !IsReadOnly) { - IReadOnlyDictionary readOnlyDictionary = dictionary; dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); - Assert.Equal(value, dictionary[missingKey]); - Assert.Equal(value, readOnlyDictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -686,12 +723,9 @@ public void IDictionary_Generic_Add_DefaultKey_NonDefaultValue(int count) TValue value = CreateTValue(1456); if (DefaultValueAllowed && !IsReadOnly) { - IReadOnlyDictionary readOnlyDictionary = dictionary; dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); - Assert.Equal(value, dictionary[missingKey]); - Assert.Equal(value, readOnlyDictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -706,14 +740,11 @@ public void IDictionary_Generic_Add_NonDefaultKey_DefaultValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = default(TValue); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); - Assert.Equal(value, dictionary[missingKey]); - Assert.Equal(value, readOnlyDictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -724,14 +755,11 @@ public void IDictionary_Generic_Add_NonDefaultKey_NonDefaultValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(1342); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(count + 1, readOnlyDictionary.Count); - Assert.Equal(value, dictionary[missingKey]); - Assert.Equal(value, readOnlyDictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -742,7 +770,6 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; int seed = 321; TValue duplicate = CreateTValue(seed++); while (dictionary.Values.Contains(duplicate)) @@ -750,7 +777,10 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) dictionary.Add(GetNewKey(dictionary), duplicate); dictionary.Add(GetNewKey(dictionary), duplicate); Assert.Equal(2, dictionary.Values.Count((value) => value.Equals(duplicate))); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Equal(2, readOnlyDictionary.Values.Count((value) => value.Equals(duplicate))); +#endif } } @@ -776,10 +806,8 @@ public void IDictionary_Generic_Add_DistinctValuesWithHashCollisions(int count) IDictionary dictionary = GenericIDictionaryFactory(new EqualityComparerConstantHashCode(EqualityComparer.Default)); if (dictionary != null) { - IReadOnlyDictionary readOnlyDictionary = dictionary; AddToCollection(dictionary, count); - Assert.Equal(count, dictionary.Count); - Assert.Equal(count, readOnlyDictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } } @@ -795,10 +823,8 @@ public void IDictionary_Generic_ContainsKey_ValidKeyNotContainedInDictionary(int if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); - Assert.False(dictionary.ContainsKey(missingKey)); - Assert.False(readOnlyDictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, false); } } @@ -809,11 +835,9 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); - Assert.True(dictionary.ContainsKey(missingKey)); - Assert.True(readOnlyDictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -822,7 +846,6 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; if (DefaultValueAllowed) { if (!IsReadOnly) @@ -831,15 +854,17 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - Assert.False(dictionary.ContainsKey(missingKey)); - Assert.False(readOnlyDictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, false); } } else { // throws ArgumentNullException Assert.Throws(() => dictionary.ContainsKey(default(TKey))); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary.ContainsKey(default(TKey))); +#endif } } @@ -850,12 +875,10 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyContainedInDictionary(int if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); if (!dictionary.ContainsKey(missingKey)) dictionary.Add(missingKey, CreateTValue(5341)); - Assert.True(dictionary.ContainsKey(missingKey)); - Assert.True(readOnlyDictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -881,13 +904,11 @@ public void IDictionary_Generic_RemoveKey_EveryKey(int count) if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.All(dictionary.Keys.ToList(), key => { Assert.True(dictionary.Remove(key)); }); - Assert.Empty(dictionary); - Assert.Empty(readOnlyDictionary); + CollectionAsserts.HasCount(dictionary, 0); } } @@ -898,11 +919,9 @@ public void IDictionary_Generic_RemoveKey_ValidKeyNotContainedInDictionary(int c if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); - Assert.Equal(count, readOnlyDictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -913,12 +932,10 @@ public void IDictionary_Generic_RemoveKey_ValidKeyContainedInDictionary(int coun if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); - Assert.Equal(count, readOnlyDictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -1009,12 +1026,10 @@ KeyValuePair, WeakReference> PopulateAndRemove(IDi public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); TValue outValue; - Assert.False(dictionary.TryGetValue(missingKey, out outValue)); - Assert.False(readOnlyDictionary.TryGetValue(missingKey, out outValue)); + CollectionAsserts.TryGetValue(dictionary, missingKey, false); } [Theory] @@ -1024,15 +1039,11 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co if (!IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); TValue outValue; dictionary.TryAdd(missingKey, value); - Assert.True(dictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); - Assert.True(readOnlyDictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); + CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } } @@ -1041,7 +1052,6 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(int count) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TValue outValue; if (DefaultValueAllowed) { @@ -1050,14 +1060,16 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - Assert.False(dictionary.TryGetValue(missingKey, out outValue)); - Assert.False(readOnlyDictionary.TryGetValue(missingKey, out outValue)); + CollectionAsserts.TryGetValue(dictionary, missingKey, false); } } else { Assert.Throws(() => dictionary.TryGetValue(default(TKey), out outValue)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary.TryGetValue(default(TKey), out outValue)); +#endif } } @@ -1068,15 +1080,11 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyContainedInDictionary(int if (DefaultValueAllowed && !IsReadOnly) { IDictionary dictionary = GenericIDictionaryFactory(count); - IReadOnlyDictionary readOnlyDictionary = dictionary; TKey missingKey = default(TKey); TValue value = CreateTValue(5123); TValue outValue; dictionary.TryAdd(missingKey, value); - Assert.True(dictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); - Assert.True(readOnlyDictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); + CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } } diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 3d80b00cca9e87..5463e83475625f 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -103,11 +103,8 @@ protected override IEnumerable GetModifyEnumerables(ModifyOper public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[-1]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[int.MinValue]); + CollectionAsserts.ThrowsElementAt(list, -1, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, int.MinValue, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -115,11 +112,8 @@ public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[count]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => readOnlyList[count + 1]); + CollectionAsserts.ThrowsElementAt(list, count, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, count + 1, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -127,10 +121,7 @@ public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; - T result; - Assert.All(Enumerable.Range(0, count), index => result = list[index]); - Assert.All(Enumerable.Range(0, count), index => result = readOnlyList[index]); + Assert.All(Enumerable.Range(0, count), index => CollectionAsserts.ElementAtSucceeds(list, index)); } #endregion @@ -144,12 +135,10 @@ public void IList_Generic_ItemSet_NegativeIndex_ThrowsException(int count) if (!IsReadOnly) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue] = validAdd); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -160,12 +149,10 @@ public void IList_Generic_ItemSet_IndexGreaterThanListCount_ThrowsException(int if (!IsReadOnly) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1] = validAdd); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -176,11 +163,9 @@ public void IList_Generic_ItemSet_OnReadOnlyList(int count) if (IsReadOnly && count > 0) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T before = list[count / 2]; Assert.Throws(() => list[count / 2] = CreateT(321432)); - Assert.Equal(before, list[count / 2]); - Assert.Equal(before, readOnlyList[count / 2]); + CollectionAsserts.EqualAt(list, count / 2, before); } } @@ -191,11 +176,9 @@ public void IList_Generic_ItemSet_FirstItemToNonDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = CreateT(123452); list[0] = value; - Assert.Equal(value, list[0]); - Assert.Equal(value, readOnlyList[0]); + CollectionAsserts.EqualAt(list, 0, value); } } @@ -206,18 +189,15 @@ public void IList_Generic_ItemSet_FirstItemToDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; if (DefaultValueAllowed) { list[0] = default(T); - Assert.Equal(default(T), list[0]); - Assert.Equal(default(T), readOnlyList[0]); + CollectionAsserts.EqualAt(list, 0, default(T)); } else { Assert.Throws(() => list[0] = default(T)); - Assert.NotEqual(default(T), list[0]); - Assert.NotEqual(default(T), readOnlyList[0]); + CollectionAsserts.NotEqualAt(list, 0, default(T)); } } } @@ -229,12 +209,10 @@ public void IList_Generic_ItemSet_LastItemToNonDefaultValue(int count) if (count > 0 && !IsReadOnly) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list[lastIndex] = value; - Assert.Equal(value, list[lastIndex]); - Assert.Equal(value, readOnlyList[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, value); } } @@ -245,19 +223,16 @@ public void IList_Generic_ItemSet_LastItemToDefaultValue(int count) if (count > 0 && !IsReadOnly && DefaultValueAllowed) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; int lastIndex = count > 0 ? count - 1 : 0; if (DefaultValueAllowed) { list[lastIndex] = default(T); - Assert.Equal(default(T), list[lastIndex]); - Assert.Equal(default(T), readOnlyList[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, default(T)); } else { Assert.Throws(() => list[lastIndex] = default(T)); - Assert.NotEqual(default(T), list[lastIndex]); - Assert.NotEqual(default(T), readOnlyList[lastIndex]); + CollectionAsserts.NotEqualAt(list, lastIndex, default(T)); } } } @@ -269,14 +244,11 @@ public void IList_Generic_ItemSet_DuplicateValues(int count) if (count >= 2 && !IsReadOnly && DuplicateValuesAllowed) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = CreateT(123452); list[0] = value; list[1] = value; - Assert.Equal(value, list[0]); - Assert.Equal(value, readOnlyList[0]); - Assert.Equal(value, list[1]); - Assert.Equal(value, readOnlyList[1]); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); } } @@ -420,12 +392,10 @@ public void IList_Generic_Insert_NegativeIndex_ThrowsArgumentOutOfRangeException if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.Insert(-1, validAdd)); Assert.Throws(() => list.Insert(int.MinValue, validAdd)); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -436,13 +406,10 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(12350); list.Insert(count, validAdd); - Assert.Equal(count + 1, list.Count); - Assert.Equal(count + 1, readOnlyList.Count); - Assert.Equal(validAdd, list[count]); - Assert.Equal(validAdd, readOnlyList[count]); + CollectionAsserts.HasCount(list, count + 1); + CollectionAsserts.EqualAt(list, count, valueAdd); } } @@ -453,10 +420,8 @@ public void IList_Generic_Insert_ToReadOnlyList(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; Assert.Throws(() => list.Insert(count / 2, CreateT(321432))); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -467,13 +432,10 @@ public void IList_Generic_Insert_FirstItemToNonDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = CreateT(123452); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(value, readOnlyList[0]); - Assert.Equal(count + 1, list.Count); - Assert.Equal(count + 1, readOnlyList.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -484,13 +446,10 @@ public void IList_Generic_Insert_FirstItemToDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DefaultValueAllowed) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = default(T); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(value, readOnlyList[0]); - Assert.Equal(count + 1, list.Count); - Assert.Equal(count + 1, readOnlyList.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -501,14 +460,11 @@ public void IList_Generic_Insert_LastItemToNonDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(value, readOnlyList[lastIndex]); - Assert.Equal(count + 1, list.Count); - Assert.Equal(count + 1, readOnlyList.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -519,14 +475,11 @@ public void IList_Generic_Insert_LastItemToDefaultValue(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DefaultValueAllowed) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T value = default(T); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(value, readOnlyList[lastIndex]); - Assert.Equal(count + 1, list.Count); - Assert.Equal(count + 1, readOnlyList.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -544,15 +497,11 @@ public void IList_Generic_Insert_DuplicateValues(int count) } else { - IReadOnlyList readOnlyList = list; list.Insert(0, value); list.Insert(1, value); - Assert.Equal(value, list[0]); - Assert.Equal(value, readOnlyList[0]); - Assert.Equal(value, list[1]); - Assert.Equal(value, readOnlyList[1]); - Assert.Equal(count + 2, list.Count); - Assert.Equal(count + 2, readOnlyList.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); + CollectionAsserts.HasCount(list, count + 2); } } } @@ -582,12 +531,10 @@ public void IList_Generic_RemoveAt_NegativeIndex_ThrowsArgumentOutOfRangeExcepti if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(-1)); Assert.Throws(() => list.RemoveAt(int.MinValue)); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -598,12 +545,10 @@ public void IList_Generic_RemoveAt_IndexGreaterThanListCount_ThrowsArgumentOutOf if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(count)); Assert.Throws(() => list.RemoveAt(count + 1)); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -614,10 +559,8 @@ public void IList_Generic_RemoveAt_OnReadOnlyList(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; Assert.Throws(() => list.RemoveAt(count / 2)); - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); } } @@ -628,14 +571,11 @@ public void IList_Generic_RemoveAt_AllValidIndices(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; - Assert.Equal(count, list.Count); - Assert.Equal(count, readOnlyList.Count); + CollectionAsserts.HasCount(list, count); Assert.All(Enumerable.Range(0, count).Reverse(), index => { list.RemoveAt(index); - Assert.Equal(index, list.Count); - Assert.Equal(index, readOnlyList.Count); + CollectionAsserts.HasCount(list, index); }); } } @@ -647,12 +587,10 @@ public void IList_Generic_RemoveAt_ZeroMultipleTimes(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - IReadOnlyList readOnlyList = list; Assert.All(Enumerable.Range(0, count), index => { list.RemoveAt(0); - Assert.Equal(count - index - 1, list.Count); - Assert.Equal(count - index - 1, readOnlyList.Count); + CollectionAsserts.HasCount(list, count - index - 1); }); } } diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 32386672503342..818aa53a291be9 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -77,7 +77,6 @@ public void ICollection_Generic_Add_ReturnValue(int count) if (!IsReadOnly) { ISet set = GenericISetFactory(count); - IReadOnlySet readOnlySet = set; int seed = 92834; T newValue = CreateT(seed++); while (set.Contains(newValue)) @@ -85,10 +84,8 @@ public void ICollection_Generic_Add_ReturnValue(int count) Assert.True(set.Add(newValue)); if (!DuplicateValuesAllowed) Assert.False(set.Add(newValue)); - Assert.Equal(count + 1, set.Count); - Assert.Equal(count + 1, readOnlySet.Count); - Assert.True(set.Contains(newValue)); - Assert.True(readOnlySet.Contains(newValue)); + CollectionAsserts.HasCount(set, count + 1); + CollectionAsserts.Contains(set, newValue); } } @@ -120,12 +117,10 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) private void Validate_ExceptWith(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; if (set.Count == 0 || enumerable == set) { set.ExceptWith(enumerable); - Assert.Equal(0, set.Count); - Assert.Equal(0, readOnlySet.Count); + CollectionAsserts.HasCount(set, 0); } else { @@ -133,28 +128,23 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) foreach (T element in enumerable) expected.Remove(element); set.ExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); - Assert.Equal(expected.Count, readOnlySet.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); - Assert.True(expected.SetEquals(readOnlySet)); } } private void Validate_IntersectWith(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; if (set.Count == 0 || Enumerable.Count(enumerable) == 0) { set.IntersectWith(enumerable); - Assert.Equal(0, set.Count); - Assert.Equal(0, readOnlySet.Count); + CollectionAsserts.HasCount(set, 0); } else if (set == enumerable) { HashSet beforeOperation = new HashSet(set, GetIEqualityComparer()); set.IntersectWith(enumerable); Assert.True(beforeOperation.SetEquals(set)); - Assert.True(beforeOperation.SetEquals(readOnlySet)); } else { @@ -164,16 +154,13 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (enumerable.Contains(value, comparer)) expected.Add(value); set.IntersectWith(enumerable); - Assert.Equal(expected.Count, set.Count); - Assert.Equal(expected.Count, readOnlySet.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); - Assert.True(expected.SetEquals(readOnlySet)); } } private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; bool setContainsValueNotInEnumerable = false; bool enumerableContainsValueNotInSet = false; IEqualityComparer comparer = GetIEqualityComparer(); @@ -193,13 +180,11 @@ private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) break; } } - Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, set.IsProperSubsetOf(enumerable)); - Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, readOnlySet.IsProperSubsetOf(enumerable)); + CollectionAsserts.IsProperSubsetOf(set, enumerable, !setContainsValueNotInEnumerable && enumerableContainsValueNotInSet); } private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; bool isProperSuperset = true; bool setContainsElementsNotInEnumerable = false; IEqualityComparer comparer = GetIEqualityComparer(); @@ -219,68 +204,55 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) break; } } - isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; - Assert.Equal(isProperSuperset, set.IsProperSupersetOf(enumerable)); - Assert.Equal(isProperSuperset, readOnlySet.IsProperSupersetOf(enumerable)); + CollectionAsserts.IsProperSupersetOf(set, enumerable, isProperSuperset); } private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in set) if (!enumerable.Contains(value, comparer)) { - Assert.False(set.IsSubsetOf(enumerable)); - Assert.False(readOnlySet.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, false); return; } - Assert.True(set.IsSubsetOf(enumerable)); - Assert.True(readOnlySet.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, true); } private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in enumerable) if (!set.Contains(value, comparer)) { - Assert.False(set.IsSupersetOf(enumerable)); - Assert.False(readOnlySet.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, false); return; } - Assert.True(set.IsSupersetOf(enumerable)); - Assert.True(readOnlySet.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, true); } private void Validate_Overlaps(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in enumerable) { if (set.Contains(value, comparer)) { - Assert.True(set.Overlaps(enumerable)); - Assert.True(readOnlySet.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, true); return; } } - Assert.False(set.Overlaps(enumerable)); - Assert.False(readOnlySet.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, false); } private void Validate_SetEquals(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); foreach (T value in set) { if (!enumerable.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); - Assert.False(readOnlySet.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } @@ -288,18 +260,15 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!set.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); - Assert.False(readOnlySet.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } - Assert.True(set.SetEquals(enumerable)); - Assert.True(readOnlySet.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, true); } private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); HashSet expected = new HashSet(comparer); foreach (T element in enumerable) @@ -309,25 +278,20 @@ private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); - Assert.Equal(expected.Count, readOnlySet.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); - Assert.True(expected.SetEquals(readOnlySet)); } private void Validate_UnionWith(ISet set, IEnumerable enumerable) { - IReadOnlySet readOnlySet = set; IEqualityComparer comparer = GetIEqualityComparer(); HashSet expected = new HashSet(set, comparer); foreach (T element in enumerable) if (!set.Contains(element, comparer)) expected.Add(element); set.UnionWith(enumerable); - Assert.Equal(expected.Count, set.Count); - Assert.Equal(expected.Count, readOnlySet.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); - Assert.True(expected.SetEquals(readOnlySet)); } #endregion @@ -339,19 +303,21 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) public void ISet_Generic_NullEnumerableArgument(int count) { ISet set = GenericISetFactory(count); - IReadOnlySet readOnlySet = set; Assert.Throws(() => set.IsProperSubsetOf(null)); - Assert.Throws(() => readOnlySet.IsProperSubsetOf(null)); Assert.Throws(() => set.IsProperSupersetOf(null)); - Assert.Throws(() => readOnlySet.IsProperSupersetOf(null)); Assert.Throws(() => set.IsSubsetOf(null)); - Assert.Throws(() => readOnlySet.IsSubsetOf(null)); Assert.Throws(() => set.IsSupersetOf(null)); - Assert.Throws(() => readOnlySet.IsSupersetOf(null)); Assert.Throws(() => set.Overlaps(null)); - Assert.Throws(() => readOnlySet.Overlaps(null)); Assert.Throws(() => set.SetEquals(null)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Throws(() => readOnlySet.IsProperSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsProperSupersetOf(null)); + Assert.Throws(() => readOnlySet.IsSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsSupersetOf(null)); + Assert.Throws(() => readOnlySet.Overlaps(null)); Assert.Throws(() => readOnlySet.SetEquals(null)); +#endif if (!IsReadOnly) { Assert.Throws(() => set.ExceptWith(null)); @@ -546,9 +512,7 @@ public void ISet_Generic_Overlaps_Itself(int setLength) public void ISet_Generic_SetEquals_Itself(int setLength) { ISet set = GenericISetFactory(setLength); - IReadOnlySet readOnlySet = set; - Assert.True(set.SetEquals(set)); - Assert.True(readOnlySet.SetEquals(readOnlySet)); + CollectionAsserts.SetEquals(set, set, true); } [Theory] @@ -690,7 +654,6 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!IsReadOnly) { ISet set = GenericISetFactory(setLength); - IReadOnlySet readOnlySet = set; T value = CreateT(532); if (!set.Contains(value)) set.Add(value); @@ -707,10 +670,8 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); - Assert.Equal(expected.Count, readOnlySet.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); - Assert.True(expected.SetEquals(readOnlySet)); } } diff --git a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs index f46358e572ca0f..6a5b458232fc5c 100644 --- a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs +++ b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs @@ -59,20 +59,24 @@ public void TryAdd_NullKeyIDictionary_ThrowsArgumentNullException() public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue() { IDictionary dictionary = new SortedDictionary(); - IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(dictionary.TryAdd("key", "value")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] public void TryAdd_KeyExistsInIDictionary_ReturnsFalse() { IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; - IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.False(dictionary.TryAdd("key", "value2")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] @@ -97,11 +101,13 @@ public void Remove_NullKeyIDictionary_ThrowsArgumentNullException() public void Remove_KeyExistsInIDictionary_ReturnsTrue() { IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; - IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.True(dictionary.Remove("key", out var value)); Assert.Equal("value", value); Assert.Throws(() => dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; Assert.Throws(() => readOnlyDictionary["key"]); +#endif } [Fact] diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs index 3eadb223acdb34..24cf81efb2b440 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs @@ -19,8 +19,6 @@ public interface ICollection : IReadOnlyCollection get; } - int IReadOnlyCollection.Count => Count; - bool IsReadOnly { #if MONO @@ -55,5 +53,7 @@ bool IsReadOnly [DynamicDependency(nameof(Array.InternalArray__ICollection_Remove) + "``1", typeof(Array))] #endif bool Remove(T item); + + int IReadOnlyCollection.Count => Count; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs index 8d8702d5b8cf92..7e3e30d8db0929 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs @@ -20,30 +20,22 @@ public interface IDictionary : ICollection.this[TKey key] => this[key]; - // Returns a collections of the keys in this dictionary. new ICollection Keys { get; } - IEnumerable IReadOnlyDictionary.Keys => Keys; - // Returns a collections of the values in this dictionary. new ICollection Values { get; } - IEnumerable IReadOnlyDictionary.Values => Values; - // Returns whether this dictionary contains a particular key. // new bool ContainsKey(TKey key); - bool IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); - // Adds a key-value pair to the dictionary. // void Add(TKey key, TValue value); @@ -54,6 +46,14 @@ public interface IDictionary : ICollection.this[TKey key] => this[key]; + + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; + + bool IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); + bool IReadOnlyDictionary.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => TryGetValue(key, out value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs index 6785fed5bb24dd..ec8098c3ff7ea1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs @@ -25,8 +25,6 @@ public interface IList : ICollection, IReadOnlyList set; } - T IReadOnlyList.this[int index] => this[index]; - // Returns the index of a particular item, if it is in the list. // Returns -1 if the item isn't in the list. #if MONO @@ -48,5 +46,7 @@ public interface IList : ICollection, IReadOnlyList [DynamicDependency(nameof(Array.InternalArray__RemoveAt), typeof(Array))] #endif void RemoveAt(int index); + + T IReadOnlyList.this[int index] => this[index]; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs index 0951aab79f653a..ce2e8e7c5f4ff1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs @@ -28,33 +28,21 @@ public interface ISet : ICollection, IReadOnlySet //Check if this set is a subset of other new bool IsSubsetOf(IEnumerable other); - bool IReadOnlySet.IsSubsetOf(IEnumerable other) => IsSubsetOf(other); - //Check if this set is a superset of other new bool IsSupersetOf(IEnumerable other); - bool IReadOnlySet.IsSupersetOf(IEnumerable other) => IsSupersetOf(other); - //Check if this set is a subset of other, but not the same as it new bool IsProperSupersetOf(IEnumerable other); - bool IReadOnlySet.IsProperSupersetOf(IEnumerable other) => IsProperSupersetOf(other); - //Check if this set is a superset of other, but not the same as it new bool IsProperSubsetOf(IEnumerable other); - bool IReadOnlySet.IsProperSubsetOf(IEnumerable other) => IsProperSubsetOf(other); - //Check if this set has any elements in common with other new bool Overlaps(IEnumerable other); - bool IReadOnlySet.Overlaps(IEnumerable other) => Overlaps(other); - //Check if this set contains the same and only the same elements as other new bool SetEquals(IEnumerable other); - bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); - /// /// Determines if the set contains a specific item /// @@ -62,6 +50,18 @@ public interface ISet : ICollection, IReadOnlySet /// if found; otherwise . new bool Contains(T item) => ((ICollection)this).Contains(item); + bool IReadOnlySet.IsSubsetOf(IEnumerable other) => IsSubsetOf(other); + + bool IReadOnlySet.IsSupersetOf(IEnumerable other) => IsSupersetOf(other); + + bool IReadOnlySet.IsProperSupersetOf(IEnumerable other) => IsProperSupersetOf(other); + + bool IReadOnlySet.IsProperSubsetOf(IEnumerable other) => IsProperSubsetOf(other); + + bool IReadOnlySet.Overlaps(IEnumerable other) => Overlaps(other); + + bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); + bool IReadOnlySet.Contains(T value) => ((ICollection)this).Contains(value); } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 9675671f4faac1..82ebc8633a4a10 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7764,13 +7764,13 @@ public partial interface IAsyncEnumerator : System.IAsyncDisposable public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection { new int Count { get; } - int System.Collections.Generic.IReadOnlyCollection.Count => Count; bool IsReadOnly { get; } void Add(T item); void Clear(); bool Contains(T item); void CopyTo(T[] array, int arrayIndex); bool Remove(T item); + int System.Collections.Generic.IReadOnlyCollection.Count => Count; } public partial interface IComparer { @@ -7779,16 +7779,16 @@ public partial interface IComparer public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection> { new TValue this[TKey key] { get; set; } - TValue System.Collections.Generic.IReadOnlyDictionary.this[TKey key] => this[key]; new System.Collections.Generic.ICollection Keys { get; } - System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys => Keys; new System.Collections.Generic.ICollection Values { get; } - System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values => Values; void Add(TKey key, TValue value); new bool ContainsKey(TKey key); - bool System.Collections.Generic.IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); bool Remove(TKey key); new bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); + TValue System.Collections.Generic.IReadOnlyDictionary.this[TKey key] => this[key]; + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys => Keys; + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values => Values; + bool System.Collections.Generic.IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); bool System.Collections.Generic.IReadOnlyDictionary.TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value) => TryGetValue(key, out value); } public partial interface IEnumerable : System.Collections.IEnumerable @@ -7807,10 +7807,10 @@ public partial interface IEqualityComparer public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection { new T this[int index] { get; set; } - T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); + T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; } public partial interface IReadOnlyCollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -7841,24 +7841,24 @@ public partial interface IReadOnlySet : System.Collections.Generic.IEnumerabl public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection { new bool Add(T item); - new bool Contains(T item) => ((ICollection)this).Contains(item); - bool System.Collections.Generic.IReadOnlySet.Contains(T item) => ((ICollection)this).Contains(item); void ExceptWith(System.Collections.Generic.IEnumerable other); void IntersectWith(System.Collections.Generic.IEnumerable other); new bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => IsProperSubsetOf(other); new bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => IsProperSupersetOf(other); new bool IsSubsetOf(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.IsSubsetOf(System.Collections.Generic.IEnumerable other) => IsSubsetOf(other); new bool IsSupersetOf(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.IsSupersetOf(System.Collections.Generic.IEnumerable other) => IsSupersetOf(other); new bool Overlaps(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.Overlaps(System.Collections.Generic.IEnumerable other) => Overlaps(other); new bool SetEquals(System.Collections.Generic.IEnumerable other); - bool System.Collections.Generic.IReadOnlySet.SetEquals(System.Collections.Generic.IEnumerable other) => SetEquals(other); void SymmetricExceptWith(System.Collections.Generic.IEnumerable other); void UnionWith(System.Collections.Generic.IEnumerable other); + new bool Contains(T item) => ((ICollection)this).Contains(item); + bool System.Collections.Generic.IReadOnlySet.Contains(T item) => ((ICollection)this).Contains(item); + bool System.Collections.Generic.IReadOnlySet.IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => IsProperSubsetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => IsProperSupersetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsSubsetOf(System.Collections.Generic.IEnumerable other) => IsSubsetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsSupersetOf(System.Collections.Generic.IEnumerable other) => IsSupersetOf(other); + bool System.Collections.Generic.IReadOnlySet.Overlaps(System.Collections.Generic.IEnumerable other) => Overlaps(other); + bool System.Collections.Generic.IReadOnlySet.SetEquals(System.Collections.Generic.IEnumerable other) => SetEquals(other); } public partial class KeyNotFoundException : System.SystemException { From b3f7aaeae92bd0a6a7f717997e5b4c13599c6cee Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 09:55:39 -0600 Subject: [PATCH 09/15] Small fix --- .../Common/tests/System/Collections/ISet.Generic.Tests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 818aa53a291be9..6facae42f964aa 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -98,15 +98,13 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) if (!DuplicateValuesAllowed) { ICollection collection = GenericICollectionFactory(count); - IReadOnlyCollection readOnlyCollection = collection; int seed = 800; T duplicateValue = CreateT(seed++); while (collection.Contains(duplicateValue)) duplicateValue = CreateT(seed++); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 1, collection.Count); - Assert.Equal(count + 1, readOnlyCollection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } } From 27c5fdf2ff73a8cd86b6e407c3e6133ee51dea2d Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 09:57:57 -0600 Subject: [PATCH 10/15] Small fix --- .../Common/tests/System/Collections/ISet.Generic.Tests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 6facae42f964aa..350faab6f44cb7 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -202,6 +202,7 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) break; } } + isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; CollectionAsserts.IsProperSupersetOf(set, enumerable, isProperSuperset); } From 140f43b6d7dac2fc4675cde3e5a0d59eeea845ce Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 10:19:04 -0600 Subject: [PATCH 11/15] Fix build --- .../Common/tests/System/Collections/CollectionAsserts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index c207236a3df8c7..1e76d40ebb411f 100644 --- a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs +++ b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs @@ -10,7 +10,7 @@ namespace System.Collections.Tests { internal static class CollectionAsserts { - public static void HasCount(ICollection collection, int count) + public static void HasCount(ICollection collection, int count) { Assert.Equal(count, collection.Count); #if !NETFRAMEWORK From 888eb0be32754862f2009cc3764271cfd4fa93fb Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 10:40:16 -0600 Subject: [PATCH 12/15] Fix --- .../Common/tests/System/Collections/IList.Generic.Tests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 5463e83475625f..6d66f143f18d65 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -409,7 +409,7 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) T validAdd = CreateT(12350); list.Insert(count, validAdd); CollectionAsserts.HasCount(list, count + 1); - CollectionAsserts.EqualAt(list, count, valueAdd); + CollectionAsserts.EqualAt(list, count, validAdd); } } From f701940c1a0dc65535bb6b6558c06a378f9fb851 Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 12 Dec 2023 10:43:00 -0600 Subject: [PATCH 13/15] Cleanup --- .../tests/System/Collections/IDictionary.Generic.Tests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index a44de75b265a0e..e6311ec89b4fc1 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -1028,7 +1028,6 @@ public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - TValue outValue; CollectionAsserts.TryGetValue(dictionary, missingKey, false); } @@ -1041,7 +1040,6 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - TValue outValue; dictionary.TryAdd(missingKey, value); CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } @@ -1082,7 +1080,6 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = default(TKey); TValue value = CreateTValue(5123); - TValue outValue; dictionary.TryAdd(missingKey, value); CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } From 0580aae7640eb6df61d2eeaf2046a1a92d08bf6b Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 9 Jan 2024 11:16:09 -0600 Subject: [PATCH 14/15] Incorporate #96672 --- .../Compiler/DependencyAnalysis/EETypeNode.cs | 2 +- .../Compiler/DependencyAnalysis/SealedVTableNode.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index e136b1057cf154..a47312d706517c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -531,7 +531,7 @@ public sealed override IEnumerable GetConditionalSt if (!isStaticInterfaceMethod && defaultIntfMethod.IsCanonicalMethod(CanonicalFormKind.Any)) { // Canonical instance default methods need to go through a thunk that adds the right generic context - defaultIntfMethod = factory.TypeSystemContext.GetDefaultInterfaceMethodImplementationThunk(defaultIntfMethod, _type.ConvertToCanonForm(CanonicalFormKind.Specific), providingInterfaceDefinitionType); + defaultIntfMethod = factory.TypeSystemContext.GetDefaultInterfaceMethodImplementationThunk(defaultIntfMethod, defType.ConvertToCanonForm(CanonicalFormKind.Specific), providingInterfaceDefinitionType); } result.Add(new CombinedDependencyListEntry(factory.MethodEntrypoint(defaultIntfMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method")); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs index d9b99d08bde3f2..d27944d434e81d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs @@ -216,9 +216,11 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly) if (BuildSealedVTableSlots(factory, relocsOnly)) { + DefType defType = _type.GetClosestDefType(); + for (int i = 0; i < _sealedVTableEntries.Count; i++) { - IMethodNode relocTarget = _sealedVTableEntries[i].GetTarget(factory, _type); + IMethodNode relocTarget = _sealedVTableEntries[i].GetTarget(factory, defType); if (factory.Target.SupportsRelativePointers) objData.EmitReloc(relocTarget, RelocType.IMAGE_REL_BASED_RELPTR32); From 79fff710a25cd6983ca9ac94e239209d9f8d7d87 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 1 Mar 2024 23:13:09 -0800 Subject: [PATCH 15/15] Check the correct inheritanceDepth in vm/array.cpp --- src/coreclr/vm/array.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index b3543e507dcad8..e1e2b31e4df647 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -1217,7 +1217,7 @@ MethodDesc* GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod(Met // OPTIMIZATION: For any method other than GetEnumerator(), we can safely substitute // "Object" for reference-type theT's. This causes fewer methods to be instantiated. - if (inheritanceDepth != 1 && !theT.IsValueType()) + if (inheritanceDepth != 0 && !theT.IsValueType()) { theT = TypeHandle(g_pObjectClass); }