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

Optimize performance of IncludeMemberByPathSelectionRule #969

Merged
merged 1 commit into from Nov 17, 2018
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
41 changes: 23 additions & 18 deletions Src/FluentAssertions/Common/MemberPath.cs
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace FluentAssertions.Common
Expand All @@ -12,47 +11,53 @@ internal class MemberPath
{
private readonly Type declaringType;
private readonly string dottedPath;
private readonly List<string> segments = new List<string>();

private string[] segments;

public MemberPath(Type declaringType, string dottedPath)
{
this.declaringType = declaringType;
this.dottedPath = dottedPath;
segments.AddRange(Segmentize(dottedPath));
}

public bool IsParentOrChildOf(string candidate)
public bool IsParentOrChildOf(MemberPath candidate)
{
return IsParent(candidate) || IsChild(candidate);
}

public bool IsSameAs(string candidate, Type memberDeclaringType)
public bool IsSameAs(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
if (candidate.declaringType != declaringType)
{
return false;
}

string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return memberDeclaringType == declaringType && candidateSegments.SequenceEqual(segments);
return candidateSegments.SequenceEqual(segments);
}

private bool IsChild(string candidate)
private bool IsChild(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return candidateSegments.Length > segments.Count &&
candidateSegments.Take(segments.Count).SequenceEqual(segments);
return candidateSegments.Length > segments.Length &&
candidateSegments.Take(segments.Length).SequenceEqual(segments);
}

private bool IsParent(string candidate)
private bool IsParent(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return candidateSegments.Length < segments.Count
return candidateSegments.Length < segments.Length
&& candidateSegments.SequenceEqual(segments.Take(candidateSegments.Length));
}

private static string[] Segmentize(string dottedPath)
{
return dottedPath.Split(new[] { '.', '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
}
private string[] GetSegments() =>
segments ?? (segments = dottedPath.Split(new[] { '.', '[', ']' }, StringSplitOptions.RemoveEmptyEntries));

public override string ToString()
{
Expand Down
Expand Up @@ -22,7 +22,7 @@ public ExcludeMemberByPathSelectionRule(MemberPath pathToExclude)
string currentPath, IMemberInfo context)
{
return selectedMembers
.Where(memberInfo => !memberToExclude.IsSameAs(currentPath.Combine(memberInfo.Name), memberInfo.DeclaringType))
.Where(memberInfo => !memberToExclude.IsSameAs(new MemberPath(memberInfo.DeclaringType, currentPath.Combine(memberInfo.Name))))
.ToArray();
}

Expand Down
Expand Up @@ -25,8 +25,8 @@ public IncludeMemberByPathSelectionRule(MemberPath pathToInclude)
{
var matchingMembers =
from member in context.RuntimeType.GetNonPrivateMembers()
let memberPath = currentPath.Combine(member.Name)
where memberToInclude.IsSameAs(memberPath, member.DeclaringType) ||
let memberPath = new MemberPath(member.DeclaringType, currentPath.Combine(member.Name))
where memberToInclude.IsSameAs(memberPath) ||
memberToInclude.IsParentOrChildOf(memberPath)
select member;

Expand Down