1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.booter;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.lang.annotation.Annotation;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.List;
30
31 import org.apache.maven.surefire.shared.utils.io.FileUtils;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.internal.runners.model.ReflectiveCallable;
36 import org.junit.internal.runners.statements.ExpectException;
37 import org.junit.internal.runners.statements.Fail;
38 import org.junit.internal.runners.statements.RunAfters;
39 import org.junit.internal.runners.statements.RunBefores;
40 import org.junit.runner.notification.RunNotifier;
41 import org.junit.runners.BlockJUnit4ClassRunner;
42 import org.junit.runners.model.FrameworkMethod;
43 import org.junit.runners.model.InitializationError;
44 import org.junit.runners.model.Statement;
45 import org.junit.runners.model.TestClass;
46
47 import static java.io.File.pathSeparator;
48
49
50
51
52
53
54
55 public class NewClassLoaderRunner extends BlockJUnit4ClassRunner {
56 private static final String PROJECT_DIR = System.getProperty("java.dir");
57
58 private Class<?> cls;
59
60 public NewClassLoaderRunner(Class<?> clazz) throws InitializationError {
61 super(clazz);
62 }
63
64 @Override
65 protected void runChild(FrameworkMethod method, RunNotifier notifier) {
66 ClassLoader backup = Thread.currentThread().getContextClassLoader();
67 try {
68 TestClassLoader loader = new TestClassLoader();
69 Thread.currentThread().setContextClassLoader(loader);
70 cls = getFromTestClassLoader(getTestClass().getName(), loader);
71 method = new FrameworkMethod(cls.getMethod(method.getName()));
72 super.runChild(method, notifier);
73 } catch (NoSuchMethodException e) {
74 throw new IllegalStateException(e);
75 } finally {
76 Thread.currentThread().setContextClassLoader(backup);
77 }
78 }
79
80 @Override
81 protected Statement methodBlock(FrameworkMethod method) {
82 try {
83 Object test = new ReflectiveCallable() {
84 @Override
85 protected Object runReflectiveCall() throws Throwable {
86 return createTest();
87 }
88 }.run();
89
90 Statement statement = methodInvoker(method, test);
91 statement = possiblyExpectingExceptions(method, test, statement);
92 statement = withBefores(method, test, statement);
93 statement = withAfters(method, test, statement);
94 return statement;
95 } catch (Throwable e) {
96 return new Fail(e);
97 }
98 }
99
100 @Override
101 @SuppressWarnings("unchecked")
102 protected Statement possiblyExpectingExceptions(FrameworkMethod method, Object test, Statement next) {
103 try {
104 Class<? extends Annotation> t = (Class<? extends Annotation>)
105 Thread.currentThread().getContextClassLoader().loadClass(Test.class.getName());
106 Annotation annotation = method.getAnnotation(t);
107 Class<? extends Throwable> exp =
108 (Class<? extends Throwable>) t.getMethod("expected").invoke(annotation);
109 boolean isException = exp != null && !Test.None.class.getName().equals(exp.getName());
110 return isException ? new ExpectException(next, exp) : next;
111 } catch (Exception e) {
112 throw new IllegalStateException(e);
113 }
114 }
115
116 @Override
117 @SuppressWarnings("unchecked")
118 protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
119 try {
120 Class<? extends Annotation> before = (Class<? extends Annotation>)
121 Thread.currentThread().getContextClassLoader().loadClass(Before.class.getName());
122 List<FrameworkMethod> befores = new TestClass(target.getClass()).getAnnotatedMethods(before);
123 return befores.isEmpty() ? statement : new RunBefores(statement, befores, target);
124 } catch (ClassNotFoundException e) {
125 throw new IllegalStateException(e);
126 }
127 }
128
129 @Override
130 @SuppressWarnings("unchecked")
131 protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
132 try {
133 Class<? extends Annotation> after = (Class<? extends Annotation>)
134 Thread.currentThread().getContextClassLoader().loadClass(After.class.getName());
135 List<FrameworkMethod> afters = new TestClass(target.getClass()).getAnnotatedMethods(after);
136 return afters.isEmpty() ? statement : new RunAfters(statement, afters, target);
137 } catch (ClassNotFoundException e) {
138 throw new IllegalStateException(e);
139 }
140 }
141
142 @Override
143 protected Object createTest() throws Exception {
144 return cls == null ? super.createTest() : cls.getConstructor().newInstance();
145 }
146
147 private static Class<?> getFromTestClassLoader(String clazz, TestClassLoader loader) {
148 try {
149 return Class.forName(clazz, true, loader);
150 } catch (ClassNotFoundException e) {
151 throw new IllegalStateException(e);
152 }
153 }
154
155 private static class TestClassLoader extends URLClassLoader {
156 TestClassLoader() {
157 super(toClassPath(), null);
158 }
159
160
161
162
163
164
165 private static URL[] toClassPath() {
166 try {
167 Collection<URL> cp = toPathList();
168 if (cp.isEmpty()) {
169
170 cp = toPathList(System.getProperty("java.class.path"));
171 }
172 return cp.toArray(new URL[cp.size()]);
173 } catch (IOException e) {
174 e.printStackTrace();
175 return new URL[0];
176 }
177 }
178
179 private static Collection<URL> toPathList(String path) throws MalformedURLException {
180 Collection<URL> classPath = new HashSet<>();
181 for (String file : path.split(pathSeparator)) {
182 classPath.add(new File(file).toURI().toURL());
183 }
184 return classPath;
185 }
186
187 private static Collection<URL> toPathList() {
188 Collection<URL> classPath = new HashSet<>();
189 try {
190 File classPathFile = new File(PROJECT_DIR, "target/test-classpath/cp.txt");
191 String[] files = FileUtils.fileRead(classPathFile, "UTF-8").split(pathSeparator);
192 for (String file : files) {
193 classPath.add(new File(file).toURI().toURL());
194 }
195 classPath.add(new File(PROJECT_DIR, "target/classes").toURI().toURL());
196 classPath.add(
197 new File(PROJECT_DIR, "target/test-classes").toURI().toURL());
198 } catch (IOException e) {
199 e.printStackTrace();
200
201 classPath.clear();
202 }
203 return classPath;
204 }
205 }
206 }