From b48bb2bc9dda7cb337ec7ac26c5be04c76def719 Mon Sep 17 00:00:00 2001 From: stakx Date: Fri, 13 Jul 2018 19:10:02 +0200 Subject: [PATCH 1/2] Don't ignore non-public interfaces unconditionally When mocking a type, Moq currently disregards all its base interfaces that are declared non-public. This was implemented in 6ad71030b1 to prevent DynamicProxy from choking on types inaccessible to it. This produces some collateral damage concerning `CallBase`: even when `CallBase == true` on the mock, base methods will not be called if they are declared in a non-public base interface. Simply excluding non-public base interfaces is too imprecise, because if there is a suitable `[assembly: InternalsVisibleTo]` custom attri- bute for DynamicProxy, then even a non-public interface might be accessible to DynamicProxy, and the error which the type exclusion supposedly protects against wouldn't occur in the first place. So instead of just excluding a non-public base interface, let's simply *ask* DynamicProxy whether it can access it or not. --- Source/Mock.Generic.cs | 2 +- Source/ProxyFactories/CastleProxyFactory.cs | 5 +++++ Source/ProxyFactories/ProxyFactory.cs | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Mock.Generic.cs b/Source/Mock.Generic.cs index 84b185cc0..ea681def8 100644 --- a/Source/Mock.Generic.cs +++ b/Source/Mock.Generic.cs @@ -69,7 +69,7 @@ static Mock() inheritedInterfaces = typeof(T) .GetInterfaces() - .Where(i => { var it = i.GetTypeInfo(); return it.IsPublic || it.IsNestedPublic && !it.IsImport; }) + .Where(i => ProxyFactory.Instance.IsTypeVisible(i) && !i.GetTypeInfo().IsImport) .ToArray(); serialNumberCounter = 0; diff --git a/Source/ProxyFactories/CastleProxyFactory.cs b/Source/ProxyFactories/CastleProxyFactory.cs index 9eb9e8131..5d0d72bb8 100644 --- a/Source/ProxyFactories/CastleProxyFactory.cs +++ b/Source/ProxyFactories/CastleProxyFactory.cs @@ -122,6 +122,11 @@ public override bool IsMethodVisible(MethodInfo method, out string messageIfNotV return ProxyUtil.IsAccessible(method, out messageIfNotVisible); } + public override bool IsTypeVisible(Type type) + { + return ProxyUtil.IsAccessible(type); + } + /// public override Type GetDelegateProxyInterface(Type delegateType, out MethodInfo delegateInterfaceMethod) { diff --git a/Source/ProxyFactories/ProxyFactory.cs b/Source/ProxyFactories/ProxyFactory.cs index 9b1148da9..71c81c39a 100644 --- a/Source/ProxyFactories/ProxyFactory.cs +++ b/Source/ProxyFactories/ProxyFactory.cs @@ -54,6 +54,8 @@ internal abstract class ProxyFactory public abstract bool IsMethodVisible(MethodInfo method, out string messageIfNotVisible); + public abstract bool IsTypeVisible(Type type); + /// /// Gets an autogenerated interface with a method on it that matches the signature of the specified /// . From 420d9e765e013efc63b5982f1de119c3432838ad Mon Sep 17 00:00:00 2001 From: stakx Date: Fri, 13 Jul 2018 19:33:39 +0200 Subject: [PATCH 2/2] Update the changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbad1a682..5a7cc57f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1 * Update package reference to `Castle.Core` (DynamicProxy) from version 4.3.0 to 4.3.1 (@stakx, #635) * Floating point values are formatted with higher precision (satisfying round-tripping) in diagnostic messages (@stakx, #637) +#### Fixed + +* `CallBase` disregarded for some base methods from non-public interfaces (@stakx, #641) #### Obsoleted