Skip to content

When chaining ContainsSingle, assertion failed because of FormatException inside FluentAssertion instead of actual difference #1404

@gcelet

Description

@gcelet

Description

When chaining ContainsSingle, assertion failed because of FormatException inside FluentAssertion instead of actual difference.

Complete minimal example reproducing the issue

using FluentAssertions;
using Microsoft.AspNetCore.Mvc.ModelBinding;

[Test]
public void Failed_On_FormatException_Inside_FluentAssertions_When_Strings_Are_Different()
{
    string propertyName = "APropertyName";
    string value = "A value";
    ModelStateDictionary modelState = new ModelStateDictionary();

    modelState.AddModelError(propertyName, $"The value '{value}' is invalid and more characters to be different than expected.");

    modelState.Should().HaveCount(1)
        .And.ContainSingle(kvp => kvp.Key == propertyName)
        .Which.Value.Errors.Should().HaveCount(1)
        .And.ContainSingle(modelError =>
            string.Equals(modelError.ErrorMessage, $"The value '{value}' is invalid."));
}

[Test]
public void Succeed_When_Strings_Are_Same()
{
    string propertyName = "APropertyName";
    string value = "A value";
    ModelStateDictionary modelState = new ModelStateDictionary();

    modelState.AddModelError(propertyName, $"The value '{value}' is invalid.");

    modelState.Should().HaveCount(1)
        .And.ContainSingle(kvp => kvp.Key == propertyName)
        .Which.Value.Errors.Should().HaveCount(1)
        .And.ContainSingle(modelError =>
            string.Equals(modelError.ErrorMessage, $"The value '{value}' is invalid."));
}

Expected behavior:

Failed_On_FormatException_Inside_FluentAssertions_When_Strings_Are_Different test should failed because actual string is different of expected string.

Actual behavior:

Failed_On_FormatException_Inside_FluentAssertions_When_Strings_Are_Different test failed on System.FormatException.

System.FormatException : Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
   at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
   at System.String.Format(String format, Object[] args)
   at FluentAssertions.Execution.MessageBuilder.FormatArgumentPlaceholders(String failureMessage, Object[] failureArgs)
   at FluentAssertions.Execution.MessageBuilder.Build(String message, Object[] messageArgs, String reason, ContextDataItems contextData, String identifier, String fallbackIdentifier)
   at FluentAssertions.Execution.AssertionScope.<>c__DisplayClass30_0.<FailWith>b__0()
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Collections.SelfReferencingCollectionAssertions`2.ContainSingle(Expression`1 predicate, String because, Object[] becauseArgs)

Versions

  • Which version of Fluent Assertions are you using?
    5.10.3

  • Which .NET runtime and version are you targeting?
    .NET Core 3.1

Additional Information

I tried with FluentAssertions 6.0.0-alpha0001: same behavior as 5.10.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions