1212
1313import  static  java .lang .String .format ;
1414import  static  java .util .Arrays .stream ;
15- import  static  java .util .stream .Collectors .joining ;
1615import  static  java .util .stream .Collectors .toList ;
1716import  static  org .junit .jupiter .params .provider .Arguments .arguments ;
1817import  static  org .junit .platform .commons .util .AnnotationUtils .isAnnotated ;
@@ -48,25 +47,33 @@ public void accept(MethodSource annotation) {
4847
4948	@ Override 
5049	public  Stream <Arguments > provideArguments (ExtensionContext  context ) {
50+ 		Class <?> testClass  = context .getRequiredTestClass ();
51+ 		Method  testMethod  = context .getRequiredTestMethod ();
5152		Object  testInstance  = context .getTestInstance ().orElse (null );
5253		// @formatter:off 
5354		return  stream (this .methodNames )
54- 				.map (factoryMethodName  -> getFactoryMethod (context , factoryMethodName ))
55+ 				.map (factoryMethodName  -> getFactoryMethod (testClass ,  testMethod , factoryMethodName ))
5556				.map (factoryMethod  -> context .getExecutableInvoker ().invoke (factoryMethod , testInstance ))
5657				.flatMap (CollectionUtils ::toStream )
5758				.map (MethodArgumentsProvider ::toArguments );
5859		// @formatter:on 
5960	}
6061
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+ 			}
6570		}
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 ();
6875		}
69- 		return  getFactoryMethodBySimpleOrQualifiedName ( context . getRequiredTestClass () , testMethod , factoryMethodName );
76+ 		return  findFactoryMethodBySimpleName ( testClass , testMethod , factoryMethodName );
7077	}
7178
7279	private  static  boolean  looksLikeAFullyQualifiedMethodName (String  factoryMethodName ) {
@@ -89,6 +96,18 @@ private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodNa
8996		return  true ;
9097	}
9198
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+ 
92111	private  Method  getFactoryMethodByFullyQualifiedName (String  fullyQualifiedMethodName ) {
93112		String [] methodParts  = ReflectionUtils .parseFullyQualifiedMethodName (fullyQualifiedMethodName );
94113		String  className  = methodParts [0 ];
@@ -100,33 +119,17 @@ private Method getFactoryMethodByFullyQualifiedName(String fullyQualifiedMethodN
100119				methodParameters , className )));
101120	}
102121
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- 
122122	/** 
123123	 * Find all methods in the given {@code testClass} with the desired {@code factoryMethodName} 
124124	 * which have return types that can be converted to a {@link Stream}, ignoring the 
125125	 * {@code testMethod} itself as well as any {@code @Test}, {@code @TestTemplate}, 
126126	 * 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 
127131	 */ 
128- 	private  List <Method > findFactoryMethodsBySimpleName (Class <?> testClass , Method  testMethod ,
129- 			String  factoryMethodName ) {
132+ 	private  Method  findFactoryMethodBySimpleName (Class <?> testClass , Method  testMethod , String  factoryMethodName ) {
130133		Predicate <Method > isCandidate  = candidate  -> factoryMethodName .equals (candidate .getName ())
131134				&& !testMethod .equals (candidate );
132135		List <Method > candidates  = ReflectionUtils .findMethods (testClass , isCandidate );
@@ -147,27 +150,10 @@ private List<Method> findFactoryMethodsBySimpleName(Class<?> testClass, Method t
147150			// Otherwise, report that we didn't find anything. 
148151			return  format ("Could not find factory method [%s] in class [%s]" , factoryMethodName , testClass .getName ());
149152		});
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 );
171157	}
172158
173159	private  boolean  isTestMethod (Method  candidate ) {
0 commit comments