org.testng.internal.annotations.AnnotationHelper 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.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.testng.ITestNGMethod;
import org.testng.ITestObjectFactory;
import org.testng.annotations.IAnnotation;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.IDataProviderAnnotation;
import org.testng.annotations.IFactoryAnnotation;
import org.testng.annotations.IParametersAnnotation;
import org.testng.annotations.ITestAnnotation;
import org.testng.collections.Maps;
import org.testng.internal.ConstructorOrMethod;
import org.testng.internal.TestNGMethod;
import org.testng.internal.Utils;
import org.testng.internal.reflect.ReflectionHelper;
import org.testng.log4testng.Logger;
import org.testng.xml.XmlTest;
/**
* Helper methods to find @Test and @Configuration tags. They minimize the amount of casting we need
* to do.
*/
public class AnnotationHelper {
private static final Logger LOGGER = Logger.getLogger(AnnotationHelper.class);
private static final String SUFFIX =
"Please check if all classes being referred to, in the annotation are available in the classpath.";
private static final List> ALL_ANNOTATIONS =
Arrays.asList(
ITestAnnotation.class,
IBeforeClass.class,
IAfterClass.class,
IBeforeMethod.class,
IAfterMethod.class,
IDataProviderAnnotation.class,
IFactoryAnnotation.class,
IParametersAnnotation.class,
IBeforeSuite.class,
IAfterSuite.class,
IBeforeTest.class,
IAfterTest.class,
IBeforeGroups.class,
IAfterGroups.class);
private static final List> CONFIGURATION_CLASSES =
Arrays.asList(
IBeforeSuite.class, IAfterSuite.class,
IBeforeTest.class, IAfterTest.class,
IBeforeGroups.class, IAfterGroups.class,
IBeforeClass.class, IAfterClass.class,
IBeforeMethod.class, IAfterMethod.class);
private AnnotationHelper() {
// Utility class.defeat instantiation.
}
public static ITestAnnotation findTest(IAnnotationFinder finder, Class cls) {
return finder.findAnnotation(cls, ITestAnnotation.class);
}
public static ITestAnnotation findTest(IAnnotationFinder finder, Method m) {
return finder.findAnnotation(m, ITestAnnotation.class);
}
public static ITestAnnotation findTest(IAnnotationFinder finder, ITestNGMethod m) {
return finder.findAnnotation(m, ITestAnnotation.class);
}
public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Method m) {
return finder.findAnnotation(m, IFactoryAnnotation.class);
}
public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Constructor c) {
return finder.findAnnotation(c, IFactoryAnnotation.class);
}
public static IConfigurationAnnotation findConfiguration(
IAnnotationFinder finder, ConstructorOrMethod m) {
IConfigurationAnnotation result = null;
IConfigurationAnnotation bs =
(IConfigurationAnnotation) finder.findAnnotation(m, IBeforeSuite.class);
IConfigurationAnnotation as =
(IConfigurationAnnotation) finder.findAnnotation(m, IAfterSuite.class);
IConfigurationAnnotation bt =
(IConfigurationAnnotation) finder.findAnnotation(m, IBeforeTest.class);
IConfigurationAnnotation at =
(IConfigurationAnnotation) finder.findAnnotation(m, IAfterTest.class);
IConfigurationAnnotation bg =
(IConfigurationAnnotation) finder.findAnnotation(m, IBeforeGroups.class);
IConfigurationAnnotation ag =
(IConfigurationAnnotation) finder.findAnnotation(m, IAfterGroups.class);
IConfigurationAnnotation bc =
(IConfigurationAnnotation) finder.findAnnotation(m, IBeforeClass.class);
IConfigurationAnnotation ac =
(IConfigurationAnnotation) finder.findAnnotation(m, IAfterClass.class);
IConfigurationAnnotation bm =
(IConfigurationAnnotation) finder.findAnnotation(m, IBeforeMethod.class);
IConfigurationAnnotation am =
(IConfigurationAnnotation) finder.findAnnotation(m, IAfterMethod.class);
if (bs != null
|| as != null
|| bt != null
|| at != null
|| bg != null
|| ag != null
|| bc != null
|| ac != null
|| bm != null
|| am != null) {
result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am);
}
return result;
}
public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Method m) {
return findConfiguration(finder, new ConstructorOrMethod(m));
}
private static IConfigurationAnnotation createConfiguration(
IConfigurationAnnotation bs,
IConfigurationAnnotation as,
IConfigurationAnnotation bt,
IConfigurationAnnotation at,
IConfigurationAnnotation bg,
IConfigurationAnnotation ag,
IConfigurationAnnotation bc,
IConfigurationAnnotation ac,
IConfigurationAnnotation bm,
IConfigurationAnnotation am) {
ConfigurationAnnotation result = new ConfigurationAnnotation();
if (bs != null) {
result.setBeforeSuite(true);
finishInitialize(result, bs);
}
if (as != null) {
result.setAfterSuite(true);
finishInitialize(result, as);
}
if (bt != null) {
result.setBeforeTest(true);
finishInitialize(result, bt);
}
if (at != null) {
result.setAfterTest(true);
finishInitialize(result, at);
}
if (bg != null) {
result.setBeforeGroups(bg.getBeforeGroups());
finishInitialize(result, bg);
}
if (ag != null) {
result.setAfterGroups(ag.getAfterGroups());
finishInitialize(result, ag);
}
if (bc != null) {
result.setBeforeTestClass(true);
finishInitialize(result, bc);
}
if (ac != null) {
result.setAfterTestClass(true);
finishInitialize(result, ac);
}
if (bm != null) {
result.setBeforeTestMethod(true);
finishInitialize(result, bm);
}
if (am != null) {
result.setAfterTestMethod(true);
finishInitialize(result, am);
}
return result;
}
private static void finishInitialize(
ConfigurationAnnotation result, IConfigurationAnnotation bs) {
result.setIsBeforeGroups(bs.isBeforeGroups());
result.setIsAfterGroups(bs.isAfterGroups());
result.setFakeConfiguration(true);
result.setAlwaysRun(bs.getAlwaysRun());
result.setDependsOnGroups(bs.getDependsOnGroups());
result.setDependsOnMethods(bs.getDependsOnMethods());
result.setDescription(bs.getDescription());
result.setEnabled(bs.getEnabled());
result.setGroups(bs.getGroups());
result.setInheritGroups(bs.getInheritGroups());
result.setTimeOut(bs.getTimeOut());
}
public static List> getAllAnnotations() {
return ALL_ANNOTATIONS;
}
/* Delegation method for creating the list of ITestMethod
s to be analysed. */
public static ITestNGMethod[] findMethodsWithAnnotation(
ITestObjectFactory objectFactory,
Class rootClass,
Class annotationClass,
IAnnotationFinder annotationFinder,
XmlTest xmlTest) {
// Keep a map of the methods we saw so that we ignore a method in a superclass if it's
// already been seen in a child class
Map vResult = Maps.newHashMap();
try {
vResult = Maps.newHashMap();
// Class[] classes = rootClass.getTestClasses();
Class cls = rootClass;
Predicate> condition =
c -> {
if (c == null) {
return false;
}
return !Object.class.equals(c);
};
while (condition.test(cls)) {
boolean hasClassAnnotation = isAnnotationPresent(annotationFinder, cls, annotationClass);
Method[] methods = ReflectionHelper.getLocalMethods(cls);
for (Method m : methods) {
boolean hasMethodAnnotation = isAnnotationPresent(annotationFinder, m, annotationClass);
boolean hasTestNGAnnotation =
isAnnotationPresent(annotationFinder, m, IFactoryAnnotation.class)
|| isAnnotationPresent(annotationFinder, m, ITestAnnotation.class)
|| isAnnotationPresent(annotationFinder, m);
boolean isPublic = Modifier.isPublic(m.getModifiers());
boolean isSynthetic = m.isSynthetic();
if ((isPublic && hasClassAnnotation && !isSynthetic && (!hasTestNGAnnotation))
|| hasMethodAnnotation) {
// Small hack to allow users to specify @Configuration classes even though
// a class-level @Test annotation is present. In this case, don't count
// that method as a @Test
if (isAnnotationPresent(annotationFinder, m, IConfigurationAnnotation.class)
&& isAnnotationPresent(annotationFinder, cls, ITestAnnotation.class)) {
Utils.log(
"",
3,
"Method "
+ m
+ " has a configuration annotation"
+ " and a class-level @Test. This method will only be kept as a"
+ " configuration method.");
continue;
}
// Skip the method if it has a return type
if (m.getReturnType() != void.class && !xmlTest.getAllowReturnValues()) {
Utils.log(
"",
2,
"Method "
+ m
+ " has a @Test annotation"
+ " but also a return value:"
+ " ignoring it. Use to fix this");
continue;
}
if (Arrays.stream(m.getAnnotations())
.anyMatch(a -> a.annotationType().getName().equals("groovy.transform.Internal"))) {
Utils.log(
"", 2, "Method " + m + " is being skipped since it a Groovy internal method.");
continue;
}
String key = createMethodKey(m);
vResult.computeIfAbsent(
key, k -> new TestNGMethod(objectFactory, m, annotationFinder, xmlTest, null));
}
} // for
// Now explore the superclass
cls = cls.getSuperclass();
} // while
} catch (SecurityException e) {
LOGGER.error(e.getMessage(), e);
}
return vResult.values().toArray(new ITestNGMethod[0]);
}
public static A findAnnotationSuperClasses(
Class annotationClass, Class parameterClass) {
Class c = parameterClass;
while (c != null) {
A result = c.getAnnotation(annotationClass);
if (result != null) {
return result;
} else {
c = c.getSuperclass();
}
}
return null;
}
private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m) {
for (Class a : AnnotationHelper.CONFIGURATION_CLASSES) {
if (annotationFinder.findAnnotation(m, a) != null) {
return true;
}
}
return false;
}
private static boolean isAnnotationPresent(
IAnnotationFinder annotationFinder, Method m, Class annotationClass) {
if (!annotationClass.equals(IConfigurationAnnotation.class)) {
return annotationFinder.findAnnotation(m, annotationClass) != null;
}
boolean found = false;
for (Class clazz : CONFIGURATION_CLASSES) {
if (annotationFinder.findAnnotation(m, clazz) != null) {
found = true;
break;
}
}
return found;
}
private static boolean isAnnotationPresent(
IAnnotationFinder annotationFinder,
Class cls,
Class annotationClass) {
return annotationFinder.findAnnotation(cls, annotationClass) != null;
}
/**
* @return A hashcode representing the name of this method and its parameters, but without its
* class
*/
private static String createMethodKey(Method m) {
StringBuilder result = new StringBuilder(m.getName());
for (Class paramClass : m.getParameterTypes()) {
result.append(' ').append(paramClass.toString());
}
return result.toString();
}
static A getAnnotationFromClass(Class clazz, Class a) {
Objects.requireNonNull(clazz, "Cannot retrieve annotations from a null class.");
Objects.requireNonNull(a, "Cannot work with a null annotation");
try {
return clazz.getAnnotation(a);
} catch (Throwable t) {
String msg =
"Encountered problems when parsing the annotation on class "
+ clazz.getCanonicalName()
+ ". ";
msg += SUFFIX;
throw new TypeNotPresentException(msg, t);
}
}
static A getAnnotationFromMethod(Method method, Class a) {
Objects.requireNonNull(method, "Cannot retrieve annotations from a null method.");
Objects.requireNonNull(a, "Cannot work with a null annotation");
try {
return method.getAnnotation(a);
} catch (Throwable t) {
String mname = method.getDeclaringClass().getCanonicalName() + "." + method.getName();
String msg = "Encountered problems when parsing the annotation on method " + mname + "(). ";
msg += SUFFIX;
throw new TypeNotPresentException(msg, t);
}
}
static A getAnnotationFromConstructor(Constructor c, Class a) {
Objects.requireNonNull(c, "Cannot retrieve annotations from a null constructor.");
Objects.requireNonNull(a, "Cannot work with a null annotation");
try {
return c.getAnnotation(a);
} catch (Throwable t) {
String msg =
"Encountered problems when parsing the annotation on constructor " + c.getName() + ". ";
msg += SUFFIX;
throw new TypeNotPresentException(msg, t);
}
}
}