-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathLambdaTest.java
113 lines (87 loc) · 2.97 KB
/
LambdaTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package org.codefx.demo.junit5;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.Executable;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static java.lang.Character.toUpperCase;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
public class LambdaTest {
private final List<DynamicTest> registeredTests = new ArrayList<>();
protected void λ(String displayName, Executable test) {
registeredTests.add(dynamicTest(displayName, test));
}
protected void λ(NamedTest test) {
String displayName = test.prettyName();
registeredTests.add(dynamicTest(displayName, () -> test.execute(displayName)));
}
@TestFactory
List<DynamicTest> registeredTests() {
return registeredTests;
}
@FunctionalInterface
public interface NamedTest extends ParameterNameFinder {
void execute(String name);
}
public interface ParameterNameFinder extends MethodFinder {
default String name() {
return parameterName(0);
}
default String prettyName() {
return stream(name().split("_"))
.map(word -> toUpperCase(word.charAt(0)) + word.substring(1))
.collect(joining(" "));
}
}
public interface MethodFinder extends Serializable {
// as seen on http://benjiweber.co.uk/blog/2015/08/17/lambda-parameter-names-with-reflection/
default SerializedLambda serialized() {
try {
Method replaceMethod = getClass().getDeclaredMethod("writeReplace");
replaceMethod.setAccessible(true);
return (SerializedLambda) replaceMethod.invoke(this);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
default Class<?> getContainingClass() {
try {
String className = serialized().getImplClass().replaceAll("/", ".");
return Class.forName(className);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
default Method method() {
SerializedLambda lambda = serialized();
Class<?> containingClass = getContainingClass();
return stream(containingClass.getDeclaredMethods())
.filter(method -> Objects.equals(method.getName(), lambda.getImplMethodName()))
.findFirst()
.orElseThrow(UnableToGuessMethodException::new);
}
default Parameter parameter(int n) {
return method().getParameters()[n];
}
default String parameterName(int n) {
return checkParameterNamesEnabled(parameter(n).getName());
}
default String checkParameterNamesEnabled(String name) {
if ("arg0".equals(name)) {
throw new IllegalStateException(
"You need to compile with javac (at least 8u60 but before 9)"
+ " with the option -parameters for parameter reflection to work.");
}
return name;
}
class UnableToGuessMethodException extends RuntimeException {
}
}
}