org.testng.internal.XmlMethodSelector 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.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.testng.IMethodSelector;
import org.testng.IMethodSelectorContext;
import org.testng.ITestNGMethod;
import org.testng.TestNGException;
import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.internal.reflect.ReflectionHelper;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;
/**
* This class is the default method selector used by TestNG to determine
* which methods need to be included and excluded based on the specification
* given in testng.xml.
*
* Created on Sep 30, 2005
* @author cbeust
*/
public class XmlMethodSelector implements IMethodSelector {
private static final long serialVersionUID = -9030548178025605629L;
// Groups included and excluded for this run
private Map m_includedGroups = Maps.newHashMap();
private Map m_excludedGroups = Maps.newHashMap();
private List m_classes = null;
// The BeanShell expression for this test, if any
private String m_expression = null;
// List of methods included implicitly
private ListMultiMap m_includedMethods = Maps.newListMultiMap();
private IBsh m_bsh = Dynamic.hasBsh() ? new Bsh() : new BshMock();
@Override
public boolean includeMethod(IMethodSelectorContext context,
ITestNGMethod tm, boolean isTestMethod)
{
// ppp("XML METHOD SELECTOR " + tm + " " + m_isInitialized);
if (! m_isInitialized) {
m_isInitialized = true;
init(context);
}
boolean result = false;
if (null != m_expression) {
return m_bsh.includeMethodFromExpression(m_expression, tm);
}
else {
result = includeMethodFromIncludeExclude(tm, isTestMethod);
}
return result;
}
private boolean includeMethodFromIncludeExclude(ITestNGMethod tm, boolean isTestMethod) {
boolean result = false;
Method m = tm.getMethod();
String[] groups = tm.getGroups();
Map includedGroups = m_includedGroups;
Map excludedGroups = m_excludedGroups;
List includeList =
m_includedMethods.get(MethodHelper.calculateMethodCanonicalName(tm));
//
// No groups were specified:
//
if (includedGroups.size() == 0 && excludedGroups.size() == 0
&& ! hasIncludedMethods() && ! hasExcludedMethods())
//
// If we don't include or exclude any methods, method is in
//
{
result = true;
}
//
// If it's a configuration method and no groups were requested, we want it in
//
else if (includedGroups.size() == 0 && excludedGroups.size() == 0 && ! isTestMethod)
{
result = true;
}
//
// Is this method included implicitly?
//
else if (!includeList.isEmpty()) {
result = true;
}
//
// Include or Exclude groups were specified:
//
else {
//
// Only add this method if it belongs to an included group and not
// to an excluded group
//
{
boolean isIncludedInGroups = isIncluded(groups, m_includedGroups.values());
boolean isExcludedInGroups = isExcluded(groups, m_excludedGroups.values());
//
// Calculate the run methods by groups first
//
if (isIncludedInGroups && !isExcludedInGroups) {
result = true;
}
else if (isExcludedInGroups) {
result = false;
}
}
if(isTestMethod) {
//
// Now filter by method name
//
Method method = tm.getMethod();
Class methodClass = method.getDeclaringClass();
String fullMethodName = methodClass.getName()
+ "."
+ method.getName();
String[] fullyQualifiedMethodName = new String[] { fullMethodName };
//
// Iterate through all the classes so we can gather all the included and
// excluded methods
//
for (XmlClass xmlClass : m_classes) {
// Only consider included/excluded methods that belong to the same class
// we are looking at
Class cls = xmlClass.getSupportClass();
if(!assignable(methodClass, cls)) {
continue;
}
List includedMethods =
createQualifiedMethodNames(xmlClass, toStringList(xmlClass.getIncludedMethods()));
boolean isIncludedInMethods = isIncluded(fullyQualifiedMethodName, includedMethods);
List excludedMethods = createQualifiedMethodNames(xmlClass,
xmlClass.getExcludedMethods());
boolean isExcludedInMethods = isExcluded(fullyQualifiedMethodName, excludedMethods);
if (result) {
// If we're about to include this method by group, make sure
// it's included by method and not excluded by method
result = isIncludedInMethods && ! isExcludedInMethods;
}
// otherwise it's already excluded and nothing will bring it back,
// since exclusions preempt inclusions
}
}
}
Package pkg = m.getDeclaringClass().getPackage();
String methodName = pkg != null ? pkg.getName() + "." + m.getName() : m.getName();
logInclusion(result ? "Including" : "Excluding", "method", methodName + "()");
return result;
}
@SuppressWarnings({"unchecked"})
private boolean assignable(Class sourceClass, Class targetClass) {
return sourceClass.isAssignableFrom(targetClass) || targetClass.isAssignableFrom(sourceClass);
}
private Map m_logged = Maps.newHashMap();
private void logInclusion(String including, String type, String name) {
if (! m_logged.containsKey(name)) {
log(4, including + " " + type + " " + name);
m_logged.put(name, name);
}
}
private boolean hasIncludedMethods() {
for (XmlClass xmlClass : m_classes) {
if (xmlClass.getIncludedMethods().size() > 0) {
return true;
}
}
return false;
}
private boolean hasExcludedMethods() {
for (XmlClass xmlClass : m_classes) {
if (xmlClass.getExcludedMethods().size() > 0) {
return true;
}
}
return false;
}
private List toStringList(List methods) {
List result = Lists.newArrayList();
for (XmlInclude m : methods) {
result.add(m.getName());
}
return result;
}
private List createQualifiedMethodNames(XmlClass xmlClass,
List methods) {
List vResult = Lists.newArrayList();
Class cls = xmlClass.getSupportClass();
while (null != cls) {
for (String im : methods) {
String methodName = im;
Method[] allMethods = ReflectionHelper.getLocalMethods(cls);
Pattern pattern = Pattern.compile(methodName);
for (Method m : allMethods) {
if (pattern.matcher(m.getName()).matches()) {
vResult.add(makeMethodName(m.getDeclaringClass().getName(), m.getName()));
}
}
}
cls = cls.getSuperclass();
}
return vResult;
}
private String makeMethodName(String className, String methodName) {
return className + "." + methodName;
}
private void checkMethod(Class> c, String methodName) {
Pattern p = Pattern.compile(methodName);
for (Method m : c.getMethods()) {
if (p.matcher(m.getName()).matches()) {
return;
}
}
Utils.log("Warning", 2, "The regular expression \"" + methodName + "\" didn't match any" +
" method in class " + c.getName());
}
public void setXmlClasses(List classes) {
m_classes = classes;
for (XmlClass c : classes) {
for (XmlInclude m : c.getIncludedMethods()) {
checkMethod(c.getSupportClass(), m.getName());
String methodName = makeMethodName(c.getName(), m.getName());
m_includedMethods.put(methodName, m);
}
}
}
/**
* @return Returns the excludedGroups.
*/
public Map getExcludedGroups() {
return m_excludedGroups;
}
/**
* @return Returns the includedGroups.
*/
public Map getIncludedGroups() {
return m_includedGroups;
}
/**
* @param excludedGroups The excludedGroups to set.
*/
public void setExcludedGroups(Map excludedGroups) {
m_excludedGroups = excludedGroups;
}
/**
* @param includedGroups The includedGroups to set.
*/
public void setIncludedGroups(Map includedGroups) {
m_includedGroups = includedGroups;
}
private static boolean isIncluded(String[] groups, Collection includedGroups) {
if (includedGroups.size() == 0) {
return true;
}
else {
return isMemberOf(groups, includedGroups);
}
}
private static boolean isExcluded(String[] groups, Collection excludedGroups) {
return isMemberOf(groups, excludedGroups);
}
/**
*
* @param groups Array of groups on the method
* @param list Map of regexps of groups to be run
*/
private static boolean isMemberOf(String[] groups, Collection list) {
for (String group : groups) {
for (Object o : list) {
String regexpStr = o.toString();
boolean match = Pattern.matches(regexpStr, group);
if (match) {
return true;
}
}
}
return false;
}
private static void log(int level, String s) {
Utils.log("XmlMethodSelector", level, s);
}
private static void ppp(String s) {
System.out.println("[XmlMethodSelector] " + s);
}
public void setExpression(String expression) {
m_expression = expression;
}
private boolean m_isInitialized = false;
private List m_testMethods = null;
@Override
public void setTestMethods(List testMethods) {
// Caution: this variable is initialized with an empty list first and then modified
// externally by the caller (TestRunner#fixMethodWithClass). Ugly.
m_testMethods = testMethods;
}
private void init(IMethodSelectorContext context) {
String[] groups = m_includedGroups.keySet().toArray(new String[m_includedGroups.size()]);
Set groupClosure = new HashSet<>();
Set methodClosure = new HashSet<>();
List includedMethods = Lists.newArrayList();
for (ITestNGMethod m : m_testMethods) {
if (includeMethod(context, m, true)) {
includedMethods.add(m);
}
}
MethodGroupsHelper.findGroupTransitiveClosure(this, includedMethods, m_testMethods,
groups, groupClosure, methodClosure);
// If we are asked to include or exclude specific groups, calculate
// the transitive closure of all the included groups. If no include groups
// were specified, don't do anything.
// Any group that is part of the transitive closure but not part of
// m_includedGroups is being added implicitly by TestNG so that if someone
// includes a group z that depends on a, b and c, they don't need to
// include a, b and c explicitly.
if (m_includedGroups.size() > 0) {
// Make the transitive closure our new included groups
for (String g : groupClosure) {
log(4, "Including group "
+ (m_includedGroups.containsKey(g) ?
": " : "(implicitly): ") + g);
m_includedGroups.put(g, g);
}
// Make the transitive closure our new included methods
for (ITestNGMethod m : methodClosure) {
String methodName = m.getQualifiedName();
XmlInclude xi = new XmlInclude(methodName);
// TODO: set the XmlClass on this xi or we won't get inheritance of parameters
m_includedMethods.put(methodName, xi);
logInclusion("Including", "method ", methodName);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy