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

fix ProtectedMock fails when arguments are of type Expression #1188 #1189

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
64 changes: 47 additions & 17 deletions src/Moq/Protected/ProtectedMock.cs
Expand Up @@ -467,26 +467,15 @@ private static Type[] ToArgTypes(object[] args)
{
types[index] = ((MethodCallExpression)expr).Method.ReturnType;
}
else if(ItRefAnyField(expr) is var itRefAnyField && itRefAnyField != null)
stakx marked this conversation as resolved.
Show resolved Hide resolved
{
types[index] = itRefAnyField.FieldType.MakeByRefType();
}
else if (expr.NodeType == ExpressionType.MemberAccess)
{
var member = (MemberExpression)expr;
if (member.Member is FieldInfo field)
{
// Test for special case: `It.Ref<TValue>.IsAny`
if (field.Name == nameof(It.Ref<object>.IsAny))
{
var fieldDeclaringType = field.DeclaringType;
if (fieldDeclaringType.IsGenericType)
{
var fieldDeclaringTypeDefinition = fieldDeclaringType.GetGenericTypeDefinition();
if (fieldDeclaringTypeDefinition == typeof(It.Ref<>))
{
types[index] = field.FieldType.MakeByRefType();
continue;
}
}
}

types[index] = field.FieldType;
}
else if (member.Member is PropertyInfo property)
Expand All @@ -510,16 +499,57 @@ private static Type[] ToArgTypes(object[] args)
return types;
}

private static FieldInfo ItRefAnyField(Expression expr)
{
FieldInfo itRefAnyField = null;

if (expr.NodeType == ExpressionType.MemberAccess)
{
var member = (MemberExpression)expr;
if (member.Member is FieldInfo field)
{
if (field.Name == nameof(It.Ref<object>.IsAny))
{
var fieldDeclaringType = field.DeclaringType;
if (fieldDeclaringType.IsGenericType)
{
var fieldDeclaringTypeDefinition = fieldDeclaringType.GetGenericTypeDefinition();
if (fieldDeclaringTypeDefinition == typeof(It.Ref<>))
{
itRefAnyField = field;
}
}
}
}
}

return itRefAnyField;
}

private static Expression ToExpressionArg(Type type, object arg)
{
if (arg is LambdaExpression lambda)
if (arg is LambdaExpression lambda && !typeof(LambdaExpression).IsAssignableFrom(type))
{
return lambda.Body;
}

if (arg is Expression expression)
{
return expression;
if (!typeof(Expression).IsAssignableFrom(type))
{
return expression;
}

if (expression.IsMatch(out _))
{
return expression;
}

if (ItRefAnyField(expression) != null)
{
return expression;
}
stakx marked this conversation as resolved.
Show resolved Hide resolved

}

return Expression.Constant(arg, type);
Expand Down
25 changes: 24 additions & 1 deletion tests/Moq.Tests/ProtectedMockFixture.cs
Expand Up @@ -2,7 +2,7 @@
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

using System;

using System.Linq.Expressions;
stakx marked this conversation as resolved.
Show resolved Hide resolved
using Moq.Protected;

using Xunit;
Expand Down Expand Up @@ -855,6 +855,23 @@ public void DoesNotThrowIfVerifySetPropertyTimesReached()
mock.Protected().VerifySet<string>("ProtectedValue", Times.Exactly(2), ItExpr.IsAny<string>());
}

[Fact]
public void SetupShouldWorkWithExpressionTypes()
{
var mock = new Mock<FooBase>();

var expression = Expression.Constant(1);
ConstantExpression setExpression = null;
mock.Protected().SetupSet<ConstantExpression>("ExpressionProperty", expression).Callback(expr => setExpression = expr);
mock.Object.SetExpressionProperty(expression);
Assert.Equal(expression, setExpression);

ConstantExpression setExpression2 = null;
mock.Protected().SetupSet<ConstantExpression>("ExpressionProperty", ItExpr.Is<ConstantExpression>( e => (int)e.Value == 2)).Callback(expr => setExpression2 = expr);
mock.Object.SetExpressionProperty(Expression.Constant(2));
Assert.NotNull(setExpression2);
}

public class MethodOverloads
{
public void ExecuteDo(int a, int b)
Expand Down Expand Up @@ -952,6 +969,12 @@ protected virtual FooBase Overloaded(MyDerived myBase)

public class FooBase
{
protected virtual ConstantExpression ExpressionProperty { get; set; }
stakx marked this conversation as resolved.
Show resolved Hide resolved
public void SetExpressionProperty(ConstantExpression expression)
{
ExpressionProperty = expression;
}

public virtual string PublicValue { get; set; }

protected internal virtual string ProtectedInternalValue { get; set; }
Expand Down