org.testng.internal.MethodHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testng Show documentation
Show all versions of testng Show documentation
Testing framework for Java
package org.testng.internal;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.testng.IInvokedMethod;
import org.testng.IMethodInstance;
import org.testng.ITestClass;
import org.testng.ITestNGMethod;
import org.testng.TestNGException;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.ITestAnnotation;
import org.testng.annotations.ITestOrConfiguration;
import org.testng.collections.Lists;
import org.testng.collections.Sets;
import org.testng.internal.annotations.AnnotationHelper;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.internal.collections.Pair;
/**
* Collection of helper methods to help sort and arrange methods.
*
* @author Cedric Beust
* @author Alexandru Popescu
*/
public class MethodHelper {
private static final Map> GRAPH_CACHE =
new ConcurrentHashMap<>();
private static final Map CANONICAL_NAME_CACHE = new ConcurrentHashMap<>();
private static final Map, Boolean> MATCH_CACHE = new ConcurrentHashMap<>();
/**
* Collects and orders test or configuration methods
*
* @param methods methods to be worked on
* @param forTests true for test methods, false for configuration methods
* @param runInfo - {@link RunInfo} object.
* @param finder annotation finder
* @param unique true for unique methods, false otherwise
* @param outExcludedMethods - A List of excluded {@link ITestNGMethod} methods.
* @return list of ordered methods
*/
public static ITestNGMethod[] collectAndOrderMethods(
List methods,
boolean forTests,
RunInfo runInfo,
IAnnotationFinder finder,
boolean unique,
List outExcludedMethods,
Comparator comparator) {
List includedMethods = Lists.newArrayList();
MethodGroupsHelper.collectMethodsByGroup(
methods.toArray(new ITestNGMethod[0]),
forTests,
includedMethods,
outExcludedMethods,
runInfo,
finder,
unique);
return sortMethods(forTests, includedMethods, comparator).toArray(new ITestNGMethod[] {});
}
/**
* Finds TestNG methods that the specified TestNG method depends upon
*
* @param m TestNG method
* @param methods list of methods to search for depended upon methods
* @return list of methods that match the criteria
*/
protected static ITestNGMethod[] findDependedUponMethods(
ITestNGMethod m, List methods) {
ITestNGMethod[] methodsArray = methods.toArray(new ITestNGMethod[0]);
return findDependedUponMethods(m, methodsArray);
}
/**
* Finds TestNG methods that the specified TestNG method depends upon
*
* @param m TestNG method
* @param methods list of methods to search for depended upon methods
* @return list of methods that match the criteria
*/
protected static ITestNGMethod[] findDependedUponMethods(
ITestNGMethod m, ITestNGMethod[] methods) {
String canonicalMethodName = calculateMethodCanonicalName(m);
List vResult = Lists.newArrayList();
String regexp = null;
for (String fullyQualifiedRegexp : m.getMethodsDependedUpon()) {
boolean foundAtLeastAMethod = false;
if (null != fullyQualifiedRegexp) {
// Escapes $ in regexps as it is not meant for end - line matching, but inner class matches.
regexp = fullyQualifiedRegexp.replace("$", "\\$");
MatchResults results = matchMethod(methods, regexp);
foundAtLeastAMethod = results.foundAtLeastAMethod;
vResult.addAll(results.matchedMethods);
if (!foundAtLeastAMethod) {
// Replace the declaring class name in the dependsOnMethods value with
// the fully qualified test class name and retry the method matching.
int lastIndex = regexp.lastIndexOf('.');
String newMethodName;
if (lastIndex != -1) {
newMethodName = m.getTestClass().getRealClass().getName() + regexp.substring(lastIndex);
results = matchMethod(methods, newMethodName);
foundAtLeastAMethod = results.foundAtLeastAMethod;
vResult.addAll(results.matchedMethods);
}
}
}
if (!foundAtLeastAMethod) {
if (m.ignoreMissingDependencies()) {
continue;
}
if (m.isAlwaysRun()) {
continue;
}
Method maybeReferringTo = findMethodByName(m, regexp);
if (maybeReferringTo != null) {
throw new TestNGException(
canonicalMethodName
+ "() is depending on method "
+ maybeReferringTo
+ ", which is not annotated with @Test or not included.");
}
throw new TestNGException(
canonicalMethodName + "() depends on nonexistent method " + regexp);
}
} // end for
return vResult.toArray(new ITestNGMethod[0]);
}
/**
* Finds method based on regex and TestNGMethod. If regex doesn't represent the class name, uses
* the TestNG method's class name.
*
* @param testngMethod TestNG method
* @param regExp regex representing a method and/or related class name
*/
private static Method findMethodByName(ITestNGMethod testngMethod, String regExp) {
if (regExp == null) {
return null;
}
int lastDot = regExp.lastIndexOf('.');
String className, methodName;
if (lastDot == -1) {
className = testngMethod.getConstructorOrMethod().getDeclaringClass().getCanonicalName();
methodName = regExp;
} else {
methodName = regExp.substring(lastDot + 1);
className = regExp.substring(0, lastDot);
}
try {
Class c = Class.forName(className);
for (Method m : c.getDeclaredMethods()) {
if (methodName.equals(m.getName())) {
return m;
}
}
} catch (Exception e) {
// only logging
Utils.log("MethodHelper", 3, "Caught exception while searching for methods using regex");
}
return null;
}
protected static boolean isEnabled(Class objectClass, IAnnotationFinder finder) {
ITestAnnotation testClassAnnotation = AnnotationHelper.findTest(finder, objectClass);
return isEnabled(testClassAnnotation);
}
protected static boolean isEnabled(Method m, IAnnotationFinder finder) {
ITestAnnotation annotation = AnnotationHelper.findTest(finder, m);
// If no method annotation, look for one on the class
if (null == annotation) {
annotation = AnnotationHelper.findTest(finder, m.getDeclaringClass());
}
return isEnabled(annotation);
}
protected static boolean isEnabled(ITestOrConfiguration test) {
return null == test || test.getEnabled();
}
static boolean isDisabled(ITestOrConfiguration test) {
return !isEnabled(test);
}
static boolean isAlwaysRun(IConfigurationAnnotation configurationAnnotation) {
if (null == configurationAnnotation) {
return false;
}
boolean alwaysRun = false;
if ((configurationAnnotation.getAfterSuite()
|| configurationAnnotation.getAfterTest()
|| configurationAnnotation.getAfterTestClass()
|| configurationAnnotation.getAfterTestMethod()
|| configurationAnnotation.getBeforeTestMethod()
|| configurationAnnotation.getBeforeTestClass()
|| configurationAnnotation.getBeforeTest()
|| configurationAnnotation.getBeforeSuite()
|| configurationAnnotation.getBeforeGroups().length != 0
|| configurationAnnotation.getAfterGroups().length != 0)
&& configurationAnnotation.getAlwaysRun()) {
alwaysRun = true;
}
return alwaysRun;
}
/** Extracts the unique list of ITestNGMethod
s. */
public static List uniqueMethodList(Collection> methods) {
Set resultSet = Sets.newHashSet();
for (List l : methods) {
resultSet.addAll(l);
}
return Lists.newArrayList(resultSet);
}
private static Graph topologicalSort(
ITestNGMethod[] methods,
List sequentialList,
List parallelList,
final Comparator comparator) {
Graph result =
new Graph<>((o1, o2) -> comparator.compare(o1.getObject(), o2.getObject()));
if (methods.length == 0) {
return result;
}
//
// Create the graph
//
Map