0

I've been having some trouble with FluentAssertions lately, and after playing around with it a little bit, it seems like there is some sort of bug that may have something to do with Guids. Here's the code that throws an error:

    class Dto
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }



    [TestMethod]
    public void TestTest()
    {
        var dto1 =
            new List<Dto>
            {
                new Dto { Id = Guid.NewGuid(), Name = "Name" }
            };
        var dto2 =
            new List<Dto>
            {
                new Dto { Id = Guid.NewGuid(), Name = "Name" }
            };
        var list1 = new List<List<Dto>> { dto1, dto2 };
        var list2 = new List<List<Dto>> { dto2, dto1 };
        list1.ShouldAllBeEquivalentTo(list2);
    }

Note the reversed order in list1 and list2, which is essential to reproduce the error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list. Result StackTrace:
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) in C:\projects\fluentassertions-vf06b\Src\Core\Execution\MessageBuilder.cs:line 66 at FluentAssertions.Execution.MessageBuilder.Build(String message, Object[] messageArgs, String reason, ContextDataItems contextData) in C:\projects\fluentassertions-vf06b\Src\Core\Execution\MessageBuilder.cs:line 39 at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args) in C:\projects\fluentassertions-vf06b\Src\Core\Execution\AssertionScope.cs:line 190 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.LooselyMatchAgainst[T](IList`1 subjects, Object expectation, Int32 expectationIndex) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 123 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.AssertElementGraphEquivalency[T](T[] subjects, Object[] expectations) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 79 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.Execute[T](T[] subject, Object[] expectation) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 39 at lambda_method(Closure ) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Delegate.DynamicInvokeImpl(Object[] args) at FluentAssertions.Equivalency.GenericEnumerableEquivalencyStep.Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\GenericEnumerableEquivalencyStep.cs:line 61 at FluentAssertions.Equivalency.EquivalencyValidator.AssertEqualityUsing(IEquivalencyValidationContext context) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EquivalencyValidator.cs:line 63 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.TryToMatch[T](T subject, Object expectation, Int32 expectationIndex) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 133 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.LooselyMatchAgainst[T](IList`1 subjects, Object expectation, Int32 expectationIndex) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 106 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.AssertElementGraphEquivalency[T](T[] subjects, Object[] expectations) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 79 at FluentAssertions.Equivalency.EnumerableEquivalencyValidator.Execute[T](T[] subject, Object[] expectation) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EnumerableEquivalencyValidator.cs:line 39 at lambda_method(Closure ) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Delegate.DynamicInvokeImpl(Object[] args) at FluentAssertions.Equivalency.GenericEnumerableEquivalencyStep.Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\GenericEnumerableEquivalencyStep.cs:line 61 at FluentAssertions.Equivalency.EquivalencyValidator.AssertEqualityUsing(IEquivalencyValidationContext context) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EquivalencyValidator.cs:line 63 at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(EquivalencyValidationContext context) in C:\projects\fluentassertions-vf06b\Src\Core\Equivalency\EquivalencyValidator.cs:line 35 at FluentAssertions.AssertionExtensions.ShouldAllBeEquivalentTo[T](IEnumerable`1 subject, IEnumerable expectation, Func`2 config, String because, Object[] becauseArgs) in C:\projects\fluentassertions-vf06b\Src\Shared\AssertionExtensions.cs:line 680 at FluentAssertions.AssertionExtensions.ShouldAllBeEquivalentTo[T](IEnumerable`1 subject, IEnumerable expectation, String because, Object[] becauseArgs) in C:\projects\fluentassertions-vf06b\Src\Shared\AssertionExtensions.cs:line 637 at (Where my code is)

Sorry for the long stack trace, but I wanted to include anything that might be relevant.

What's going on here? Is there something I'm missing?

yinnonsanders
  • 1,831
  • 11
  • 28
  • 1
    For reference: http://fluentassertions.com/documentation.html#collections-and-dictionaries – yinnonsanders Aug 03 '17 at 21:05
  • 1
    Does it work without using `Guid`? Given that the exception is being thrown by a string formatter trying to format a failure message, I suspect that the failure message is appending the guid as a string (e.g. `{25afc5e0-6fbb-4762-a357-562d8a464c78}`, which gets interpreted as a formatting placeholder – D Stanley Aug 03 '17 at 21:10
  • @DStanley The error doesn't occur when I use `short`, for instance. That seems like a good interpretation of what's happening. – yinnonsanders Aug 03 '17 at 21:14
  • 2
    Gvien that the [author is on SO](https://stackoverflow.com/users/253961/dennis-doomen) you might get a direct answer; in the meantime you can [report an issue on GitHub](https://github.com/fluentassertions/fluentassertions/issues) – D Stanley Aug 03 '17 at 21:17
  • I will! Just wanted to make sure this was an actual bug and not just something I didn't understand correctly. – yinnonsanders Aug 03 '17 at 21:19
  • @yinnonsanders I was able to reproduce the error even comparing dto1 to dto2 – Nkosi Aug 03 '17 at 21:20
  • @Nkosi Interesting. Although that's not quite as bad because `dto1` and `dto2` are not equivalent, but FluentAssertions should give a helpful error message. – yinnonsanders Aug 03 '17 at 21:24
  • @yinnonsanders yes, strange indeed. Just thought I'd mention that so it could be included when you raise the issue with the author. – Nkosi Aug 03 '17 at 21:25
  • 1
    Yep. Definitely a bug. If you're willing to file a bug, it shouldn't take long to fix that. – Dennis Doomen Aug 04 '17 at 04:17

0 Answers0