public InnerMockSetup(Expression originalExpression, Mock mock, MethodExpectation expectation, object returnValue) : base(originalExpression, mock, expectation) { Debug.Assert(Awaitable.TryGetResultRecursive(returnValue) is IMocked); this.returnValue = returnValue; this.MarkAsVerifiable(); }
protected SetupWithOutParameterSupport(Expression originalExpression, Mock mock, MethodExpectation expectation) : base(originalExpression, mock, expectation) { Debug.Assert(expectation != null); this.outValues = GetOutValues(expectation.Arguments, expectation.Method.GetParameters()); }
public bool Matches(MethodExpectation expectation) { return(this.expectation.Equals(expectation)); }
protected MethodSetup(Expression originalExpression, Mock mock, MethodExpectation expectation) : base(originalExpression, mock, expectation) { }
public MethodCall(Expression originalExpression, Mock mock, Condition condition, MethodExpectation expectation) : base(originalExpression, mock, expectation) { this.condition = condition; if ((mock.Switches & Switches.CollectDiagnosticFileInfoForSetups) != 0) { this.declarationSite = GetUserCodeCallSite(); } }
/// <summary> /// Splits an expression such as `<c>m => m.A.B(x).C[y] = z</c>` into a chain of parts /// that can be set up one at a time: /// <list> /// <item>`<c>m => m.A</c>`</item>, /// <item>`<c>... => ....B(x)</c>`</item>, /// <item>`<c>... => ....C</c>`</item>, /// <item>`<c>... => ...[y] = z</c>`</item>. /// </list> /// <para> /// The split points are chosen such that each part has exactly one associated /// <see cref="MethodInfo"/> and optionally some argument expressions. /// </para> /// </summary> /// <exception cref="ArgumentException"> /// It was not possible to completely split up the expression. /// </exception> internal static Stack <MethodExpectation> Split(this LambdaExpression expression, bool allowNonOverridableLastProperty = false) { Debug.Assert(expression != null); var parts = new Stack <MethodExpectation>(); Expression remainder = expression.Body; while (CanSplit(remainder)) { Split(remainder, out remainder, out var part, allowNonOverridableLastProperty: allowNonOverridableLastProperty && parts.Count == 0); parts.Push(part); } if (parts.Count > 0 && remainder is ParameterExpression) { return(parts); } else { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.UnsupportedExpression, remainder.ToStringFixed())); } void Split(Expression e, out Expression r /* remainder */, out MethodExpectation p /* part */, bool assignment = false, bool allowNonOverridableLastProperty = false) { const string ParameterName = "..."; switch (e.NodeType) { case ExpressionType.Assign: // assignment to a property or indexer case ExpressionType.AddAssign: // subscription of event handler to event case ExpressionType.SubtractAssign: // unsubscription of event handler from event { var assignmentExpression = (BinaryExpression)e; Split(assignmentExpression.Left, out r, out var lhs, assignment: true); var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var arguments = new Expression[lhs.Method.GetParameters().Length]; for (var ai = 0; ai < arguments.Length - 1; ++ai) { arguments[ai] = lhs.Arguments[ai]; } arguments[arguments.Length - 1] = assignmentExpression.Right; p = new MethodExpectation( expression: Expression.Lambda( Expression.MakeBinary(e.NodeType, lhs.Expression.Body, assignmentExpression.Right), parameter), method: lhs.Method, arguments); return; } case ExpressionType.Call: // regular method call { var methodCallExpression = (MethodCallExpression)e; if (methodCallExpression.Method.IsGenericMethod) { foreach (var typeArgument in methodCallExpression.Method.GetGenericArguments()) { if (typeArgument.IsOrContainsTypeMatcher()) { // This is a (somewhat roundabout) way of ensuring that the type matchers used // will be usable. They will not be usable if they don't implement the type // matcher protocol correctly; and `SubstituteTypeMatchers` tests for that, so // we'll reuse its recursive logic instead of having to reimplement our own. _ = typeArgument.SubstituteTypeMatchers(typeArgument); } } } if (!methodCallExpression.Method.IsStatic) { r = methodCallExpression.Object; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var method = methodCallExpression.Method; var arguments = methodCallExpression.Arguments; p = new MethodExpectation( expression: Expression.Lambda( Expression.Call(parameter, method, arguments), parameter), method, arguments); } else { Debug.Assert(methodCallExpression.Method.IsExtensionMethod()); Debug.Assert(methodCallExpression.Arguments.Count > 0); r = methodCallExpression.Arguments[0]; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var method = methodCallExpression.Method; var arguments = methodCallExpression.Arguments.ToArray(); arguments[0] = parameter; p = new MethodExpectation( expression: Expression.Lambda( Expression.Call(method, arguments), parameter), method, arguments); } return; } case ExpressionType.Index: // indexer query { var indexExpression = (IndexExpression)e; r = indexExpression.Object; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var indexer = indexExpression.Indexer; var arguments = indexExpression.Arguments; MethodInfo method; if (!assignment && indexer.CanRead(out var getter, out var getterIndexer)) { method = getter; indexer = getterIndexer; } else if (indexer.CanWrite(out var setter, out var setterIndexer)) { method = setter; indexer = setterIndexer; } else // This should be unreachable. { method = null; } p = new MethodExpectation( expression: Expression.Lambda( Expression.MakeIndex(parameter, indexer, arguments), parameter), method, arguments, skipMatcherInitialization: assignment, allowNonOverridable: allowNonOverridableLastProperty); return; } case ExpressionType.Invoke: // delegate invocation { var invocationExpression = (InvocationExpression)e; Debug.Assert(invocationExpression.Expression.Type.IsDelegateType()); r = invocationExpression.Expression; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var arguments = invocationExpression.Arguments; p = new MethodExpectation( expression: Expression.Lambda( Expression.Invoke(parameter, arguments), parameter), method: r.Type.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), arguments); return; } case ExpressionType.MemberAccess: // property query { var memberAccessExpression = (MemberExpression)e; Debug.Assert(memberAccessExpression.Member is PropertyInfo); if (IsResult(memberAccessExpression.Member, out var awaitableFactory)) { Split(memberAccessExpression.Expression, out r, out p); p.AddResultExpression( awaitable => Expression.MakeMemberAccess(awaitable, memberAccessExpression.Member), awaitableFactory); return; } r = memberAccessExpression.Expression; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var property = memberAccessExpression.GetReboundProperty(); MethodInfo method; if (!assignment && property.CanRead(out var getter, out var getterProperty)) { method = getter; property = getterProperty; } else if (property.CanWrite(out var setter, out var setterProperty)) { method = setter; property = setterProperty; } else // This should be unreachable. { method = null; } p = new MethodExpectation( expression: Expression.Lambda( Expression.MakeMemberAccess(parameter, property), parameter), method, skipMatcherInitialization: assignment, allowNonOverridable: allowNonOverridableLastProperty); return; } default: Debug.Assert(!CanSplit(e)); throw new InvalidOperationException(); // this should be unreachable } } bool IsResult(MemberInfo member, out IAwaitableFactory awaitableFactory) { var instanceType = member.DeclaringType; awaitableFactory = AwaitableFactory.TryGet(instanceType); var returnType = member switch { PropertyInfo p => p.PropertyType, _ => null }; return(awaitableFactory != null && object.Equals(returnType, awaitableFactory.ResultType)); } }
public SequenceSetup(Expression originalExpression, Mock mock, MethodExpectation expectation) : base(originalExpression, mock, expectation) { this.behaviors = new ConcurrentQueue <Behavior>(); }