Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OrderedDictionary #103309

Merged
merged 7 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ namespace System.Collections.Generic
/// </summary>
internal static partial class EnumerableHelpers
{
/// <summary>Calls Reset on an enumerator instance.</summary>
/// <remarks>Enables Reset to be called without boxing on a struct enumerator that lacks a public Reset.</remarks>
internal static void Reset<T>(ref T enumerator) where T : IEnumerator => enumerator.Reset();

/// <summary>Gets an enumerator singleton for an empty collection.</summary>
internal static IEnumerator<T> GetEmptyEnumerator<T>() =>
((IEnumerable<T>)Array.Empty<T>()).GetEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,6 @@ public virtual void IDictionary_NonGeneric_Values_Enumeration_ParentDictionaryMo
{
Assert.Throws<InvalidOperationException>(() => valuesEnum.MoveNext());
Assert.Throws<InvalidOperationException>(() => valuesEnum.Reset());
Assert.Throws<InvalidOperationException>(() => valuesEnum.Current);
}
else
{
Expand Down Expand Up @@ -832,7 +831,7 @@ public virtual void IDictionary_NonGeneric_IDictionaryEnumerator_Current_AfterEn
object current, key, value, entry;
IDictionaryEnumerator enumerator = NonGenericIDictionaryFactory(count).GetEnumerator();
while (enumerator.MoveNext()) ;
if (Enumerator_Current_UndefinedOperation_Throws)
if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throw : Enumerator_Current_UndefinedOperation_Throws)
{
Assert.Throws<InvalidOperationException>(() => enumerator.Current);
Assert.Throws<InvalidOperationException>(() => enumerator.Key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ public abstract partial class IEnumerable_NonGeneric_Tests : TestBase
/// </summary>
protected virtual bool Enumerator_Current_UndefinedOperation_Throws => false;

/// <summary>
/// When calling Current of the empty enumerator before the first MoveNext, after the end of the collection,
/// or after modification of the enumeration, the resulting behavior is undefined. Tests are included
/// to cover two behavioral scenarios:
/// - Throwing an InvalidOperationException
/// - Returning an undefined value.
///
/// If this property is set to true, the tests ensure that the exception is thrown. The default value is
/// false.
/// </summary>
protected virtual bool Enumerator_Empty_Current_UndefinedOperation_Throw => Enumerator_Current_UndefinedOperation_Throws;

/// <summary>
/// When calling MoveNext or Reset after modification of the enumeration, the resulting behavior is
/// undefined. Tests are included to cover two behavioral scenarios:
Expand Down Expand Up @@ -305,7 +317,7 @@ public virtual void Enumerator_Current_BeforeFirstMoveNext_UndefinedBehavior(int
object current;
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
if (Enumerator_Current_UndefinedOperation_Throws)
if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throw : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws<InvalidOperationException>(() => enumerator.Current);
else
current = enumerator.Current;
Expand All @@ -319,7 +331,7 @@ public virtual void Enumerator_Current_AfterEndOfEnumerable_UndefinedBehavior(in
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) ;
if (Enumerator_Current_UndefinedOperation_Throws)
if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throw : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws<InvalidOperationException>(() => enumerator.Current);
else
current = enumerator.Current;
Expand All @@ -336,7 +348,7 @@ public virtual void Enumerator_Current_ModifiedDuringEnumeration_UndefinedBehavi
IEnumerator enumerator = enumerable.GetEnumerator();
if (ModifyEnumerable(enumerable))
{
if (Enumerator_Current_UndefinedOperation_Throws)
if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throw : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws<InvalidOperationException>(() => enumerator.Current);
else
current = enumerator.Current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,31 @@ protected override IEnumerable<ModifyEnumerable> GetModifyEnumerables(ModifyOper
public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count)
{
IList<T> list = GenericIListFactory(count);

Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]);
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]);

if (list is IReadOnlyList<T> rol)
{
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => rol[-1]);
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => rol[int.MinValue]);
}
}

[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count)
{
IList<T> list = GenericIListFactory(count);

Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]);
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]);

if (list is IReadOnlyList<T> rol)
{
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => rol[count]);
Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => rol[count + 1]);
}
}

[Theory]
Expand All @@ -122,7 +136,15 @@ public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count)
{
IList<T> list = GenericIListFactory(count);
T result;

Assert.All(Enumerable.Range(0, count), index => result = list[index]);
Assert.All(Enumerable.Range(0, count), index => Assert.Equal(list[index], list[index]));

if (list is IReadOnlyList<T> rol)
{
Assert.All(Enumerable.Range(0, count), index => result = rol[index]);
Assert.All(Enumerable.Range(0, count), index => Assert.Equal(rol[index], rol[index]));
}
}

#endregion
Expand Down Expand Up @@ -369,7 +391,7 @@ public void IList_Generic_IndexOf_InvalidValue(int count)
[MemberData(nameof(ValidCollectionSizes))]
public void IList_Generic_IndexOf_ReturnsFirstMatchingValue(int count)
{
if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported)
if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported && DuplicateValuesAllowed)
{
IList<T> list = GenericIListFactory(count);
foreach (T duplicate in list.ToList()) // hard copies list to circumvent enumeration error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ protected virtual object CreateT(int seed)
/// </summary>
protected virtual bool IList_CurrentAfterAdd_Throws => Enumerator_Current_UndefinedOperation_Throws;

/// <summary>
/// When calling Current of the empty enumerator after the end of the list and list is extended by new items.
/// Tests are included to cover two behavioral scenarios:
/// - Throwing an InvalidOperationException
/// - Returning an undefined value.
///
/// If this property is set to true, the tests ensure that the exception is thrown. The default value is
/// the same as Enumerator_Current_UndefinedOperation_Throws.
/// </summary>
protected virtual bool IList_Empty_CurrentAfterAdd_Throws => Enumerator_Empty_Current_UndefinedOperation_Throw;

#endregion

#region ICollection Helper Methods
Expand Down Expand Up @@ -697,7 +708,7 @@ public void IList_NonGeneric_IndexOf_InvalidValue(int count)
[MemberData(nameof(ValidCollectionSizes))]
public void IList_NonGeneric_IndexOf_ReturnsFirstMatchingValue(int count)
{
if (!IsReadOnly && !ExpectedFixedSize)
if (!IsReadOnly && !ExpectedFixedSize && DuplicateValuesAllowed)
{
IList list = NonGenericIListFactory(count);

Expand Down Expand Up @@ -1084,7 +1095,7 @@ public void IList_NonGeneric_CurrentAtEnd_AfterAdd(int count)
IEnumerator enumerator = collection.GetEnumerator();
while (enumerator.MoveNext()) ; // Go to end of enumerator

if (Enumerator_Current_UndefinedOperation_Throws)
if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throw : Enumerator_Current_UndefinedOperation_Throws)
{
Assert.Throws<InvalidOperationException>(() => enumerator.Current); // Enumerator.Current should fail
}
Expand All @@ -1099,7 +1110,7 @@ public void IList_NonGeneric_CurrentAtEnd_AfterAdd(int count)
{
collection.Add(CreateT(seed++));

if (IList_CurrentAfterAdd_Throws)
if (count == 0 ? IList_Empty_CurrentAfterAdd_Throws : IList_CurrentAfterAdd_Throws)
{
Assert.Throws<InvalidOperationException>(() => enumerator.Current); // Enumerator.Current should fail
}
Expand Down
Loading
Loading