-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
ParameterizedTestExtension.java
139 lines (124 loc) · 5.45 KB
/
ParameterizedTestExtension.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* Copyright 2015-2017 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.jupiter.params;
import static java.util.Collections.singletonList;
import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations;
import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.junit.jupiter.api.extension.ContainerExtensionContext;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.platform.commons.JUnitException;
import org.junit.platform.commons.util.AnnotationUtils;
import org.junit.platform.commons.util.ExceptionUtils;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.ReflectionUtils;
import org.junit.platform.commons.util.ReflectionUtils.MethodSortOrder;
class ParameterizedTestExtension implements TestTemplateInvocationContextProvider {
@Override
public boolean supports(ContainerExtensionContext context) {
// @formatter:off
return context.getTestMethod()
.filter(method -> isAnnotated(method, ParameterizedTest.class))
.map(method -> true)
.orElse(false);
// @formatter:on
}
@Override
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
Method templateMethod = Preconditions.notNull(context.getTestMethod().orElse(null),
"test method must not be null");
ParameterizedTestNameFormatter formatter = createNameFormatter(templateMethod);
// @formatter:off
return findRepeatableAnnotations(templateMethod, ArgumentsSource.class)
.stream()
.map(ArgumentsSource::value)
.map(ReflectionUtils::newInstance)
.peek(provider -> initialize(templateMethod, provider))
.flatMap(ParameterizedTestExtension::toArgumentsStream)
.map(Arguments::getArguments)
.map(arguments -> toTestTemplateInvocationContext(formatter, arguments));
// @formatter:on
}
private ParameterizedTestNameFormatter createNameFormatter(Method templateMethod) {
ParameterizedTest parameterizedTestAnnotation = AnnotationUtils.findAnnotation(templateMethod,
ParameterizedTest.class).get();
return new ParameterizedTestNameFormatter(parameterizedTestAnnotation.name());
}
@SuppressWarnings("unchecked")
private void initialize(Method templateMethod, ArgumentsProvider provider) {
if (provider instanceof AnnotationInitialized) {
Predicate<Method> methodPredicate = method -> method.getName().equals("initialize")
&& method.getParameterCount() == 1
&& Annotation.class.isAssignableFrom(method.getParameterTypes()[0]);
Method method = ReflectionUtils.findMethods(provider.getClass(), methodPredicate,
MethodSortOrder.HierarchyUp).get(0);
Class<? extends Annotation> annotationType = (Class<? extends Annotation>) method.getParameterTypes()[0];
Annotation annotation = AnnotationUtils.findAnnotation(templateMethod, annotationType) //
.orElseThrow(() -> new JUnitException(provider.getClass().getName() + " needs to be used with a "
+ annotationType.getName() + " annotation"));
callInitialize((AnnotationInitialized) provider, annotation);
}
}
private <A extends Annotation> void callInitialize(AnnotationInitialized<A> provider, A annotation) {
provider.initialize(annotation);
}
private static Stream<? extends Arguments> toArgumentsStream(ArgumentsProvider provider) {
try {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(provider.arguments(), Spliterator.ORDERED),
false);
}
catch (Exception e) {
// TODO #14 Test
throw ExceptionUtils.throwAsUncheckedException(e);
}
}
private static TestTemplateInvocationContext toTestTemplateInvocationContext(
ParameterizedTestNameFormatter formatter, Object[] arguments) {
return new TestTemplateInvocationContext() {
@Override
public String getDisplayName(int invocationIndex) {
return formatter.format(invocationIndex, arguments);
}
@Override
public List<Extension> getAdditionalExtensions() {
return singletonList(new ParameterResolver() {
@Override
public boolean supports(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return parameterContext.getIndex() < arguments.length;
}
@Override
public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
Object argument = arguments[parameterContext.getIndex()];
if (argument instanceof String
&& parameterContext.getParameter().getType().equals(Integer.TYPE)) {
return Integer.parseInt((String) argument);
}
return argument;
}
});
}
};
}
}