From 6ad71030b15677fcc629a79c717ddb6e43479a83 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Tue, 5 Aug 2014 19:58:51 +0800 Subject: [PATCH 1/8] should only add public interfaces If the interface is not public, the castle dynamic proxy will throw: Castle.DynamicProxy.Generators.GeneratorException : Type System.Data.Entity.Internal.Linq.IInternalQueryAdapter is not visible to DynamicProxy. Can not create proxy for types that are not accessible. Make the type public, or internal and mark your assembly with [assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)] attribute. --- Source/Mock.Generic.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index d60cdc5d5..d54260799 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -40,6 +40,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Linq.Expressions; using Moq.Language.Flow; using Moq.Proxy; @@ -111,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces()); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); From f026616be817c846c05e8222b2875ca6f1dd0e2e Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Tue, 5 Aug 2014 20:01:12 +0800 Subject: [PATCH 2/8] Update Mock.Generic.cs use tabs instead of spaces --- Source/Mock.Generic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index d54260799..530f45ed9 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); From ecd350c4377cb9ed8fb0b04517c1c931ee1c66a5 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Tue, 5 Aug 2014 22:43:32 +0800 Subject: [PATCH 3/8] Unit tests added --- Source/Mock.Generic.cs | 2 +- UnitTests/AsInterfaceFixture.cs | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 530f45ed9..f60b4d4ad 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); diff --git a/UnitTests/AsInterfaceFixture.cs b/UnitTests/AsInterfaceFixture.cs index d71fdf4bf..6756fd805 100644 --- a/UnitTests/AsInterfaceFixture.cs +++ b/UnitTests/AsInterfaceFixture.cs @@ -152,6 +152,14 @@ public void VerifiesExpectationOnAddedInterfaceCastedDynamically() bag.As().Verify(f => f.Execute()); } + [Fact] + public void ShouldBeAbleToCastToImplementedInterface() + { + var fooBar = new Mock(); + var obj = fooBar.Object; + Assert.DoesNotThrow(() => fooBar.As()); + } + public interface IFoo { void Execute(); @@ -168,5 +176,66 @@ public interface IBag void Add(string key, object o); object Get(string key); } + + internal interface IBar + { + void Test(); + } + + public abstract class FooBar : IFoo, IBag, IBar + { + + public void Execute() + { + throw new NotImplementedException(); + } + + public string Execute(string command) + { + throw new NotImplementedException(); + } + + public string Execute(string arg1, string arg2) + { + throw new NotImplementedException(); + } + + public string Execute(string arg1, string arg2, string arg3) + { + throw new NotImplementedException(); + } + + public string Execute(string arg1, string arg2, string arg3, string arg4) + { + throw new NotImplementedException(); + } + + public int Value + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public void Add(string key, object o) + { + throw new NotImplementedException(); + } + + public object Get(string key) + { + throw new NotImplementedException(); + } + + public void Test() + { + throw new NotImplementedException(); + } + } } } From 5c98f5e89f16fddb1834ee5cbf9f63f5c35855f3 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Wed, 6 Aug 2014 00:14:42 +0800 Subject: [PATCH 4/8] Fixed Unit tests --- Source/InterceptorStrategies.cs | 1 + Source/Mock.Generic.cs | 2 +- UnitTests/AsInterfaceFixture.cs | 53 ++++++--------------------------- 3 files changed, 11 insertions(+), 45 deletions(-) diff --git a/Source/InterceptorStrategies.cs b/Source/InterceptorStrategies.cs index 3fb9dacfe..9e102e223 100644 --- a/Source/InterceptorStrategies.cs +++ b/Source/InterceptorStrategies.cs @@ -34,6 +34,7 @@ internal class InvokeBase : IInterceptStrategy public InterceptionAction HandleIntercept(ICallContext invocation, InterceptorContext ctx, CurrentInterceptContext localctx) { if (invocation.Method.DeclaringType == typeof(object) || + ctx.Mock.ImplementedInterfaces.Contains(invocation.Method.DeclaringType) && !invocation.Method.IsEventAttach() && !invocation.Method.IsEventDetach() && ctx.Mock.CallBase || invocation.Method.DeclaringType.IsClass && !invocation.Method.IsAbstract && ctx.Mock.CallBase ) { diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index f60b4d4ad..ed84ea96b 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic && !i.IsImport)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); diff --git a/UnitTests/AsInterfaceFixture.cs b/UnitTests/AsInterfaceFixture.cs index 6756fd805..97398874d 100644 --- a/UnitTests/AsInterfaceFixture.cs +++ b/UnitTests/AsInterfaceFixture.cs @@ -184,58 +184,23 @@ internal interface IBar public abstract class FooBar : IFoo, IBag, IBar { + public abstract void Execute(); - public void Execute() - { - throw new NotImplementedException(); - } + public abstract string Execute(string command); - public string Execute(string command) - { - throw new NotImplementedException(); - } + public abstract string Execute(string arg1, string arg2); - public string Execute(string arg1, string arg2) - { - throw new NotImplementedException(); - } + public abstract string Execute(string arg1, string arg2, string arg3); - public string Execute(string arg1, string arg2, string arg3) - { - throw new NotImplementedException(); - } + public abstract string Execute(string arg1, string arg2, string arg3, string arg4); - public string Execute(string arg1, string arg2, string arg3, string arg4) - { - throw new NotImplementedException(); - } + public abstract int Value { get; set; } - public int Value - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } + public abstract void Add(string key, object o); - public void Add(string key, object o) - { - throw new NotImplementedException(); - } + public abstract object Get(string key); - public object Get(string key) - { - throw new NotImplementedException(); - } - - public void Test() - { - throw new NotImplementedException(); - } + public abstract void Test(); } } } From 5f8dd0c52a2525ca8ed42226398ab92a8fd56201 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Wed, 6 Aug 2014 00:17:55 +0800 Subject: [PATCH 5/8] Tabify --- Source/Mock.Generic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index ed84ea96b..9a01b4cd9 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic && !i.IsImport)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic && !i.IsImport)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); From 5eb50df45be2c3599f937eb2008b5e25dfff11ab Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Wed, 6 Aug 2014 10:29:37 +0800 Subject: [PATCH 6/8] Exclude COM interfaces --- Source/Mock.Generic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 9a01b4cd9..922d35fd1 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => i.IsPublic || i.IsNestedPublic && !i.IsImport)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where((i => i.IsPublic || i.IsNestedPublic) && !i.IsImport)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); From 5804548f23a84f2e6597efbdd448228cf27c9e63 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Wed, 6 Aug 2014 22:55:46 +0800 Subject: [PATCH 7/8] Correct the bracket's position --- Source/Mock.Generic.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 922d35fd1..9ec5c4734 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -112,7 +112,7 @@ public Mock(MockBehavior behavior, params object[] args) this.Behavior = behavior; this.Interceptor = new Interceptor(behavior, typeof(T), this); this.constructorArguments = args; - this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where((i => i.IsPublic || i.IsNestedPublic) && !i.IsImport)); + this.ImplementedInterfaces.AddRange(typeof(T).GetInterfaces().Where(i => (i.IsPublic || i.IsNestedPublic) && !i.IsImport)); this.ImplementedInterfaces.Add(typeof(IMocked)); this.CheckParameters(); From ceca9b60a15c299cdf3cdfcf814900b2886bc3f3 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Wed, 6 Aug 2014 23:32:34 +0800 Subject: [PATCH 8/8] More comments --- Source/InterceptorStrategies.cs | 6 +++--- UnitTests/AsInterfaceFixture.cs | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Source/InterceptorStrategies.cs b/Source/InterceptorStrategies.cs index 9e102e223..d58b0ad0a 100644 --- a/Source/InterceptorStrategies.cs +++ b/Source/InterceptorStrategies.cs @@ -33,9 +33,9 @@ internal class InvokeBase : IInterceptStrategy { public InterceptionAction HandleIntercept(ICallContext invocation, InterceptorContext ctx, CurrentInterceptContext localctx) { - if (invocation.Method.DeclaringType == typeof(object) || - ctx.Mock.ImplementedInterfaces.Contains(invocation.Method.DeclaringType) && !invocation.Method.IsEventAttach() && !invocation.Method.IsEventDetach() && ctx.Mock.CallBase || - invocation.Method.DeclaringType.IsClass && !invocation.Method.IsAbstract && ctx.Mock.CallBase + if (invocation.Method.DeclaringType == typeof(object) || // interface proxy + ctx.Mock.ImplementedInterfaces.Contains(invocation.Method.DeclaringType) && !invocation.Method.IsEventAttach() && !invocation.Method.IsEventDetach() && ctx.Mock.CallBase || // class proxy with explicitly implemented interfaces. The method's declaring type is the interface and the method couldn't be abstract + invocation.Method.DeclaringType.IsClass && !invocation.Method.IsAbstract && ctx.Mock.CallBase // class proxy ) { // Invoke underlying implementation. diff --git a/UnitTests/AsInterfaceFixture.cs b/UnitTests/AsInterfaceFixture.cs index 97398874d..13e6a0596 100644 --- a/UnitTests/AsInterfaceFixture.cs +++ b/UnitTests/AsInterfaceFixture.cs @@ -160,6 +160,15 @@ public void ShouldBeAbleToCastToImplementedInterface() Assert.DoesNotThrow(() => fooBar.As()); } + [Fact] + public void ShouldNotThrowIfCallExplicitlyImplementedInterfacesMethodWhenCallBaseIsTrue() + { + var fooBar = new Mock(); + fooBar.CallBase = true; + var bag = (IBag)fooBar.Object; + Assert.DoesNotThrow(() => bag.Get("test")); + } + public interface IFoo { void Execute(); @@ -196,9 +205,14 @@ public abstract class FooBar : IFoo, IBag, IBar public abstract int Value { get; set; } - public abstract void Add(string key, object o); + void IBag.Add(string key, object o) + { + } - public abstract object Get(string key); + object IBag.Get(string key) + { + return null; + } public abstract void Test(); }