diff --git a/Pipeline/Build.cs b/Pipeline/Build.cs index a07a0cc08..25356ef59 100644 --- a/Pipeline/Build.cs +++ b/Pipeline/Build.cs @@ -19,7 +19,7 @@ partial class Build : NukeBuild /// /// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag. /// - readonly BuildScope BuildScope = BuildScope.Default; + readonly BuildScope BuildScope = BuildScope.CoreOnly; [Parameter("Github Token")] readonly string GithubToken; diff --git a/Source/aweXpect.Core/Core/MemberAccessor.cs b/Source/aweXpect.Core/Core/MemberAccessor.cs index 80ec6bb46..dbbe3483c 100644 --- a/Source/aweXpect.Core/Core/MemberAccessor.cs +++ b/Source/aweXpect.Core/Core/MemberAccessor.cs @@ -56,5 +56,29 @@ public static MemberAccessor FromFunc( Func func, string name) => new(func, name); + /// + /// Creates a member accessor from the given . + /// + public static MemberAccessor FromFuncAsMemberAccessor( + Func func, string name) + => new(func, ExtractMemberPath(name.Trim())); + + private static string ExtractMemberPath(string expression) + { + // Example: "x => x.Foo" would result in ".Foo" + int idx = expression.IndexOf("=>", StringComparison.Ordinal); + if (idx > 0) + { + string? prefix = expression.Substring(0, idx).Trim(); + idx = expression.IndexOf(prefix, idx, StringComparison.Ordinal); + if (idx > 0) + { + expression = expression.Substring(idx + prefix.Length).TrimStart(); + } + } + + return $"{expression} "; + } + internal TTarget AccessMember(TSource value) => _accessor.Invoke(value); } diff --git a/Source/aweXpect.Core/Delegates/ThatDelegateThrows.Whose.cs b/Source/aweXpect.Core/Delegates/ThatDelegateThrows.Whose.cs index 8edb4e995..43f6c2c7f 100644 --- a/Source/aweXpect.Core/Delegates/ThatDelegateThrows.Whose.cs +++ b/Source/aweXpect.Core/Delegates/ThatDelegateThrows.Whose.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using System.Runtime.CompilerServices; using aweXpect.Core; using aweXpect.Results; @@ -11,10 +11,11 @@ public partial class ThatDelegateThrows /// Verifies the on the member selected by the . /// public AndOrResult> Whose( - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") => new(ExpectationBuilder.ForMember( - MemberAccessor.FromExpression(memberSelector), + MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, expectation) => expectation.Append("whose ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))), this); diff --git a/Source/aweXpect.Core/Results/AndOrWhichResult.cs b/Source/aweXpect.Core/Results/AndOrWhichResult.cs index 6951647e4..2dd19af80 100644 --- a/Source/aweXpect.Core/Results/AndOrWhichResult.cs +++ b/Source/aweXpect.Core/Results/AndOrWhichResult.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using System.Runtime.CompilerServices; using aweXpect.Core; namespace aweXpect.Results; @@ -38,11 +38,12 @@ public class AndOrWhichResult( /// public AdditionalAndOrWhichResult Which( - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") => new( _expectationBuilder - .ForMember(MemberAccessor.FromExpression(memberSelector), + .ForMember(MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, stringBuilder) => stringBuilder.Append(" which ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))), _returnValue); @@ -67,14 +68,15 @@ public class AdditionalAndOrWhichResult( /// public AdditionalAndOrWhichResult AndWhich( - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { _expectationBuilder.And(" and"); return new AdditionalAndOrWhichResult( _expectationBuilder .ForMember( - MemberAccessor.FromExpression(memberSelector), + MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, stringBuilder) => stringBuilder.Append(" which ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))), diff --git a/Source/aweXpect.Core/Results/AndOrWhoseResult.cs b/Source/aweXpect.Core/Results/AndOrWhoseResult.cs index cac598a1e..3e3a53022 100644 --- a/Source/aweXpect.Core/Results/AndOrWhoseResult.cs +++ b/Source/aweXpect.Core/Results/AndOrWhoseResult.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using System.Runtime.CompilerServices; using aweXpect.Core; namespace aweXpect.Results; @@ -38,11 +38,12 @@ public class AndOrWhoseResult( /// public AdditionalAndOrWhoseResult Whose( - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") => new( _expectationBuilder - .ForMember(MemberAccessor.FromExpression(memberSelector), + .ForMember(MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, stringBuilder) => stringBuilder.Append(" whose ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))), _returnValue); @@ -67,14 +68,15 @@ public class AdditionalAndOrWhoseResult( /// public AdditionalAndOrWhoseResult AndWhose( - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { _expectationBuilder.And(" and"); return new AdditionalAndOrWhoseResult( _expectationBuilder .ForMember( - MemberAccessor.FromExpression(memberSelector), + MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, stringBuilder) => stringBuilder.Append(" whose ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))), diff --git a/Source/aweXpect/That/ThatGeneric.For.cs b/Source/aweXpect/That/ThatGeneric.For.cs index 87f83629b..27802154d 100644 --- a/Source/aweXpect/That/ThatGeneric.For.cs +++ b/Source/aweXpect/That/ThatGeneric.For.cs @@ -1,5 +1,5 @@ using System; -using System.Linq.Expressions; +using System.Runtime.CompilerServices; using aweXpect.Core; using aweXpect.Helpers; using aweXpect.Results; @@ -13,13 +13,14 @@ public static partial class ThatGeneric /// public static AndOrResult> For( this IThat source, - Expression> memberSelector, - Action> expectations) + Func memberSelector, + Action> expectations, + [CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { ExpectationBuilder expectationBuilder = source.Get().ExpectationBuilder; expectationBuilder .ForMember( - MemberAccessor.FromExpression(memberSelector), + MemberAccessor.FromFuncAsMemberAccessor(memberSelector, doNotPopulateThisValue), (member, stringBuilder) => stringBuilder.Append("for ").Append(member)) .AddExpectations(e => expectations(new ThatSubject(e))); return new AndOrResult>(expectationBuilder, source); diff --git a/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt b/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt index d92c552c5..5a080c70f 100644 --- a/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt +++ b/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt @@ -678,7 +678,7 @@ namespace aweXpect public static aweXpect.Results.RepeatedCheckResult> CompliesWith(this aweXpect.Core.IThat source, System.Action> expectations) { } public static aweXpect.Results.RepeatedCheckResult> DoesNotComplyWith(this aweXpect.Core.IThat source, System.Action> expectations) { } public static aweXpect.Results.AndOrResult> DoesNotSatisfy(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { } - public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public static aweXpect.Results.RepeatedCheckResult> Satisfies(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { } } public static class ThatGuid diff --git a/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt b/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt index cde40b326..4285af7a1 100644 --- a/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt +++ b/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt @@ -463,7 +463,7 @@ namespace aweXpect public static aweXpect.Results.RepeatedCheckResult> CompliesWith(this aweXpect.Core.IThat source, System.Action> expectations) { } public static aweXpect.Results.RepeatedCheckResult> DoesNotComplyWith(this aweXpect.Core.IThat source, System.Action> expectations) { } public static aweXpect.Results.AndOrResult> DoesNotSatisfy(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { } - public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public static aweXpect.Results.RepeatedCheckResult> Satisfies(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { } } public static class ThatGuid diff --git a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt index 04751646d..cab636cb1 100644 --- a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt +++ b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt @@ -250,6 +250,7 @@ namespace aweXpect.Core { public static aweXpect.Core.MemberAccessor FromExpression(System.Linq.Expressions.Expression> expression) { } public static aweXpect.Core.MemberAccessor FromFunc(System.Func func, string name) { } + public static aweXpect.Core.MemberAccessor FromFuncAsMemberAccessor(System.Func func, string name) { } } public class ResultContext { @@ -490,7 +491,7 @@ namespace aweXpect.Delegates public aweXpect.Core.ExpectationBuilder ExpectationBuilder { get; } public aweXpect.Core.IThat Which { get; } public aweXpect.Delegates.ThatDelegateThrows OnlyIf(bool predicate) { } - public aweXpect.Results.AndOrResult> Whose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrResult> Whose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public aweXpect.Results.AndOrResult> WithInner(System.Type innerExceptionType) { } public aweXpect.Results.AndOrResult> WithInner(System.Type innerExceptionType, System.Action> expectations) { } public aweXpect.Results.AndOrResult> WithInner() @@ -918,11 +919,11 @@ namespace aweXpect.Results where TSelf : aweXpect.Results.AndOrWhichResult { public AndOrWhichResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult Which(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult Which(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public class AdditionalAndOrWhichResult : aweXpect.Results.AndOrResult { public AdditionalAndOrWhichResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult AndWhich(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult AndWhich(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } } } public class AndOrWhoseResult : aweXpect.Results.AndOrWhoseResult> @@ -933,11 +934,11 @@ namespace aweXpect.Results where TSelf : aweXpect.Results.AndOrWhoseResult { public AndOrWhoseResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult Whose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult Whose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public class AdditionalAndOrWhoseResult : aweXpect.Results.AndOrResult { public AdditionalAndOrWhoseResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult AndWhose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult AndWhose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } } } public class AndResult : aweXpect.Results.ExpectationResult diff --git a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt index 0ab2efa3d..5330d0db7 100644 --- a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt +++ b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt @@ -250,6 +250,7 @@ namespace aweXpect.Core { public static aweXpect.Core.MemberAccessor FromExpression(System.Linq.Expressions.Expression> expression) { } public static aweXpect.Core.MemberAccessor FromFunc(System.Func func, string name) { } + public static aweXpect.Core.MemberAccessor FromFuncAsMemberAccessor(System.Func func, string name) { } } public class ResultContext { @@ -490,7 +491,7 @@ namespace aweXpect.Delegates public aweXpect.Core.ExpectationBuilder ExpectationBuilder { get; } public aweXpect.Core.IThat Which { get; } public aweXpect.Delegates.ThatDelegateThrows OnlyIf(bool predicate) { } - public aweXpect.Results.AndOrResult> Whose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrResult> Whose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public aweXpect.Results.AndOrResult> WithInner(System.Type innerExceptionType) { } public aweXpect.Results.AndOrResult> WithInner(System.Type innerExceptionType, System.Action> expectations) { } public aweXpect.Results.AndOrResult> WithInner() @@ -901,11 +902,11 @@ namespace aweXpect.Results where TSelf : aweXpect.Results.AndOrWhichResult { public AndOrWhichResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult Which(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult Which(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public class AdditionalAndOrWhichResult : aweXpect.Results.AndOrResult { public AdditionalAndOrWhichResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult AndWhich(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhichResult.AdditionalAndOrWhichResult AndWhich(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } } } public class AndOrWhoseResult : aweXpect.Results.AndOrWhoseResult> @@ -916,11 +917,11 @@ namespace aweXpect.Results where TSelf : aweXpect.Results.AndOrWhoseResult { public AndOrWhoseResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult Whose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult Whose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } public class AdditionalAndOrWhoseResult : aweXpect.Results.AndOrResult { public AdditionalAndOrWhoseResult(aweXpect.Core.ExpectationBuilder expectationBuilder, TThat returnValue) { } - public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult AndWhose(System.Linq.Expressions.Expression> memberSelector, System.Action> expectations) { } + public aweXpect.Results.AndOrWhoseResult.AdditionalAndOrWhoseResult AndWhose(System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { } } } public class AndResult : aweXpect.Results.ExpectationResult diff --git a/Tests/aweXpect.Core.Tests/Core/MemberAccessorTests.cs b/Tests/aweXpect.Core.Tests/Core/MemberAccessorTests.cs new file mode 100644 index 000000000..81cf44ce7 --- /dev/null +++ b/Tests/aweXpect.Core.Tests/Core/MemberAccessorTests.cs @@ -0,0 +1,39 @@ +namespace aweXpect.Core.Tests.Core; + +public sealed class MemberAccessorTests +{ + [Fact] + public async Task FromExpression_ShouldGetMemberPath() + { + MemberAccessor subject = MemberAccessor + .FromExpression(x => x.Length); + + await That(subject.ToString()).IsEqualTo(".Length "); + } + + [Theory] + [InlineData("Foo")] + [InlineData(" x => x.Foo")] + [InlineData("x => x.Foo ")] + public async Task FromFunc_ShouldKeepNameUnchanged(string expression) + { + MemberAccessor subject = MemberAccessor + .FromFunc(x => x.Length, expression); + + await That(subject.ToString()).IsEqualTo(expression); + } + + [Theory] + [InlineData("Foo", "Foo ")] + [InlineData("x => x.Foo", ".Foo ")] + [InlineData(" x => x.Foo", ".Foo ")] + [InlineData("x => x.Foo ", ".Foo ")] + [InlineData("itIs => itIs.Foo ", ".Foo ")] + public async Task FromFuncAsMemberAccessor_ShouldTryToExtractMemberAccessor(string expression, string expected) + { + MemberAccessor subject = MemberAccessor + .FromFuncAsMemberAccessor(x => x.Length, expression); + + await That(subject.ToString()).IsEqualTo(expected); + } +}