Fix and tests for invoking static methods

This commit is contained in:
Mark van Renswoude 2022-11-23 12:52:36 +01:00
parent 871072d9c3
commit b2ec59a3f3
4 changed files with 247 additions and 6 deletions

View File

@ -12,12 +12,19 @@ namespace Tapeti.Tests.Config
public void RegisterController()
{
var bindings = GetControllerBindings<TestController>();
bindings.Should().HaveCount(1);
bindings.Should().HaveCount(2);
var handleSimpleMessageBinding = bindings.Single(b => b is IControllerMethodBinding cmb &&
cmb.Controller == typeof(TestController) &&
cmb.Method.Name == "HandleSimpleMessage");
handleSimpleMessageBinding.QueueType.Should().Be(QueueType.Dynamic);
var handleSimpleMessageStaticBinding = bindings.Single(b => b is IControllerMethodBinding cmb &&
cmb.Controller == typeof(TestController) &&
cmb.Method.Name == "HandleSimpleMessageStatic");
handleSimpleMessageStaticBinding.QueueType.Should().Be(QueueType.Dynamic);
}
@ -35,6 +42,10 @@ namespace Tapeti.Tests.Config
public void HandleSimpleMessage(TestMessage message)
{
}
public static void HandleSimpleMessageStatic(TestMessage message)
{
}
}
#pragma warning restore

View File

@ -0,0 +1,227 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using FluentAssertions;
using Tapeti.Helpers;
using Xunit;
namespace Tapeti.Tests.Helpers
{
public class ExpressionInvokerTest
{
[Fact]
public void InstanceMethodVoidNoParameters()
{
const string methodName = nameof(InvokeTarget.InstanceMethodVoidNoParameters);
var invoker = InvokerFor(methodName);
var target = new InvokeTarget();
invoker.Invoke(target);
target.Verify(methodName);
}
[Fact]
public void InstanceMethodReturnValueNoParameters()
{
const string methodName = nameof(InvokeTarget.InstanceMethodReturnValueNoParameters);
var invoker = InvokerFor(methodName);
var target = new InvokeTarget();
var returnValue = invoker.Invoke(target);
target.Verify(methodName);
returnValue.Should().Be("Hello world!");
}
[Fact]
public void InstanceMethodVoidParameters()
{
const string methodName = nameof(InvokeTarget.InstanceMethodVoidParameters);
var invoker = InvokerFor(methodName);
var target = new InvokeTarget();
invoker.Invoke(target, 42);
target.Verify(methodName, "42");
}
[Fact]
public void InstanceMethodReturnValueParameters()
{
const string methodName = nameof(InvokeTarget.InstanceMethodReturnValueParameters);
var invoker = InvokerFor(methodName);
var target = new InvokeTarget();
var returnValue = invoker.Invoke(target, new byte[] { 42, 69 });
target.Verify(methodName, "42,69");
returnValue.Should().Be(true);
}
[Fact]
public void StaticMethodVoidNoParameters()
{
InvokeTarget.ResetStatic();
const string methodName = nameof(InvokeTarget.StaticMethodVoidNoParameters);
var invoker = InvokerFor(methodName);
invoker.Invoke(null);
InvokeTarget.VerifyStatic(methodName);
}
[Fact]
public void StaticMethodReturnValueNoParameters()
{
InvokeTarget.ResetStatic();
const string methodName = nameof(InvokeTarget.StaticMethodReturnValueNoParameters);
var invoker = InvokerFor(methodName);
var returnValue = invoker.Invoke(null);
InvokeTarget.VerifyStatic(methodName);
returnValue.Should().Be("Hello world!");
}
[Fact]
public void StaticMethodVoidParameters()
{
InvokeTarget.ResetStatic();
const string methodName = nameof(InvokeTarget.StaticMethodVoidParameters);
var invoker = InvokerFor(methodName);
invoker.Invoke(null, 42);
InvokeTarget.VerifyStatic(methodName, "42");
}
[Fact]
public void StaticMethodReturnValueParameters()
{
InvokeTarget.ResetStatic();
const string methodName = nameof(InvokeTarget.StaticMethodReturnValueParameters);
var invoker = InvokerFor(methodName);
var returnValue = invoker.Invoke(null, new byte[] { 42, 69 });
InvokeTarget.VerifyStatic(methodName, "42,69");
returnValue.Should().Be(true);
}
private static ExpressionInvoke InvokerFor(string invokeTargetMethodName)
{
var method = typeof(InvokeTarget).GetMethod(invokeTargetMethodName);
return method!.CreateExpressionInvoke();
}
// ReSharper disable ParameterHidesMember
private class InvokeTarget
{
private static string? staticMethodName;
private static string? staticParameters;
private string? methodName;
private string? parameters;
public void InstanceMethodVoidNoParameters()
{
MethodCalled();
}
public string InstanceMethodReturnValueNoParameters()
{
MethodCalled();
return "Hello world!";
}
public void InstanceMethodVoidParameters(int answer)
{
MethodCalled(answer.ToString());
}
public bool InstanceMethodReturnValueParameters(IEnumerable<byte> values)
{
MethodCalled(string.Join(',', values.Select(v => v.ToString())));
return true;
}
public static void StaticMethodVoidNoParameters()
{
StaticMethodCalled();
}
public static string StaticMethodReturnValueNoParameters()
{
StaticMethodCalled();
return "Hello world!";
}
public static void StaticMethodVoidParameters(int answer)
{
StaticMethodCalled(answer.ToString());
}
public static bool StaticMethodReturnValueParameters(IEnumerable<byte> values)
{
StaticMethodCalled(string.Join(',', values.Select(v => v.ToString())));
return true;
}
private void MethodCalled(string parameters = "", [CallerMemberName]string methodName = "")
{
this.methodName.Should().BeNull();
this.methodName = methodName;
this.parameters = parameters;
}
public static void ResetStatic()
{
staticMethodName = null;
staticParameters = null;
}
private static void StaticMethodCalled(string parameters = "", [CallerMemberName] string methodName = "")
{
staticMethodName.Should().BeNull();
staticMethodName = methodName;
staticParameters = parameters;
}
public void Verify(string methodName, string parameters = "")
{
this.methodName.Should().Be(methodName);
this.parameters.Should().Be(parameters);
}
public static void VerifyStatic(string methodName, string parameters = "")
{
staticMethodName.Should().Be(methodName);
staticParameters.Should().Be(parameters);
}
}
}
}

View File

@ -44,22 +44,25 @@ namespace Tapeti.Helpers
.ToArray();
var target = Expression.Parameter(typeof(object), "target");
var castTarget = Expression.Convert(target, method.DeclaringType);
var invoke = Expression.Call(castTarget, method, parameters);
var instanceParameter = Expression.Parameter(typeof(object), "target");
Expression? instance = method.IsStatic
? null
: Expression.Convert(instanceParameter, method.DeclaringType);
var invoke = Expression.Call(instance, method, parameters);
Expression<ExpressionInvoke> lambda;
if (method.ReturnType != typeof(void))
{
var result = Expression.Convert(invoke, typeof(object));
lambda = Expression.Lambda<ExpressionInvoke>(result, target, argsParameter);
lambda = Expression.Lambda<ExpressionInvoke>(result, instanceParameter, argsParameter);
}
else
{
var nullResult = Expression.Constant(null, typeof(object));
var body = Expression.Block(invoke, nullResult);
lambda = Expression.Lambda<ExpressionInvoke>(body, target, argsParameter);
lambda = Expression.Lambda<ExpressionInvoke>(body, instanceParameter, argsParameter);
}
return lambda.Compile();