/// <inheritdoc /> public IMethodReturn Invoke(IMethodInvocation invocation, GetNextBehavior getNext) { var arguments = invocation.Arguments.ToArray(); var parameters = invocation.MethodBase.GetParameters(); for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; // This covers both out & ref if (parameter.ParameterType.IsByRef) { arguments[i] = DefaultValue.For(parameter.ParameterType); } } var returnValue = default(object); if (invocation.MethodBase is MethodInfo info && info.ReturnType != typeof(void)) { returnValue = DefaultValue.For(info.ReturnType); } return(invocation.CreateValueReturn(returnValue, arguments)); }
/// <summary> /// Gets the behavior for the current invocation. /// </summary> public static IBehavior GetBehavior() { if (lastPipeline.Value != null) { return(lastPipeline.Value); } // This behavior is key to enabling static extension methods // on arbitrary types and allow transparent "recording" // behavior. The moment an extension method such as // Returns<T>(this T target, T value) invokes this GetBehavior // method, we assume the most recent call (the retrieval of // a property value, or invocation of a method that returns // some value T) was intended for matching purposes only, // so we need to "unwind" it and build a pipeline with it // so that it can be further customized by the extension method // implementation. // Here's what we do: // Use last invocation, argument matchers, // actual invocation arguments, build // list of matchers for all arguments, // and add pipeline to mock. if (lastInvocation.Value == null) { throw new InvalidOperationException("There is no mock being called."); } var currentMatchers = argumentMatchers.Value; var finalMatchers = new List <IArgumentMatcher>(); var invocation = lastInvocation.Value; var parameters = invocation.Method.GetParameters(); for (int i = 0; i < invocation.Arguments.Length; i++) { var argument = invocation.Arguments[i]; var parameter = parameters[i]; if (Object.Equals(argument, DefaultValue.For(parameter.ParameterType)) && currentMatchers.Count != 0 && parameter.ParameterType.IsAssignableFrom(currentMatchers.Peek().ArgumentType)) { finalMatchers.Add(currentMatchers.Pop()); } else { finalMatchers.Add(new Arguments.ConstantMatcher(parameter.ParameterType, argument)); } } lastPipeline.Value = new Behavior( invocation.Mock.DefaultBehavior, invocation.Mock.SelectorFactory.CreateSelector(invocation, finalMatchers)); invocation.Mock.Invocations.Remove(CallContext.LastInvocation); return(lastPipeline.Value); }
/// <summary> /// Gets the behavior pipeline for the current invocation. /// </summary> /// <returns></returns> public static BehaviorPipeline GetBehavior() { if (lastPipeline.Value != null) { return(lastPipeline.Value); } // Use last invocation, argument matchers, // actual invocation arguments, build // list of matchers for all arguments, // and add pipeline to mock. // Clean last invocation and matchers, // as well as the actual mock invocation // that was tracked, as it was used // for recording purposes. if (lastInvocation.Value == null) { throw new InvalidOperationException("There is no mock being called."); } var currentMatchers = argumentMatchers.Value; var finalMatchers = new List <IArgumentMatcher>(); var invocation = lastInvocation.Value; var parameters = invocation.Method.GetParameters(); for (int i = 0; i < invocation.Arguments.Length; i++) { var argument = invocation.Arguments[i]; var parameter = parameters[i]; if (Object.Equals(argument, DefaultValue.For(parameter.ParameterType)) && currentMatchers.Count != 0 && parameter.ParameterType.IsAssignableFrom(currentMatchers.Peek().ArgumentType)) { finalMatchers.Add(currentMatchers.Pop()); } else { finalMatchers.Add(new Arguments.ConstantMatcher(parameter.ParameterType, argument)); } } lastPipeline.Value = new BehaviorPipeline(new Behaviors.ReturnDefaultValue(), finalMatchers); return(lastPipeline.Value); }