Skip to content

Commit

Permalink
ContainItemsAssignableTo Now Expects At Least One Item Assignable t…
Browse files Browse the repository at this point in the history
…o `T` (#1765)
  • Loading branch information
MullerWasHere committed Jan 10, 2022
1 parent c7fe3e6 commit 305b36a
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 62 deletions.
33 changes: 11 additions & 22 deletions Src/FluentAssertions/Collections/GenericCollectionAssertions.cs
Expand Up @@ -946,7 +946,7 @@ public AndConstraint<TAssertions> ContainInOrder(params T[] expected)
}

/// <summary>
/// Asserts that the current collection only contains items that are assignable to the type <typeparamref name="TExpectation" />.
/// Asserts that the current collection contains at least one element that is assignable to the type <typeparamref name="TExpectation" />.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
Expand All @@ -957,29 +957,18 @@ public AndConstraint<TAssertions> ContainInOrder(params T[] expected)
/// </param>
public AndConstraint<TAssertions> ContainItemsAssignableTo<TExpectation>(string because = "", params object[] becauseArgs)
{
bool success = Execute.Assertion
Execute.Assertion
.BecauseOf(because, becauseArgs)
.WithExpectation("Expected {context:collection} to contain at least one element assignable to type {0}{reason}, ",
typeof(TExpectation).FullName)
.ForCondition(Subject is not null)
.FailWith("Expected {context:collection} to contain element assignable to type {0}{reason}, but found <null>.",
typeof(TExpectation));

if (success)
{
int index = 0;
foreach (T item in Subject)
{
if (item is not TExpectation)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith(
"Expected {context:collection} to contain only items of type {0}{reason}" +
", but item {1} at index {2} is of type {3}.", typeof(TExpectation), item, index, item.GetType());
}

++index;
}
}
.FailWith("but found <null>.")
.Then
.Given(() => Subject.ConvertOrCastToCollection())
.ForCondition(subject => subject.Any(x => typeof(TExpectation).IsAssignableFrom(GetType(x))))
.FailWith("but found {0}.", subject => subject.Select(x => GetType(x)))
.Then
.ClearExpectation();

return new AndConstraint<TAssertions>((TAssertions)this);
}
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Common/Configuration.cs
Expand Up @@ -76,7 +76,7 @@ private ValueFormatterDetectionMode DetermineFormatterDetectionMode()

/// <summary>
/// Gets or sets the assembly name to scan for custom value formatters in case <see cref="ValueFormatterDetectionMode"/>
/// is set to <see cref="ValueFormatterDetectionMode.Specific"/>.
/// is set to <see cref="Common.ValueFormatterDetectionMode.Specific"/>.
/// </summary>
public string ValueFormatterAssembly
{
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Execution/GivenSelector.cs
Expand Up @@ -49,7 +49,7 @@ public GivenSelector<T> ForCondition(Func<T, bool> predicate)
/// The <paramref name="selector"/> will not be invoked if the prior assertion failed,
/// nor will <see cref="FailWith(string, Func{T,object}[])"/> throw any exceptions.
/// </remarks>
/// <inheritdoc cref="IAssertionScope.Given"/>
/// <inheritdoc cref="IAssertionScope.Given{T}"/>
public GivenSelector<TOut> Given<TOut>(Func<T, TOut> selector)
{
Guard.ThrowIfArgumentIsNull(selector, nameof(selector));
Expand Down
Expand Up @@ -24,7 +24,7 @@ public void Should_succeed_when_asserting_collection_with_all_items_of_same_type
}

[Fact]
public void Should_fail_when_asserting_collection_with_items_of_different_types_only_contains_item_of_one_type()
public void Should_succeed_when_asserting_collection_with_items_of_different_types_contains_item_of_expected_type()
{
// Arrange
var collection = new List<object>
Expand All @@ -33,68 +33,50 @@ public void Should_fail_when_asserting_collection_with_items_of_different_types_
"2"
};

// Act
Action act = () => collection.Should().ContainItemsAssignableTo<string>();

// Assert
act.Should().Throw<XunitException>();
// Act / Assert
collection.Should().ContainItemsAssignableTo<string>();
}

[Fact]
public void When_a_collection_contains_anything_other_than_strings_it_should_throw_and_report_details()
public void When_asserting_collection_contains_item_assignable_to_against_null_collection_it_should_throw()
{
// Arrange
var collection = new List<object>
{
1,
"2"
};
int[] collection = null;

// Act
Action act = () => collection.Should().ContainItemsAssignableTo<string>();
Action act = () =>
{
using var _ = new AssertionScope();
collection.Should().ContainItemsAssignableTo<string>("because we want to test the behaviour with a null subject");
};

// Assert
act.Should().Throw<XunitException>().WithMessage(
"Expected collection to contain only items of type System.String, but item 1 at index 0 is of type System.Int32.");
"Expected collection to contain at least one element assignable to type \"System.String\" because we want to test the behaviour with a null subject, but found <null>.");
}

[Fact]
public void When_a_collection_contains_anything_other_than_strings_it_should_use_the_reason()
public void When_a_collection_is_empty_an_exception_should_be_thrown()
{
// Arrange
var collection = new List<object>
{
1,
"2"
};
int[] collection = Array.Empty<int>();

// Act
Action act = () => collection.Should().ContainItemsAssignableTo<string>(
"because we want to test the failure {0}", "message");
Action act = () => collection.Should().ContainItemsAssignableTo<int>();

// Assert
act.Should().Throw<XunitException>()
.WithMessage(
"Expected collection to contain only items of type System.String because we want to test the failure message" +
", but item 1 at index 0 is of type System.Int32.");
act.Should().Throw<XunitException>().WithMessage("Expected collection to contain at least one element assignable to type \"System.Int32\", but found {empty}.");
}

[Fact]
public void When_asserting_collection_contains_item_assignable_to_against_null_collection_it_should_throw()
public void Should_throw_exception_when_asserting_collection_for_missing_item_type()
{
// Arrange
int[] collection = null;
var collection = new object[] { "1", 1.0m };

// Act
Action act = () =>
{
using var _ = new AssertionScope();
collection.Should().ContainItemsAssignableTo<string>("because we want to test the behaviour with a null subject");
};
Action act = () => collection.Should().ContainItemsAssignableTo<int>();

// Assert
act.Should().Throw<XunitException>().WithMessage(
"Expected collection to contain element assignable to type System.String because we want to test the behaviour with a null subject, but found <null>.");
act.Should().Throw<XunitException>()
.WithMessage("Expected collection to contain at least one element assignable to type \"System.Int32\", but found {System.String, System.Decimal}.");
}

#endregion
Expand Down
1 change: 1 addition & 0 deletions docs/_pages/releases.md
Expand Up @@ -14,6 +14,7 @@ sidebar:
* Adding new assertions for the `HttpStatusCode` of an `HttpResponseMessage` - [#1737](https://github.com/fluentassertions/fluentassertions/pull/1737)

### Fixes
* `ContainItemsAssignableTo` now expects at least one item assignable to `T` - [#1765](https://github.com/fluentassertions/fluentassertions/pull/1765)
* Querying methods on classes, e.g. `typeof(MyController).Methods()`, now also includes static methods - [#1740](https://github.com/fluentassertions/fluentassertions/pull/1740)

## 6.3.0
Expand Down

0 comments on commit 305b36a

Please sign in to comment.