public static EventInfo ParseAddHandlerAction(this MocksRepository repo, Action addHandlerAction, out object instance) { EventInfo theEvent = null; object instanceVar = null; var recorder = new DelegatingRecorder(); recorder.Record += invocation => { var candidateEvent = invocation.Method.GetEventFromAddOrRemove(); if (candidateEvent != null) { theEvent = candidateEvent; instanceVar = MocksRepository.GetMockMixin(invocation.Instance, theEvent.DeclaringType) ?? invocation.Instance; } }; using (repo.StartRecording(recorder, true)) { addHandlerAction(); } instance = instanceVar; return(theEvent); }
internal Invocation(object instance, MethodBase method, object[] args) { this.Instance = instance; this.Method = method; this.Args = args; this.MockMixin = method.IsExtensionMethod() && args.Length >= 1 ? MocksRepository.GetMockMixin(args[0], null) : MocksRepository.GetMockMixin(instance, method.DeclaringType); }
private MethodInfo GetGenericMethodInstance(Type targetType, Type returnType, string memberName, Type[] typeArguments, params object[] args) { var type = targetType; var mixin = MocksRepository.GetMockMixin(targetType, null); if (mixin != null) { type = mixin.DeclaringType; } var method = MockingUtil.GetGenericMethodInstanceByName(type, returnType, memberName, typeArguments, ref args); return(method); }
/// <summary> /// Implementation detail. /// </summary> /// <param name="value"></param> protected void ProcessReturnsValue(TReturn value) { this.CheckConstructorArrangement(); this.ProcessDoInstead(new Func <TReturn>(() => value), false); if ((object)value != null) { var mock = MocksRepository.GetMockMixin(value, typeof(TReturn)); if (mock != null && this.Mock != null) { this.Mock.DependentMocks.Add(value); } } }
public int GetTimesCalled(object target, string memberName, params object[] args) { return(ProfilerInterceptor.GuardInternal(() => { var type = target.GetType(); var mixin = MocksRepository.GetMockMixin(target, null); if (mixin != null) { type = mixin.DeclaringType; } var method = GetMethodByName(type, typeof(void), memberName, ref args); return MockingContext.CurrentRepository.GetTimesCalledFromMethodInfo(target, method, args); })); }
public FuncExpectation <TReturn> Arrange <TReturn>(object target, string memberName, params object[] args) { return(ProfilerInterceptor.GuardInternal(() => { var type = target.GetType(); var mixin = MocksRepository.GetMockMixin(target, null); if (mixin != null) { type = mixin.DeclaringType; } var method = GetMethodByName(type, typeof(TReturn), memberName, ref args); return MockingContext.CurrentRepository.Arrange(target, method, args, () => new FuncExpectation <TReturn>()); })); }
public void Assert(object target, string memberName, Occurs occurs, params object[] args) { ProfilerInterceptor.GuardInternal(() => { var type = target.GetType(); var mixin = MocksRepository.GetMockMixin(target, null); if (mixin != null) { type = mixin.DeclaringType; } var method = GetMethodByName(type, typeof(void), memberName, ref args); MockingContext.CurrentRepository.AssertMethodInfo(target, method, args, occurs); }); }
public void Assert <TReturn>(object target, string memberName, params object[] args) { ProfilerInterceptor.GuardInternal(() => { var type = target.GetType(); var mixin = MocksRepository.GetMockMixin(target, null); if (mixin != null) { type = mixin.DeclaringType; } var message = MockingUtil.GetAssertionMessage(args); var method = MockingUtil.GetMethodByName(type, typeof(TReturn), memberName, ref args); MockingContext.CurrentRepository.AssertMethodInfo(message, target, method, args, null); }); }
public static void RaiseEventImpl(object instance, EventInfo evt, object[] args) { if (evt == null) { throw new MockException("Unable to deduce which event was specified in the parameter."); } if (args == null) { args = new object[] { null }; } if (args.Length == 1 && (evt.EventHandlerType.IsGenericType && evt.EventHandlerType.GetGenericTypeDefinition() == typeof(EventHandler <>) || evt.EventHandlerType == typeof(EventHandler) || args[0] is EventArgs) ) { args = new[] { instance, args[0] }; } if (!(instance is IMockMixin)) { var mockMixin = MocksRepository.GetMockMixin(instance, evt.DeclaringType); if (mockMixin != null) { instance = mockMixin; } } var mixin = instance as IEventsMixin; if (mixin != null) { mixin.RaiseEvent(evt, args); } else { MockingUtil.RaiseEventThruReflection(instance, evt, args); } }
public void Process(Invocation invocation) { if (invocation.Recording || invocation.InArrange || invocation.InAssertSet) { return; } var returnType = invocation.Method.GetReturnType(); if (!typeof(Task).IsAssignableFrom(returnType)) { MockingContext.Fail("Wrong invocation to arrangement: return type of {0}.{1} is not a task", invocation.Instance != null ? MockingUtil.GetUnproxiedType(invocation.Instance) : invocation.Method.DeclaringType, invocation.Method.Name); } var elementType = returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task <>) ? returnType.GetGenericArguments()[0] : typeof(object); Expression <Func <Task <object> > > taskFromException = () => MockingUtil.TaskFromException <object>((Exception)null); var mock = ((MethodCallExpression)taskFromException.Body).Method .GetGenericMethodDefinition() .MakeGenericMethod(elementType) .Invoke(null, new object[] { this.exception }); var parentMock = invocation.MockMixin; var mockMixin = MocksRepository.GetMockMixin(mock, null); if (parentMock != null && mockMixin != null) { parentMock.DependentMocks.Add(mock); } invocation.ReturnValue = mock; invocation.CallOriginal = false; invocation.UserProvidedImplementation = true; }
public void Process(Invocation invocation) { if (invocation.IsReturnValueSet) { return; } var returnType = invocation.Method.GetReturnType(); if (returnType == typeof(void) || returnType.IsValueType) { return; } if (invocation.Method.Name == "ToString" && invocation.Method.GetParameters().Length == 0 && invocation.UserProvidedImplementation) { return; } if (invocation.Method.Name == "GetType" && invocation.Method.GetReturnType() == typeof(Type) && invocation.Method.GetParameters().Length == 0) { return; } object mock = null; List <KeyValuePair <object, object> > mocksList; if (mocks.TryGetValue(invocation.Method, out mocksList)) { // can't put the key part in a Dictionary, // because we can't be sure that GetHashCode() works mock = mocksList.FirstOrDefault(kvp => Equals(kvp.Key, invocation.Instance)).Value; } if (mock == null) { var parentMock = invocation.MockMixin; var repository = parentMock.Repository; if (MustReturnMock(invocation) || this.type == RecursiveMockingBehaviorType.ReturnDefault) { mock = CreateMock(returnType, repository, invocation); } if (mock == null) { return; } if (mocksList == null) { mocksList = new List <KeyValuePair <object, object> >(); mocks.Add(invocation.Method, mocksList); } mocksList.Add(new KeyValuePair <object, object>(invocation.Instance, mock)); var mockMixin = MocksRepository.GetMockMixin(mock, null); if (parentMock != null && mockMixin != null) { parentMock.DependentMocks.Add(mock); } } invocation.ReturnValue = mock; invocation.CallOriginal = false; invocation.UserProvidedImplementation = true; }
internal static CallPattern FromExpression(MocksRepository repository, Expression expr) { var callPattern = new CallPattern(); expr = ((LambdaExpression)expr).Body; // the expression may end with a boxing conversion, remove that while (expr.NodeType == ExpressionType.Convert) { expr = ((UnaryExpression)expr).Operand; } Expression target; MethodBase method = null; Expression[] args; // We're parsing either a property/field expression or a method call. // parse the top of the expression tree and extract the expressions // that will turn into the constituents of the call pattern. if (expr is MemberExpression) { var memberExpr = (MemberExpression)expr; if (!(memberExpr.Member is PropertyInfo)) { throw new MockException("Fields cannot be mocked, only properties."); } var property = (PropertyInfo)memberExpr.Member; target = memberExpr.Expression; method = property.GetGetMethod(true); args = null; } else if (expr is MethodCallExpression) { var methodCall = (MethodCallExpression)expr; method = methodCall.Method; target = methodCall.Object; args = methodCall.Arguments.ToArray(); if (target != null && !target.Type.IsInterface && !target.Type.IsProxy() && target.Type != method.DeclaringType) { method = MockingUtil.GetConcreteImplementer((MethodInfo)method, target.Type); } } else if (expr is NewExpression) { #if !PORTABLE if (ProfilerInterceptor.IsReJitEnabled) { throw new MockException("Mocking the new operator is not avaiable with OnDemand option enabled. Please use .IgnoreInstance()"); } #endif var newExpr = (NewExpression)expr; method = newExpr.Constructor; if (method == null && newExpr.Type.IsValueType) { throw new MockException("Empty constructor of value type is not associated with runnable code and cannot be intercepted."); } target = null; args = newExpr.Arguments.ToArray(); } else if (expr is InvocationExpression) { var invocation = (InvocationExpression)expr; target = invocation.Expression; args = invocation.Arguments.ToArray(); } else if (expr.NodeType == ExpressionType.Assign) { var binary = (BinaryExpression)expr; if (binary.Left is MemberExpression) { MemberExpression memberExpr = (MemberExpression)binary.Left; if (!(memberExpr.Member is PropertyInfo)) { throw new MockException("Fields cannot be mocked, only properties."); } var property = (PropertyInfo)memberExpr.Member; target = memberExpr.Expression; method = property.GetSetMethod(true); args = new[] { binary.Right }; } else if (binary.Left is IndexExpression) { IndexExpression indexExpr = (IndexExpression)binary.Left; target = indexExpr.Object; method = indexExpr.Indexer.GetSetMethod(true); args = indexExpr.Arguments.Concat(new[] { binary.Right }).ToArray(); } else { throw new MockException("Left-hand of assignment is not a member or indexer."); } } else if (expr is IndexExpression) { var index = (IndexExpression)expr; target = index.Object; var property = index.Indexer; method = property.GetGetMethod(true); args = index.Arguments.ToArray(); } else { throw new MockException("The expression does not represent a method call, property access, new expression or a delegate invocation."); } // Create the matcher for the instance part of the call pattern. // If the base of the target expression is a new expression (new T()), // or null (e.g. (null as T) or ((T) null)), then use AnyMatcher for the instance part, // otherwise evaluate the instance expression and use a value matcher with the evaluated result. var rootTarget = expr; Expression prevToRoot = null; while (true) { var memberExpr = rootTarget as MemberExpression; if (memberExpr != null && memberExpr.Expression != null && memberExpr.Member is PropertyInfo) { prevToRoot = rootTarget; rootTarget = memberExpr.Expression; continue; } var callExpr = rootTarget as MethodCallExpression; if (callExpr != null && callExpr.Object != null) { prevToRoot = rootTarget; rootTarget = callExpr.Object; continue; } if (rootTarget != null && (rootTarget.NodeType == ExpressionType.Convert || rootTarget.NodeType == ExpressionType.TypeAs)) { rootTarget = ((UnaryExpression)rootTarget).Operand; continue; } if (rootTarget is InvocationExpression) { prevToRoot = rootTarget; rootTarget = ((InvocationExpression)rootTarget).Expression; continue; } if (rootTarget is BinaryExpression) { prevToRoot = rootTarget; rootTarget = ((BinaryExpression)rootTarget).Left; continue; } if (rootTarget is IndexExpression) { prevToRoot = rootTarget; rootTarget = ((IndexExpression)rootTarget).Object; continue; } break; } object targetMockObject = null; Type targetMockType = null; bool isStatic = false; var rootMatcher = MocksRepository.TryCreateMatcherFromArgMember(rootTarget); if (rootMatcher != null) { callPattern.InstanceMatcher = rootMatcher; } else if (rootTarget is MemberExpression) { var memberExpr = (MemberExpression)rootTarget; targetMockObject = memberExpr.Member is FieldInfo?memberExpr.EvaluateExpression() : memberExpr.Expression != null?memberExpr.Expression.EvaluateExpression() : null; targetMockType = memberExpr.Member is FieldInfo ? memberExpr.Type : memberExpr.Member.DeclaringType; var asPropertyInfo = memberExpr.Member as PropertyInfo; isStatic = asPropertyInfo != null ? (asPropertyInfo.GetGetMethod(true) ?? asPropertyInfo.GetSetMethod(true)).IsStatic : false; } else if (rootTarget is MethodCallExpression) { var methodCallExpr = (MethodCallExpression)rootTarget; targetMockObject = methodCallExpr.Object != null?methodCallExpr.Object.EvaluateExpression() : null; targetMockType = methodCallExpr.Method.DeclaringType; isStatic = methodCallExpr.Method.IsStatic; } else if (rootTarget is NewExpression) { callPattern.InstanceMatcher = new AnyMatcher(); } else if (rootTarget is ConstantExpression) { var constant = (ConstantExpression)rootTarget; if (constant.Value == null) { callPattern.InstanceMatcher = new AnyMatcher(); } else { if (constant.Type.IsCompilerGenerated() && prevToRoot != null && prevToRoot.Type != typeof(void)) { targetMockObject = prevToRoot.EvaluateExpression(); targetMockType = prevToRoot.Type; } else { targetMockObject = constant.Value; targetMockType = constant.Type; } } } if (targetMockObject != null) { targetMockType = targetMockObject.GetType(); } if (callPattern.InstanceMatcher != null && prevToRoot != expr && prevToRoot != null) { throw new MockException("Using a matcher for the root member together with recursive mocking is not supported. Arrange the property or method of the root member in a separate statement."); } if (callPattern.InstanceMatcher == null) { // TODO: implicit creation of mock mixins shouldn't explicitly refer to behaviors, but // should get them from some configuration made outside the Core. Debug.Assert(targetMockObject != null || targetMockType != null); MockingUtil.UnwrapDelegateTarget(ref targetMockObject); var mixin = MocksRepository.GetMockMixin(targetMockObject, targetMockType); if (mixin == null) { if (isStatic) { MockCreationSettings settings = MockCreationSettings.GetSettings(Behavior.CallOriginal); repository.InterceptStatics(targetMockType, settings, false); } else if (targetMockObject != null) { MockCreationSettings settings = MockCreationSettings.GetSettings(Behavior.CallOriginal); repository.CreateExternalMockMixin(targetMockType, targetMockObject, settings); } } var targetValue = target != null?target.EvaluateExpression() : null; var delgMethod = MockingUtil.UnwrapDelegateTarget(ref targetValue); if (delgMethod != null) { method = delgMethod.GetInheritanceChain().First(m => !m.DeclaringType.IsProxy()); } callPattern.InstanceMatcher = new ReferenceMatcher(targetValue); } // now we have the method part of the call pattern Debug.Assert(method != null); callPattern.SetMethod(method, checkCompatibility: true); //Finally, construct the arguments part of the call pattern. using (repository.StartArrangeArgMatching()) { bool hasParams = false; bool hasSingleValueInParams = false; if (args != null && args.Length > 0) { var lastParameter = method.GetParameters().Last(); if (Attribute.IsDefined(lastParameter, typeof(ParamArrayAttribute)) && args.Last() is NewArrayExpression) { hasParams = true; var paramsArg = (NewArrayExpression)args.Last(); args = args.Take(args.Length - 1).Concat(paramsArg.Expressions).ToArray(); if (paramsArg.Expressions.Count == 1) { hasSingleValueInParams = true; } } foreach (var argument in args) { callPattern.ArgumentMatchers.Add(MocksRepository.CreateMatcherForArgument(argument)); } if (hasParams) { int paramsCount = method.GetParameters().Count(); if (hasSingleValueInParams) { IMatcher matcher = callPattern.ArgumentMatchers[paramsCount - 1]; ITypedMatcher typeMatcher = matcher as ITypedMatcher; if (typeMatcher != null && typeMatcher.Type != method.GetParameters().Last().ParameterType) { callPattern.ArgumentMatchers[paramsCount - 1] = new ParamsMatcher(new IMatcher[] { matcher }); } } else { IEnumerable <IMatcher> paramMatchers = callPattern.ArgumentMatchers.Skip(paramsCount - 1).Take(callPattern.ArgumentMatchers.Count - paramsCount + 1); callPattern.ArgumentMatchers = callPattern.ArgumentMatchers.Take(paramsCount - 1).ToList(); callPattern.ArgumentMatchers.Add(new ParamsMatcher(paramMatchers.ToArray())); } } } } MethodBase methodFromCallPattern = repository.GetMethodFromCallPattern(callPattern); callPattern.AdjustForExtensionMethod(); callPattern.SetMethod(methodFromCallPattern, checkCompatibility: false); return(callPattern); }
public void Process(Invocation invocation) { if (invocation.IsReturnValueSet) { return; } var returnType = invocation.Method.GetReturnType(); if (returnType == typeof(void) || returnType.IsValueType) { return; } if (invocation.Method.Name == "ToString" && invocation.Method.GetParameters().Length == 0 && invocation.UserProvidedImplementation) { return; } object mock = null; List <KeyValuePair <object, object> > mocksList; if (mocks.TryGetValue(invocation.Method, out mocksList)) { // can't put the key part in a Dictionary, // because we can't be sure that GetHashCode() works mock = mocksList.FirstOrDefault(kvp => Equals(kvp.Key, invocation.Instance)).Value; } if (mock == null) { var parentMock = MocksRepository.GetMockMixinFromInvocation(invocation); var repository = parentMock.Repository; var replicator = parentMock as IMockReplicator; bool mustReturnAMock = invocation.InArrange || this.type == RecursiveMockingBehaviorType.ReturnMock; if (mustReturnAMock || this.type == RecursiveMockingBehaviorType.ReturnDefault) { if (returnType.IsArray) { mock = Array.CreateInstance(returnType.GetElementType(), Enumerable.Repeat(0, returnType.GetArrayRank()).ToArray()); } var idictionaryType = returnType.GetImplementationOfGenericInterface(typeof(IDictionary <,>)); if (mock == null && idictionaryType != null) { var dictType = typeof(Dictionary <,>).MakeGenericType(idictionaryType.GetGenericArguments()); mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(dictType)); } var ienumerableType = returnType.GetImplementationOfGenericInterface(typeof(IEnumerable <>)); if (mock == null && ienumerableType != null) { var listType = typeof(List <>).MakeGenericType(ienumerableType.GetGenericArguments()); mock = MockCollection.Create(returnType, repository, replicator, (IEnumerable)MockingUtil.CreateInstance(listType)); } if (mock == null && mustReturnAMock) { #if !LITE_EDITION var stackTrace = new StackTrace(); var methodCallingArrange = stackTrace.EnumerateFrames() .SkipWhile(m => !Attribute.IsDefined(m, typeof(ArrangeMethodAttribute))) .SkipWhile(m => m.Module.Assembly == typeof(MocksRepository).Assembly) .FirstOrDefault(); if (methodCallingArrange != null && invocation.Method.DeclaringType.IsAssignableFrom(methodCallingArrange.DeclaringType)) { return; } #endif if (typeof(String) == returnType) { mock = String.Empty; } else { try { mock = replicator.CreateSimilarMock(repository, returnType, null, true, null); } catch (MockException) { } } } } if (mock == null) { return; } if (mocksList == null) { mocksList = new List <KeyValuePair <object, object> >(); mocks.Add(invocation.Method, mocksList); } mocksList.Add(new KeyValuePair <object, object>(invocation.Instance, mock)); var mockMixin = MocksRepository.GetMockMixin(mock, null); if (parentMock != null && mockMixin != null) { parentMock.DependentMocks.Add(mock); } } invocation.ReturnValue = mock; invocation.CallOriginal = false; invocation.UserProvidedImplementation = true; }
public static object Create(Type resultCollectionType, MocksRepository repo, IMockReplicator replicator, IEnumerable collection) { if (resultCollectionType == typeof(string)) { return(null); } Type sourceType = collection.GetType(); if (resultCollectionType.IsAssignableFrom(sourceType)) { return(collection); } var enumerableType = resultCollectionType.GetImplementationOfGenericInterface(typeof(IEnumerable <>)) ?? typeof(IEnumerable); if (!enumerableType.IsAssignableFrom(resultCollectionType)) { throw new MockException("Return value is not an enumerable type."); } var elementType = enumerableType.IsGenericType ? enumerableType.GetGenericArguments()[0] : typeof(object); var ilistType = typeof(IList <>).MakeGenericType(elementType); var iqueryableType = typeof(IQueryable <>).MakeGenericType(elementType); IEnumerable list; if (typeof(ICollection).IsAssignableFrom(sourceType)) { list = collection; } else { var listType = typeof(List <>).MakeGenericType(elementType); var castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(elementType); var castCollection = castMethod.Invoke(null, new[] { collection }); list = (IEnumerable)MockingUtil.CreateInstance(listType, castCollection); } var listBehavior = new DelegatedImplementationBehavior(list, new[] { ilistType, typeof(IList), }); var queryable = list.AsQueryable(); var queryableType = queryable.GetType(); var queryableBehavior = new DelegatedImplementationBehavior(queryable, new[] { queryableType.GetImplementationOfGenericInterface(typeof(IQueryable <>)) }); if (replicator != null) { var mock = replicator.CreateSimilarMock(repo, resultCollectionType, null, true, null); var mockMixin = MocksRepository.GetMockMixin(mock, null); mockMixin.FallbackBehaviors.Insert(0, queryableBehavior); mockMixin.FallbackBehaviors.Insert(0, listBehavior); return(mock); } else { return(repo.Create(resultCollectionType, null, Behavior.Loose, MockingUtil.EmptyTypes, null, null, null, new List <IBehavior> { listBehavior, queryableBehavior })); } }