diff --git a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs index 2fa8ca7c7a..93de6b5bb8 100644 --- a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs @@ -920,16 +920,15 @@ public AndConstraint ContainInOrder(params T[] expected) IList expectedItems = expected.ConvertOrCastToList(); IList actualItems = Subject.ConvertOrCastToList(); + int subjectIndex = 0; + Func areSameOrEqual = ObjectExtensions.GetComparer(); 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) @@ -2261,43 +2260,28 @@ public AndConstraint NotContainInOrder(params T[] unexpected) } IList unexpectedItems = unexpected.ConvertOrCastToList(); - IList actualItems = Subject.ConvertOrCastToList(); - - if (unexpectedItems.Count > actualItems.Count) + if (unexpectedItems.Any()) { - return new AndConstraint((TAssertions)this); - } - - var actualItemsSkipped = 0; - Func areSameOrEqual = ObjectExtensions.GetComparer(); - for (int index = 0; index < unexpectedItems.Count; index++) - { - T unexpectedItem = unexpectedItems[index]; + IList actualItems = Subject.ConvertOrCastToList(); + int subjectIndex = 0; - actualItems = actualItems.SkipWhile(actualItem => + Func areSameOrEqual = ObjectExtensions.GetComparer(); + 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)this); } - - actualItems = actualItems.Skip(1).ToArray(); - } - else - { - return new AndConstraint((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)this); @@ -3310,4 +3294,18 @@ private AndConstraint NotBeInOrder(IComparer comparer, SortOrder return new AndConstraint((TAssertions)this); } + + private static int IndexOf(IList items, T item, int index, Func comparer) + { + for (; index < items.Count; index++) + { + if (comparer(items[index], item)) + { + index++; + return index; + } + } + + return -1; + } } diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainInOrder.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainInOrder.cs index b9065c6a2a..b16d1ca46a 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainInOrder.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainInOrder.cs @@ -100,6 +100,20 @@ public void When_passing_in_null_while_checking_for_ordered_containment_it_shoul "Cannot verify ordered containment against a 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() + { + // 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() {