Пример #1
0
        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());
        }
Пример #3
0
 public bool Matches(MethodExpectation expectation)
 {
     return(this.expectation.Equals(expectation));
 }
Пример #4
0
 protected MethodSetup(Expression originalExpression, Mock mock, MethodExpectation expectation)
     : base(originalExpression, mock, expectation)
 {
 }
Пример #5
0
        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();
            }
        }
Пример #6
0
        /// <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));
            }
        }
Пример #7
0
 public SequenceSetup(Expression originalExpression, Mock mock, MethodExpectation expectation)
     : base(originalExpression, mock, expectation)
 {
     this.behaviors = new ConcurrentQueue <Behavior>();
 }