Skip to content

Commit b2ec59a

Browse files
committed
Fix and tests for invoking static methods
1 parent 871072d commit b2ec59a

File tree

4 files changed

+247
-6
lines changed

4 files changed

+247
-6
lines changed

Tapeti.Tests/Config/SimpleControllerTest.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,19 @@ public class SimpleControllerTest : BaseControllerTest
1212
public void RegisterController()
1313
{
1414
var bindings = GetControllerBindings<TestController>();
15-
bindings.Should().HaveCount(1);
15+
bindings.Should().HaveCount(2);
1616

1717
var handleSimpleMessageBinding = bindings.Single(b => b is IControllerMethodBinding cmb &&
1818
cmb.Controller == typeof(TestController) &&
1919
cmb.Method.Name == "HandleSimpleMessage");
2020
handleSimpleMessageBinding.QueueType.Should().Be(QueueType.Dynamic);
21+
22+
23+
var handleSimpleMessageStaticBinding = bindings.Single(b => b is IControllerMethodBinding cmb &&
24+
cmb.Controller == typeof(TestController) &&
25+
cmb.Method.Name == "HandleSimpleMessageStatic");
26+
handleSimpleMessageStaticBinding.QueueType.Should().Be(QueueType.Dynamic);
27+
2128
}
2229

2330

@@ -35,6 +42,10 @@ private class TestController
3542
public void HandleSimpleMessage(TestMessage message)
3643
{
3744
}
45+
46+
public static void HandleSimpleMessageStatic(TestMessage message)
47+
{
48+
}
3849
}
3950

4051
#pragma warning restore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Runtime.CompilerServices;
4+
using FluentAssertions;
5+
using Tapeti.Helpers;
6+
using Xunit;
7+
8+
namespace Tapeti.Tests.Helpers
9+
{
10+
public class ExpressionInvokerTest
11+
{
12+
[Fact]
13+
public void InstanceMethodVoidNoParameters()
14+
{
15+
const string methodName = nameof(InvokeTarget.InstanceMethodVoidNoParameters);
16+
var invoker = InvokerFor(methodName);
17+
18+
var target = new InvokeTarget();
19+
invoker.Invoke(target);
20+
21+
target.Verify(methodName);
22+
}
23+
24+
25+
[Fact]
26+
public void InstanceMethodReturnValueNoParameters()
27+
{
28+
const string methodName = nameof(InvokeTarget.InstanceMethodReturnValueNoParameters);
29+
var invoker = InvokerFor(methodName);
30+
31+
var target = new InvokeTarget();
32+
var returnValue = invoker.Invoke(target);
33+
34+
target.Verify(methodName);
35+
returnValue.Should().Be("Hello world!");
36+
}
37+
38+
39+
[Fact]
40+
public void InstanceMethodVoidParameters()
41+
{
42+
const string methodName = nameof(InvokeTarget.InstanceMethodVoidParameters);
43+
var invoker = InvokerFor(methodName);
44+
45+
var target = new InvokeTarget();
46+
invoker.Invoke(target, 42);
47+
48+
target.Verify(methodName, "42");
49+
}
50+
51+
52+
[Fact]
53+
public void InstanceMethodReturnValueParameters()
54+
{
55+
const string methodName = nameof(InvokeTarget.InstanceMethodReturnValueParameters);
56+
var invoker = InvokerFor(methodName);
57+
58+
var target = new InvokeTarget();
59+
var returnValue = invoker.Invoke(target, new byte[] { 42, 69 });
60+
61+
target.Verify(methodName, "42,69");
62+
returnValue.Should().Be(true);
63+
}
64+
65+
66+
[Fact]
67+
public void StaticMethodVoidNoParameters()
68+
{
69+
InvokeTarget.ResetStatic();
70+
71+
const string methodName = nameof(InvokeTarget.StaticMethodVoidNoParameters);
72+
var invoker = InvokerFor(methodName);
73+
74+
invoker.Invoke(null);
75+
76+
InvokeTarget.VerifyStatic(methodName);
77+
}
78+
79+
80+
[Fact]
81+
public void StaticMethodReturnValueNoParameters()
82+
{
83+
InvokeTarget.ResetStatic();
84+
85+
const string methodName = nameof(InvokeTarget.StaticMethodReturnValueNoParameters);
86+
var invoker = InvokerFor(methodName);
87+
88+
var returnValue = invoker.Invoke(null);
89+
90+
InvokeTarget.VerifyStatic(methodName);
91+
returnValue.Should().Be("Hello world!");
92+
}
93+
94+
95+
[Fact]
96+
public void StaticMethodVoidParameters()
97+
{
98+
InvokeTarget.ResetStatic();
99+
100+
const string methodName = nameof(InvokeTarget.StaticMethodVoidParameters);
101+
var invoker = InvokerFor(methodName);
102+
103+
invoker.Invoke(null, 42);
104+
105+
InvokeTarget.VerifyStatic(methodName, "42");
106+
}
107+
108+
109+
[Fact]
110+
public void StaticMethodReturnValueParameters()
111+
{
112+
InvokeTarget.ResetStatic();
113+
114+
const string methodName = nameof(InvokeTarget.StaticMethodReturnValueParameters);
115+
var invoker = InvokerFor(methodName);
116+
117+
var returnValue = invoker.Invoke(null, new byte[] { 42, 69 });
118+
119+
InvokeTarget.VerifyStatic(methodName, "42,69");
120+
returnValue.Should().Be(true);
121+
}
122+
123+
124+
private static ExpressionInvoke InvokerFor(string invokeTargetMethodName)
125+
{
126+
var method = typeof(InvokeTarget).GetMethod(invokeTargetMethodName);
127+
return method!.CreateExpressionInvoke();
128+
}
129+
130+
131+
132+
// ReSharper disable ParameterHidesMember
133+
private class InvokeTarget
134+
{
135+
private static string? staticMethodName;
136+
private static string? staticParameters;
137+
138+
private string? methodName;
139+
private string? parameters;
140+
141+
142+
public void InstanceMethodVoidNoParameters()
143+
{
144+
MethodCalled();
145+
}
146+
147+
public string InstanceMethodReturnValueNoParameters()
148+
{
149+
MethodCalled();
150+
return "Hello world!";
151+
}
152+
153+
public void InstanceMethodVoidParameters(int answer)
154+
{
155+
MethodCalled(answer.ToString());
156+
}
157+
158+
public bool InstanceMethodReturnValueParameters(IEnumerable<byte> values)
159+
{
160+
MethodCalled(string.Join(',', values.Select(v => v.ToString())));
161+
return true;
162+
}
163+
164+
165+
public static void StaticMethodVoidNoParameters()
166+
{
167+
StaticMethodCalled();
168+
}
169+
170+
public static string StaticMethodReturnValueNoParameters()
171+
{
172+
StaticMethodCalled();
173+
return "Hello world!";
174+
}
175+
176+
public static void StaticMethodVoidParameters(int answer)
177+
{
178+
StaticMethodCalled(answer.ToString());
179+
}
180+
181+
public static bool StaticMethodReturnValueParameters(IEnumerable<byte> values)
182+
{
183+
StaticMethodCalled(string.Join(',', values.Select(v => v.ToString())));
184+
return true;
185+
}
186+
187+
188+
private void MethodCalled(string parameters = "", [CallerMemberName]string methodName = "")
189+
{
190+
this.methodName.Should().BeNull();
191+
this.methodName = methodName;
192+
this.parameters = parameters;
193+
194+
}
195+
196+
197+
public static void ResetStatic()
198+
{
199+
staticMethodName = null;
200+
staticParameters = null;
201+
}
202+
203+
204+
private static void StaticMethodCalled(string parameters = "", [CallerMemberName] string methodName = "")
205+
{
206+
staticMethodName.Should().BeNull();
207+
staticMethodName = methodName;
208+
staticParameters = parameters;
209+
}
210+
211+
212+
213+
public void Verify(string methodName, string parameters = "")
214+
{
215+
this.methodName.Should().Be(methodName);
216+
this.parameters.Should().Be(parameters);
217+
}
218+
219+
220+
public static void VerifyStatic(string methodName, string parameters = "")
221+
{
222+
staticMethodName.Should().Be(methodName);
223+
staticParameters.Should().Be(parameters);
224+
}
225+
}
226+
}
227+
}

Tapeti/Helpers/ExpressionInvoker.cs

+8-5
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,25 @@ public static ExpressionInvoke CreateExpressionInvoke(this MethodInfo method)
4444
.ToArray();
4545

4646

47-
var target = Expression.Parameter(typeof(object), "target");
48-
var castTarget = Expression.Convert(target, method.DeclaringType);
49-
var invoke = Expression.Call(castTarget, method, parameters);
47+
var instanceParameter = Expression.Parameter(typeof(object), "target");
48+
Expression? instance = method.IsStatic
49+
? null
50+
: Expression.Convert(instanceParameter, method.DeclaringType);
51+
52+
var invoke = Expression.Call(instance, method, parameters);
5053

5154
Expression<ExpressionInvoke> lambda;
5255

5356
if (method.ReturnType != typeof(void))
5457
{
5558
var result = Expression.Convert(invoke, typeof(object));
56-
lambda = Expression.Lambda<ExpressionInvoke>(result, target, argsParameter);
59+
lambda = Expression.Lambda<ExpressionInvoke>(result, instanceParameter, argsParameter);
5760
}
5861
else
5962
{
6063
var nullResult = Expression.Constant(null, typeof(object));
6164
var body = Expression.Block(invoke, nullResult);
62-
lambda = Expression.Lambda<ExpressionInvoke>(body, target, argsParameter);
65+
lambda = Expression.Lambda<ExpressionInvoke>(body, instanceParameter, argsParameter);
6366
}
6467

6568
return lambda.Compile();

0 commit comments

Comments
 (0)