From a5ef1b95f654c9750973844b40adb974cc32eaac Mon Sep 17 00:00:00 2001 From: Chris Missal Date: Sat, 29 Dec 2012 13:49:32 -0600 Subject: [PATCH 1/4] added overload to Verify to accept Times as a Method Group --- Source/Mock.Generic.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 64f0bff4c..7f948bb79 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -252,6 +252,13 @@ public void Verify(Expression> expression, Times times) Mock.Verify(this, expression, times, null); } + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + public void Verify(Expression> expression, Func times) + { + Verify(expression, times()); + } + /// [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] public void Verify(Expression> expression, string failMessage) From 810c4a146575a6ea4e518f723dd848989675d549 Mon Sep 17 00:00:00 2001 From: FelicePollano Date: Wed, 3 Oct 2012 10:04:05 +0200 Subject: [PATCH 2/4] refactored Interceptor.Intercept to use a set of strategies. Function was broken in 8 separated strategies --- Source.Silverlight/Moq.Silverlight.csproj | 10 +- Source/IInterceptStrategy.cs | 47 ++++ Source/Interceptor.cs | 216 ++-------------- Source/InterceptorStrategies.cs | 292 ++++++++++++++++++++++ Source/Moq.csproj | 2 + 5 files changed, 374 insertions(+), 193 deletions(-) create mode 100644 Source/IInterceptStrategy.cs create mode 100644 Source/InterceptorStrategies.cs diff --git a/Source.Silverlight/Moq.Silverlight.csproj b/Source.Silverlight/Moq.Silverlight.csproj index b849974f1..30d149ac0 100644 --- a/Source.Silverlight/Moq.Silverlight.csproj +++ b/Source.Silverlight/Moq.Silverlight.csproj @@ -83,7 +83,7 @@ False ..\Lib\Castle\bin-SL4\Castle.Core.dll - - + @@ -138,6 +138,9 @@ IHideObjectMembers.cs + + IInterceptStrategy.cs + IMatcher.cs @@ -147,6 +150,9 @@ Interceptor.cs + + InterceptorStrategies.cs + IProxyCall.cs diff --git a/Source/IInterceptStrategy.cs b/Source/IInterceptStrategy.cs new file mode 100644 index 000000000..5f9edc2df --- /dev/null +++ b/Source/IInterceptStrategy.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Moq.Proxy; + +namespace Moq +{ + internal interface IInterceptStrategy + { + /// + /// Handle interception + /// + /// the current invocation context + /// shared data among the strategies during an interception + /// true if further interception has to be processed, otherwise false + bool HandleIntercept(ICallContext invocation,InterceptStrategyContext ctx); + + } + + internal class InterceptStrategyContext + { + public InterceptStrategyContext(Mock Mock + , Type targetType + , Dictionary> invocationLists + , List actualInvocations + , MockBehavior behavior + , List orderedCalls + ) + { + this.Behavior = behavior; + this.Mock = Mock; + this.InvocationLists = invocationLists; + this.ActualInvocations = actualInvocations; + this.TargetType = targetType; + this.OrderedCalls = orderedCalls; + } + public Mock Mock {get;private set;} + public Type TargetType { get; private set; } + public Dictionary> InvocationLists { get; private set; } + public List ActualInvocations { get; private set; } + public MockBehavior Behavior { get; private set; } + public List OrderedCalls { get; private set; } + public IProxyCall CurrentCall { get; set; } + } + +} diff --git a/Source/Interceptor.cs b/Source/Interceptor.cs index 516afcbee..ab6a7110f 100644 --- a/Source/Interceptor.cs +++ b/Source/Interceptor.cs @@ -130,207 +130,41 @@ public void AddCall(IProxyCall call, SetupKind kind) orderedCalls.Add(call); } + private IEnumerable InterceptionStrategies() + { + yield return new HandleDestructor(); + yield return new HandleTracking(); + yield return new CheckMockMixing(); + yield return new AddActualInvocation(); + yield return new ExtractProxyCall(); + yield return new ExecuteCall(); + yield return new InvokeBase(); + yield return new HandleMockRecursion(); + } + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] public void Intercept(ICallContext invocation) { - if (invocation.Method.IsDestructor()) + + lock (Mock) // this solves issue #249 { - return; - } - - // Track current invocation if we're in "record" mode in a fluent invocation context. - if (FluentMockContext.IsActive) - { - FluentMockContext.Current.Add(this.Mock, invocation); - } - lock (Mock) // this solves issue #249, but actually worsen method complexity :( - { - // TODO: too many ifs in this method. - // see how to refactor with strategies. - if (invocation.Method.DeclaringType.IsGenericType && - invocation.Method.DeclaringType.GetGenericTypeDefinition() == typeof(IMocked<>)) - { - // "Mixin" of IMocked.Mock - invocation.ReturnValue = this.Mock; - return; - } - else if (invocation.Method.DeclaringType == typeof(IMocked)) - { - // "Mixin" of IMocked.Mock - invocation.ReturnValue = this.Mock; - return; - } - - // Special case for events. - if (!FluentMockContext.IsActive) - { - if (invocation.Method.IsEventAttach()) - { - var delegateInstance = (Delegate)invocation.Arguments[0]; - // TODO: validate we can get the event? - var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(4)); - - if (this.Mock.CallBase) - { - invocation.InvokeBase(); - } - else if (delegateInstance != null) - { - this.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]); - } - - return; - } - else if (invocation.Method.IsEventDetach()) - { - var delegateInstance = (Delegate)invocation.Arguments[0]; - // TODO: validate we can get the event? - var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(7)); - - if (this.Mock.CallBase) - { - invocation.InvokeBase(); - } - else if (delegateInstance != null) - { - this.RemoveEventHandler(eventInfo, (Delegate)invocation.Arguments[0]); - } - - return; - } - - // Save to support Verify[expression] pattern. - // In a fluent invocation context, which is a recorder-like - // mode we use to evaluate delegates by actually running them, - // we don't want to count the invocation, or actually run - // previous setups. - actualInvocations.Add(invocation); - } - - var call = FluentMockContext.IsActive ? (IProxyCall)null : orderedCalls.LastOrDefault(c => c.Matches(invocation)); - if (call == null && !FluentMockContext.IsActive && behavior == MockBehavior.Strict) - { - throw new MockException(MockException.ExceptionReason.NoSetup, behavior, invocation); - } - - if (call != null) - { - call.SetOutParameters(invocation); - - // We first execute, as there may be a Throws - // and therefore we might never get to the - // next line. - call.Execute(invocation); - ThrowIfReturnValueRequired(call, invocation); - } - else if (invocation.Method.DeclaringType == typeof(object)) + var interceptionContext = new InterceptStrategyContext(Mock + , targetType + , invocationLists + , actualInvocations + , behavior + , orderedCalls + ); + foreach (var strategy in InterceptionStrategies()) { - // Invoke underlying implementation. - invocation.InvokeBase(); - } - else if (invocation.Method.DeclaringType.IsClass && !invocation.Method.IsAbstract && this.Mock.CallBase) - { - // For mocked classes, if the target method was not abstract, - // invoke directly. - // Will only get here for Loose behavior. - // TODO: we may want to provide a way to skip this by the user. - invocation.InvokeBase(); - } - else if (invocation.Method != null && invocation.Method.ReturnType != null && - invocation.Method.ReturnType != typeof(void)) - { - Mock recursiveMock; - if (this.Mock.InnerMocks.TryGetValue(invocation.Method, out recursiveMock)) + if (!strategy.HandleIntercept(invocation, interceptionContext)) { - invocation.ReturnValue = recursiveMock.Object; - } - else - { - invocation.ReturnValue = this.Mock.DefaultValueProvider.ProvideDefault(invocation.Method); + break; } } } } - - /// - /// Get an eventInfo for a given event name. Search type ancestors depth first if necessary. - /// - /// Name of the event, with the set_ or get_ prefix already removed - private EventInfo GetEventFromName(string eventName) - { - var depthFirstProgress = new Queue(this.Mock.ImplementedInterfaces.Skip(1)); - depthFirstProgress.Enqueue(targetType); - while (depthFirstProgress.Count > 0) - { - var currentType = depthFirstProgress.Dequeue(); - var eventInfo = currentType.GetEvent(eventName); - if (eventInfo != null) - { - return eventInfo; - } - - foreach (var implementedType in GetAncestorTypes(currentType)) - { - depthFirstProgress.Enqueue(implementedType); - } - } - - return null; - } - - /// - /// Given a type return all of its ancestors, both types and interfaces. - /// - /// The type to find immediate ancestors of - private static IEnumerable GetAncestorTypes(Type initialType) - { - var baseType = initialType.BaseType; - if (baseType != null) - { - return new[] { baseType }; - } - - return initialType.GetInterfaces(); - } - - private void ThrowIfReturnValueRequired(IProxyCall call, ICallContext invocation) - { - if (behavior != MockBehavior.Loose && - invocation.Method != null && - invocation.Method.ReturnType != null && - invocation.Method.ReturnType != typeof(void)) - { - var methodCall = call as MethodCallReturn; - if (methodCall == null || !methodCall.HasReturnValue) - { - throw new MockException( - MockException.ExceptionReason.ReturnValueRequired, - behavior, - invocation); - } - } - } - - internal void AddEventHandler(EventInfo ev, Delegate handler) - { - List handlers; - if (!this.invocationLists.TryGetValue(ev.Name, out handlers)) - { - handlers = new List(); - invocationLists.Add(ev.Name, handlers); - } - - handlers.Add(handler); - } - - internal void RemoveEventHandler(EventInfo ev, Delegate handler) - { - List handlers; - if (this.invocationLists.TryGetValue(ev.Name, out handlers)) - { - handlers.Remove(handler); - } - } + internal IEnumerable GetInvocationList(EventInfo ev) { diff --git a/Source/InterceptorStrategies.cs b/Source/InterceptorStrategies.cs new file mode 100644 index 000000000..3b936a75a --- /dev/null +++ b/Source/InterceptorStrategies.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Moq.Proxy; +using System.Reflection; + +namespace Moq +{ + internal class HandleMockRecursion : IInterceptStrategy + { + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + if (invocation.Method != null && invocation.Method.ReturnType != null && + invocation.Method.ReturnType != typeof(void)) + { + Mock recursiveMock; + if (ctx.Mock.InnerMocks.TryGetValue(invocation.Method, out recursiveMock)) + { + invocation.ReturnValue = recursiveMock.Object; + } + else + { + invocation.ReturnValue = ctx.Mock.DefaultValueProvider.ProvideDefault(invocation.Method); + } + return false; + } + return true; + } + } + + internal class InvokeBase : IInterceptStrategy + { + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + if (invocation.Method.DeclaringType == typeof(object) + || + invocation.Method.DeclaringType.IsClass && !invocation.Method.IsAbstract && ctx.Mock.CallBase + ) + { + // Invoke underlying implementation. + + // For mocked classes, if the target method was not abstract, + // invoke directly. + // Will only get here for Loose behavior. + // TODO: we may want to provide a way to skip this by the user. + invocation.InvokeBase(); + return false; + } + else + { + return true; + } + } + } + + internal class ExecuteCall : IInterceptStrategy + { + InterceptStrategyContext ctx; + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + this.ctx = ctx; + if (ctx.CurrentCall != null) + { + ctx.CurrentCall.SetOutParameters(invocation); + + // We first execute, as there may be a Throws + // and therefore we might never get to the + // next line. + ctx.CurrentCall.Execute(invocation); + ThrowIfReturnValueRequired(ctx.CurrentCall, invocation); + return false; + } + else + { + return true; + } + } + private void ThrowIfReturnValueRequired(IProxyCall call, ICallContext invocation) + { + if (ctx.Behavior != MockBehavior.Loose && + invocation.Method != null && + invocation.Method.ReturnType != null && + invocation.Method.ReturnType != typeof(void)) + { + var methodCall = call as MethodCallReturn; + if (methodCall == null || !methodCall.HasReturnValue) + { + throw new MockException( + MockException.ExceptionReason.ReturnValueRequired, + ctx.Behavior, + invocation); + } + } + } + } + + internal class ExtractProxyCall : IInterceptStrategy + { + + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + ctx.CurrentCall = FluentMockContext.IsActive ? (IProxyCall)null : ctx.OrderedCalls.LastOrDefault(c => c.Matches(invocation)); + if (ctx.CurrentCall == null && !FluentMockContext.IsActive && ctx.Behavior == MockBehavior.Strict) + { + throw new MockException(MockException.ExceptionReason.NoSetup, ctx.Behavior, invocation); + } + return true; + } + } + + internal class CheckMockMixing:IInterceptStrategy + { + + public CheckMockMixing() + { + + } + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + if (invocation.Method.DeclaringType.IsGenericType && + invocation.Method.DeclaringType.GetGenericTypeDefinition() == typeof(IMocked<>)) + { + // "Mixin" of IMocked.Mock + invocation.ReturnValue = ctx.Mock; + return false; + } + else if (invocation.Method.DeclaringType == typeof(IMocked)) + { + // "Mixin" of IMocked.Mock + invocation.ReturnValue = ctx.Mock; + return false; + } + return true; + } + } + + internal class HandleTracking : IInterceptStrategy + { + + public HandleTracking() + { + + } + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + // Track current invocation if we're in "record" mode in a fluent invocation context. + if (FluentMockContext.IsActive) + { + FluentMockContext.Current.Add(ctx.Mock, invocation); + } + return true; + } + } + + internal class HandleDestructor : IInterceptStrategy + { + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + if (invocation.Method.IsDestructor()) + { + return false; + } + else + { + return true; + } + } + } + + internal class AddActualInvocation : IInterceptStrategy + { + + public AddActualInvocation() + { + + } + /// + /// Get an eventInfo for a given event name. Search type ancestors depth first if necessary. + /// + /// Name of the event, with the set_ or get_ prefix already removed + private EventInfo GetEventFromName(string eventName) + { + var depthFirstProgress = new Queue(ctx.Mock.ImplementedInterfaces.Skip(1)); + depthFirstProgress.Enqueue(ctx.TargetType); + while (depthFirstProgress.Count > 0) + { + var currentType = depthFirstProgress.Dequeue(); + var eventInfo = currentType.GetEvent(eventName); + if (eventInfo != null) + { + return eventInfo; + } + + foreach (var implementedType in GetAncestorTypes(currentType)) + { + depthFirstProgress.Enqueue(implementedType); + } + } + + return null; + } + /// + /// Given a type return all of its ancestors, both types and interfaces. + /// + /// The type to find immediate ancestors of + private static IEnumerable GetAncestorTypes(Type initialType) + { + var baseType = initialType.BaseType; + if (baseType != null) + { + return new[] { baseType }; + } + + return initialType.GetInterfaces(); + } + internal void AddEventHandler(EventInfo ev, Delegate handler) + { + List handlers; + if (!ctx.InvocationLists.TryGetValue(ev.Name, out handlers)) + { + handlers = new List(); + ctx.InvocationLists.Add(ev.Name, handlers); + } + + handlers.Add(handler); + } + internal void RemoveEventHandler(EventInfo ev, Delegate handler) + { + List handlers; + if (ctx.InvocationLists.TryGetValue(ev.Name, out handlers)) + { + handlers.Remove(handler); + } + } + InterceptStrategyContext ctx; + public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + { + this.ctx = ctx; + if (!FluentMockContext.IsActive) + { + //Special case for events + if (invocation.Method.IsEventAttach()) + { + var delegateInstance = (Delegate)invocation.Arguments[0]; + // TODO: validate we can get the event? + var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(4)); + + if (ctx.Mock.CallBase) + { + invocation.InvokeBase(); + } + else if (delegateInstance != null) + { + this.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]); + } + + return false; + } + else if (invocation.Method.IsEventDetach()) + { + + + if (ctx.Mock.CallBase) + { + invocation.InvokeBase(); + } + else + { + var delegateInstance = (Delegate)invocation.Arguments[0]; + if (delegateInstance != null) + { + // TODO: validate we can get the event? + var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(7)); + this.RemoveEventHandler(eventInfo, (Delegate)invocation.Arguments[0]); + } + } + + return false; + } + + // Save to support Verify[expression] pattern. + // In a fluent invocation context, which is a recorder-like + // mode we use to evaluate delegates by actually running them, + // we don't want to count the invocation, or actually run + // previous setups. + ctx.ActualInvocations.Add(invocation); + } + return true; + } + } +} diff --git a/Source/Moq.csproj b/Source/Moq.csproj index 7ee466f8b..d2d4f8fd4 100644 --- a/Source/Moq.csproj +++ b/Source/Moq.csproj @@ -71,6 +71,8 @@ + + True From 0d09ada3ec8ec705060689ccf5a0ab5e13c0fccf Mon Sep 17 00:00:00 2001 From: FelicePollano Date: Thu, 4 Oct 2012 12:33:35 +0200 Subject: [PATCH 3/4] Added an enum as a result of a single interception strategy to clarify when following action need to be executed --- Source/IInterceptStrategy.cs | 7 ++++- Source/Interceptor.cs | 2 +- Source/InterceptorStrategies.cs | 53 ++++++++++++++------------------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Source/IInterceptStrategy.cs b/Source/IInterceptStrategy.cs index 5f9edc2df..6458b2c04 100644 --- a/Source/IInterceptStrategy.cs +++ b/Source/IInterceptStrategy.cs @@ -6,6 +6,11 @@ namespace Moq { + + internal enum InterceptionAction + { + Continue,Stop + } internal interface IInterceptStrategy { /// @@ -14,7 +19,7 @@ internal interface IInterceptStrategy /// the current invocation context /// shared data among the strategies during an interception /// true if further interception has to be processed, otherwise false - bool HandleIntercept(ICallContext invocation,InterceptStrategyContext ctx); + InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx); } diff --git a/Source/Interceptor.cs b/Source/Interceptor.cs index ab6a7110f..c49ab1d46 100644 --- a/Source/Interceptor.cs +++ b/Source/Interceptor.cs @@ -157,7 +157,7 @@ public void Intercept(ICallContext invocation) ); foreach (var strategy in InterceptionStrategies()) { - if (!strategy.HandleIntercept(invocation, interceptionContext)) + if (InterceptionAction.Stop == strategy.HandleIntercept(invocation, interceptionContext)) { break; } diff --git a/Source/InterceptorStrategies.cs b/Source/InterceptorStrategies.cs index 3b936a75a..247216e1f 100644 --- a/Source/InterceptorStrategies.cs +++ b/Source/InterceptorStrategies.cs @@ -9,7 +9,7 @@ namespace Moq { internal class HandleMockRecursion : IInterceptStrategy { - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { if (invocation.Method != null && invocation.Method.ReturnType != null && invocation.Method.ReturnType != typeof(void)) @@ -23,15 +23,15 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct { invocation.ReturnValue = ctx.Mock.DefaultValueProvider.ProvideDefault(invocation.Method); } - return false; + return InterceptionAction.Stop; } - return true; + return InterceptionAction.Continue; } } internal class InvokeBase : IInterceptStrategy { - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { if (invocation.Method.DeclaringType == typeof(object) || @@ -45,11 +45,11 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct // Will only get here for Loose behavior. // TODO: we may want to provide a way to skip this by the user. invocation.InvokeBase(); - return false; + return InterceptionAction.Stop; } else { - return true; + return InterceptionAction.Continue; } } } @@ -57,7 +57,7 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct internal class ExecuteCall : IInterceptStrategy { InterceptStrategyContext ctx; - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { this.ctx = ctx; if (ctx.CurrentCall != null) @@ -69,11 +69,11 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct // next line. ctx.CurrentCall.Execute(invocation); ThrowIfReturnValueRequired(ctx.CurrentCall, invocation); - return false; + return InterceptionAction.Stop; } else { - return true; + return InterceptionAction.Continue; } } private void ThrowIfReturnValueRequired(IProxyCall call, ICallContext invocation) @@ -98,14 +98,14 @@ private void ThrowIfReturnValueRequired(IProxyCall call, ICallContext invocation internal class ExtractProxyCall : IInterceptStrategy { - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { ctx.CurrentCall = FluentMockContext.IsActive ? (IProxyCall)null : ctx.OrderedCalls.LastOrDefault(c => c.Matches(invocation)); if (ctx.CurrentCall == null && !FluentMockContext.IsActive && ctx.Behavior == MockBehavior.Strict) { throw new MockException(MockException.ExceptionReason.NoSetup, ctx.Behavior, invocation); } - return true; + return InterceptionAction.Continue; } } @@ -116,22 +116,22 @@ public CheckMockMixing() { } - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { if (invocation.Method.DeclaringType.IsGenericType && invocation.Method.DeclaringType.GetGenericTypeDefinition() == typeof(IMocked<>)) { // "Mixin" of IMocked.Mock invocation.ReturnValue = ctx.Mock; - return false; + return InterceptionAction.Stop; } else if (invocation.Method.DeclaringType == typeof(IMocked)) { // "Mixin" of IMocked.Mock invocation.ReturnValue = ctx.Mock; - return false; + return InterceptionAction.Stop; } - return true; + return InterceptionAction.Continue; } } @@ -142,29 +142,22 @@ public HandleTracking() { } - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { // Track current invocation if we're in "record" mode in a fluent invocation context. if (FluentMockContext.IsActive) { FluentMockContext.Current.Add(ctx.Mock, invocation); } - return true; + return InterceptionAction.Continue; } } internal class HandleDestructor : IInterceptStrategy { - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { - if (invocation.Method.IsDestructor()) - { - return false; - } - else - { - return true; - } + return invocation.Method.IsDestructor()?InterceptionAction.Stop:InterceptionAction.Continue; } } @@ -234,7 +227,7 @@ internal void RemoveEventHandler(EventInfo ev, Delegate handler) } } InterceptStrategyContext ctx; - public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) + public InterceptionAction HandleIntercept(ICallContext invocation, InterceptStrategyContext ctx) { this.ctx = ctx; if (!FluentMockContext.IsActive) @@ -255,7 +248,7 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct this.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]); } - return false; + return InterceptionAction.Stop; } else if (invocation.Method.IsEventDetach()) { @@ -276,7 +269,7 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct } } - return false; + return InterceptionAction.Stop; } // Save to support Verify[expression] pattern. @@ -286,7 +279,7 @@ public bool HandleIntercept(ICallContext invocation, InterceptStrategyContext ct // previous setups. ctx.ActualInvocations.Add(invocation); } - return true; + return InterceptionAction.Continue; } } } From cdbcd71209af7ed7d6979216c676c22326ba2815 Mon Sep 17 00:00:00 2001 From: Chris Missal Date: Wed, 27 Feb 2013 20:29:55 -0600 Subject: [PATCH 4/4] added remaining overloads to Verify --- Source/Mock.Generic.cs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 7f948bb79..21df471d9 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -273,6 +273,13 @@ public void Verify(Expression> expression, Times times, string failMes Mock.Verify(this, expression, times, failMessage); } + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + public void Verify(Expression> expression, Func times, string failMessage) + { + Verify(this, expression, times(), failMessage); + } + /// [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] public void Verify(Expression> expression) @@ -287,6 +294,13 @@ public void Verify(Expression> expression, Times times Mock.Verify(this, expression, times, null); } + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + public void Verify(Expression> expression, Func times) + { + Verify(this, expression, times(), null); + } + /// [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] public void Verify(Expression> expression, string failMessage) @@ -315,6 +329,13 @@ public void VerifyGet(Expression> expression, Time Mock.VerifyGet(this, expression, times, null); } + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + public void VerifyGet(Expression> expression, Func times) + { + VerifyGet(this, expression, times(), null); + } + /// [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] public void VerifyGet(Expression> expression, string failMessage) @@ -329,6 +350,13 @@ public void VerifyGet(Expression> expression, Time Mock.VerifyGet(this, expression, times, failMessage); } + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + public void VerifyGet(Expression> expression, Func times, string failMessage) + { + VerifyGet(this, expression, times(), failMessage); + } + /// public void VerifySet(Action setterExpression) { @@ -341,6 +369,12 @@ public void VerifySet(Action setterExpression, Times times) Mock.VerifySet(this, setterExpression, times, null); } + /// + public void VerifySet(Action setterExpression, Func times) + { + Mock.VerifySet(this, setterExpression, times(), null); + } + /// public void VerifySet(Action setterExpression, string failMessage) { @@ -353,6 +387,12 @@ public void VerifySet(Action setterExpression, Times times, string failMessag Mock.VerifySet(this, setterExpression, times, failMessage); } + /// + public void VerifySet(Action setterExpression, Func times, string failMessage) + { + Mock.VerifySet(this, setterExpression, times(), failMessage); + } + #endregion #region Raise