Skip to content

Commit

Permalink
Add null default to ToSet constraint parameter that matches any value (
Browse files Browse the repository at this point in the history
  • Loading branch information
devodo authored Sep 24, 2022
1 parent c5cf8bd commit 1e4ac16
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 18 deletions.
4 changes: 2 additions & 2 deletions src/DivertR/IVia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ public interface IVia<TTarget> : IVia where TTarget : class?
/// Creates a Redirect builder from an Expression with a call constraint that matches a property setter member of <typeparamref name="TTarget"/> />.
/// </summary>
/// <param name="memberExpression">The expression for matching the property setter member.</param>
/// <param name="constraintExpression">The call constraint expression for the input value of the setter.</param>
/// <param name="constraintExpression">Optional constraint expression on the setter input argument. If null, the constraint defaults to match any value</param>
/// <typeparam name="TProperty">The member type of the property setter.</typeparam>
/// <returns>The Redirect builder instance.</returns>
IActionViaBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty?>> constraintExpression);
IActionViaBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty>>? constraintExpression = null);
}
}
13 changes: 7 additions & 6 deletions src/DivertR/Internal/CallExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@ public static ICallValidator FromExpression(Expression expression)
};
}

public static ICallValidator FromPropertySetter(MemberExpression propertyExpression, Expression valueExpression)
public static ICallValidator FromPropertySetter(MemberExpression propertyExpression, Expression? valueExpression)
{
if (propertyExpression == null) throw new ArgumentNullException(nameof(propertyExpression));
if (valueExpression == null) throw new ArgumentNullException(nameof(valueExpression));

if (!(propertyExpression.Member is PropertyInfo property))

if (propertyExpression.Member is not PropertyInfo property)
{
throw new ArgumentException($"Member expression must be of type PropertyInfo but got: {propertyExpression.Member.GetType()}", nameof(propertyExpression));
}

var methodInfo = property.GetSetMethod(true);
var parameterInfos = methodInfo.GetParameters();
var methodConstraint = CreateMethodConstraint(methodInfo);
var argumentConstraints = CreateArgumentConstraints(parameterInfos, new[] { valueExpression });
var argumentConstraints = valueExpression == null
? new[] { TrueArgumentConstraint.Instance }
: CreateArgumentConstraints(parameterInfos, new[] { valueExpression });

return new ExpressionCallValidator(methodInfo, parameterInfos, methodConstraint, argumentConstraints);
}
Expand All @@ -51,7 +52,7 @@ private static ICallValidator FromProperty(MemberExpression propertyExpression)
{
if (propertyExpression == null) throw new ArgumentNullException(nameof(propertyExpression));

if (!(propertyExpression.Member is PropertyInfo property))
if (propertyExpression.Member is not PropertyInfo property)
{
throw new ArgumentException($"Member expression must be of type PropertyInfo but got: {propertyExpression.Member.GetType()}", nameof(propertyExpression));
}
Expand Down
12 changes: 6 additions & 6 deletions src/DivertR/Internal/MethodCallConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace DivertR.Internal
internal class MethodCallConstraint : ICallConstraint
{
private readonly IMethodConstraint _methodConstraint;
private readonly IArgumentConstraint[] _argumentConditions;
private readonly IArgumentConstraint[] _argumentConstraints;

public MethodCallConstraint(IMethodConstraint methodConstraint, IArgumentConstraint[] argumentConditions)
public MethodCallConstraint(IMethodConstraint methodConstraint, IArgumentConstraint[] argumentConstraints)
{
_methodConstraint = methodConstraint;
_argumentConditions = argumentConditions;
_argumentConstraints = argumentConstraints;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -21,14 +21,14 @@ public bool IsMatch(ICallInfo callInfo)
return false;
}

if (_argumentConditions.Length != callInfo.Arguments.Count)
if (_argumentConstraints.Length != callInfo.Arguments.Count)
{
return false;
}

for (var i = 0; i < _argumentConditions.Length; i++)
for (var i = 0; i < _argumentConstraints.Length; i++)
{
if (!_argumentConditions[i].IsMatch(callInfo.Arguments[i]))
if (!_argumentConstraints[i].IsMatch(callInfo.Arguments[i]))
{
return false;
}
Expand Down
15 changes: 15 additions & 0 deletions src/DivertR/Internal/TrueArgumentConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Runtime.CompilerServices;

namespace DivertR.Internal
{
internal class TrueArgumentConstraint : IArgumentConstraint
{
public static readonly TrueArgumentConstraint Instance = new();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMatch(object? argument)
{
return true;
}
}
}
6 changes: 3 additions & 3 deletions src/DivertR/RedirectBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ public static IActionRedirectBuilder<TTarget> To(Expression<Action<TTarget>> con
return new ActionRedirectBuilder<TTarget>(callValidator, callConstraint.Of<TTarget>());
}

public static IActionRedirectBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty?>> constraintExpression)
public static IActionRedirectBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty>>? constraintExpression = null)
{
if (memberExpression.Body == null) throw new ArgumentNullException(nameof(memberExpression));
if (constraintExpression.Body == null) throw new ArgumentNullException(nameof(constraintExpression));
if (constraintExpression is { Body: null }) throw new ArgumentNullException(nameof(constraintExpression));

if (!(memberExpression.Body is MemberExpression propertyExpression))
{
throw new ArgumentException("Must be a property member expression", nameof(memberExpression));
}

var parsedCall = CallExpressionParser.FromPropertySetter(propertyExpression, constraintExpression.Body);
var parsedCall = CallExpressionParser.FromPropertySetter(propertyExpression, constraintExpression?.Body);
var callConstraint = parsedCall.CreateCallConstraint();

return new ActionRedirectBuilder<TTarget>(parsedCall, callConstraint.Of<TTarget>());
Expand Down
2 changes: 1 addition & 1 deletion src/DivertR/Via.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public IActionViaBuilder<TTarget> To(Expression<Action<TTarget>> constraintExpre
return new ActionViaBuilder<TTarget>(this, RedirectBuilder<TTarget>.To(constraintExpression));
}

public IActionViaBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty?>> constraintExpression)
public IActionViaBuilder<TTarget> ToSet<TProperty>(Expression<Func<TTarget, TProperty>> memberExpression, Expression<Func<TProperty>>? constraintExpression = null)
{
return new ActionViaBuilder<TTarget>(this, RedirectBuilder<TTarget>.ToSet(memberExpression, constraintExpression));
}
Expand Down
16 changes: 16 additions & 0 deletions test/DivertR.UnitTests/ViaRedirectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,22 @@ public void GivenExpressionMethodBodyRedirect_WhenCallMatches_ShouldRedirect()
// ASSERT
result.ShouldBe("matched");
}

[Fact]
public void GivenSetPropertyRedirectWithNoValueConstraint_WhenValueMatches_ShouldRedirect()
{
// ARRANGE
_via
.ToSet(x => x.Name)
.Redirect<(string value, __)>(call => call.Relay.Root.Name = $"New {call.Args.value} set");

// ACT
var proxy = _via.Proxy(new Foo("hello foo"));
proxy.Name = "test";

// ASSERT
proxy.Name.ShouldBe("New test set");
}

[Fact]
public void GivenSetPropertyRedirect_WhenValueMatches_ShouldRedirect()
Expand Down

0 comments on commit 1e4ac16

Please sign in to comment.