Skip to content

AssertionScope.FormattingOptions configured in surrounding AssertionScope do not seem to be respected by Should().BeEquivalentTo(collection) #2170

@jkalmeij

Description

@jkalmeij

Description

AssertionScope.FormattingOptions configured in surrounding AssertionScope do not seem to be respected by Should().BeEquivalentTo(collection)

Could be that this is not a bug (couldn't find any documentation on this), but I do think it is confusing.

See attached reproduction steps.

When I configure the FormattingOptions on a newly created AssertionScope, the FormattingOptions are not respected when EquivalentTo assertion fails. (I used MaxDepth as an example to demonstrate; it seems the FormattingOptions are not respected entirely)

I took a brief look at the source code and it could be as simple as (but honestly I didn't think about the repercussions):

    private AssertionScope(IAssertionStrategy assertionStrategy, AssertionScope parent)
    {
        this.assertionStrategy = assertionStrategy
                                 ?? throw new ArgumentNullException(nameof(assertionStrategy));
        this.parent = parent;
    
        if (parent is not null)
        {
            contextData.Add(parent.contextData);
            Context = parent.Context;
            callerIdentityProvider = parent.callerIdentityProvider;
+           formattingOptions = parent.FormattingOptions.Clone();
        }
    }

Reproduction Steps

private class Container
{
    public Guid Id { get; set; }
    
    public Child1[] Children { get; set; }

    public class Child1
    {
        public Guid Id { get; set; }

        public Child2[] Children { get; set; }
    }

    public class Child2
    {
        public string StringProperty { get; set; }

        public int IntProperty { get; set; }
    }
}

[TestMethod]
public void Scope_Formatting_Options_Not_Respected()
{
    var a = new[]
    {
        new Container()
        {
            Id = Guid.NewGuid(),
            Children = new []
            {
                new Container.Child1()
                {
                    Id = Guid.NewGuid(),
                    Children = new []
                    {
                        new Container.Child2()
                        {
                            StringProperty = "A",
                            IntProperty = 1,
                        }
                    }
                }
            }
        }
    };
    var b = new[]
    {
        new Container()
        {
            Id = Guid.NewGuid(),
            Children = new []
            {
                new Container.Child1()
                {
                    Id = Guid.NewGuid(),
                    Children = new []
                    {
                        new Container.Child2()
                        {
                            StringProperty = "B",
                            IntProperty = 1,
                        }
                    }
                }
            }
        },
        new Container()
        {
            Id = Guid.NewGuid(),
            Children = new []
            {
                new Container.Child1()
                {
                    Id = Guid.NewGuid(),
                    Children = new []
                    {
                        new Container.Child2()
                        {
                            StringProperty = "B",
                            IntProperty = 1,
                        }
                    }
                }
            }
        },
    };

    var messageWithoutMaxDepthRespected = "";
    try
    {
        using (var scope = new AssertionScope())
        {
            scope.FormattingOptions.MaxDepth = 1;
            a.Should().BeEquivalentTo(b);
        }
    }
    catch (Exception ex)
    {
        messageWithoutMaxDepthRespected = ex.Message;
    }

    AssertionOptions.FormattingOptions.MaxDepth = 1;
    var messageWithMaxDepthCorrectlyRespected = "";
    try
    {
        a.Should().BeEquivalentTo(b);
    }
    catch (Exception ex)
    {
        messageWithMaxDepthCorrectlyRespected = ex.Message;
    }

    messageWithMaxDepthCorrectlyRespected.Should().Be(messageWithoutMaxDepthRespected);
}

Expected behavior

Should state Maximum recursion depth of 1 was reached

Actual behavior

States Maximum recursion depth of 5 was reached

Regression?

Don't know.

Known Workarounds

Use AssertionOptions.FormattingOptions and manually reset them at the end of the AssertionScope.

Configuration

.NET Framework 4.8
FluentAssertions 6.10.0

Other information

No response

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