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

Avoid allocating sub-arrays in ContainInOrder #1960

Merged
merged 1 commit into from Jul 22, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 34 additions & 36 deletions Src/FluentAssertions/Collections/GenericCollectionAssertions.cs
Expand Up @@ -920,16 +920,15 @@ public AndConstraint<TAssertions> ContainInOrder(params T[] expected)
IList<T> expectedItems = expected.ConvertOrCastToList();
IList<T> actualItems = Subject.ConvertOrCastToList();

int subjectIndex = 0;

Func<T, T, bool> areSameOrEqual = ObjectExtensions.GetComparer<T>();
for (int index = 0; index < expectedItems.Count; index++)
{
T expectedItem = expectedItems[index];
actualItems = actualItems.SkipWhile(actualItem => !areSameOrEqual(actualItem, expectedItem)).ToArray();
if (actualItems.Any())
{
actualItems = actualItems.Skip(1).ToArray();
}
else
subjectIndex = IndexOf(actualItems, expectedItem, subjectIndex, areSameOrEqual);

if (subjectIndex == -1)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand Down Expand Up @@ -2261,43 +2260,28 @@ public AndConstraint<TAssertions> NotContainInOrder(params T[] unexpected)
}

IList<T> unexpectedItems = unexpected.ConvertOrCastToList();
IList<T> actualItems = Subject.ConvertOrCastToList();

if (unexpectedItems.Count > actualItems.Count)
if (unexpectedItems.Any())
{
return new AndConstraint<TAssertions>((TAssertions)this);
}

var actualItemsSkipped = 0;
Func<T, T, bool> areSameOrEqual = ObjectExtensions.GetComparer<T>();
for (int index = 0; index < unexpectedItems.Count; index++)
{
T unexpectedItem = unexpectedItems[index];
IList<T> actualItems = Subject.ConvertOrCastToList();
int subjectIndex = 0;

actualItems = actualItems.SkipWhile(actualItem =>
Func<T, T, bool> areSameOrEqual = ObjectExtensions.GetComparer<T>();
jnyrup marked this conversation as resolved.
Show resolved Hide resolved
foreach (var unexpectedItem in unexpectedItems)
{
actualItemsSkipped++;
return !areSameOrEqual(actualItem, unexpectedItem);
}).ToArray();
subjectIndex = IndexOf(actualItems, unexpectedItem, subjectIndex, areSameOrEqual);

if (actualItems.Any())
{
if (index == unexpectedItems.Count - 1)
if (subjectIndex == -1)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith(
"Expected {context:collection} {0} to not contain items {1} in order{reason}, " +
"but items appeared in order ending at index {2}.",
Subject, unexpected, actualItemsSkipped - 1);
return new AndConstraint<TAssertions>((TAssertions)this);
}

actualItems = actualItems.Skip(1).ToArray();
}
else
{
return new AndConstraint<TAssertions>((TAssertions)this);
}

Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith(
"Expected {context:collection} {0} to not contain items {1} in order{reason}, " +
"but items appeared in order ending at index {2}.",
Subject, unexpected, subjectIndex - 1);
}

return new AndConstraint<TAssertions>((TAssertions)this);
Expand Down Expand Up @@ -3310,4 +3294,18 @@ private AndConstraint<TAssertions> NotBeInOrder(IComparer<T> comparer, SortOrder

return new AndConstraint<TAssertions>((TAssertions)this);
}

private static int IndexOf(IList<T> items, T item, int index, Func<T, T, bool> comparer)
{
for (; index < items.Count; index++)
{
if (comparer(items[index], item))
{
index++;
return index;
}
}

return -1;
}
}
Expand Up @@ -100,6 +100,20 @@ public void When_passing_in_null_while_checking_for_ordered_containment_it_shoul
"Cannot verify ordered containment against a <null> collection.*");
}

[Fact]
public void Collections_contain_the_empty_sequence()
{
// Assert
new[] { 1 }.Should().ContainInOrder(new int[0]);
}

[Fact]
public void Collections_do_not_not_contain_the_empty_sequence()
jnyrup marked this conversation as resolved.
Show resolved Hide resolved
{
// Assert
new[] { 1 }.Should().NotContainInOrder(new int[0]);
}

[Fact]
public void When_asserting_collection_contains_some_values_in_order_but_collection_is_null_it_should_throw()
{
Expand Down