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 
findTest(IAnnotationFinder finder, Class<?> cls)31   public static ITestAnnotation findTest(IAnnotationFinder finder, Class<?> cls) {
32     return finder.findAnnotation(cls, ITestAnnotation.class);
33   }
34 
findTest(IAnnotationFinder finder, Method m)35   public static ITestAnnotation findTest(IAnnotationFinder finder, Method m) {
36     return finder.findAnnotation(m, ITestAnnotation.class);
37   }
38 
findTest(IAnnotationFinder finder, ITestNGMethod m)39   public static ITestAnnotation findTest(IAnnotationFinder finder, ITestNGMethod m) {
40     return finder.findAnnotation(m, ITestAnnotation.class);
41   }
42 
findFactory(IAnnotationFinder finder, Method m)43   public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Method m) {
44     return finder.findAnnotation(m, IFactoryAnnotation.class);
45   }
46 
findFactory(IAnnotationFinder finder, Constructor c)47   public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Constructor c) {
48     return finder.findAnnotation(c, IFactoryAnnotation.class);
49   }
50 
findTest(IAnnotationFinder finder, Constructor ctor)51   public static ITestAnnotation findTest(IAnnotationFinder finder, Constructor ctor) {
52     return finder.findAnnotation(ctor, ITestAnnotation.class);
53   }
54 
findConfiguration(IAnnotationFinder finder, Constructor ctor)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 
findConfiguration(IAnnotationFinder finder, Method m)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 
createConfiguration(IConfigurationAnnotation bs, IConfigurationAnnotation as, IConfigurationAnnotation bt, IConfigurationAnnotation at, IConfigurationAnnotation bg, IConfigurationAnnotation ag, IConfigurationAnnotation bc, IConfigurationAnnotation ac, IConfigurationAnnotation bm, IConfigurationAnnotation am)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"})
finishInitialize(ConfigurationAnnotation result, IConfigurationAnnotation bs)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 
getAllAnnotations()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    */
findMethodsWithAnnotation(Class<?> rootClass, Class<? extends IAnnotation> annotationClass, IAnnotationFinder annotationFinder, XmlTest xmlTest)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 
findAnnotationSuperClasses(Class<?> annotationClass, Class c)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 
isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class[] annotationClasses)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 
isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class<? extends IAnnotation> annotationClass)298   private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m,
299       Class<? extends IAnnotation> annotationClass) {
300     return annotationFinder.findAnnotation(m, annotationClass) != null;
301   }
302 
isAnnotationPresent(IAnnotationFinder annotationFinder, Class<?> cls, Class<? extends IAnnotation> annotationClass)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    */
createMethodKey(Method m)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