12
12
13
13
import static java .lang .String .format ;
14
14
import static java .util .Arrays .stream ;
15
- import static java .util .stream .Collectors .joining ;
16
15
import static java .util .stream .Collectors .toList ;
17
16
import static org .junit .jupiter .params .provider .Arguments .arguments ;
18
17
import static org .junit .platform .commons .util .AnnotationUtils .isAnnotated ;
@@ -48,25 +47,33 @@ public void accept(MethodSource annotation) {
48
47
49
48
@ Override
50
49
public Stream <Arguments > provideArguments (ExtensionContext context ) {
50
+ Class <?> testClass = context .getRequiredTestClass ();
51
+ Method testMethod = context .getRequiredTestMethod ();
51
52
Object testInstance = context .getTestInstance ().orElse (null );
52
53
// @formatter:off
53
54
return stream (this .methodNames )
54
- .map (factoryMethodName -> getFactoryMethod (context , factoryMethodName ))
55
+ .map (factoryMethodName -> getFactoryMethod (testClass , testMethod , factoryMethodName ))
55
56
.map (factoryMethod -> context .getExecutableInvoker ().invoke (factoryMethod , testInstance ))
56
57
.flatMap (CollectionUtils ::toStream )
57
58
.map (MethodArgumentsProvider ::toArguments );
58
59
// @formatter:on
59
60
}
60
61
61
- private Method getFactoryMethod (ExtensionContext context , String factoryMethodName ) {
62
- Method testMethod = context .getRequiredTestMethod ();
63
- if (StringUtils .isBlank (factoryMethodName )) {
64
- factoryMethodName = testMethod .getName ();
62
+ private Method getFactoryMethod (Class <?> testClass , Method testMethod , String factoryMethodName ) {
63
+ if (!StringUtils .isBlank (factoryMethodName )) {
64
+ if (looksLikeAFullyQualifiedMethodName (factoryMethodName )) {
65
+ return getFactoryMethodByFullyQualifiedName (factoryMethodName );
66
+ }
67
+ else if (looksLikeALocalQualifiedMethodName (factoryMethodName )) {
68
+ return getFactoryMethodByFullyQualifiedName (testClass .getName () + "#" + factoryMethodName );
69
+ }
65
70
}
66
- if (looksLikeAFullyQualifiedMethodName (factoryMethodName )) {
67
- return getFactoryMethodByFullyQualifiedName (factoryMethodName );
71
+ else {
72
+ // User did not provide a factory method name, so we search for a
73
+ // factory method with the same name as the parameterized test method.
74
+ factoryMethodName = testMethod .getName ();
68
75
}
69
- return getFactoryMethodBySimpleOrQualifiedName ( context . getRequiredTestClass () , testMethod , factoryMethodName );
76
+ return findFactoryMethodBySimpleName ( testClass , testMethod , factoryMethodName );
70
77
}
71
78
72
79
private static boolean looksLikeAFullyQualifiedMethodName (String factoryMethodName ) {
@@ -89,6 +96,18 @@ private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodNa
89
96
return true ;
90
97
}
91
98
99
+ private static boolean looksLikeALocalQualifiedMethodName (String factoryMethodName ) {
100
+ // This method is intended to be called after looksLikeAFullyQualifiedMethodName()
101
+ // and therefore does not check for the absence of '#' and does not reason about
102
+ // the presence or absence of a fully qualified class name.
103
+ if (factoryMethodName .endsWith ("()" )) {
104
+ return true ;
105
+ }
106
+ int indexOfLastOpeningParenthesis = factoryMethodName .lastIndexOf ('(' );
107
+ return (indexOfLastOpeningParenthesis > 0 )
108
+ && (indexOfLastOpeningParenthesis < factoryMethodName .lastIndexOf (')' ));
109
+ }
110
+
92
111
private Method getFactoryMethodByFullyQualifiedName (String fullyQualifiedMethodName ) {
93
112
String [] methodParts = ReflectionUtils .parseFullyQualifiedMethodName (fullyQualifiedMethodName );
94
113
String className = methodParts [0 ];
@@ -100,33 +119,17 @@ private Method getFactoryMethodByFullyQualifiedName(String fullyQualifiedMethodN
100
119
methodParameters , className )));
101
120
}
102
121
103
- private Method getFactoryMethodBySimpleOrQualifiedName (Class <?> testClass , Method testMethod ,
104
- String simpleOrQualifiedMethodName ) {
105
- String [] methodParts = ReflectionUtils .parseQualifiedMethodName (simpleOrQualifiedMethodName );
106
- String methodSimpleName = methodParts [0 ];
107
- String methodParameters = methodParts [1 ];
108
-
109
- List <Method > factoryMethods = findFactoryMethodsBySimpleName (testClass , testMethod , methodSimpleName );
110
- if (factoryMethods .size () == 1 ) {
111
- return factoryMethods .get (0 );
112
- }
113
-
114
- List <Method > exactMatches = filterFactoryMethodsWithMatchingParameters (factoryMethods ,
115
- simpleOrQualifiedMethodName , methodParameters );
116
- Preconditions .condition (exactMatches .size () == 1 ,
117
- () -> format ("%d factory methods named [%s] were found in class [%s]: %s" , factoryMethods .size (),
118
- simpleOrQualifiedMethodName , testClass .getName (), factoryMethods ));
119
- return exactMatches .get (0 );
120
- }
121
-
122
122
/**
123
123
* Find all methods in the given {@code testClass} with the desired {@code factoryMethodName}
124
124
* which have return types that can be converted to a {@link Stream}, ignoring the
125
125
* {@code testMethod} itself as well as any {@code @Test}, {@code @TestTemplate},
126
126
* or {@code @TestFactory} methods with the same name.
127
+ * @return the factory method, if found
128
+ * @throws org.junit.platform.commons.PreconditionViolationException if the
129
+ * factory method was not found or if multiple competing factory methods with
130
+ * the same name were found
127
131
*/
128
- private List <Method > findFactoryMethodsBySimpleName (Class <?> testClass , Method testMethod ,
129
- String factoryMethodName ) {
132
+ private Method findFactoryMethodBySimpleName (Class <?> testClass , Method testMethod , String factoryMethodName ) {
130
133
Predicate <Method > isCandidate = candidate -> factoryMethodName .equals (candidate .getName ())
131
134
&& !testMethod .equals (candidate );
132
135
List <Method > candidates = ReflectionUtils .findMethods (testClass , isCandidate );
@@ -147,27 +150,10 @@ private List<Method> findFactoryMethodsBySimpleName(Class<?> testClass, Method t
147
150
// Otherwise, report that we didn't find anything.
148
151
return format ("Could not find factory method [%s] in class [%s]" , factoryMethodName , testClass .getName ());
149
152
});
150
- return factoryMethods ;
151
- }
152
-
153
- private static List <Method > filterFactoryMethodsWithMatchingParameters (List <Method > factoryMethods ,
154
- String factoryMethodName , String factoryMethodParameters ) {
155
-
156
- if (!factoryMethodName .endsWith (")" )) {
157
- // If parameters are not specified, nothing is filtered.
158
- return factoryMethods ;
159
- }
160
-
161
- // Compare against canonical parameter list, ignoring whitespace.
162
- String parameterList = factoryMethodParameters .replaceAll ("\\ s+" , "" );
163
- Predicate <Method > hasRequiredParameters = method -> {
164
- if (parameterList .isEmpty ()) {
165
- return method .getParameterCount () == 0 ;
166
- }
167
- return parameterList .equals (stream (method .getParameterTypes ()).map (Class ::getName ).collect (joining ("," )));
168
- };
169
-
170
- return factoryMethods .stream ().filter (hasRequiredParameters ).collect (toList ());
153
+ Preconditions .condition (factoryMethods .size () == 1 ,
154
+ () -> format ("%d factory methods named [%s] were found in class [%s]: %s" , factoryMethods .size (),
155
+ factoryMethodName , testClass .getName (), factoryMethods ));
156
+ return factoryMethods .get (0 );
171
157
}
172
158
173
159
private boolean isTestMethod (Method candidate ) {
0 commit comments