1package org.testng.junit;
2
3import org.testng.ITestMethodFinder;
4import org.testng.ITestNGMethod;
5import org.testng.collections.Lists;
6import org.testng.internal.TestNGMethod;
7import org.testng.internal.annotations.IAnnotationFinder;
8import org.testng.xml.XmlTest;
9
10import java.lang.reflect.Constructor;
11import java.lang.reflect.InvocationTargetException;
12import java.lang.reflect.Method;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16
17
18/**
19 * This class locates all test and configuration methods according to JUnit.
20 * It is used to change the strategy used by TestRunner to locate its test
21 * methods.
22 *
23 * @author Cedric Beust, May 3, 2004
24 *
25 */
26public class JUnitMethodFinder implements ITestMethodFinder {
27  private String m_testName = null;
28  private IAnnotationFinder m_annotationFinder = null;
29
30  public JUnitMethodFinder(String testName, IAnnotationFinder finder) {
31    m_testName = testName;
32    m_annotationFinder = finder;
33  }
34
35  private Constructor findConstructor(Class cls, Class[] parameters) {
36    Constructor result = null;
37
38    try {
39      result = cls.getConstructor(parameters);
40    }
41    catch (SecurityException | NoSuchMethodException ex) {
42      // ignore
43    }
44
45    return result;
46  }
47
48  @Override
49  public ITestNGMethod[] getTestMethods(Class cls, XmlTest xmlTest) {
50    ITestNGMethod[] result =
51      privateFindTestMethods(new INameFilter() {
52        @Override
53        public boolean accept(Method method) {
54          return method.getName().startsWith("test") &&
55            method.getParameterTypes().length == 0;
56        }
57    }, cls);
58
59//    ppp("=====");
60//    ppp("FIND TEST METHOD RETURNING ");
61//    for (ITestMethod m : result) {
62//      ppp("  " + m);
63//    }
64//    ppp("=====");
65    return result;
66  }
67
68  private ITestNGMethod[] privateFindTestMethods(INameFilter filter, Class cls) {
69    List<ITestNGMethod> vResult = Lists.newArrayList();
70
71    // We do not want to walk up the class hierarchy and accept the
72    // same method twice (e.g. setUp) which would lead to double-invocation.
73    // All relevant JUnit methods are parameter-less so we store accepted
74    // method names in a Set to filter out duplicates.
75    Set<String> acceptedMethodNames = new HashSet<>();
76
77    //
78    // Collect all methods that start with test
79    //
80    Class current = cls;
81    while(!(current == Object.class)) {
82      Method[] allMethods = current.getDeclaredMethods();
83      for(Method allMethod : allMethods) {
84        ITestNGMethod m = new TestNGMethod(/* allMethods[i].getDeclaringClass(), */ allMethod,
85            m_annotationFinder, null,
86            null); /* @@@ */
87        Method method = m.getMethod();
88        String methodName = method.getName();
89        if(filter.accept(method) && !acceptedMethodNames.contains(methodName)) {
90          //          if (m.getName().startsWith("test")) {
91          //            ppp("Found JUnit test method: " + tm);
92          vResult.add(m);
93          acceptedMethodNames.add(methodName);
94        }
95      }
96      current = current.getSuperclass();
97    }
98
99    return vResult.toArray(new ITestNGMethod[vResult.size()]);
100  }
101
102  private static void ppp(String s) {
103    System.out.println("[JUnitMethodFinder] " + s);
104  }
105
106  private Object instantiate(Class cls) {
107    Object result = null;
108
109    Constructor ctor = findConstructor(cls, new Class[] { String.class });
110    try {
111      if (null != ctor) {
112        result = ctor.newInstance(new Object[] { m_testName });
113      }
114      else {
115        ctor = cls.getConstructor(new Class[0]);
116        result = ctor.newInstance(new Object[0]);
117      }
118    }
119    catch (IllegalArgumentException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | SecurityException ex) {
120      ex.printStackTrace();
121    } catch (InstantiationException ex) {
122      System.err.println("Couldn't find a constructor with a String parameter on your JUnit test class.");
123      ex.printStackTrace();
124    }
125
126    return result;
127  }
128
129
130  @Override
131  public ITestNGMethod[] getBeforeTestMethods(Class cls) {
132    ITestNGMethod[] result = privateFindTestMethods(new INameFilter() {
133        @Override
134        public boolean accept(Method method) {
135          return "setUp".equals(method.getName());
136        }
137      }, cls);
138
139    return result;
140  }
141
142  @Override
143  public ITestNGMethod[] getAfterTestMethods(Class cls) {
144    ITestNGMethod[] result =  privateFindTestMethods(new INameFilter() {
145        @Override
146        public boolean accept(Method method) {
147          return "tearDown".equals(method.getName());
148        }
149      }, cls);
150
151    return result;
152  }
153
154  @Override
155  public ITestNGMethod[] getAfterClassMethods(Class cls) {
156    return new ITestNGMethod[0];
157  }
158
159  @Override
160  public ITestNGMethod[] getBeforeClassMethods(Class cls) {
161    return new ITestNGMethod[0];
162  }
163
164  @Override
165  public ITestNGMethod[] getBeforeSuiteMethods(Class cls) {
166    return new ITestNGMethod[0];
167  }
168
169  @Override
170  public ITestNGMethod[] getAfterSuiteMethods(Class cls) {
171    return new ITestNGMethod[0];
172  }
173
174  @Override
175  public ITestNGMethod[] getBeforeTestConfigurationMethods(Class testClass) {
176    return new ITestNGMethod[0];
177  }
178
179  @Override
180  public ITestNGMethod[] getAfterTestConfigurationMethods(Class testClass) {
181    return new ITestNGMethod[0];
182  }
183
184  @Override
185  public ITestNGMethod[] getBeforeGroupsConfigurationMethods(Class testClass) {
186    return new ITestNGMethod[0];
187  }
188
189  @Override
190  public ITestNGMethod[] getAfterGroupsConfigurationMethods(Class testClass) {
191    return new ITestNGMethod[0];
192  }
193}
194
195/////////////
196
197interface INameFilter {
198  public boolean accept(Method method);
199}
200