/// <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); }