Skip to content

Combination of ComparingByMember and IgnoreCyclicReferences doesn't work #1370

@kostgr

Description

@kostgr

Description

If I keep it short: having override Equals on objects I have to disable using it with ComparingByMembers. But if I do so, the IgnoreCyclicReferences seem to stop working.

Here the details.

We have written a lot of NHibernate persistence tests, where we are using FluentAssertions BeEquivalentOf.
After adding a recommended for NH Equals-override in the DomainBase class we've got multiple issues with FluentAssertions.
We had to add a Configuration option ComparingByMembers<DomainBase>() to prevent FluentAssertions using Equals-override for comparing objects equivalence. And it worked nice for the most of cases, but has introduced another issue - now FluentAssertions seem to ignore the option IgnoreCyclicReferences()

Complete minimal example reproducing the issue

Here is the minimal example I could make to reproduce the issue:

[TestFixture]
public class FluentAssertionsIssueTest {
    public class Base {
        public Guid Id { get; set; }
        // NHibernate recommends overriding Equals for preventing issues with Sets and while working with multiple sessions, as well as issues with proxies in collections
        public override bool Equals(object obj)  {
            if (ReferenceEquals(this, obj))
                return true;
            return (obj is Base baseObj) && baseObj.Id == Id;
        }
    }

    public class Item : Base {
        public string Title { get; set; }
        public Item Previous { get; set; }
        public Item Next { get; set; }
    }

    [Test]
    public void IgnoreCyclicReferences_Broken()  {
        // imitating NHibernate save in one session
        var first = new Item() {Id = Guid.NewGuid(), Title = "First"};
        var second = new Item() {Id = Guid.NewGuid(), Title = "Second", Previous = first};
        first.Next = second;

        // imitating NHibernate load in another session
        var firstCopy = new Item() {Id = first.Id, Title = first.Title};
        var secondCopy = new Item() {Id = second.Id, Title = second.Title, Previous = firstCopy};
        firstCopy.Next = secondCopy;

        // I'd like to check, that all the properties could be persisted correctly.

        // "The maximum recursion depth was reached" is generated here (IgnoringCyclicReferences doesn't seem to work)
        firstCopy.Should().BeEquivalentTo(first, opt => opt.ComparingByMembers<Base>()
            .IgnoringCyclicReferences(), "they are equivalent");
        first.Title = "Changed";
        //  Removing Equals-override from Base class fixes FA issues, but introduces NHibernate-issues
        //  Removing ComparingByMembers-option removes "The maximum recursion depth was reached", but breaks this check (changed Title is not considered)
        firstCopy.Should().NotBeEquivalentTo(first, opt => opt.ComparingByMembers<Base>()
            .IgnoringCyclicReferences(), "after change");
    }
}

Expected behavior:

Deep object comparison should be done, handling cyclic references correctly. The test should pass

Actual behavior:

I cannot use deep object comparison on objects with overridden Equals and cyclic references.
The test fails with message:

The maximum recursion depth was reached.  
The maximum recursion depth was reached.  
The maximum recursion depth was reached.  
The maximum recursion depth was reached.  

With configuration:
- Use declared types and members
- Compare enums by value
- Ignoring cyclic references
- Match member by name (or throw)
- Without automatic conversion.
- Be strict about the order of items in byte arrays

   bei FluentAssertions.Execution.LateBoundTestFramework.Throw(String message)
   bei FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context)
   bei FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(EquivalencyValidationContext context)

If I comment out override Equals everything works in FA, but introduces issues with NHibernate.
If I remove options ComparingByMembers<Base>() in both BeEquivalentTo / NotBeEquivalentTo, then the difference of Title in firstCopy and first is not detected in the NotBeEquivalentTo-Check.

Versions

  • 5.10.3, 5.10.2
  • Using .NET framework 4.6.1

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions