Skip to content

Commit

Permalink
Fix the out parameter issue of delegate mock
Browse files Browse the repository at this point in the history
The out parameter of delegate mock was handled as same as ref parameter of method mock, because `ParameterInfo.Attributes` wasn't copied when creating delegate proxy.
  • Loading branch information
urasandesu committed Apr 9, 2016
1 parent 8594b26 commit 1d761f6
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 4 deletions.
13 changes: 9 additions & 4 deletions Source/Proxy/CastleProxyFactory.cs
Expand Up @@ -120,10 +120,15 @@ public Type GetDelegateProxyInterface(Type delegateType, out MethodInfo delegate
var delegateParameterTypes = invokeMethodOnDelegate.GetParameters().Select(p => p.ParameterType).ToArray();

// Create a method on the interface with the same signature as the delegate.
newTypeBuilder.DefineMethod("Invoke",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract,
CallingConventions.HasThis,
invokeMethodOnDelegate.ReturnType, delegateParameterTypes);
var newMethBuilder = newTypeBuilder.DefineMethod("Invoke",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract,
CallingConventions.HasThis,
invokeMethodOnDelegate.ReturnType, delegateParameterTypes);

foreach (var param in invokeMethodOnDelegate.GetParameters())
{
newMethBuilder.DefineParameter(param.Position + 1, param.Attributes, param.Name);
}

delegateInterfaceType = newTypeBuilder.CreateType();
delegateInterfaceCache[delegateType] = delegateInterfaceType;
Expand Down
81 changes: 81 additions & 0 deletions UnitTests/MockedDelegatesFixture.cs
Expand Up @@ -86,6 +86,78 @@ public void DelegateInterfacesAreReused()
Assert.Same(mock1.DelegateInterfaceMethod, mock2.DelegateInterfaceMethod);
}

[Fact]
public void CanHandleOutParameterOfActionAsSameAsVoidMethod()
{
var out1 = 42;
var methMock = new Mock<TypeOutAction<int>>();
methMock.Setup(t => t.Invoke(out out1));
var dlgtMock = new Mock<DelegateOutAction<int>>();
dlgtMock.Setup(f => f(out out1));

var methOut1 = default(int);
methMock.Object.Invoke(out methOut1);
var dlgtOut1 = default(int);
dlgtMock.Object(out dlgtOut1);

Assert.Equal(methOut1, dlgtOut1);
}

[Fact]
public void CanHandleRefParameterOfActionAsSameAsVoidMethod()
{
var ref1 = 42;
var methMock = new Mock<TypeRefAction<int>>(MockBehavior.Strict);
methMock.Setup(t => t.Invoke(ref ref1));
var dlgtMock = new Mock<DelegateRefAction<int>>(MockBehavior.Strict);
dlgtMock.Setup(f => f(ref ref1));

var methRef1 = 42;
methMock.Object.Invoke(ref methRef1);
var dlgtRef1 = 42;
dlgtMock.Object(ref dlgtRef1);

methMock.VerifyAll();
dlgtMock.VerifyAll();
}

[Fact]
public void CanHandleOutParameterOfFuncAsSameAsReturnableMethod()
{
var out1 = 42;
var methMock = new Mock<TypeOutFunc<int, int>>();
methMock.Setup(t => t.Invoke(out out1)).Returns(114514);
var dlgtMock = new Mock<DelegateOutFunc<int, int>>();
dlgtMock.Setup(f => f(out out1)).Returns(114514);

var methOut1 = default(int);
var methResult = methMock.Object.Invoke(out methOut1);
var dlgtOut1 = default(int);
var dlgtResult = dlgtMock.Object(out dlgtOut1);

Assert.Equal(methOut1, dlgtOut1);
Assert.Equal(methResult, dlgtResult);
}

[Fact]
public void CanHandleRefParameterOfFuncAsSameAsReturnableMethod()
{
var ref1 = 42;
var methMock = new Mock<TypeRefFunc<int, int>>(MockBehavior.Strict);
methMock.Setup(t => t.Invoke(ref ref1)).Returns(114514);
var dlgtMock = new Mock<DelegateRefFunc<int, int>>(MockBehavior.Strict);
dlgtMock.Setup(f => f(ref ref1)).Returns(114514);

var methRef1 = 42;
var methResult = methMock.Object.Invoke(ref methRef1);
var dlgtRef1 = 42;
var dlgtResult = dlgtMock.Object(ref dlgtRef1);

methMock.VerifyAll();
dlgtMock.VerifyAll();
Assert.Equal(methResult, dlgtResult);
}

private static void Use(Action<int> action, int valueToPass)
{
action(valueToPass);
Expand Down Expand Up @@ -115,5 +187,14 @@ public int Value
}
}
}

public interface TypeOutAction<TOut1> { void Invoke(out TOut1 out1); }
public delegate void DelegateOutAction<TOut1>(out TOut1 out1);
public interface TypeRefAction<TRef1> { void Invoke(ref TRef1 ref1); }
public delegate void DelegateRefAction<TRef1>(ref TRef1 ref1);
public interface TypeOutFunc<TOut1, TResult> { TResult Invoke(out TOut1 out1); }
public delegate TResult DelegateOutFunc<TOut1, TResult>(out TOut1 out1);
public interface TypeRefFunc<TRef1, TResult> { TResult Invoke(ref TRef1 ref1); }
public delegate TResult DelegateRefFunc<TRef1, TResult>(ref TRef1 ref1);
}
}

0 comments on commit 1d761f6

Please sign in to comment.