Skip to content

Commit

Permalink
SAVEPOINT
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisdoomen committed Jul 2, 2022
1 parent 59e96d4 commit acc9ed4
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 8 deletions.
3 changes: 3 additions & 0 deletions Src/FluentAssertions/Equivalency/Execution/ObjectInfo.cs
Expand Up @@ -7,12 +7,15 @@ internal class ObjectInfo : IObjectInfo
public ObjectInfo(Comparands comparands, INode currentNode)
{
Type = currentNode.Type;
ParentType = currentNode.ParentType;
Path = currentNode.PathAndName;
CompileTimeType = comparands.CompileTimeType;
RuntimeType = comparands.RuntimeType;
}

public Type Type { get; }

public Type ParentType { get; }

public string Path { get; set; }

Expand Down
1 change: 1 addition & 0 deletions Src/FluentAssertions/Equivalency/Field.cs
Expand Up @@ -27,6 +27,7 @@ public Field(Type reflectedType, FieldInfo fieldInfo, INode parent)
GetSubjectId = parent.GetSubjectId;
Name = fieldInfo.Name;
Type = fieldInfo.FieldType;
ParentType = fieldInfo.DeclaringType;
RootIsCollection = parent.RootIsCollection;
}

Expand Down
15 changes: 13 additions & 2 deletions Src/FluentAssertions/Equivalency/INode.cs
@@ -1,9 +1,11 @@
using System;
using JetBrains.Annotations;

namespace FluentAssertions.Equivalency;

/// <summary>
/// Represents a node in the object graph as it is expected in a structural equivalency check.
/// Represents a node in the object graph that is being compared as part of a structural equivalency check.
/// This can be the root object, a collection item, a dictionary element, a property or a field.
/// </summary>
public interface INode
{
Expand All @@ -22,9 +24,18 @@ public interface INode
string Name { get; set; }

/// <summary>
/// Gets the type of this node.
/// Gets the type of this node, e.g. the type of the field or property, or the type of the collection item.
/// </summary>
Type Type { get; }

/// <summary>
/// Gets the type of the parent node, e.g. the type that declares a property or field.
/// </summary>
/// <value>
/// Is <c>null</c> for the root object.
/// </value>
[CanBeNull]
Type ParentType { get; }

/// <summary>
/// Gets the path from the root object UNTIL the current node, separated by dots or index/key brackets.
Expand Down
13 changes: 12 additions & 1 deletion Src/FluentAssertions/Equivalency/IObjectInfo.cs
@@ -1,4 +1,5 @@
using System;
using JetBrains.Annotations;

namespace FluentAssertions.Equivalency;

Expand All @@ -8,9 +9,19 @@ namespace FluentAssertions.Equivalency;
public interface IObjectInfo
{
/// <summary>
/// Gets the type of this node.
/// Gets the type of the object
/// </summary>
[Obsolete("Use CompileTimeType or RunTimeType instead")]
Type Type { get; }

/// <summary>
/// Gets the type of the parent, e.g. the type that declares a property or field.
/// </summary>
/// <value>
/// Is <c>null</c> for the root object.
/// </value>
[CanBeNull]
Type ParentType { get; }

/// <summary>
/// Gets the full path from the root object until the current node separated by dots.
Expand Down
9 changes: 5 additions & 4 deletions Src/FluentAssertions/Equivalency/Node.cs
@@ -1,15 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using FluentAssertions.Common;

namespace FluentAssertions.Equivalency;

/// <summary>
/// Represents a node in the object graph that is being compared as part of a structural equivalency check.
/// </summary>
public class Node : INode
{
private static readonly Regex MatchFirstIndex = new(@"^\[\d+\]$");
Expand All @@ -21,6 +17,8 @@ public class Node : INode
public GetSubjectId GetSubjectId { get; protected set; } = () => string.Empty;

public Type Type { get; protected set; }

public Type ParentType { get; protected set; }

public string Path
{
Expand Down Expand Up @@ -82,6 +80,7 @@ public static INode From<T>(GetSubjectId getSubjectId)
Name = string.Empty,
Path = string.Empty,
Type = typeof(T),
ParentType = null,
RootIsCollection = IsCollection(typeof(T))
};
}
Expand All @@ -91,6 +90,7 @@ public static INode FromCollectionItem<T>(string index, INode parent)
return new Node
{
Type = typeof(T),
ParentType = parent.Type,
Name = "[" + index + "]",
Path = parent.PathAndName,
GetSubjectId = parent.GetSubjectId,
Expand All @@ -103,6 +103,7 @@ public static INode FromDictionaryItem<T>(object key, INode parent)
return new Node
{
Type = typeof(T),
ParentType = parent.Type,
Name = "[" + key + "]",
Path = parent.PathAndName,
GetSubjectId = parent.GetSubjectId,
Expand Down
Expand Up @@ -7,7 +7,12 @@ internal class CollectionMemberObjectInfo : IObjectInfo
public CollectionMemberObjectInfo(IObjectInfo context)
{
Path = GetAdjustedPropertyPath(context.Path);

#pragma warning disable CS0618
Type = context.Type;
#pragma warning restore CS0618

ParentType = context.ParentType;
RuntimeType = context.RuntimeType;
CompileTimeType = context.CompileTimeType;
}
Expand All @@ -18,6 +23,8 @@ private static string GetAdjustedPropertyPath(string propertyPath)
}

public Type Type { get; }

public Type ParentType { get; }

public string Path { get; set; }

Expand Down
3 changes: 2 additions & 1 deletion Src/FluentAssertions/Equivalency/Property.cs
Expand Up @@ -26,6 +26,7 @@ public Property(Type reflectedType, PropertyInfo propertyInfo, INode parent)
DeclaringType = propertyInfo.DeclaringType;
Name = propertyInfo.Name;
Type = propertyInfo.PropertyType;
ParentType = propertyInfo.DeclaringType;
Path = parent.PathAndName;
GetSubjectId = parent.GetSubjectId;
RootIsCollection = parent.RootIsCollection;
Expand All @@ -36,7 +37,7 @@ public object GetValue(object obj)
return propertyInfo.GetValue(obj);
}

public Type DeclaringType { get; private set; }
public Type DeclaringType { get; }

public Type ReflectedType { get; }

Expand Down
21 changes: 21 additions & 0 deletions Tests/FluentAssertions.Equivalency.Specs/ExtensibilitySpecs.cs
Expand Up @@ -226,6 +226,27 @@ public void When_property_of_other_is_incompatible_with_generic_type_the_message
.WithMessage("*Id*from expectation*System.String*System.Double*");
}

[Fact]
public void Can_exclude_all_properties_of_the_parent_type()
{
// Arrange
var subject = new
{
Id = "foo",
};

var other = new
{
Id = 0.5d,
};

// Act
subject.Should().BeEquivalentTo(other,
o => o
.Using<string>(c => c.Subject.Should().Be(c.Expectation))
.When(si => si.ParentType != other.GetType() && si.Path == "Id"));
}

[Fact]
public void When_property_of_subject_is_incompatible_with_generic_type_the_message_should_include_generic_type()
{
Expand Down
5 changes: 5 additions & 0 deletions docs/_pages/releases.md
Expand Up @@ -7,6 +7,11 @@ sidebar:
nav: "sidebar"
---

Unreleased

### What's new
* Adds a `ParentType` to `IObjectInfo` to help determining the parent in a call to `Using`/`When` constructs - [#2000](https://github.com/fluentassertions/fluentassertions/pull/2000)

## 6.7.0

### What's new
Expand Down

0 comments on commit acc9ed4

Please sign in to comment.