Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pipeline/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ partial class Build : NukeBuild
/// <para />
/// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag.
/// </summary>
readonly BuildScope BuildScope = BuildScope.Default;
readonly BuildScope BuildScope = BuildScope.CoreOnly;

[Parameter("Github Token")] readonly string GithubToken;

Expand Down
56 changes: 29 additions & 27 deletions Source/aweXpect.Core/Equivalency/EquivalencyComparison.Compare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,20 @@ private static async Task<bool>
if (typeOptions.Fields != IncludeMembers.None)
{
BindingFlags fieldBindingFlags = typeOptions.Fields.GetBindingFlags();
foreach (string fieldName in expected.GetType().GetFields(typeOptions.Fields).Select(x => x.Name))
foreach (FieldInfo? fieldInfo in expected.GetType().GetFields(typeOptions.Fields))
{
memberCount++;
string fieldMemberPath = ConcatMemberPath(memberPath, fieldName);
if (typeOptions.MembersToIgnore.Contains(fieldMemberPath))
string fieldMemberPath = ConcatMemberPath(memberPath, fieldInfo.Name);
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(fieldMemberPath, fieldInfo.FieldType, fieldInfo)))
{
continue;
}

object? actualFieldValue =
actual.GetType().GetField(fieldName, fieldBindingFlags)?.GetValue(actual);
actual.GetType().GetField(fieldInfo.Name, fieldBindingFlags)?.GetValue(actual);
object? expectedFieldValue =
expected.GetType().GetField(fieldName, fieldBindingFlags)?.GetValue(expected);
expected.GetType().GetField(fieldInfo.Name, fieldBindingFlags)?.GetValue(expected);

if (!await Compare(actualFieldValue, expectedFieldValue,
options, options.GetTypeOptions(actualFieldValue?.GetType(), typeOptions),
Expand All @@ -224,20 +225,20 @@ private static async Task<bool>
if (typeOptions.Properties != IncludeMembers.None)
{
BindingFlags propertyBindingFlags = typeOptions.Properties.GetBindingFlags();
foreach (string propertyName in expected.GetType().GetProperties(typeOptions.Properties)
.Select(x => x.Name))
foreach (PropertyInfo? propertyInfo in expected.GetType().GetProperties(typeOptions.Properties))
{
memberCount++;
string propertyMemberPath = ConcatMemberPath(memberPath, propertyName);
if (typeOptions.MembersToIgnore.Contains(propertyMemberPath))
string propertyMemberPath = ConcatMemberPath(memberPath, propertyInfo.Name);
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(propertyMemberPath, propertyInfo.PropertyType, propertyInfo)))
{
continue;
}

object? actualPropertyValue = actual.GetType().GetProperty(propertyName, propertyBindingFlags)
object? actualPropertyValue = actual.GetType().GetProperty(propertyInfo.Name, propertyBindingFlags)
?.GetValue(actual);
object? expectedPropertyValue =
expected.GetType().GetProperty(propertyName, propertyBindingFlags)?.GetValue(expected);
expected.GetType().GetProperty(propertyInfo.Name, propertyBindingFlags)?.GetValue(expected);

if (!await Compare(actualPropertyValue, expectedPropertyValue,
options, options.GetTypeOptions(actualPropertyValue?.GetType(), typeOptions),
Expand Down Expand Up @@ -287,12 +288,13 @@ private static async Task<bool>
foreach (object? key in actual.Keys)
{
string elementMemberPath = $"{memberPath}[{key}]";
if (typeOptions.MembersToIgnore.Contains(elementMemberPath))

object? actualObject = actual[key];
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(elementMemberPath, actualObject?.GetType() ?? typeof(object), null)))
{
continue;
}

object? actualObject = actual[key];
if (expected.Contains(key))
{
object? expectedObject = expected[key];
Expand Down Expand Up @@ -328,14 +330,13 @@ private static async Task<bool>
}

string elementMemberPath = $"{memberPath}[{key}]";
if (typeOptions.MembersToIgnore.Contains(elementMemberPath))
object? expectedObject = expected[key];
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(elementMemberPath, expectedObject?.GetType() ?? typeof(object), null)))
{
continue;
}


object? expectedObject = expected[key];

failureBuilder.AppendLine();
if (failureBuilder.Length > 2)
{
Expand Down Expand Up @@ -385,12 +386,13 @@ private static async Task<bool>
for (int i = 0; i < Math.Min(actualObjects.Length, expectedObjects.Length); i++)
{
string elementMemberPath = $"{memberPath}[{(keys is null ? i : keys[i])}]";
if (typeOptions.MembersToIgnore.Contains(elementMemberPath))
object? actualObject = actualObjects.ElementAtOrDefault(i);
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(elementMemberPath, actualObject?.GetType() ?? typeof(object), null)))
{
continue;
}

object? actualObject = actualObjects.ElementAtOrDefault(i);

object? expectedObject = expectedObjects.ElementAtOrDefault(i);

if (!await Compare(actualObject, expectedObject,
Expand All @@ -406,13 +408,13 @@ private static async Task<bool>
for (int i = actualObjects.Length; i < expectedObjects.Length; i++)
{
string elementMemberPath = $"{memberPath}[{i}]";
if (typeOptions.MembersToIgnore.Contains(elementMemberPath))
object? expectedObject = expectedObjects.ElementAtOrDefault(i);
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(elementMemberPath, expectedObject?.GetType() ?? typeof(object), null)))
{
continue;
}

object? expectedObject = expectedObjects.ElementAtOrDefault(i);

failureBuilder.AppendLine();
if (failureBuilder.Length > 2)
{
Expand All @@ -432,13 +434,13 @@ private static async Task<bool>
for (int i = expectedObjects.Length; i < actualObjects.Length; i++)
{
string elementMemberPath = $"{memberPath}[{(keys is null ? i : keys[i])}]";
if (typeOptions.MembersToIgnore.Contains(elementMemberPath))
object? actualObject = actualObjects.ElementAtOrDefault(i);
if (typeOptions.MembersToIgnore.Any(memberToIgnore
=> memberToIgnore.IgnoreMember(elementMemberPath, actualObject?.GetType() ?? typeof(object), null)))
{
continue;
}

object? actualObject = actualObjects.ElementAtOrDefault(i);

failureBuilder.AppendLine();
if (failureBuilder.Length > 2)
{
Expand Down
3 changes: 2 additions & 1 deletion Source/aweXpect.Core/Equivalency/EquivalencyTypeOptions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Linq;
using System.Text;

namespace aweXpect.Equivalency;
Expand All @@ -18,7 +19,7 @@ public record EquivalencyTypeOptions
/// <summary>
/// The members that should be ignored when checking for equivalency.
/// </summary>
public string[] MembersToIgnore { get; init; } = [];
public MemberToIgnore[] MembersToIgnore { get; init; } = [];

/// <summary>
/// Specifies which fields to include in the object comparison.
Expand Down
41 changes: 41 additions & 0 deletions Source/aweXpect.Core/Equivalency/MemberToIgnore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Reflection;

namespace aweXpect.Equivalency;

/// <summary>
/// Class to specify which members to ignore.
/// </summary>
public abstract class MemberToIgnore
{
/// <summary>
/// Checks if the member should be ignored.
/// </summary>
public abstract bool IgnoreMember(string memberPath, Type memberType, MemberInfo? memberInfo);

/// <summary>
/// Ignores all members that satisfy the <paramref name="predicate" />.
/// </summary>
public class ByPredicate(Func<string, Type, MemberInfo?, bool> predicate, string description) : MemberToIgnore
{
/// <inheritdoc cref="MemberToIgnore.IgnoreMember(string, Type, MemberInfo?)" />
public override bool IgnoreMember(string memberPath, Type memberType, MemberInfo? memberInfo)
=> predicate(memberPath, memberType, memberInfo);

/// <inheritdoc cref="object.ToString()" />
public override string ToString() => description;
}

/// <summary>
/// Ignores all members that have the provided <paramref name="memberName" />.
/// </summary>
public class ByName(string memberName) : MemberToIgnore
{
/// <inheritdoc cref="MemberToIgnore.IgnoreMember(string, Type, MemberInfo?)" />
public override bool IgnoreMember(string memberPath, Type memberType, MemberInfo? memberInfo)
=> memberPath.EndsWith(memberName, StringComparison.OrdinalIgnoreCase);

/// <inheritdoc cref="object.ToString()" />
public override string ToString() => $"\"{memberName}\"";
}
}
79 changes: 78 additions & 1 deletion Source/aweXpect/Equivalency/EquivalencyOptionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using aweXpect.Customization;

namespace aweXpect.Equivalency;
Expand All @@ -17,7 +19,82 @@ public static TEquivalencyOptions IgnoringMember<TEquivalencyOptions>(
where TEquivalencyOptions : EquivalencyTypeOptions
=> @this with
{
MembersToIgnore = [..@this.MembersToIgnore, memberToIgnore,],
MembersToIgnore = [..@this.MembersToIgnore, new MemberToIgnore.ByName(memberToIgnore),],
};

/// <summary>
/// Ignores members matching the <paramref name="predicate" /> when checking for equivalency.
/// </summary>
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(
this TEquivalencyOptions @this,
Func<string, Type, bool> predicate,
[CallerArgumentExpression("predicate")]
string doNotPopulateThisValue = "")
where TEquivalencyOptions : EquivalencyTypeOptions
=> @this with
{
MembersToIgnore =
[
..@this.MembersToIgnore,
new MemberToIgnore.ByPredicate((memberName, memberType, _) => predicate(memberName, memberType),
doNotPopulateThisValue),
],
};

/// <summary>
/// Ignores members matching the <paramref name="predicate" /> when checking for equivalency.
/// </summary>
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(
this TEquivalencyOptions @this,
Func<string, bool> predicate,
[CallerArgumentExpression("predicate")]
string doNotPopulateThisValue = "")
where TEquivalencyOptions : EquivalencyTypeOptions
=> @this with
{
MembersToIgnore =
[
..@this.MembersToIgnore,
new MemberToIgnore.ByPredicate((memberName, _, _) => predicate(memberName),
doNotPopulateThisValue),
],
};

/// <summary>
/// Ignores members matching the <paramref name="predicate" /> when checking for equivalency.
/// </summary>
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(
this TEquivalencyOptions @this,
Func<Type, bool> predicate,
[CallerArgumentExpression("predicate")]
string doNotPopulateThisValue = "")
where TEquivalencyOptions : EquivalencyTypeOptions
=> @this with
{
MembersToIgnore =
[
..@this.MembersToIgnore,
new MemberToIgnore.ByPredicate((_, memberType, _) => predicate(memberType),
doNotPopulateThisValue),
],
};

/// <summary>
/// Ignores members matching the <paramref name="predicate" /> when checking for equivalency.
/// </summary>
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(
this TEquivalencyOptions @this,
Func<string, Type, MemberInfo?, bool> predicate,
[CallerArgumentExpression("predicate")]
string doNotPopulateThisValue = "")
where TEquivalencyOptions : EquivalencyTypeOptions
=> @this with
{
MembersToIgnore =
[
..@this.MembersToIgnore,
new MemberToIgnore.ByPredicate(predicate, doNotPopulateThisValue),
],
};

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,14 @@ namespace aweXpect.Equivalency
}
public static class EquivalencyOptionsExtensions
{
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<System.Type, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, System.Type, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, System.Type, System.Reflection.MemberInfo?, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions IgnoringCollectionOrder<TEquivalencyOptions>(this TEquivalencyOptions @this, bool ignoreCollectionOrder = true)
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions IgnoringMember<TEquivalencyOptions>(this TEquivalencyOptions @this, string memberToIgnore)
Expand Down
8 changes: 8 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,14 @@ namespace aweXpect.Equivalency
}
public static class EquivalencyOptionsExtensions
{
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<System.Type, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, System.Type, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions Ignoring<TEquivalencyOptions>(this TEquivalencyOptions @this, System.Func<string, System.Type, System.Reflection.MemberInfo?, bool> predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "")
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions IgnoringCollectionOrder<TEquivalencyOptions>(this TEquivalencyOptions @this, bool ignoreCollectionOrder = true)
where TEquivalencyOptions : aweXpect.Equivalency.EquivalencyTypeOptions { }
public static TEquivalencyOptions IgnoringMember<TEquivalencyOptions>(this TEquivalencyOptions @this, string memberToIgnore)
Expand Down
19 changes: 18 additions & 1 deletion Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ namespace aweXpect.Equivalency
public aweXpect.Equivalency.EquivalencyComparisonType? ComparisonType { get; init; }
public aweXpect.Equivalency.IncludeMembers Fields { get; init; }
public bool IgnoreCollectionOrder { get; init; }
public string[] MembersToIgnore { get; init; }
public aweXpect.Equivalency.MemberToIgnore[] MembersToIgnore { get; init; }
public aweXpect.Equivalency.IncludeMembers Properties { get; init; }
}
[System.Flags]
Expand All @@ -590,6 +590,23 @@ namespace aweXpect.Equivalency
public override string? ToString() { }
}
}
public abstract class MemberToIgnore
{
protected MemberToIgnore() { }
public abstract bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo);
public class ByName : aweXpect.Equivalency.MemberToIgnore
{
public ByName(string memberName) { }
public override bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo) { }
public override string ToString() { }
}
public class ByPredicate : aweXpect.Equivalency.MemberToIgnore
{
public ByPredicate(System.Func<string, System.Type, System.Reflection.MemberInfo?, bool> predicate, string description) { }
public override bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo) { }
public override string ToString() { }
}
}
}
namespace aweXpect
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ namespace aweXpect.Equivalency
public aweXpect.Equivalency.EquivalencyComparisonType? ComparisonType { get; init; }
public aweXpect.Equivalency.IncludeMembers Fields { get; init; }
public bool IgnoreCollectionOrder { get; init; }
public string[] MembersToIgnore { get; init; }
public aweXpect.Equivalency.MemberToIgnore[] MembersToIgnore { get; init; }
public aweXpect.Equivalency.IncludeMembers Properties { get; init; }
}
[System.Flags]
Expand All @@ -576,6 +576,23 @@ namespace aweXpect.Equivalency
public override string? ToString() { }
}
}
public abstract class MemberToIgnore
{
protected MemberToIgnore() { }
public abstract bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo);
public class ByName : aweXpect.Equivalency.MemberToIgnore
{
public ByName(string memberName) { }
public override bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo) { }
public override string ToString() { }
}
public class ByPredicate : aweXpect.Equivalency.MemberToIgnore
{
public ByPredicate(System.Func<string, System.Type, System.Reflection.MemberInfo?, bool> predicate, string description) { }
public override bool IgnoreMember(string memberPath, System.Type memberType, System.Reflection.MemberInfo? memberInfo) { }
public override string ToString() { }
}
}
}
namespace aweXpect
{
Expand Down
Loading
Loading