1 package org.testng.internal.annotations; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Modifier; 7 import java.util.Map; 8 9 import org.testng.ITestNGMethod; 10 import org.testng.annotations.IAnnotation; 11 import org.testng.annotations.IConfigurationAnnotation; 12 import org.testng.annotations.IDataProviderAnnotation; 13 import org.testng.annotations.IExpectedExceptionsAnnotation; 14 import org.testng.annotations.IFactoryAnnotation; 15 import org.testng.annotations.IParametersAnnotation; 16 import org.testng.annotations.ITestAnnotation; 17 import org.testng.collections.Maps; 18 import org.testng.internal.TestNGMethod; 19 import org.testng.internal.Utils; 20 import org.testng.xml.XmlTest; 21 22 /** 23 * Helper methods to find @Test and @Configuration tags. They minimize 24 * the amount of casting we need to do. 25 * 26 * Created on Dec 20, 2005 27 * @author cbeust 28 */ 29 public class AnnotationHelper { 30 31 public static ITestAnnotation findTest(IAnnotationFinder finder, Class<?> cls) { 32 return finder.findAnnotation(cls, ITestAnnotation.class); 33 } 34 35 public static ITestAnnotation findTest(IAnnotationFinder finder, Method m) { 36 return finder.findAnnotation(m, ITestAnnotation.class); 37 } 38 39 public static ITestAnnotation findTest(IAnnotationFinder finder, ITestNGMethod m) { 40 return finder.findAnnotation(m, ITestAnnotation.class); 41 } 42 43 public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Method m) { 44 return finder.findAnnotation(m, IFactoryAnnotation.class); 45 } 46 47 public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Constructor c) { 48 return finder.findAnnotation(c, IFactoryAnnotation.class); 49 } 50 51 public static ITestAnnotation findTest(IAnnotationFinder finder, Constructor ctor) { 52 return finder.findAnnotation(ctor, ITestAnnotation.class); 53 } 54 55 public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Constructor ctor) { 56 IConfigurationAnnotation result = finder.findAnnotation(ctor, IConfigurationAnnotation.class); 57 if (result == null) { 58 IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeSuite.class); 59 IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterSuite.class); 60 IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeTest.class); 61 IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterTest.class); 62 IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeGroups.class); 63 IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterGroups.class); 64 IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeClass.class); 65 IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterClass.class); 66 IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeMethod.class); 67 IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterMethod.class); 68 69 if (bs != null || as != null || bt != null || at != null || bg != null || ag != null 70 || bc != null || ac != null || bm != null || am != null) 71 { 72 result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); 73 } 74 } 75 76 return result; 77 } 78 79 public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Method m) { 80 IConfigurationAnnotation result = finder.findAnnotation(m, IConfigurationAnnotation.class); 81 if (result == null) { 82 IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeSuite.class); 83 IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterSuite.class); 84 IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeTest.class); 85 IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterTest.class); 86 IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeGroups.class); 87 IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterGroups.class); 88 IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeClass.class); 89 IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterClass.class); 90 IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeMethod.class); 91 IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterMethod.class); 92 93 if (bs != null || as != null || bt != null || at != null || bg != null || ag != null 94 || bc != null || ac != null || bm != null || am != null) 95 { 96 result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); 97 } 98 } 99 100 return result; 101 } 102 103 private static IConfigurationAnnotation createConfiguration(IConfigurationAnnotation bs, IConfigurationAnnotation as, 104 IConfigurationAnnotation bt, IConfigurationAnnotation at, IConfigurationAnnotation bg, IConfigurationAnnotation ag, 105 IConfigurationAnnotation bc, IConfigurationAnnotation ac, IConfigurationAnnotation bm, IConfigurationAnnotation am) 106 { 107 ConfigurationAnnotation result = new ConfigurationAnnotation(); 108 109 if (bs != null) { 110 result.setBeforeSuite(true); 111 finishInitialize(result, bs); 112 } 113 if (as != null) { 114 result.setAfterSuite(true); 115 finishInitialize(result, as); 116 } 117 if (bt != null) { 118 result.setBeforeTest(true); 119 finishInitialize(result, bt); 120 } 121 if (at != null) { 122 result.setAfterTest(true); 123 finishInitialize(result, at); 124 } 125 if (bg != null) { 126 result.setBeforeGroups(bg.getBeforeGroups()); 127 finishInitialize(result, bg); 128 } 129 if (ag != null) { 130 result.setAfterGroups(ag.getAfterGroups()); 131 finishInitialize(result, ag); 132 } 133 if (bc != null) { 134 result.setBeforeTestClass(true); 135 finishInitialize(result, bc); 136 } 137 if (ac != null) { 138 result.setAfterTestClass(true); 139 finishInitialize(result, ac); 140 } 141 if (bm != null) { 142 result.setBeforeTestMethod(true); 143 finishInitialize(result, bm); 144 } 145 if (am != null) { 146 result.setAfterTestMethod(true); 147 finishInitialize(result, am); 148 } 149 150 return result; 151 } 152 153 @SuppressWarnings({"deprecation"}) 154 private static void finishInitialize(ConfigurationAnnotation result, IConfigurationAnnotation bs) { 155 result.setFakeConfiguration(true); 156 result.setAlwaysRun(bs.getAlwaysRun()); 157 result.setDependsOnGroups(bs.getDependsOnGroups()); 158 result.setDependsOnMethods(bs.getDependsOnMethods()); 159 result.setDescription(bs.getDescription()); 160 result.setEnabled(bs.getEnabled()); 161 result.setGroups(bs.getGroups()); 162 result.setInheritGroups(bs.getInheritGroups()); 163 result.setParameters(bs.getParameters()); 164 result.setTimeOut(bs.getTimeOut()); 165 } 166 167 private static final Class[] ALL_ANNOTATIONS = new Class[] { 168 ITestAnnotation.class, IConfigurationAnnotation.class, 169 IBeforeClass.class, IAfterClass.class, 170 IBeforeMethod.class, IAfterMethod.class, 171 IDataProviderAnnotation.class, IExpectedExceptionsAnnotation.class, 172 IFactoryAnnotation.class, IParametersAnnotation.class, 173 IBeforeSuite.class, IAfterSuite.class, 174 IBeforeTest.class, IAfterTest.class, 175 IBeforeGroups.class, IAfterGroups.class 176 }; 177 178 public static final Class[] CONFIGURATION_CLASSES = new Class[] { 179 IConfigurationAnnotation.class, 180 IBeforeSuite.class, IAfterSuite.class, 181 IBeforeTest.class, IAfterTest.class, 182 IBeforeGroups.class, IAfterGroups.class, 183 IBeforeClass.class, IAfterClass.class, 184 IBeforeMethod.class, IAfterMethod.class 185 }; 186 187 public static Class[] getAllAnnotations() { 188 return ALL_ANNOTATIONS; 189 } 190 191 /** 192 * Delegation method for creating the list of <CODE>ITestMethod</CODE>s to be 193 * analysed. 194 */ 195 public static ITestNGMethod[] findMethodsWithAnnotation(Class<?> rootClass, 196 Class<? extends IAnnotation> annotationClass, IAnnotationFinder annotationFinder, 197 XmlTest xmlTest) 198 { 199 // Keep a map of the methods we saw so that we ignore a method in a superclass if it's 200 // already been seen in a child class 201 Map<String, ITestNGMethod> vResult = Maps.newHashMap(); 202 203 try { 204 vResult = Maps.newHashMap(); 205 // Class[] classes = rootClass.getTestClasses(); 206 Class<?> cls = rootClass; 207 208 // 209 // If the annotation is on the class or superclass, it applies to all public methods 210 // except methods marked with @Configuration 211 // 212 213 // 214 // Otherwise walk through all the methods and keep those 215 // that have the annotation 216 // 217 // for (Class<?> cls : classes) { 218 while (null != cls) { 219 boolean hasClassAnnotation = isAnnotationPresent(annotationFinder, cls, annotationClass); 220 Method[] methods = cls.getDeclaredMethods(); 221 for (Method m : methods) { 222 boolean hasMethodAnnotation = isAnnotationPresent(annotationFinder, m, annotationClass); 223 boolean hasTestNGAnnotation = 224 isAnnotationPresent(annotationFinder, m, IFactoryAnnotation.class) || 225 isAnnotationPresent(annotationFinder, m, ITestAnnotation.class) || 226 isAnnotationPresent(annotationFinder, m, CONFIGURATION_CLASSES); 227 boolean isPublic = Modifier.isPublic(m.getModifiers()); 228 boolean isSynthetic = m.isSynthetic(); 229 if ((isPublic && hasClassAnnotation && !isSynthetic && (! hasTestNGAnnotation)) || hasMethodAnnotation) { 230 231 // Small hack to allow users to specify @Configuration classes even though 232 // a class-level @Test annotation is present. In this case, don't count 233 // that method as a @Test 234 if (isAnnotationPresent(annotationFinder, m, IConfigurationAnnotation.class) && 235 isAnnotationPresent(annotationFinder, cls, ITestAnnotation.class)) 236 { 237 Utils.log("", 3, "Method " + m + " has a configuration annotation" 238 + " and a class-level @Test. This method will only be kept as a" 239 + " configuration method."); 240 241 continue; 242 } 243 244 // Skip the method if it has a return type 245 if (m.getReturnType() != void.class && ! xmlTest.getAllowReturnValues()) { 246 Utils.log("", 2, "Method " + m + " has a @Test annotation" 247 + " but also a return value:" 248 + " ignoring it. Use <suite allow-return-values=\"true\"> to fix this"); 249 continue; 250 } 251 252 String key = createMethodKey(m); 253 if (null == vResult.get(key)) { 254 ITestNGMethod tm = new TestNGMethod(/* m.getDeclaringClass(), */ m, 255 annotationFinder, xmlTest, null); /* @@@ */ 256 vResult.put(key,tm); 257 } 258 } 259 } // for 260 // Now explore the superclass 261 cls = cls.getSuperclass(); 262 } // while 263 264 } 265 catch (SecurityException e) { 266 e.printStackTrace(); 267 } 268 ITestNGMethod[] result = vResult.values().toArray(new ITestNGMethod[vResult.size()]); 269 270 // for (Method m : result) { 271 // ppp(" METHOD FOUND: " + m); 272 // } 273 274 return result; 275 } 276 277 public static Annotation findAnnotationSuperClasses(Class<?> annotationClass, Class c) { 278 while (c != null) { 279 Annotation result = c.getAnnotation(annotationClass); 280 if (result != null) return result; 281 else c = c.getSuperclass(); 282 } 283 return null; 284 } 285 286 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, 287 Method m, Class[] annotationClasses) 288 { 289 for (Class a : annotationClasses) { 290 if (annotationFinder.findAnnotation(m, a) != null) { 291 return true; 292 } 293 } 294 295 return false; 296 } 297 298 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, 299 Class<? extends IAnnotation> annotationClass) { 300 return annotationFinder.findAnnotation(m, annotationClass) != null; 301 } 302 303 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Class<?> cls, 304 Class<? extends IAnnotation> annotationClass) { 305 return annotationFinder.findAnnotation(cls, annotationClass) != null; 306 } 307 308 /** 309 * @return A hashcode representing the name of this method and its parameters, 310 * but without its class 311 */ 312 private static String createMethodKey(Method m) { 313 StringBuffer result = new StringBuffer(m.getName()); 314 for (Class paramClass : m.getParameterTypes()) { 315 result.append(' ').append(paramClass.toString()); 316 } 317 318 return result.toString(); 319 } 320 321 } 322