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

ContainItemsAssignableTo Now Expects At Least One Item Assignable to T #1765

Merged
merged 9 commits into from Jan 10, 2022
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)
{
MullerWasHere marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -13,6 +13,7 @@ sidebar:
* Adding `ThatAreStatic()` and `ThatAreNotStatic()` for filtering in method assertions - [#1740](https://github.com/fluentassertions/fluentassertions/pull/1740)

### 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