forked from devlooped/moq
/
DuckSetterReplacer.cs
52 lines (46 loc) · 1.59 KB
/
DuckSetterReplacer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Moq.Protected
{
internal sealed class DuckSetterReplacer<TMock, TAnalog> : ExpressionVisitor
{
private ParameterExpression parameterToReplace;
private ParameterExpression mockParameter;
private Type mockType = typeof(TMock);
private PropertyInfo GetMockProperty(PropertyInfo property)
{
return mockType.GetProperty(
property.Name,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
property.PropertyType,
property.GetIndexParameters().Select(p => p.ParameterType).ToArray(),
new ParameterModifier[] { }
);
}
protected override Expression VisitIndex(IndexExpression node)
{
if (node.Object is ParameterExpression parameterExpression && parameterExpression == parameterToReplace)
{
return Expression.MakeIndex(mockParameter, GetMockProperty(node.Indexer), node.Arguments);
}
return base.VisitIndex(node);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression is ParameterExpression parameterExpression && parameterExpression == parameterToReplace)
{
return Expression.MakeMemberAccess(mockParameter, GetMockProperty(node.Member as PropertyInfo));
}
return base.VisitMember(node);
}
public Expression<Action<TMock>> Replace(Expression<Action<TAnalog>> expression)
{
parameterToReplace = expression.Parameters[0];
mockParameter = Expression.Parameter(typeof(TMock), parameterToReplace.Name);
return Expression.Lambda<Action<TMock>>(expression.Body.Apply(this), mockParameter);
}
}
}