1 /*******************************************************************************
2  * Copyright (c) 2006, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     David Saff (saff@mit.edu) - initial API and implementation
13  *             (bug 102632: [JUnit] Support for JUnit 4.)
14  *     Andrew Eisenberg <andrew@eisenberg.as> - [JUnit] Rerun failed first does not work with JUnit4 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140392
15  *******************************************************************************/
16 package org.eclipse.jdt.internal.junit4.runner;
17 
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 import java.util.List;
21 
22 import junit.framework.Test;
23 
24 import org.junit.runner.Description;
25 import org.junit.runner.Request;
26 import org.junit.runner.Runner;
27 
28 import org.eclipse.jdt.internal.junit.runner.ITestLoader;
29 import org.eclipse.jdt.internal.junit.runner.ITestReference;
30 import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
31 import org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader;
32 import org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference;
33 
34 
35 public class JUnit4TestLoader implements ITestLoader {
36 
loadTests( Class<?>[] testClasses, String testName, String[] failureNames, String[] packages, String[][] includeExcludeTags, String uniqueId, RemoteTestRunner listener)37 	public ITestReference[] loadTests(
38 			Class<?>[] testClasses,
39 			String testName,
40 			String[] failureNames,
41 			String[] packages,
42 			String[][] includeExcludeTags,
43 			String uniqueId,
44 			RemoteTestRunner listener) {
45 
46 		ITestReference[] refs= new ITestReference[testClasses.length];
47 		for (int i= 0; i < testClasses.length; i++) {
48 			Class<?> clazz= testClasses[i];
49 			ITestReference ref= createTest(clazz, testName, failureNames, listener);
50 			refs[i]= ref;
51 		}
52 		return refs;
53 	}
54 
getRootDescription(Runner runner, DescriptionMatcher matcher)55 	private Description getRootDescription(Runner runner, DescriptionMatcher matcher) {
56 		Description current= runner.getDescription();
57 		while (true) {
58 			List<Description> children= current.getChildren();
59 			if (children.size() != 1 || matcher.matches(current))
60 				return current;
61 			current= children.get(0);
62 		}
63 	}
64 
createTest(Class<?> clazz, String testName, String[] failureNames, RemoteTestRunner listener)65 	private ITestReference createTest(Class<?> clazz, String testName, String[] failureNames, RemoteTestRunner listener) {
66 		if (clazz == null)
67 			return null;
68 		if (testName != null && isJUnit3SetUpTest(clazz, testName)) {
69 			JUnit3TestLoader jUnit3TestLoader= new JUnit3TestLoader();
70 			Test test= jUnit3TestLoader.getTest(clazz, testName, listener);
71 			return new JUnit3TestReference(test);
72 		}
73 		if (testName != null) {
74 			return createFilteredTest(clazz, testName, failureNames);
75 		}
76 		return createUnfilteredTest(clazz, failureNames);
77 	}
78 
createFilteredTest(Class<?> clazz, String testName, String[] failureNames)79 	private ITestReference createFilteredTest(Class<?> clazz, String testName, String[] failureNames) {
80 		DescriptionMatcher matcher= DescriptionMatcher.create(clazz, testName);
81 		SubForestFilter filter= new SubForestFilter(matcher);
82 		Request request= sortByFailures(Request.classWithoutSuiteMethod(clazz).filterWith(filter), failureNames);
83 		Runner runner= request.getRunner();
84 		Description description= getRootDescription(runner, matcher);
85 		return new JUnit4TestReference(runner, description);
86 	}
87 
createUnfilteredTest(Class<?> clazz, String[] failureNames)88 	private ITestReference createUnfilteredTest(Class<?> clazz, String[] failureNames) {
89 		Request request= sortByFailures(Request.aClass(clazz), failureNames);
90 		Runner runner= request.getRunner();
91 		Description description= runner.getDescription();
92 		return new JUnit4TestReference(runner, description);
93 	}
94 
sortByFailures(Request request, String[] failureNames)95 	private Request sortByFailures(Request request, String[] failureNames) {
96 		if (failureNames != null) {
97 			return request.sortWith(new FailuresFirstSorter(failureNames));
98 		}
99 		return request;
100 	}
101 
isJUnit3SetUpTest(Class<?> clazz, String testName)102 	private boolean isJUnit3SetUpTest(Class<?> clazz, String testName) {
103 		if (!Test.class.isAssignableFrom(clazz))
104 			return false;
105 		try {
106 			Method testMethod= clazz.getMethod(testName);
107 			if (testMethod.getAnnotation(org.junit.Test.class) != null)
108 				return false;
109 
110 			Method setup= clazz.getMethod(JUnit3TestLoader.SET_UP_TEST_METHOD_NAME, new Class[] { Test.class });
111 			int modifiers= setup.getModifiers();
112 			if (setup.getReturnType() == Test.class && Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers))
113 				return true;
114 		} catch (SecurityException e1) {
115 		} catch (NoSuchMethodException e) {
116 		}
117 		return false;
118 	}
119 }
120