diff --git a/Directory.Build.props b/Directory.Build.props
index 5c2d966030..c675073db2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,7 +23,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Src/FluentAssertions/Equivalency/EquivalencyValidator.cs b/Src/FluentAssertions/Equivalency/EquivalencyValidator.cs
index 233e558afa..230952a4aa 100644
--- a/Src/FluentAssertions/Equivalency/EquivalencyValidator.cs
+++ b/Src/FluentAssertions/Equivalency/EquivalencyValidator.cs
@@ -35,7 +35,11 @@ public void RecursivelyAssertEquality(Comparands comparands, IEquivalencyValidat
{
TrackWhatIsNeededToProvideContextToFailures(scope, comparands, context.CurrentNode);
- if (!context.IsCyclicReference(comparands.Expectation))
+ if (context.IsCyclicReference(comparands.Expectation))
+ {
+ AssertComparandsPointToActualObjects(comparands);
+ }
+ else
{
TryToProveNodesAreEquivalent(comparands, context);
}
@@ -62,6 +66,19 @@ private static void TrackWhatIsNeededToProvideContextToFailures(AssertionScope s
scope.TrackComparands(comparands.Subject, comparands.Expectation);
}
+ private static void AssertComparandsPointToActualObjects(Comparands comparands)
+ {
+ if (ReferenceEquals(comparands.Subject, comparands.Expectation))
+ {
+ return;
+ }
+
+ if (comparands.Subject is null)
+ {
+ comparands.Subject.Should().BeSameAs(comparands.Expectation);
+ }
+ }
+
private void TryToProveNodesAreEquivalent(Comparands comparands, IEquivalencyValidationContext context)
{
using var _ = context.Tracer.WriteBlock(node => node.Description);
diff --git a/Tests/FluentAssertions.Equivalency.Specs/CyclicReferencesSpecs.cs b/Tests/FluentAssertions.Equivalency.Specs/CyclicReferencesSpecs.cs
index ca99887b63..b57ed1a148 100644
--- a/Tests/FluentAssertions.Equivalency.Specs/CyclicReferencesSpecs.cs
+++ b/Tests/FluentAssertions.Equivalency.Specs/CyclicReferencesSpecs.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using JetBrains.Annotations;
using Xunit;
using Xunit.Sdk;
@@ -68,6 +69,73 @@ public void By_default_cyclic_references_are_not_valid()
.WithMessage("Expected property cyclicRoot.Level.Root to be*but it contains a cyclic reference*");
}
+ [Fact]
+ public void The_cyclic_reference_itself_will_be_compared_using_simple_equality()
+ {
+ // Arrange
+ var expectedChild = new Child
+ {
+ Stuff = 1
+ };
+
+ var expectedParent = new Parent
+ {
+ Child1 = expectedChild
+ };
+
+ expectedChild.Parent = expectedParent;
+
+ var actualChild = new Child
+ {
+ Stuff = 1
+ };
+
+ var actualParent = new Parent
+ {
+ Child1 = actualChild
+ };
+
+ // Act
+ var act = () => actualParent.Should().BeEquivalentTo(expectedParent, options => options.IgnoringCyclicReferences());
+
+ // Assert
+ act.Should().Throw()
+ .WithMessage("Expected property actualParent.Child1.Parent to refer to*but found*null*");
+ }
+
+ [Fact]
+ public void The_cyclic_reference_can_be_ignored_if_the_comparands_point_to_the_same_object()
+ {
+ // Arrange
+ var expectedChild = new Child
+ {
+ Stuff = 1
+ };
+
+ var expectedParent = new Parent
+ {
+ Child1 = expectedChild
+ };
+
+ expectedChild.Parent = expectedParent;
+
+ var actualChild = new Child
+ {
+ Stuff = 1
+ };
+
+ var actualParent = new Parent
+ {
+ Child1 = actualChild
+ };
+
+ // Connect this child to the same parent as the expectation child
+ actualChild.Parent = expectedParent;
+
+ // Act
+ actualParent.Should().BeEquivalentTo(expectedParent, options => options.IgnoringCyclicReferences());
+ }
+
[Fact]
public void Two_graphs_with_ignored_cyclic_references_can_be_compared()
{
@@ -93,20 +161,23 @@ private class Parent
{
public Child Child1 { get; set; }
+ [UsedImplicitly]
public Child Child2 { get; set; }
}
private class Child
{
- public Child(Parent parent, int stuff = 0)
+ public Child(Parent parent = null, int stuff = 0)
{
Parent = parent;
Stuff = stuff;
}
- public Parent Parent { get; }
+ [UsedImplicitly]
+ public Parent Parent { get; set; }
- public int Stuff { get; }
+ [UsedImplicitly]
+ public int Stuff { get; set; }
}
[Fact]
@@ -216,7 +287,7 @@ public void Can_ignore_cyclic_references_for_inequivalency_assertions()
// Act / Assert
recursiveClass1.Should().NotBeEquivalentTo(recursiveClass2,
- options => options.AllowingInfiniteRecursion());
+ options => options.AllowingInfiniteRecursion());
}
[Fact]
diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md
index dacd0b0866..96620b92f4 100644
--- a/docs/_pages/releases.md
+++ b/docs/_pages/releases.md
@@ -7,6 +7,12 @@ sidebar:
nav: "sidebar"
---
+## 6.12.3
+
+### Fixes
+
+* The expectation node identified as a cyclic reference is still compared to the subject node using simple equality - [2819](https://github.com/fluentassertions/fluentassertions/pull/2819)
+
## 6.12.2
### Fixes