예제 #1
0
        /// <summary>
        /// Handle a method call for the underlying mocked object
        /// </summary>
        /// <param name="invocation"></param>
        /// <param name="method"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public object HandleMethodCall(IInvocation invocation, MethodInfo method, object[] arguments)
        {
            if (arguments == null)
            {
                arguments = new object[0];
            }

            if (method.IsSpecialName)
            {
                var methodName = method.Name;
                if (methodName.StartsWith("get_", StringComparison.Ordinal) ||
                    methodName.StartsWith("set_", StringComparison.Ordinal))
                {
                    if (container.Any(x => x.Type == ExpectationType.Property))
                    {
                        return(HandlePropertyCall(invocation, method, arguments));
                    }
                }

                if (methodName.StartsWith("add_", StringComparison.Ordinal) ||
                    methodName.StartsWith("remove_", StringComparison.Ordinal))
                {
                    if (container.Any(x => x.Type == ExpectationType.Event))
                    {
                        return(HandleEventCall(invocation, method, arguments));
                    }
                }
            }

            var actual = new Actuals(method, arguments);

            actuals.Add(actual);

            var methodCollection = container
                                   .Where(x => x.Type == ExpectationType.Method)
                                   .ToArray();

            Expectation expectation = null;

            for (int entryIndex = 0; entryIndex < methodCollection.Length; entryIndex++)
            {
                var entry = methodCollection[entryIndex];
                if (!entry.MatchesCall(method, arguments))
                {
                    continue;
                }

                if (entry.ExpectationSatisfied)
                {
                    continue;
                }

                expectation = entry;
                break;
            }

            //NOTE: this could be where a "strict" mock call would throw an exception
            if (expectation == null)
            {
                for (int entryIndex = 0; entryIndex < methodCollection.Length; entryIndex++)
                {
                    var entry = methodCollection[entryIndex];
                    if (!entry.MatchesCall(method, arguments))
                    {
                        continue;
                    }

                    if (entry.ExpectationSatisfied)
                    {
                        entry.AddActualCall(actual);
                        continue;
                    }
                }

                return(HandleUnexpectedMethodCall(invocation, method, arguments));
            }

            RhinoMocks.Logger.LogExpectedMethodCall(invocation);
            expectation.AddActualCall(actual);

            if (expectation.HasDelegateToInvoke)
            {
                var methodParameters = method.GetParameters();

                var callback           = expectation.DelegateToInvoke;
                var callbackParameters = callback.Method.GetParameters();

                try
                {
                    if (callbackParameters.Length == 0)
                    {
                        var value = callback.DynamicInvoke(new object[0]);

                        if (callback.Method.ReturnType != (typeof(void)) &&
                            expectation.DelegateReturnsValue)
                        {
                            expectation.SetReturnValue(value);
                        }
                    }
                    else
                    {
                        var invokeCallback  = true;
                        var invokeArguments = new object[callbackParameters.Length];
                        for (int index = 0; index < callbackParameters.Length; index++)
                        {
                            var parameter     = callbackParameters[index];
                            var parameterType = parameter.ParameterType;

                            var argument     = methodParameters[index];
                            var argumentType = argument.ParameterType;

                            if (!parameterType.IsAssignableFrom(argumentType))
                            {
                                invokeCallback = false;
                                break;
                            }
                        }

                        if (invokeCallback)
                        {
                            var value = callback.DynamicInvoke(arguments);

                            if (callback.Method.ReturnType != (typeof(void)) &&
                                expectation.DelegateReturnsValue)
                            {
                                expectation.SetReturnValue(value);
                            }
                        }
                    }
                }
                catch (TargetInvocationException ex)
                {
                    throw ex.InnerException;
                }
            }

            if (expectation.ReturnArguments != null && expectation.ReturnArguments.Any())
            {
                var lenth      = expectation.ReturnArguments.Length;
                var parameters = method.GetParameters();
                for (int index = 0, returnIndex = 0; index < parameters.Length && returnIndex < lenth; index++)
                {
                    var parameter = parameters[index];
                    if (!parameter.IsOut && !parameter.ParameterType.IsByRef)
                    {
                        continue;
                    }

                    arguments[index] = expectation.ReturnArguments[returnIndex];
                    returnIndex++;
                }
            }

            if (expectation.ThrowsException)
            {
                throw expectation.ExceptionToThrow;
            }

            if (expectation.ForceProceed)
            {
                invocation.Proceed();

                if (expectation.HasDelegateToIntercept)
                {
                    expectation.DelegateToIntercept(new MethodInvocation(invocation));
                }

                return(invocation.ReturnValue);
            }

            invocation.ReturnValue = expectation.ReturnValue;

            if (expectation.HasDelegateToIntercept)
            {
                expectation.DelegateToIntercept(new MethodInvocation(invocation));
            }

            return(invocation.ReturnValue);
        }