Skip to content

Commit

Permalink
Add FrozenDictionary/Set (#77799)
Browse files Browse the repository at this point in the history
* Import original frozen collections source with updates to successfully compile

Co-authored-by: Martin Taillefer <mataille@microsoft.com>
Co-authored-by: Stephen Toub <stoub@microsoft.com>

* Overhaul frozen collections (API, implementation, tests)

* Address PR feedback

Co-authored-by: Martin Taillefer <mataille@microsoft.com>
  • Loading branch information
stephentoub and Martin Taillefer authored Nov 4, 2022
1 parent 182833e commit 6c5a440
Show file tree
Hide file tree
Showing 50 changed files with 4,387 additions and 295 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ public void ICollection_Generic_CopyTo_IndexEqualToArrayCount_ThrowsArgumentExce
ICollection<T> collection = GenericICollectionFactory(count);
T[] array = new T[count];
if (count > 0)
Assert.Throws<ArgumentException>(() => collection.CopyTo(array, count));
Assert.ThrowsAny<ArgumentException>(() => collection.CopyTo(array, count));
else
collection.CopyTo(array, count); // does nothing since the array is empty
}
Expand All @@ -511,7 +511,7 @@ public void ICollection_Generic_CopyTo_NotEnoughSpaceInOffsettedArray_ThrowsArgu
{
ICollection<T> collection = GenericICollectionFactory(count);
T[] array = new T[count];
Assert.Throws<ArgumentException>(() => collection.CopyTo(array, 1));
Assert.ThrowsAny<ArgumentException>(() => collection.CopyTo(array, 1));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ public void ICollection_NonGeneric_SyncRootUnique(int count)
{
ICollection collection1 = NonGenericICollectionFactory(count);
ICollection collection2 = NonGenericICollectionFactory(count);
Assert.NotSame(collection1.SyncRoot, collection2.SyncRoot);
if (!ReferenceEquals(collection1, collection2))
{
Assert.NotSame(collection1.SyncRoot, collection2.SyncRoot);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,19 @@ protected override IEnumerable<ModifyEnumerable> GetModifyEnumerables(ModifyOper
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_ItemGet_DefaultKey(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
if (!DefaultValueAllowed)
{
Assert.Throws<ArgumentNullException>(() => dictionary[default(TKey)]);
}
else
if (!IsReadOnly)
{
TValue value = CreateTValue(3452);
dictionary[default(TKey)] = value;
Assert.Equal(value, dictionary[default(TKey)]);
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
if (!DefaultValueAllowed)
{
Assert.Throws<ArgumentNullException>(() => dictionary[default(TKey)]);
}
else
{
TValue value = CreateTValue(3452);
dictionary[default(TKey)] = value;
Assert.Equal(value, dictionary[default(TKey)]);
}
}
}

Expand Down Expand Up @@ -315,16 +318,19 @@ public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count)
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_ItemSet_DefaultKey(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
if (!DefaultValueAllowed)
{
Assert.Throws<ArgumentNullException>(() => dictionary[default(TKey)] = CreateTValue(3));
}
else
if (!IsReadOnly)
{
TValue value = CreateTValue(3452);
dictionary[default(TKey)] = value;
Assert.Equal(value, dictionary[default(TKey)]);
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
if (!DefaultValueAllowed)
{
Assert.Throws<ArgumentNullException>(() => dictionary[default(TKey)] = CreateTValue(3));
}
else
{
TValue value = CreateTValue(3452);
dictionary[default(TKey)] = value;
Assert.Equal(value, dictionary[default(TKey)]);
}
}
}

Expand All @@ -344,23 +350,29 @@ public void IDictionary_Generic_ItemSet_OnReadOnlyDictionary_ThrowsNotSupportedE
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
TKey missingKey = GetNewKey(dictionary);
dictionary[missingKey] = CreateTValue(543);
Assert.Equal(count + 1, dictionary.Count);
if (!IsReadOnly)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
TKey missingKey = GetNewKey(dictionary);
dictionary[missingKey] = CreateTValue(543);
Assert.Equal(count + 1, dictionary.Count);
}
}

[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
TKey existingKey = GetNewKey(dictionary);
dictionary.Add(existingKey, CreateTValue(5342));
TValue newValue = CreateTValue(1234);
dictionary[existingKey] = newValue;
Assert.Equal(count + 1, dictionary.Count);
Assert.Equal(newValue, dictionary[existingKey]);
if (!IsReadOnly)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
TKey existingKey = GetNewKey(dictionary);
dictionary.Add(existingKey, CreateTValue(5342));
TValue newValue = CreateTValue(1234);
dictionary[existingKey] = newValue;
Assert.Equal(count + 1, dictionary.Count);
Assert.Equal(newValue, dictionary[existingKey]);
}
}

#endregion
Expand All @@ -380,42 +392,48 @@ public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count)
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TKey> keys = dictionary.Keys;
int previousCount = keys.Count;
if (count > 0)
Assert.NotEmpty(keys);
dictionary.Clear();
if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection)
{
Assert.Empty(keys);
}
else
if (!IsReadOnly)
{
Assert.Equal(previousCount, keys.Count);
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TKey> keys = dictionary.Keys;
int previousCount = keys.Count;
if (count > 0)
Assert.NotEmpty(keys);
dictionary.Clear();
if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection)
{
Assert.Empty(keys);
}
else
{
Assert.Equal(previousCount, keys.Count);
}
}
}

[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalidates(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TKey> keys = dictionary.Keys;
IEnumerator<TKey> keysEnum = keys.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
Assert.Throws<InvalidOperationException>(() => keysEnum.MoveNext());
Assert.Throws<InvalidOperationException>(() => keysEnum.Reset());
}
else
if (!IsReadOnly)
{
if (keysEnum.MoveNext())
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TKey> keys = dictionary.Keys;
IEnumerator<TKey> keysEnum = keys.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
_ = keysEnum.Current;
Assert.Throws<InvalidOperationException>(() => keysEnum.MoveNext());
Assert.Throws<InvalidOperationException>(() => keysEnum.Reset());
}
else
{
if (keysEnum.MoveNext())
{
_ = keysEnum.Current;
}
keysEnum.Reset();
}
keysEnum.Reset();
}
}

Expand Down Expand Up @@ -461,16 +479,19 @@ public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count)
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
int seed = 431;
foreach (KeyValuePair<TKey, TValue> pair in dictionary.ToList())
if (!IsReadOnly)
{
TKey missingKey = CreateTKey(seed++);
while (dictionary.ContainsKey(missingKey))
missingKey = CreateTKey(seed++);
dictionary.Add(missingKey, pair.Value);
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
int seed = 431;
foreach (KeyValuePair<TKey, TValue> pair in dictionary.ToList())
{
TKey missingKey = CreateTKey(seed++);
while (dictionary.ContainsKey(missingKey))
missingKey = CreateTKey(seed++);
dictionary.Add(missingKey, pair.Value);
}
Assert.Equal(count * 2, dictionary.Values.Count);
}
Assert.Equal(count * 2, dictionary.Values.Count);
}

[Theory]
Expand All @@ -482,37 +503,44 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio
int previousCount = values.Count;
if (count > 0)
Assert.NotEmpty(values);
dictionary.Clear();
if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection)
{
Assert.Empty(values);
}
else

if (!IsReadOnly)
{
Assert.Equal(previousCount, values.Count);
dictionary.Clear();
if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection)
{
Assert.Empty(values);
}
else
{
Assert.Equal(previousCount, values.Count);
}
}
}

[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInvalidates(int count)
{
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TValue> values = dictionary.Values;
IEnumerator<TValue> valuesEnum = values.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
Assert.Throws<InvalidOperationException>(() => valuesEnum.MoveNext());
Assert.Throws<InvalidOperationException>(() => valuesEnum.Reset());
}
else
if (!IsReadOnly)
{
if (valuesEnum.MoveNext())
IDictionary<TKey, TValue> dictionary = GenericIDictionaryFactory(count);
ICollection<TValue> values = dictionary.Values;
IEnumerator<TValue> valuesEnum = values.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
_ = valuesEnum.Current;
Assert.Throws<InvalidOperationException>(() => valuesEnum.MoveNext());
Assert.Throws<InvalidOperationException>(() => valuesEnum.Reset());
}
else
{
if (valuesEnum.MoveNext())
{
_ = valuesEnum.Current;
}
valuesEnum.Reset();
}
valuesEnum.Reset();
}
}

Expand Down
Loading

0 comments on commit 6c5a440

Please sign in to comment.