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
A testing framework for the JVM
package org.testng.internal;
import java.lang.reflect.Method;
import java.util.ArrayList;
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 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.Graph.Node;
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
* @param finder annotation finder
* @param unique true for unique methods, false otherwise
* @param outExcludedMethods
* @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[methods.size()]),
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[methods.size()]);
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[vResult.size()]);
}
/**
* 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.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<>(new Comparator>() {
@Override
public int compare(Node o1, Node o2) {
return comparator.compare(o1.getObject(), o2.getObject());
}
});
if (methods.length == 0) {
return result;
}
//
// Create the graph
//
Map