protected SetupWithOutParameterSupport(FluentSetup fluentSetup, Mock mock, InvocationShape expectation) : base(fluentSetup, mock, expectation) { Debug.Assert(expectation != null); this.outValues = GetOutValues(expectation.Arguments, expectation.Method.GetParameters()); }
internal static void VerifySet(Mock mock, Delegate setterExpression, Times times, string failMessage) { var(targetMock, expression, method, value) = SetupSetImpl(mock, setterExpression); var expectation = new InvocationShape(method, value); VerifyCalls(targetMock, expectation, expression, times, failMessage); }
protected Setup(InvocationShape expectation, LambdaExpression expression) { Debug.Assert(expression != null); this.expectation = expectation; this.expression = expression; }
/// <remarks> /// Only use this constructor when you know that the specified <paramref name="method"/> has no `out` parameters, /// and when you want to avoid the <see cref="MatcherFactory"/>-related overhead of the other constructor overload. /// </remarks> public MethodCall(Mock mock, Condition condition, LambdaExpression originalExpression, MethodInfo method, IMatcher[] argumentMatchers) { this.condition = condition; this.expectation = new InvocationShape(method, argumentMatchers); this.mock = mock; this.originalExpression = originalExpression; this.outValues = null; }
protected Setup(Mock mock, InvocationShape expectation) { Debug.Assert(mock != null); Debug.Assert(expectation != null); this.expectation = expectation; this.mock = mock; }
public InnerMockSetup(Expression originalExpression, Mock mock, InvocationShape expectation, object returnValue) : base(originalExpression, mock, expectation) { Debug.Assert(Awaitable.TryGetResultRecursive(returnValue) is IMocked); this.returnValue = returnValue; this.MarkAsVerifiable(); }
protected Setup(FluentSetup fluentSetup, Mock mock, InvocationShape expectation) { Debug.Assert(mock != null); Debug.Assert(expectation != null); this.fluentSetup = fluentSetup; this.expectation = expectation; this.mock = mock; }
protected Setup(Expression originalExpression, Mock mock, InvocationShape expectation) { Debug.Assert(mock != null); Debug.Assert(expectation != null); this.originalExpression = originalExpression; this.expectation = expectation; this.mock = mock; }
public InnerMockSetup(Expression originalExpression, Mock mock, InvocationShape expectation, object returnValue) : base(originalExpression, mock, expectation) { Debug.Assert(Unwrap.ResultIfCompletedTask(returnValue) is IMocked); this.returnValue = returnValue; this.MarkAsVerifiable(); }
public MethodCall(Mock mock, Condition condition, LambdaExpression originalExpression, MethodInfo method, IReadOnlyList <Expression> arguments) { this.condition = condition; this.expectation = new InvocationShape(method, arguments); this.mock = mock; this.originalExpression = originalExpression; this.outValues = GetOutValues(arguments, method.GetParameters()); this.SetFileInfo(); }
internal static void VerifyGet(Mock mock, LambdaExpression expression, Times times, string failMessage) { var method = expression.ToPropertyInfo().GetGetMethod(true); ThrowIfVerifyExpressionInvolvesUnsupportedMember(expression, method); var expectation = new InvocationShape(method, new IMatcher[0]); VerifyCalls(GetTargetMock(((MemberExpression)expression.Body).Expression, mock), expectation, expression, times, failMessage); }
internal static void VerifyVoid(Mock mock, LambdaExpression expression, Times times, string failMessage) { Guard.NotNull(times, nameof(times)); var(obj, method, args) = expression.GetCallInfo(mock); ThrowIfVerifyExpressionInvolvesUnsupportedMember(expression, method); var expectation = new InvocationShape(method, args); VerifyCalls(GetTargetMock(obj, mock), expectation, expression, times, failMessage); }
public MethodCall(FluentSetup fluentSetup, Mock mock, Condition condition, InvocationShape expectation) : base(fluentSetup, mock, expectation) { this.condition = condition; this.flags = expectation.Method.ReturnType != typeof(void) ? Flags.MethodIsNonVoid : 0; if ((mock.Switches & Switches.CollectDiagnosticFileInfoForSetups) != 0) { this.declarationSite = GetUserCodeCallSite(); } }
protected SetupWithOutParameterSupport( Expression originalExpression, Mock mock, InvocationShape expectation ) : base(originalExpression, mock, expectation) { Debug.Assert(expectation != null); this.outValues = GetOutValues( expectation.Arguments, expectation.Method.GetParameters() ); }
public MethodCall( Expression originalExpression, Mock mock, Condition condition, InvocationShape expectation ) : base(originalExpression, mock, expectation) { this.condition = condition; if ((mock.Switches & Switches.CollectDiagnosticFileInfoForSetups) != 0) { this.declarationSite = GetUserCodeCallSite(); } }
public MethodCall(Mock mock, Condition condition, InvocationShape expectation) : base(expectation) { this.condition = condition; this.flags = expectation.Method.ReturnType != typeof(void) ? Flags.MethodIsNonVoid : 0; this.mock = mock; #if FEATURE_CALLERINFO if ((mock.Switches & Switches.CollectDiagnosticFileInfoForSetups) != 0) { this.declarationSite = GetUserCodeCallSite(); } #endif }
internal static void VerifySet <T, TProperty>( Mock mock, Expression <Func <T, TProperty> > expression, Times times, string failMessage) where T : class { var method = expression.ToPropertyInfo().SetMethod; ThrowIfVerifyExpressionInvolvesUnsupportedMember(expression, method); var expectation = new InvocationShape(method, new IMatcher[] { AnyMatcher.Instance }); VerifyCalls(GetTargetMock(((MemberExpression)expression.Body).Expression, mock), expectation, expression, times, failMessage); }
public static bool TryFind(this IEnumerable <Setup> innerMockSetups, InvocationShape expectation, out Setup setup) { Debug.Assert(innerMockSetups.All(s => s.ReturnsInnerMock(out _))); foreach (Setup innerMockSetup in innerMockSetups) { if (innerMockSetup.Expectation.Equals(expectation)) { setup = innerMockSetup; return(true); } } setup = default; return(false); }
internal static void Verify <T, TResult>( Mock <T> mock, Expression <Func <T, TResult> > expression, Times times, string failMessage) where T : class { Guard.NotNull(times, nameof(times)); if (expression.IsProperty()) { VerifyGet <T, TResult>(mock, expression, times, failMessage); } else { var(obj, method, args) = expression.GetCallInfo(mock); ThrowIfVerifyExpressionInvolvesUnsupportedMember(expression, method); var expectation = new InvocationShape(method, args); VerifyCalls(GetTargetMock(obj, mock), expectation, expression, times, failMessage); } }
private static void VerifyCalls( Mock targetMock, InvocationShape expectation, LambdaExpression expression, Times times, string failMessage) { var allInvocations = targetMock.MutableInvocations.ToArray(); var matchingInvocations = allInvocations.Where(expectation.IsMatch).ToArray(); var matchingInvocationCount = matchingInvocations.Length; if (!times.Verify(matchingInvocationCount)) { Setup[] setups; if (targetMock.IsDelegateMock) { // For delegate mocks, there's no need to compare methods as for regular mocks (below) // since there's only one single method, so include all setups unconditionally. setups = targetMock.Setups.ToArrayLive(s => true); } else { setups = targetMock.Setups.ToArrayLive(oc => AreSameMethod(oc.Expression, expression)); } throw MockException.NoMatchingCalls(failMessage, setups, allInvocations, expression, times, matchingInvocationCount); } else { foreach (var matchingInvocation in matchingInvocations) { matchingInvocation.MarkAsVerified(); } } bool AreSameMethod(LambdaExpression l, LambdaExpression r) => l.Body is MethodCallExpression lc && r.Body is MethodCallExpression rc && lc.Method == rc.Method; }
protected Setup(InvocationShape expectation) { Debug.Assert(expectation != null); this.expectation = expectation; }
/// <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 <InvocationShape> Split(this LambdaExpression expression) { Debug.Assert(expression != null); var parts = new Stack <InvocationShape>(); Expression remainder = expression.Body; while (CanSplit(remainder)) { Split(remainder, out remainder, out var part); parts.Push(part); } if (parts.Count > 0 && remainder is ParameterExpression) { return(parts); } else { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Resources.UnsupportedExpression, remainder.ToStringFixed())); } bool CanSplit(Expression e) { switch (e.NodeType) { case ExpressionType.Assign: case ExpressionType.AddAssign: case ExpressionType.SubtractAssign: { var assignmentExpression = (BinaryExpression)e; return(CanSplit(assignmentExpression.Left)); } case ExpressionType.Call: case ExpressionType.Index: { return(true); } case ExpressionType.Invoke: { var invocationExpression = (InvocationExpression)e; return(typeof(Delegate).IsAssignableFrom(invocationExpression.Expression.Type)); } case ExpressionType.MemberAccess: { var memberAccessExpression = (MemberExpression)e; return(memberAccessExpression.Member is PropertyInfo); } case ExpressionType.Parameter: default: { return(false); } } } void Split(Expression e, out Expression r /* remainder */, out InvocationShape p /* part */) { 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); PropertyInfo property; if (lhs.Expression.Body is MemberExpression me) { Debug.Assert(me.Member is PropertyInfo); property = (PropertyInfo)me.Member; } else { Debug.Assert(lhs.Expression.Body is IndexExpression); property = ((IndexExpression)lhs.Expression.Body).Indexer; } var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var arguments = new Expression[lhs.Arguments.Count + 1]; for (var ai = 0; ai < arguments.Length - 1; ++ai) { arguments[ai] = lhs.Arguments[ai]; } arguments[arguments.Length - 1] = assignmentExpression.Right; p = new InvocationShape( expression: Expression.Lambda( Expression.MakeBinary(e.NodeType, lhs.Expression.Body, assignmentExpression.Right), parameter), method: property.GetSetMethod(true), arguments); return; } case ExpressionType.Call: // regular method call { var methodCallExpression = (MethodCallExpression)e; 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 InvocationShape( 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 InvocationShape( 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; p = new InvocationShape( expression: Expression.Lambda( Expression.MakeIndex(parameter, indexer, arguments), parameter), method: indexer.GetGetMethod(true), arguments); return; } case ExpressionType.Invoke: // delegate invocation { var invocationExpression = (InvocationExpression)e; Debug.Assert(invocationExpression.Expression.Type.IsDelegate()); r = invocationExpression.Expression; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var arguments = invocationExpression.Arguments; p = new InvocationShape( 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); r = memberAccessExpression.Expression; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var property = memberAccessExpression.GetReboundProperty(); var method = property.CanRead ? property.GetGetMethod(true) : property.GetSetMethod(true); // ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // We're in the switch case block for property read access, therefore we prefer the // getter. When a read-write property is being assigned to, we end up here, too, and // select the wrong accessor. However, that doesn't matter because it will be over- // ridden in the above `Assign` case. Finally, if a write-only property is being // assigned to, we fall back to the setter here in order to not end up without a // method at all. p = new InvocationShape( expression: Expression.Lambda( Expression.MakeMemberAccess(parameter, property), parameter), method); return; } default: Debug.Assert(!CanSplit(e)); throw new InvalidOperationException(); // this should be unreachable } } }
/// <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 <InvocationShape> Split(this LambdaExpression expression) { Debug.Assert(expression != null); var parts = new Stack <InvocationShape>(); Expression remainder = expression.Body; while (CanSplit(remainder)) { Split(remainder, out remainder, out var part); 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 InvocationShape p /* part */, bool assignment = 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 InvocationShape( 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.IsTypeMatcher(out var typeMatcherType)) { Guard.ImplementsTypeMatcherProtocol(typeMatcherType); } } } 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 InvocationShape( 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 InvocationShape( 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; var method = !assignment && indexer.CanRead(out var getter) ? getter : indexer.CanWrite(out var setter) ? setter : null; p = new InvocationShape( expression: Expression.Lambda( Expression.MakeIndex(parameter, indexer, arguments), parameter), method, arguments, skipMatcherInitialization: assignment); 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 InvocationShape( 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); r = memberAccessExpression.Expression; var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName); var property = memberAccessExpression.GetReboundProperty(); var method = !assignment && property.CanRead(out var getter) ? getter : property.CanWrite(out var setter) ? setter : null; p = new InvocationShape( expression: Expression.Lambda( Expression.MakeMemberAccess(parameter, property), parameter), method, skipMatcherInitialization: assignment); return; } default: Debug.Assert(!CanSplit(e)); throw new InvalidOperationException(); // this should be unreachable } } }
public SequenceSetup(Expression originalExpression, Mock mock, InvocationShape expectation) : base(originalExpression, mock, expectation) { this.responses = new ConcurrentQueue <Response>(); }
public SequenceSetup(InvocationShape expectation) : base(expectation) { this.responses = new ConcurrentQueue <Response>(); }
public SequenceSetup(Expression originalExpression, Mock mock, InvocationShape expectation) : base(originalExpression, mock, expectation) { this.behaviors = new ConcurrentQueue <Behavior>(); }
public static Setup TryFind(this IEnumerable <Setup> setups, InvocationShape expectation) { return(setups.FirstOrDefault(setup => setup.Expectation.Equals(expectation))); }
/// <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 <InvocationShape> Split(this LambdaExpression expression, bool allowNonOverridableLastProperty = false) { Debug.Assert(expression != null); var parts = new Stack <InvocationShape>(); 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 InvocationShape 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 InvocationShape( 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 InvocationShape( 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 InvocationShape( 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 InvocationShape( 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 InvocationShape( 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); 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 InvocationShape( 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 } } }
public SequenceSetup(FluentSetup fluentSetup, Mock mock, InvocationShape expectation) : base(fluentSetup, mock, expectation) { this.responses = new ConcurrentQueue <Response>(); }