Home | History | Annotate | Download | only in annotations
      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