From 756460f6bb3dafb196c2290064d38efeb71811ae Mon Sep 17 00:00:00 2001 From: stakx Date: Thu, 25 Jan 2018 08:24:59 +0100 Subject: [PATCH 1/3] Add failing test `CallBase` currently tries to call the base method implementation even for methods of additional interfaces (i. e. interfaces that were added to the proxy using `.As()` that the base class does not implement). --- Moq.Tests/Regressions/IssueReportsFixture.cs | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Moq.Tests/Regressions/IssueReportsFixture.cs b/Moq.Tests/Regressions/IssueReportsFixture.cs index b19e67aad..8cb97fe4c 100644 --- a/Moq.Tests/Regressions/IssueReportsFixture.cs +++ b/Moq.Tests/Regressions/IssueReportsFixture.cs @@ -1810,6 +1810,31 @@ public object DoSomething() #endregion + #region 582 + + public sealed class Issue582 + { + public interface IFoo + { + void Method(); + } + + public class Bar + { + } + + [Fact] + public void CallBase_has_no_effect_for_methods_of_additional_interfaces() + { + var bar = new Mock() { CallBase = true }; + var foo = bar.As().Object; + + foo.Method(); + } + } + + #endregion + // Old @ Google Code #region #47 From 94417fcc5e8a3f9a9b06d28a3015b6a81182a7cb Mon Sep 17 00:00:00 2001 From: stakx Date: Thu, 25 Jan 2018 08:28:25 +0100 Subject: [PATCH 2/3] Make CallBase base method detection more accurate For explicitly implemented interfaces aka `.As()`, there are actually two subcases to consider wrt to `CallBase`: Reimplemented and additional interfaces. For the latter, the base class will never have an implementation, we need to add a check for that. --- Source/Interception/InterceptionAspects.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Source/Interception/InterceptionAspects.cs b/Source/Interception/InterceptionAspects.cs index 2c4fcd903..ecafa6019 100644 --- a/Source/Interception/InterceptionAspects.cs +++ b/Source/Interception/InterceptionAspects.cs @@ -345,11 +345,23 @@ public override InterceptionAction Handle(Invocation invocation, Mock mock) Debug.Assert(mock.ImplementsInterface(declaringType)); // Case 2: Explicitly implemented interface method of a class proxy. - // Only call base method if it isn't an event accessor. - if (!method.LooksLikeEventAttach() && !method.LooksLikeEventDetach()) + + if (mock.InheritedInterfaces.Contains(declaringType)) { - invocation.ReturnBase(); - return InterceptionAction.Stop; + // Case 2a: Re-implemented interface. + // The base class has its own implementation. Only call base method if it isn't an event accessor. + if (!method.LooksLikeEventAttach() && !method.LooksLikeEventDetach()) + { + invocation.ReturnBase(); + return InterceptionAction.Stop; + } + } + else + { + Debug.Assert(mock.AdditionalInterfaces.Contains(declaringType)); + + // Case 2b: Additional interface. + // There is no base method to call, so fall through. } } } From 47f603657703bbd873c7ad98ea072c0ac740220b Mon Sep 17 00:00:00 2001 From: stakx Date: Thu, 25 Jan 2018 08:32:36 +0100 Subject: [PATCH 3/3] Update the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97da8ffa7..386a13044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1 #### Fixed * Wrong parameters count for extension methods in `Callback` and `Returns` (@Caraul, #575) +* `CallBase` regression with members of additional interfaces (@stakx, #583) ## 4.8.1 (2018-01-08)