Skip to content

Commit

Permalink
Setup: Throw when method inaccessible to proxy generator
Browse files Browse the repository at this point in the history
  • Loading branch information
stakx committed Sep 23, 2017
1 parent dc3a00f commit 0de9646
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
17 changes: 17 additions & 0 deletions Source/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ internal static MethodCall<T> Setup<T>(Mock<T> mock, Expression<Action<T>> expre
var args = methodCall.Arguments.ToArray();
ThrowIfSetupExpressionInvolvesUnsupportedMember(expression, method);
ThrowIfSetupMethodNotVisibleToProxyFactory(method);
var call = new MethodCall<T>(mock, condition, expression, method, args);
var targetInterceptor = GetInterceptor(methodCall.Object, mock);
Expand Down Expand Up @@ -464,6 +465,7 @@ internal static MethodCallReturn<T, TResult> Setup<T, TResult>(
var args = methodCall.Arguments.ToArray();
ThrowIfSetupExpressionInvolvesUnsupportedMember(expression, method);
ThrowIfSetupMethodNotVisibleToProxyFactory(method);
var call = new MethodCallReturn<T, TResult>(mock, condition, expression, method, args);
var targetInterceptor = GetInterceptor(methodCall.Object, mock);
Expand Down Expand Up @@ -493,6 +495,7 @@ internal static MethodCallReturn<T, TProperty> SetupGet<T, TProperty>(
var propGet = prop.GetGetMethod(true);
ThrowIfSetupExpressionInvolvesUnsupportedMember(expression, propGet);
ThrowIfSetupMethodNotVisibleToProxyFactory(propGet);
var call = new MethodCallReturn<T, TProperty>(mock, condition, expression, propGet, new Expression[0]);
// Directly casting to MemberExpression is fine as ToPropertyInfo would throw if it wasn't
Expand Down Expand Up @@ -551,6 +554,7 @@ internal static SetterMethodCall<T, TProperty> SetupSet<T, TProperty>(

var propSet = prop.GetSetMethod(true);
ThrowIfSetupExpressionInvolvesUnsupportedMember(expression, propSet);
ThrowIfSetupMethodNotVisibleToProxyFactory(propSet);

var call = new SetterMethodCall<T, TProperty>(mock, expression, propSet);
var targetInterceptor = GetInterceptor(((MemberExpression)expression.Body).Expression, mock);
Expand Down Expand Up @@ -802,6 +806,19 @@ private static void ThrowIfPropertyNotReadable(PropertyInfo prop)
}
}

private static void ThrowIfSetupMethodNotVisibleToProxyFactory(MethodInfo method)
{
if (Mock.ProxyFactory.IsMethodVisible(method, out string messageIfNotVisible) == false)
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.MethodNotVisibleToProxyFactory,
method.DeclaringType.Name,
method.Name,
messageIfNotVisible));
}
}

private static void ThrowIfSetupExpressionInvolvesUnsupportedMember(Expression setup, MethodInfo method)
{
if (method.IsStatic)
Expand Down
14 changes: 12 additions & 2 deletions Source/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Source/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,8 @@ Expected invocation on the mock once, but was {4} times: {1}</value>
<data name="UseItExprIsNullRatherThanNullArgumentValue" xml:space="preserve">
<value>Use ItExpr.IsNull&lt;TValue&gt; rather than a null argument value, as it prevents proper method lookup.</value>
</data>
<data name="MethodNotVisibleToProxyFactory" xml:space="preserve">
<value>Cannot set up {0}.{1} because it is not accessible to the proxy generator used by Moq:
{2}</value>
</data>
</root>
5 changes: 5 additions & 0 deletions Source/Proxy/CastleProxyFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ public object CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] in
}
}

public bool IsMethodVisible(MethodInfo method, out string messageIfNotVisible)
{
return Castle.DynamicProxy.ProxyUtil.IsAccessible(method, out messageIfNotVisible);
}

private static readonly Dictionary<Type, Type> delegateInterfaceCache = new Dictionary<Type, Type>();
private static readonly ProxyGenerationOptions proxyOptions;
private static int delegateInterfaceSuffix;
Expand Down
2 changes: 2 additions & 0 deletions Source/Proxy/IProxyFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ internal interface IProxyFactory
{
object CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, object[] arguments);

bool IsMethodVisible(MethodInfo method, out string messageIfNotVisible);

/// <summary>
/// Gets an autogenerated interface with a method on it that matches the signature of the specified
/// <paramref name="delegateType"/>.
Expand Down

0 comments on commit 0de9646

Please sign in to comment.