forked from FakeItEasy/FakeItEasy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ExpressionArgumentConstraintFactory.cs
114 lines (93 loc) · 3.96 KB
/
ExpressionArgumentConstraintFactory.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
namespace FakeItEasy.Expressions
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
#if FEATURE_NETCORE_REFLECTION
using System.Reflection;
#endif
using FakeItEasy.Core;
using FakeItEasy.Expressions.ArgumentConstraints;
internal class ExpressionArgumentConstraintFactory
{
private readonly IArgumentConstraintTrapper argumentConstraintTrapper;
public ExpressionArgumentConstraintFactory(IArgumentConstraintTrapper argumentConstraintTrapper)
{
this.argumentConstraintTrapper = argumentConstraintTrapper;
}
public virtual IArgumentConstraint GetArgumentConstraint(ParsedArgumentExpression argument)
{
if (IsParamArrayExpression(argument))
{
return this.CreateParamArrayConstraint((NewArrayExpression)argument.Expression);
}
var isByRefArgument = IsByRefArgument(argument);
if (isByRefArgument && IsOutArgument(argument))
{
return new OutArgumentConstraint(argument.Value);
}
var constraint = this.GetArgumentConstraintFromExpression(argument.Expression);
if (isByRefArgument)
{
object value;
try
{
value = argument.Value;
}
catch
{
value = argument.ArgumentInformation.ParameterType.GetDefaultValue();
}
constraint = new RefArgumentConstraint(constraint, value);
}
return constraint;
}
private static IArgumentConstraint TryCreateConstraintFromTrappedConstraints(ICollection<IArgumentConstraint> trappedConstraints)
{
return trappedConstraints.FirstOrDefault();
}
private static bool IsParamArrayExpression(ParsedArgumentExpression argument)
{
return IsTaggedWithParamArrayAttribute(argument) && argument.Expression is NewArrayExpression;
}
private static bool IsTaggedWithParamArrayAttribute(ParsedArgumentExpression argument)
{
return argument.ArgumentInformation.GetCustomAttributes(typeof(ParamArrayAttribute), true).Any();
}
private static bool IsOutArgument(ParsedArgumentExpression argument)
{
return argument.ArgumentInformation.IsOut;
}
private static bool IsByRefArgument(ParsedArgumentExpression argument)
{
return argument.ArgumentInformation.ParameterType.IsByRef;
}
private static IArgumentConstraint CreateEqualityConstraint(object expressionValue)
{
return new EqualityArgumentConstraint(expressionValue);
}
private static object InvokeExpression(Expression expression)
{
return Expression.Lambda(expression).Compile().DynamicInvoke();
}
private IArgumentConstraint GetArgumentConstraintFromExpression(Expression expression)
{
object expressionValue = null;
var trappedConstraints = this.argumentConstraintTrapper.TrapConstraints(() =>
{
expressionValue = InvokeExpression(expression);
});
return TryCreateConstraintFromTrappedConstraints(trappedConstraints.ToArray()) ?? CreateEqualityConstraint(expressionValue);
}
private IArgumentConstraint CreateParamArrayConstraint(NewArrayExpression expression)
{
var result = new List<IArgumentConstraint>();
foreach (var argumentExpression in expression.Expressions)
{
result.Add(this.GetArgumentConstraintFromExpression(argumentExpression));
}
return new AggregateArgumentConstraint(result);
}
}
}