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