1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package com.gargoylesoftware.base.testing;
39
40 import com.gargoylesoftware.base.collections.StringComparator;
41 import com.gargoylesoftware.base.trace.Trace;
42 import com.gargoylesoftware.base.util.DetailedIllegalArgumentException;
43 import java.io.File;
44 import java.io.IOException;
45 import java.lang.reflect.Method;
46 import java.util.ArrayList;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Set;
51 import java.util.SortedSet;
52 import java.util.TreeSet;
53 import junit.framework.Test;
54 import junit.framework.TestCase;
55 import junit.framework.TestSuite;
56 import junit.textui.TestRunner;
57
58 /***
59 * A launching point for executing test cases. This recusively walks through
60 * the directory structure looking for classes that end in Test.class. It then
61 * loads these classes to see if they are instances of TestCase. If so, they
62 * are added to the test suite. Once all directories have been scanned, the
63 * test cases are executed.
64 *
65 * @version $Revision: 1.4 $
66 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
67 */
68 public class RecursiveTestSuite extends TestSuite {
69
70 private final TestFilter testFilter_;
71
72
73 /***
74 * Create a new instance
75 *
76 * @param testFilter The object that will filter out tests that we don't
77 * wish to run
78 * @param startingPath The directory that we will start our descent in.
79 * @exception IOException If anything goes wrong during the directory
80 * scanning.
81 */
82 public RecursiveTestSuite(
83 final String startingPath,
84 final TestFilter testFilter )
85 throws
86 IOException {
87
88 this( new File( startingPath ), testFilter );
89 }
90
91
92 /***
93 * Create an instance
94 *
95 * @param testFilter The object that will filter out tests that we don't
96 * wish to run
97 * @param startingPath The directory that we will start our descent in.
98 * @exception IOException If anything goes wrong during the directory
99 * scanning.
100 */
101 public RecursiveTestSuite(
102 final File startingPath,
103 final TestFilter testFilter )
104 throws
105 IOException {
106
107 super( "RecursiveTestSuite(" + startingPath + ")" );
108
109 if( testFilter == null ) {
110 throw new NullPointerException( "testFilter" );
111 }
112 if( startingPath == null ) {
113 throw new NullPointerException( "startingPath" );
114 }
115 testFilter_ = testFilter;
116
117 if( startingPath.exists() == false ) {
118 throw new DetailedIllegalArgumentException( "startingPath", startingPath, "Doesn't exist");
119 }
120 if( startingPath.isDirectory() == false ) {
121 throw new DetailedIllegalArgumentException( "startingPath", startingPath, "Isn't a directory" );
122 }
123
124 final long startTime = System.currentTimeMillis();
125 final Set classNames = findAllTestClasses( startingPath );
126 final long endTime = System.currentTimeMillis();
127 System.out.println( "Scanning for classes: Time=["
128 + ( ( endTime - startTime ) / 1000F )
129 + " seconds] Found=["
130 + classNames.size()
131 + " classes]" );
132
133 final Iterator iterator = classNames.iterator();
134
135 while( iterator.hasNext() ) {
136 addTest( getTestForClass( (Class)iterator.next() ) );
137 }
138 }
139
140
141 /***
142 * Main entry point.
143 *
144 * @param args The arguments
145 */
146 public static void main( final String args[] ) {
147
148 Trace.getController().setOutRedirected( true );
149 Trace.getController().setErrRedirected( true );
150
151
152 new javax.swing.JPanel();
153
154 try {
155 final String startingPath;
156 if( args.length == 0 ) {
157 startingPath = ".";
158 }
159 else {
160 startingPath = args[0];
161 }
162 final RecursiveTestSuite suite = new RecursiveTestSuite( startingPath, new AcceptAllTestFilter() );
163
164
165
166 Trace.getController().setBufferingEnabled( false );
167
168 if( suite.testCount() == 0 ) {
169 Trace.println( "Nothing to do." );
170 }
171 else {
172 TestRunner.run( suite );
173 }
174 }
175 catch( final Throwable t ) {
176 Trace.printStackTrace( Trace.out, t );
177 }
178 Trace.exit( 0 );
179 }
180
181
182 /***
183 * Dummy test so that JUnit doesn't complain that this suite doesn't have
184 * any tests.
185 */
186 public void testFoo() {
187 }
188
189
190
191
192
193
194
195
196 /***
197 * Return a test suite containing all the tests for the specified class. If
198 * the class has a suite() method then it will be used to get the tests,
199 * otherwise reflection will be used.
200 *
201 * @param clazz Description of Parameter
202 * @return The testSuiteForClass value
203 */
204 private Test getTestForClass( final Class clazz ) {
205 try {
206 final Method method = clazz.getDeclaredMethod( "suite", new Class[0] );
207 return (Test)method.invoke( null, new Object[0] );
208 }
209 catch( final NoSuchMethodException e ) {
210
211 }
212 catch( final Exception e ) {
213 e.printStackTrace();
214 }
215
216 return new TestSuite( clazz );
217 }
218
219
220 /***
221 * @param startingDirectory Description of Parameter
222 * @return Description of the Returned Value
223 * @exception IOException Description of Exception
224 */
225 private Set findAllTestClasses( final File startingDirectory )
226 throws IOException {
227
228 final List list = new ArrayList();
229 final SortedSet set
230 = new TreeSet( new StringComparator( Locale.getDefault() ) );
231
232 findAllTestClasses( startingDirectory, list );
233
234 final String startingDirectoryFullPath
235 = startingDirectory.getCanonicalPath();
236 final int startingDirLength
237 = startingDirectoryFullPath.length() + File.separator.length();
238
239 String className;
240 Class clazz;
241
242 final Iterator iterator = list.iterator();
243 while( iterator.hasNext() ) {
244 className = ( (String)iterator.next() );
245 className = className.substring( startingDirLength,
246 className.length() - ".class".length() );
247 className = className.replace( File.separatorChar, '.' );
248
249 try {
250 clazz = Class.forName( className );
251 if( TestCase.class.isAssignableFrom( clazz )
252 && testFilter_.accept( clazz ) ) {
253 set.add( clazz );
254 }
255 }
256 catch( final ClassNotFoundException e ) {
257 Trace.printStackTrace( Trace.out, e );
258 }
259 }
260 return set;
261 }
262
263
264 /***
265 * @param directory Description of Parameter
266 * @param list Description of Parameter
267 * @exception IOException Description of Exception
268 */
269 private void findAllTestClasses( final File directory, final List list )
270 throws IOException {
271
272 final String files[] = directory.list();
273 if( files == null ) {
274 return;
275 }
276
277 final String directoryName = directory.getCanonicalPath();
278 String fileName;
279
280 int i;
281 for( i = 0; i < files.length; i++ ) {
282 fileName = directoryName + File.separator + files[i];
283 if( files[i].endsWith( "Test.class" ) ) {
284 list.add( fileName );
285 }
286 else {
287 final File file = new File( fileName );
288 if( file.isDirectory() ) {
289 findAllTestClasses( file, list );
290 }
291 }
292 }
293 }
294 }
295