Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves how BeEquivalentTo handles fields hiding base-class fields #1990

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 22 additions & 16 deletions Src/FluentAssertions/Common/TypeExtensions.cs
Expand Up @@ -178,16 +178,19 @@ public static bool OverridesEquals(this Type type)
/// <returns>
/// Returns <see langword="null"/> if no such property exists.
/// </returns>
public static PropertyInfo FindProperty(this Type type, string propertyName, Type preferredType)
public static PropertyInfo FindProperty(this Type type, string propertyName)
{
List<PropertyInfo> properties =
type.GetProperties(AllInstanceMembersFlag)
.Where(pi => pi.Name == propertyName)
.ToList();
while (type != typeof(object))
{
if (type.GetProperty(propertyName, AllInstanceMembersFlag | BindingFlags.DeclaredOnly) is { } property)
{
return property;
}

type = type.BaseType;
}

return properties.Count > 1
? properties.SingleOrDefault(p => p.PropertyType == preferredType)
: properties.SingleOrDefault();
return null;
}
dennisdoomen marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
Expand All @@ -196,16 +199,19 @@ public static PropertyInfo FindProperty(this Type type, string propertyName, Typ
/// <returns>
/// Returns <see langword="null"/> if no such property exists.
/// </returns>
public static FieldInfo FindField(this Type type, string fieldName, Type preferredType)
public static FieldInfo FindField(this Type type, string fieldName)
{
List<FieldInfo> properties =
type.GetFields(AllInstanceMembersFlag)
.Where(pi => pi.Name == fieldName)
.ToList();
while (type != typeof(object))
{
if (type.GetField(fieldName, AllInstanceMembersFlag | BindingFlags.DeclaredOnly) is { } field)
{
return field;
}

type = type.BaseType;
}

return properties.Count > 1
? properties.SingleOrDefault(p => p.FieldType == preferredType)
: properties.SingleOrDefault();
return null;
}

public static IEnumerable<MemberInfo> GetNonPrivateMembers(this Type typeToReflect, MemberVisibility visibility)
Expand Down
Expand Up @@ -35,7 +35,7 @@ public IMember Match(IMember expectedMember, object subject, INode parent, IEqui
{
if (expectedMember.Name == expectationMemberName)
{
var member = MemberFactory.Find(subject, subjectMemberName, expectedMember.Type, parent);
var member = MemberFactory.Find(subject, subjectMemberName, parent);
if (member is null)
{
throw new ArgumentException(
Expand Down
Expand Up @@ -50,7 +50,7 @@ public IMember Match(IMember expectedMember, object subject, INode parent, IEqui

if (path.IsEquivalentTo(expectedMember.PathAndName))
{
var member = MemberFactory.Find(subject, subjectPath.MemberName, expectedMember.Type, parent);
var member = MemberFactory.Find(subject, subjectPath.MemberName, parent);
if (member is null)
{
throw new ArgumentException(
Expand Down
Expand Up @@ -15,13 +15,13 @@ public IMember Match(IMember expectedMember, object subject, INode parent, IEqui

if (config.IncludedProperties != MemberVisibility.None)
{
PropertyInfo propertyInfo = subject.GetType().FindProperty(expectedMember.Name, expectedMember.Type);
PropertyInfo propertyInfo = subject.GetType().FindProperty(expectedMember.Name);
subjectMember = (propertyInfo is not null) && !propertyInfo.IsIndexer() ? new Property(propertyInfo, parent) : null;
}

if ((subjectMember is null) && config.IncludedFields != MemberVisibility.None)
{
FieldInfo fieldInfo = subject.GetType().FindField(expectedMember.Name, expectedMember.Type);
FieldInfo fieldInfo = subject.GetType().FindField(expectedMember.Name);
subjectMember = (fieldInfo is not null) ? new Field(fieldInfo, parent) : null;
}

Expand Down
Expand Up @@ -10,13 +10,13 @@ internal class TryMatchByNameRule : IMemberMatchingRule
{
public IMember Match(IMember expectedMember, object subject, INode parent, IEquivalencyAssertionOptions config)
{
PropertyInfo property = subject.GetType().FindProperty(expectedMember.Name, expectedMember.Type);
PropertyInfo property = subject.GetType().FindProperty(expectedMember.Name);
if ((property is not null) && !property.IsIndexer())
{
return new Property(property, parent);
}

FieldInfo field = subject.GetType().FindField(expectedMember.Name, expectedMember.Type);
FieldInfo field = subject.GetType().FindField(expectedMember.Name);
return (field is not null) ? new Field(field, parent) : null;
}

Expand Down
6 changes: 3 additions & 3 deletions Src/FluentAssertions/Equivalency/MemberFactory.cs
Expand Up @@ -21,15 +21,15 @@ public static IMember Create(MemberInfo memberInfo, INode parent)
throw new NotSupportedException($"Don't know how to deal with a {memberInfo.MemberType}");
}

internal static IMember Find(object target, string memberName, Type preferredMemberType, INode parent)
internal static IMember Find(object target, string memberName, INode parent)
{
PropertyInfo property = target.GetType().FindProperty(memberName, preferredMemberType);
PropertyInfo property = target.GetType().FindProperty(memberName);
if ((property is not null) && !property.IsIndexer())
{
return new Property(property, parent);
}

FieldInfo field = target.GetType().FindField(memberName, preferredMemberType);
FieldInfo field = target.GetType().FindField(memberName);
return (field is not null) ? new Field(field, parent) : null;
}
}