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 de7b3021c458f..74e0739848168 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -694,7 +694,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 ffb6e6def99ce..e1e2b31e4df64 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -1210,29 +1210,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 != 0 && !theT.IsValueType()) { theT = TypeHandle(g_pObjectClass); } diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index 2de26be1737fd..1e76d40ebb411 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); @@ -43,6 +189,12 @@ public static void Equal(ICollection expected, ICollection actual) 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()) 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 a94a9308b99ab..8ae72dea074ab 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,7 @@ public void ICollection_Generic_IsReadOnly_Validity(int count) public void ICollection_Generic_Count_Validity(int count) { ICollection collection = GenericICollectionFactory(count); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } #endregion @@ -145,7 +145,7 @@ public virtual void ICollection_Generic_Add_DefaultValue(int count) { ICollection collection = GenericICollectionFactory(count); collection.Add(default(T)); - Assert.Equal(count + 1, collection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } @@ -161,7 +161,7 @@ public void ICollection_Generic_Add_InvalidValueToMiddleOfCollection(int count) collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count * 2, collection.Count); + CollectionAsserts.HasCount(collection, count * 2); }); } } @@ -178,7 +178,7 @@ public void ICollection_Generic_Add_InvalidValueToBeginningOfCollection(int coun collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -192,8 +192,9 @@ public void ICollection_Generic_Add_InvalidValueToEndOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); + collection.Add(invalidValue); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -208,7 +209,7 @@ public void ICollection_Generic_Add_DuplicateValue(int count) T duplicateValue = CreateT(700); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 2, collection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -221,7 +222,7 @@ public void ICollection_Generic_Add_AfterCallingClear(int count) ICollection collection = GenericICollectionFactory(count); collection.Clear(); AddToCollection(collection, 5); - Assert.Equal(5, collection.Count); + CollectionAsserts.HasCount(collection, 5); } } @@ -261,7 +262,7 @@ public void ICollection_Generic_Add_AfterRemovingAllItems(int count) for (int i = 0; i < count; i++) collection.Remove(collection.ElementAt(0)); collection.Add(CreateT(254)); - Assert.Equal(1, collection.Count); + CollectionAsserts.HasCount(collection, 1); } } @@ -273,7 +274,7 @@ public void ICollection_Generic_Add_ToReadOnlyCollection(int count) { ICollection collection = GenericICollectionFactory(count); Assert.Throws(() => collection.Add(CreateT(0))); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -306,12 +307,12 @@ public void ICollection_Generic_Clear(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); - Assert.Equal(0, collection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -325,14 +326,14 @@ public void ICollection_Generic_Clear_Repeatedly(int count) Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); collection.Clear(); collection.Clear(); - Assert.Equal(0, collection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -434,7 +435,7 @@ public void ICollection_Generic_Contains_ValidValueThatExistsTwiceInTheCollectio T item = CreateT(12); collection.Add(item); collection.Add(item); - Assert.Equal(count + 2, collection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -567,7 +568,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int count--; } Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -583,7 +584,7 @@ public void ICollection_Generic_Remove_NonDefaultValueNotContainedInCollection(i while (collection.Contains(value) || Enumerable.Contains(InvalidValues, value)) value = CreateT(seed++); Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -602,7 +603,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -621,7 +622,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -639,7 +640,7 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun count += 2; Assert.True(collection.Remove(value)); Assert.True(collection.Contains(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -654,7 +655,7 @@ public void ICollection_Generic_Remove_EveryValue(int count) { Assert.True(collection.Remove(value)); }); - Assert.Empty(collection); + CollectionAsserts.HasCount(collection, 0); } } @@ -667,7 +668,7 @@ public void ICollection_Generic_Remove_InvalidValue_ThrowsArgumentException(int { Assert.Throws(() => collection.Remove(value)); }); - Assert.Equal(count, collection.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 df92ab206f668..e6311ec89b4fc 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -266,12 +266,16 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) 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)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -283,6 +287,10 @@ public void IDictionary_Generic_ItemGet_MissingNonDefaultKey_ThrowsKeyNotFoundEx IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } [Theory] @@ -296,6 +304,10 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } } @@ -306,7 +318,7 @@ public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count) IDictionary dictionary = GenericIDictionaryFactory(count); foreach (KeyValuePair pair in dictionary) { - Assert.Equal(pair.Value, dictionary[pair.Key]); + CollectionAsserts.EqualAt(dictionary, pair.Key, pair.Value); } } @@ -329,7 +341,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - Assert.Equal(value, dictionary[default(TKey)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -355,7 +367,7 @@ public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count) IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary[missingKey] = CreateTValue(543); - Assert.Equal(count + 1, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count + 1); } } @@ -370,8 +382,8 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou dictionary.Add(existingKey, CreateTValue(5342)); TValue newValue = CreateTValue(1234); dictionary[existingKey] = newValue; - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(newValue, dictionary[existingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, existingKey, newValue); } } @@ -386,6 +398,10 @@ public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count) IDictionary dictionary = GenericIDictionaryFactory(count); 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] @@ -396,6 +412,10 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( { IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; +#endif int previousCount = keys.Count; if (count > 0) Assert.NotEmpty(keys); @@ -403,10 +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 } } } @@ -420,11 +446,20 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.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 { @@ -433,6 +468,13 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid _ = keysEnum.Current; } keysEnum.Reset(); +#if !NETFRAMEWORK + if (readOnlyKeysEnum.MoveNext()) + { + _ = readOnlyKeysEnum.Current; + } + readOnlyKeysEnum.Reset(); +#endif } } } @@ -456,10 +498,25 @@ public void IDictionary_Generic_Keys_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.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 + } } #endregion @@ -473,6 +530,10 @@ public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count) IDictionary dictionary = GenericIDictionaryFactory(count); 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] @@ -491,6 +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 } } @@ -500,9 +565,18 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio { IDictionary dictionary = GenericIDictionaryFactory(count); 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) { @@ -510,10 +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 } } } @@ -527,11 +607,20 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.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 { @@ -540,6 +629,13 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval _ = valuesEnum.Current; } valuesEnum.Reset(); +#if !NETFRAMEWORK + if (readOnlyValuesEnum.MoveNext()) + { + _ = readOnlyValuesEnum.Current; + } + readOnlyValuesEnum.Reset(); +#endif } } } @@ -563,10 +659,25 @@ public void IDictionary_Generic_Values_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.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 + } } #endregion @@ -594,8 +705,8 @@ public void IDictionary_Generic_Add_DefaultKey_DefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -613,8 +724,8 @@ public void IDictionary_Generic_Add_DefaultKey_NonDefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -632,8 +743,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_DefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = default(TValue); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -647,8 +758,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_NonDefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(1342); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -666,6 +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 } } @@ -692,7 +807,7 @@ public void IDictionary_Generic_Add_DistinctValuesWithHashCollisions(int count) if (dictionary != null) { AddToCollection(dictionary, count); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } } @@ -709,7 +824,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyNotContainedInDictionary(int { IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); - Assert.False(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, false); } } @@ -722,7 +837,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); - Assert.True(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -739,13 +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)); + 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 } } @@ -759,7 +878,7 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyContainedInDictionary(int TKey missingKey = default(TKey); if (!dictionary.ContainsKey(missingKey)) dictionary.Add(missingKey, CreateTValue(5341)); - Assert.True(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -789,7 +908,7 @@ public void IDictionary_Generic_RemoveKey_EveryKey(int count) { Assert.True(dictionary.Remove(key)); }); - Assert.Empty(dictionary); + CollectionAsserts.HasCount(dictionary, 0); } } @@ -802,7 +921,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyNotContainedInDictionary(int c IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -816,7 +935,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyContainedInDictionary(int coun TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -909,8 +1028,7 @@ public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - TValue outValue; - Assert.False(dictionary.TryGetValue(missingKey, out outValue)); + CollectionAsserts.TryGetValue(dictionary, missingKey, false); } [Theory] @@ -922,10 +1040,8 @@ 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); - Assert.True(dictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); + CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } } @@ -942,12 +1058,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)); + 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 } } @@ -960,10 +1080,8 @@ 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); - Assert.True(dictionary.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 44f67e0ca24f8..6d66f143f18d6 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,8 @@ protected override IEnumerable GetModifyEnumerables(ModifyOper public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) { IList list = GenericIListFactory(count); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]); + CollectionAsserts.ThrowsElementAt(list, -1, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, int.MinValue, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -112,8 +112,8 @@ public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count) { IList list = GenericIListFactory(count); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]); + CollectionAsserts.ThrowsElementAt(list, count, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, count + 1, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -121,8 +121,7 @@ public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count) { IList list = GenericIListFactory(count); - T result; - Assert.All(Enumerable.Range(0, count), index => result = list[index]); + Assert.All(Enumerable.Range(0, count), index => CollectionAsserts.ElementAtSucceeds(list, index)); } #endregion @@ -139,7 +138,7 @@ public void IList_Generic_ItemSet_NegativeIndex_ThrowsException(int count) 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); + CollectionAsserts.HasCount(list, count); } } @@ -153,7 +152,7 @@ public void IList_Generic_ItemSet_IndexGreaterThanListCount_ThrowsException(int 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); + CollectionAsserts.HasCount(list, count); } } @@ -166,7 +165,7 @@ public void IList_Generic_ItemSet_OnReadOnlyList(int count) IList list = GenericIListFactory(count); T before = list[count / 2]; Assert.Throws(() => list[count / 2] = CreateT(321432)); - Assert.Equal(before, list[count / 2]); + CollectionAsserts.EqualAt(list, count / 2, before); } } @@ -179,7 +178,7 @@ public void IList_Generic_ItemSet_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list[0] = value; - Assert.Equal(value, list[0]); + CollectionAsserts.EqualAt(list, 0, value); } } @@ -193,12 +192,12 @@ public void IList_Generic_ItemSet_FirstItemToDefaultValue(int count) if (DefaultValueAllowed) { list[0] = default(T); - Assert.Equal(default(T), list[0]); + CollectionAsserts.EqualAt(list, 0, default(T)); } else { Assert.Throws(() => list[0] = default(T)); - Assert.NotEqual(default(T), list[0]); + CollectionAsserts.NotEqualAt(list, 0, default(T)); } } } @@ -213,7 +212,7 @@ public void IList_Generic_ItemSet_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list[lastIndex] = value; - Assert.Equal(value, list[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, value); } } @@ -228,12 +227,12 @@ public void IList_Generic_ItemSet_LastItemToDefaultValue(int count) if (DefaultValueAllowed) { list[lastIndex] = default(T); - Assert.Equal(default(T), list[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, default(T)); } else { Assert.Throws(() => list[lastIndex] = default(T)); - Assert.NotEqual(default(T), list[lastIndex]); + CollectionAsserts.NotEqualAt(list, lastIndex, default(T)); } } } @@ -248,8 +247,8 @@ public void IList_Generic_ItemSet_DuplicateValues(int count) T value = CreateT(123452); list[0] = value; list[1] = value; - Assert.Equal(value, list[0]); - Assert.Equal(value, list[1]); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); } } @@ -396,7 +395,7 @@ public void IList_Generic_Insert_NegativeIndex_ThrowsArgumentOutOfRangeException T validAdd = CreateT(0); Assert.Throws(() => list.Insert(-1, validAdd)); Assert.Throws(() => list.Insert(int.MinValue, validAdd)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -409,8 +408,8 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) IList list = GenericIListFactory(count); T validAdd = CreateT(12350); list.Insert(count, validAdd); - Assert.Equal(count + 1, list.Count); - Assert.Equal(validAdd, list[count]); + CollectionAsserts.HasCount(list, count + 1); + CollectionAsserts.EqualAt(list, count, validAdd); } } @@ -422,7 +421,7 @@ public void IList_Generic_Insert_ToReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.Insert(count / 2, CreateT(321432))); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -435,8 +434,8 @@ public void IList_Generic_Insert_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -449,8 +448,8 @@ public void IList_Generic_Insert_FirstItemToDefaultValue(int count) IList list = GenericIListFactory(count); T value = default(T); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -464,8 +463,8 @@ public void IList_Generic_Insert_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -479,8 +478,8 @@ public void IList_Generic_Insert_LastItemToDefaultValue(int count) T value = default(T); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -500,9 +499,9 @@ public void IList_Generic_Insert_DuplicateValues(int count) { list.Insert(0, value); list.Insert(1, value); - Assert.Equal(value, list[0]); - Assert.Equal(value, list[1]); - Assert.Equal(count + 2, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); + CollectionAsserts.HasCount(list, count + 2); } } } @@ -535,7 +534,7 @@ public void IList_Generic_RemoveAt_NegativeIndex_ThrowsArgumentOutOfRangeExcepti T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(-1)); Assert.Throws(() => list.RemoveAt(int.MinValue)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -549,7 +548,7 @@ public void IList_Generic_RemoveAt_IndexGreaterThanListCount_ThrowsArgumentOutOf T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(count)); Assert.Throws(() => list.RemoveAt(count + 1)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -561,7 +560,7 @@ public void IList_Generic_RemoveAt_OnReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.RemoveAt(count / 2)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -572,11 +571,11 @@ public void IList_Generic_RemoveAt_AllValidIndices(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); Assert.All(Enumerable.Range(0, count).Reverse(), index => { list.RemoveAt(index); - Assert.Equal(index, list.Count); + CollectionAsserts.HasCount(list, index); }); } } @@ -591,7 +590,7 @@ public void IList_Generic_RemoveAt_ZeroMultipleTimes(int count) Assert.All(Enumerable.Range(0, count), index => { list.RemoveAt(0); - Assert.Equal(count - index - 1, list.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 303001e8bd144..350faab6f44cb 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -84,8 +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.True(set.Contains(newValue)); + CollectionAsserts.HasCount(set, count + 1); + CollectionAsserts.Contains(set, newValue); } } @@ -104,7 +104,7 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) duplicateValue = CreateT(seed++); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 1, collection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } } @@ -118,7 +118,7 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || enumerable == set) { set.ExceptWith(enumerable); - Assert.Equal(0, set.Count); + CollectionAsserts.HasCount(set, 0); } else { @@ -126,7 +126,7 @@ 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); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } @@ -136,7 +136,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || Enumerable.Count(enumerable) == 0) { set.IntersectWith(enumerable); - Assert.Equal(0, set.Count); + CollectionAsserts.HasCount(set, 0); } else if (set == enumerable) { @@ -152,7 +152,7 @@ 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); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } @@ -178,7 +178,7 @@ private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) break; } } - Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, set.IsProperSubsetOf(enumerable)); + CollectionAsserts.IsProperSubsetOf(set, enumerable, !setContainsValueNotInEnumerable && enumerableContainsValueNotInSet); } private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) @@ -203,7 +203,7 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) } } isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; - Assert.Equal(isProperSuperset, set.IsProperSupersetOf(enumerable)); + CollectionAsserts.IsProperSupersetOf(set, enumerable, isProperSuperset); } private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) @@ -212,10 +212,10 @@ private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) foreach (T value in set) if (!enumerable.Contains(value, comparer)) { - Assert.False(set.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, false); return; } - Assert.True(set.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, true); } private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) @@ -224,10 +224,10 @@ private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) foreach (T value in enumerable) if (!set.Contains(value, comparer)) { - Assert.False(set.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, false); return; } - Assert.True(set.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, true); } private void Validate_Overlaps(ISet set, IEnumerable enumerable) @@ -237,11 +237,11 @@ private void Validate_Overlaps(ISet set, IEnumerable enumerable) { if (set.Contains(value, comparer)) { - Assert.True(set.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, true); return; } } - Assert.False(set.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, false); } private void Validate_SetEquals(ISet set, IEnumerable enumerable) @@ -251,7 +251,7 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!enumerable.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } @@ -259,11 +259,11 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!set.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } - Assert.True(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, true); } private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) @@ -277,7 +277,7 @@ 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); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } @@ -289,7 +289,7 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) if (!set.Contains(element, comparer)) expected.Add(element); set.UnionWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } @@ -308,6 +308,15 @@ public void ISet_Generic_NullEnumerableArgument(int count) Assert.Throws(() => set.IsSupersetOf(null)); Assert.Throws(() => set.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)); @@ -502,7 +511,7 @@ public void ISet_Generic_Overlaps_Itself(int setLength) public void ISet_Generic_SetEquals_Itself(int setLength) { ISet set = GenericISetFactory(setLength); - Assert.True(set.SetEquals(set)); + CollectionAsserts.SetEquals(set, set, true); } [Theory] @@ -660,7 +669,7 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } diff --git a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs index 213d9d6faca99..6a5b458232fc5 100644 --- a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs +++ b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs @@ -61,6 +61,10 @@ public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue() IDictionary dictionary = new SortedDictionary(); Assert.True(dictionary.TryAdd("key", "value")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] @@ -69,6 +73,10 @@ public void TryAdd_KeyExistsInIDictionary_ReturnsFalse() IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; Assert.False(dictionary.TryAdd("key", "value2")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] @@ -96,6 +104,10 @@ public void Remove_KeyExistsInIDictionary_ReturnsTrue() 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 1c1095f8a5cf7..24cf81efb2b44 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))] @@ -53,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 56a03106c205b..7e3e30d8db092 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,32 @@ 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; } // Returns a collections of the keys in this dictionary. - ICollection Keys + new ICollection Keys { get; } // Returns a collections of the values in this dictionary. - ICollection Values + new ICollection Values { get; } // Returns whether this dictionary contains a particular key. // - bool ContainsKey(TKey key); + new bool ContainsKey(TKey key); // Adds a key-value pair to the dictionary. // @@ -44,6 +44,16 @@ 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); + + TValue IReadOnlyDictionary.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 f45ae823daf65..ec8098c3ff7ea 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))] @@ -46,5 +46,7 @@ public interface IList : ICollection [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 cee05d198cda0..ce2e8e7c5f4ff 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,42 @@ 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); //Check if this set is a superset of other - bool IsSupersetOf(IEnumerable other); + new bool IsSupersetOf(IEnumerable 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); //Check if this set is a superset of other, but not the same as it - bool IsProperSubsetOf(IEnumerable other); + new bool IsProperSubsetOf(IEnumerable other); //Check if this set has any elements in common with other - bool Overlaps(IEnumerable other); + new bool Overlaps(IEnumerable other); //Check if this set contains the same and only the same elements as other - bool SetEquals(IEnumerable other); + new bool SetEquals(IEnumerable 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.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 a3f2a4b07e2f4..c2f175247dc9b 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7803,29 +7803,35 @@ 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(); 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 { 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); + 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 { @@ -7840,12 +7846,13 @@ 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); + T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; } public partial interface IReadOnlyCollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -7873,19 +7880,27 @@ 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); 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); + 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 {