1package org.testng.internal.annotations;
2
3import java.lang.annotation.Annotation;
4import java.lang.reflect.Method;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
9import org.testng.IAnnotationTransformer;
10import org.testng.TestNGException;
11import org.testng.annotations.AfterClass;
12import org.testng.annotations.AfterGroups;
13import org.testng.annotations.AfterMethod;
14import org.testng.annotations.AfterSuite;
15import org.testng.annotations.AfterTest;
16import org.testng.annotations.BeforeClass;
17import org.testng.annotations.BeforeGroups;
18import org.testng.annotations.BeforeMethod;
19import org.testng.annotations.BeforeSuite;
20import org.testng.annotations.BeforeTest;
21import org.testng.annotations.Configuration;
22import org.testng.annotations.DataProvider;
23import org.testng.annotations.ExpectedExceptions;
24import org.testng.annotations.Factory;
25import org.testng.annotations.IAnnotation;
26import org.testng.annotations.IConfigurationAnnotation;
27import org.testng.annotations.IDataProviderAnnotation;
28import org.testng.annotations.IExpectedExceptionsAnnotation;
29import org.testng.annotations.IFactoryAnnotation;
30import org.testng.annotations.IListenersAnnotation;
31import org.testng.annotations.IObjectFactoryAnnotation;
32import org.testng.annotations.IParametersAnnotation;
33import org.testng.annotations.ITestAnnotation;
34import org.testng.annotations.Listeners;
35import org.testng.annotations.Parameters;
36import org.testng.annotations.Test;
37import org.testng.collections.Lists;
38import org.testng.internal.Utils;
39
40/**
41 * This class creates implementations of IAnnotations based on the JDK5
42 * annotation that was found on the Java element.
43 *
44 * Created on Dec 20, 2005
45 * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
46 */
47public class JDK15TagFactory {
48
49  public <A extends IAnnotation> A createTag(Class<?> cls, Annotation a,
50                                             Class<A> annotationClass, IAnnotationTransformer transformer) {
51    IAnnotation result = null;
52
53    if (a != null) {
54      if (annotationClass == IConfigurationAnnotation.class) {
55        result = createConfigurationTag(cls, a);
56      }
57      else if (annotationClass == IDataProviderAnnotation.class) {
58        result = createDataProviderTag(a);
59      }
60      else if (annotationClass == IExpectedExceptionsAnnotation.class) {
61        result = createExpectedExceptionsTag(a);
62      }
63      else if (annotationClass == IFactoryAnnotation.class) {
64        result = createFactoryTag(cls, a);
65      }
66      else if (annotationClass == IParametersAnnotation.class) {
67        result = createParametersTag(a);
68      }
69      else if (annotationClass == IObjectFactoryAnnotation.class) {
70        result = createObjectFactoryTag(a);
71      }
72      else if (annotationClass == ITestAnnotation.class) {
73        result = createTestTag(cls, a, transformer);
74      }
75      else if (annotationClass == IListenersAnnotation.class) {
76        result = createListenersTag(cls, a, transformer);
77      }
78      else if (annotationClass == IBeforeSuite.class || annotationClass == IAfterSuite.class ||
79          annotationClass == IBeforeTest.class || annotationClass == IAfterTest.class ||
80          annotationClass == IBeforeGroups.class || annotationClass == IAfterGroups.class ||
81          annotationClass == IBeforeClass.class || annotationClass == IAfterClass.class ||
82          annotationClass == IBeforeMethod.class || annotationClass == IAfterMethod.class)
83      {
84        result = maybeCreateNewConfigurationTag(cls, a, annotationClass);
85      }
86
87      else {
88        throw new TestNGException("Unknown annotation requested:" + annotationClass);
89      }
90    }
91
92    //noinspection unchecked
93    return (A) result;
94  }
95
96  private IAnnotation maybeCreateNewConfigurationTag(Class<?> cls, Annotation a,
97      Class<?> annotationClass)
98  {
99    IAnnotation result = null;
100
101    if (annotationClass == IBeforeSuite.class) {
102      BeforeSuite bs = (BeforeSuite) a;
103      result = createConfigurationTag(cls, a,
104          true, false,
105          false, false,
106          new String[0], new String[0],
107          false, false,
108          false, false,
109          bs.alwaysRun(),
110          bs.dependsOnGroups(), bs.dependsOnMethods(),
111          bs.description(), bs.enabled(), bs.groups(),
112          bs.inheritGroups(), null,
113          false, false,
114          bs.timeOut());
115    }
116    else if (annotationClass == IAfterSuite.class) {
117      AfterSuite bs = (AfterSuite) a;
118      result = createConfigurationTag(cls, a,
119          false, true,
120          false, false,
121          new String[0], new String[0],
122          false, false,
123          false, false,
124          bs.alwaysRun(),
125          bs.dependsOnGroups(), bs.dependsOnMethods(),
126          bs.description(), bs.enabled(), bs.groups(),
127          bs.inheritGroups(), null,
128          false, false,
129          bs.timeOut());
130    }
131    else if (annotationClass == IBeforeTest.class) {
132      BeforeTest bs = (BeforeTest) a;
133      result = createConfigurationTag(cls, a,
134          false, false,
135          true, false,
136          new String[0], new String[0],
137          false, false,
138          false, false,
139          bs.alwaysRun(),
140          bs.dependsOnGroups(), bs.dependsOnMethods(),
141          bs.description(), bs.enabled(), bs.groups(),
142          bs.inheritGroups(), null,
143          false, false,
144          bs.timeOut());
145    }
146    else if (annotationClass == IAfterTest.class) {
147      AfterTest bs = (AfterTest) a;
148      result = createConfigurationTag(cls, a,
149          false, false,
150          false, true,
151          new String[0], new String[0],
152          false, false,
153          false, false,
154          bs.alwaysRun(),
155          bs.dependsOnGroups(), bs.dependsOnMethods(),
156          bs.description(), bs.enabled(), bs.groups(),
157          bs.inheritGroups(), null,
158          false, false,
159          bs.timeOut());
160    }
161    else if (annotationClass == IBeforeGroups.class) {
162      BeforeGroups bs = (BeforeGroups) a;
163      final String[] groups= bs.value().length > 0 ? bs.value() : bs.groups();
164      result = createConfigurationTag(cls, a,
165          false, false,
166          false, false,
167          groups, new String[0],
168          false, false,
169          false, false,
170          bs.alwaysRun(),
171          bs.dependsOnGroups(), bs.dependsOnMethods(),
172          bs.description(), bs.enabled(), bs.groups(),
173          bs.inheritGroups(), null,
174          false, false,
175          bs.timeOut());
176    }
177    else if (annotationClass == IAfterGroups.class) {
178      AfterGroups bs = (AfterGroups) a;
179      final String[] groups= bs.value().length > 0 ? bs.value() : bs.groups();
180      result = createConfigurationTag(cls, a,
181          false, false,
182          false, false,
183          new String[0], groups,
184          false, false,
185          false, false,
186          bs.alwaysRun(),
187          bs.dependsOnGroups(), bs.dependsOnMethods(),
188          bs.description(), bs.enabled(), bs.groups(),
189          bs.inheritGroups(), null,
190          false, false,
191          bs.timeOut());
192    }
193    else if (annotationClass == IBeforeClass.class) {
194      BeforeClass bs = (BeforeClass) a;
195      result = createConfigurationTag(cls, a,
196          false, false,
197          false, false,
198          new String[0], new String[0],
199          true, false,
200          false, false,
201          bs.alwaysRun(),
202          bs.dependsOnGroups(), bs.dependsOnMethods(),
203          bs.description(), bs.enabled(), bs.groups(),
204          bs.inheritGroups(), null,
205          false, false,
206          bs.timeOut());
207    }
208    else if (annotationClass == IAfterClass.class) {
209      AfterClass bs = (AfterClass) a;
210      result = createConfigurationTag(cls, a,
211          false, false,
212          false, false,
213          new String[0], new String[0],
214          false, true,
215          false, false,
216          bs.alwaysRun(),
217          bs.dependsOnGroups(), bs.dependsOnMethods(),
218          bs.description(), bs.enabled(), bs.groups(),
219          bs.inheritGroups(), null,
220          false, false,
221          bs.timeOut());
222    }
223    else if (annotationClass == IBeforeMethod.class) {
224      BeforeMethod bs = (BeforeMethod) a;
225      result = createConfigurationTag(cls, a,
226          false, false,
227          false, false,
228          new String[0], new String[0],
229          false, false,
230          true, false,
231          bs.alwaysRun(),
232          bs.dependsOnGroups(), bs.dependsOnMethods(),
233          bs.description(), bs.enabled(), bs.groups(),
234          bs.inheritGroups(), null,
235          bs.firstTimeOnly(), false,
236          bs.timeOut());
237    }
238    else if (annotationClass == IAfterMethod.class) {
239      AfterMethod bs = (AfterMethod) a;
240      result = createConfigurationTag(cls, a,
241          false, false,
242          false, false,
243          new String[0], new String[0],
244          false, false,
245          false, true,
246          bs.alwaysRun(),
247          bs.dependsOnGroups(), bs.dependsOnMethods(),
248          bs.description(), bs.enabled(), bs.groups(),
249          bs.inheritGroups(), null,
250          false, bs.lastTimeOnly(),
251          bs.timeOut());
252    }
253
254    return result;
255  }
256
257  @SuppressWarnings({"deprecation"})
258  private ConfigurationAnnotation createConfigurationTag(Class<?> cls, Annotation a) {
259    ConfigurationAnnotation result = new ConfigurationAnnotation();
260    Configuration c = (Configuration) a;
261    result.setBeforeTestClass(c.beforeTestClass());
262    result.setAfterTestClass(c.afterTestClass());
263    result.setBeforeTestMethod(c.beforeTestMethod());
264    result.setAfterTestMethod(c.afterTestMethod());
265    result.setBeforeTest(c.beforeTest());
266    result.setAfterTest(c.afterTest());
267    result.setBeforeSuite(c.beforeSuite());
268    result.setAfterSuite(c.afterSuite());
269    result.setBeforeGroups(c.beforeGroups());
270    result.setAfterGroups(c.afterGroups());
271    result.setParameters(c.parameters());
272    result.setEnabled(c.enabled());
273
274    result.setGroups(join(c.groups(), findInheritedStringArray(cls, Test.class, "groups")));
275    result.setDependsOnGroups(c.dependsOnGroups());
276    result.setDependsOnMethods(c.dependsOnMethods());
277    result.setAlwaysRun(c.alwaysRun());
278    result.setInheritGroups(c.inheritGroups());
279    result.setDescription(c.description());
280
281    return result;
282  }
283
284  private IAnnotation createConfigurationTag(Class<?> cls, Annotation a,
285      boolean beforeSuite, boolean afterSuite,
286      boolean beforeTest, boolean afterTest,
287      String[] beforeGroups, String[] afterGroups,
288      boolean beforeClass, boolean afterClass,
289      boolean beforeMethod, boolean afterMethod,
290      boolean alwaysRun,
291      String[] dependsOnGroups, String[] dependsOnMethods,
292      String description, boolean enabled, String[] groups,
293      boolean inheritGroups, String[] parameters,
294      boolean firstTimeOnly, boolean lastTimeOnly,
295      long timeOut)
296  {
297    ConfigurationAnnotation result = new ConfigurationAnnotation();
298    result.setFakeConfiguration(true);
299    result.setBeforeSuite(beforeSuite);
300    result.setAfterSuite(afterSuite);
301    result.setBeforeTest(beforeTest);
302    result.setAfterTest(afterTest);
303    result.setBeforeTestClass(beforeClass);
304    result.setAfterTestClass(afterClass);
305    result.setBeforeGroups(beforeGroups);
306    result.setAfterGroups(afterGroups);
307    result.setBeforeTestMethod(beforeMethod);
308    result.setAfterTestMethod(afterMethod);
309
310    result.setAlwaysRun(alwaysRun);
311    result.setDependsOnGroups(dependsOnGroups);
312    result.setDependsOnMethods(dependsOnMethods);
313    result.setDescription(description);
314    result.setEnabled(enabled);
315    result.setGroups(groups);
316    result.setInheritGroups(inheritGroups);
317    result.setParameters(parameters);
318    result.setFirstTimeOnly(firstTimeOnly);
319    result.setLastTimeOnly(lastTimeOnly);
320    result.setTimeOut(timeOut);
321
322    return result;
323  }
324
325  private IAnnotation createDataProviderTag(Annotation a) {
326    DataProviderAnnotation result = new DataProviderAnnotation();
327    DataProvider c = (DataProvider) a;
328    result.setName(c.name());
329    result.setParallel(c.parallel());
330
331    return result;
332  }
333
334  @SuppressWarnings({"deprecation"})
335  private IAnnotation createExpectedExceptionsTag(Annotation a) {
336    ExpectedExceptionsAnnotation result = new ExpectedExceptionsAnnotation ();
337    ExpectedExceptions c = (ExpectedExceptions ) a;
338    result.setValue(c.value());
339
340    return result;
341  }
342
343  @SuppressWarnings({"deprecation"})
344  private IAnnotation createFactoryTag(Class<?> cls, Annotation a) {
345    FactoryAnnotation result = new FactoryAnnotation();
346    Factory c = (Factory) a;
347    result.setParameters(c.parameters());
348    result.setDataProvider(c.dataProvider());
349    result.setDataProviderClass(
350        findInherited(c.dataProviderClass(), cls, Factory.class, "dataProviderClass",
351            DEFAULT_CLASS));
352    result.setEnabled(c.enabled());
353
354    return result;
355  }
356
357  private IAnnotation createObjectFactoryTag(Annotation a) {
358    return new ObjectFactoryAnnotation();
359  }
360
361  private IAnnotation createParametersTag(Annotation a) {
362    ParametersAnnotation result = new ParametersAnnotation();
363    Parameters c = (Parameters) a;
364    result.setValue(c.value());
365
366    return result;
367  }
368
369  @SuppressWarnings({"deprecation"})
370  private IAnnotation createListenersTag(Class<?> cls, Annotation a,
371      IAnnotationTransformer transformer)
372  {
373    ListenersAnnotation result = new ListenersAnnotation();
374    Listeners l = (Listeners) a;
375    result.setValue(l.value());
376
377    return result;
378  }
379
380  @SuppressWarnings({"deprecation"})
381  private IAnnotation createTestTag(Class<?> cls, Annotation a,
382      IAnnotationTransformer transformer)
383  {
384    TestAnnotation result = new TestAnnotation();
385    Test test = (Test) a;
386
387    result.setEnabled(test.enabled());
388    result.setGroups(join(test.groups(), findInheritedStringArray(cls, Test.class, "groups")));
389    result.setParameters(test.parameters());
390    result.setDependsOnGroups(join(test.dependsOnGroups(),
391        findInheritedStringArray(cls, Test.class, "dependsOnGroups")));
392    result.setDependsOnMethods(join(test.dependsOnMethods(),
393        findInheritedStringArray(cls, Test.class, "dependsOnMethods")));
394    result.setTimeOut(test.timeOut());
395    result.setInvocationTimeOut(test.invocationTimeOut());
396    result.setInvocationCount(test.invocationCount());
397    result.setThreadPoolSize(test.threadPoolSize());
398    result.setSuccessPercentage(test.successPercentage());
399    result.setDataProvider(test.dataProvider());
400//    result.setDataProviderClass(test.dataProviderClass() != Object.class ?
401//        test.dataProviderClass() : null);
402    result.setDataProviderClass(
403        findInherited(test.dataProviderClass(), cls, Test.class, "dataProviderClass",
404            DEFAULT_CLASS));
405    result.setAlwaysRun(test.alwaysRun());
406    result.setDescription(
407        findInherited(test.description(), cls, Test.class, "description", DEFAULT_STRING));
408    result.setExpectedExceptions(test.expectedExceptions());
409    result.setExpectedExceptionsMessageRegExp(test.expectedExceptionsMessageRegExp());
410    result.setSuiteName(test.suiteName());
411    result.setTestName(test.testName());
412    result.setSequential(test.sequential());
413    result.setSingleThreaded(test.singleThreaded());
414    result.setRetryAnalyzer(test.retryAnalyzer());
415    result.setSkipFailedInvocations(test.skipFailedInvocations());
416    result.setIgnoreMissingDependencies(test.ignoreMissingDependencies());
417    result.setPriority(test.priority());
418
419    return result;
420  }
421
422  private String[] join(String[] strings, String[] strings2) {
423    List<String> result = Lists.newArrayList(strings);
424    Set<String> seen = new HashSet<>(Lists.newArrayList(strings));
425    for (String s : strings2) {
426      if (! seen.contains(s)) {
427        result.add(s);
428      }
429    }
430
431    return result.toArray(new String[result.size()]);
432  }
433
434  /**
435   * This interface is used to calculate the default value for various
436   * annotation return types. This is used when looking for an annotation in a
437   * hierarchy. We can't use null as a default since annotation don't allow
438   * nulls, so each type has a different way of defining its own default.
439   */
440  static interface Default<T> {
441    boolean isDefault(T t);
442  }
443
444  private static final Default<Class<?>> DEFAULT_CLASS = new Default<Class<?>>() {
445    @Override
446    public boolean isDefault(Class<?> c) {
447      return c == Object.class;
448    }
449  };
450
451  private static final Default<String> DEFAULT_STRING = new Default<String>() {
452    @Override
453    public boolean isDefault(String s) {
454      return Utils.isStringEmpty(s);
455    }
456  };
457
458  /**
459   * Find the value of an annotation, starting with the annotation found on the
460   * method, then the class and then parent classes until we either find a
461   * non-default value or we reach the top of the hierarchy (Object).
462   */
463  private <T> T findInherited(T methodValue, Class<?> cls,
464      Class<? extends Annotation> annotationClass, String methodName,
465      Default<T> def) {
466
467    // Look on the method first and return right away if the annotation is there
468    if (!def.isDefault(methodValue)) {
469      return methodValue;
470    }
471
472    // Not found, look on the class and then up the hierarchy
473    while (cls != null && cls != Object.class) {
474      Annotation annotation = cls.getAnnotation(annotationClass);
475      if (annotation != null) {
476        T result = (T) invokeMethod(annotation, methodName);
477        if (!def.isDefault(result)) {
478          return result;
479        }
480      }
481      cls = cls.getSuperclass();
482    }
483
484    return null;
485  }
486
487  /**
488   * Find the value of a String[] annotation. The difference with the
489   * findInherited method above is that TestNG aggregates String[] values across
490   * hierarchies. For example, of the method annotation has { "a", "b" } and the
491   * class has { "c" }, the returned value will be { "a", "b", "c" }.
492   */
493  private String[] findInheritedStringArray(Class<?> cls,
494      Class<? extends Annotation> annotationClass, String methodName)
495  {
496    if (null == cls) {
497      return new String[0];
498    }
499
500    List<String> result = Lists.newArrayList();
501
502    while (cls != null && cls != Object.class) {
503      Annotation annotation = cls.getAnnotation(annotationClass);
504      if (annotation != null) {
505        String[] g = (String[]) invokeMethod(annotation, methodName);
506        for (String s : g) {
507          result.add(s);
508        }
509      }
510      cls = cls.getSuperclass();
511    }
512
513    return result.toArray(new String[result.size()]);
514  }
515
516  private Object invokeMethod(Annotation test, String methodName) {
517    Object result = null;
518    try {
519      // Note:  we should cache methods already looked up
520      Method m = test.getClass().getMethod(methodName, new Class[0]);
521      result = m.invoke(test, new Object[0]);
522    }
523    catch (Exception e) {
524      e.printStackTrace();
525    }
526    return result;
527  }
528
529  private void ppp(String string) {
530    System.out.println("[JDK15TagFactory] " + string);
531  }
532
533}
534