KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > xml > driver > TestCaseBase


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: TestCaseBase.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
22  */

23
24 package org.enhydra.xml.driver;
25
26 import java.io.File JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.lang.reflect.Constructor JavaDoc;
29 import java.lang.reflect.InvocationTargetException JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.lang.reflect.Modifier JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.net.URLClassLoader JavaDoc;
34 import java.util.ArrayList JavaDoc;
35
36 import junit.framework.Test;
37 import junit.framework.TestCase;
38 import junit.framework.TestSuite;
39
40 /**
41  * Base class of all test classes. Derived class implement
42  * <CODE>testXXX()</CODE> methods for each test. Each generated method is run
43  * in an instance of this class. Set package overview doc for why this
44  * approach was chosen.
45  * <P>
46  * The derived test case class should defined a method:
47  * <PRE>
48  * public static Test suite();
49  * </PRE>
50  * that create methods by calling <CODE>createSuite()</CODE>.
51  * <p>
52  * Note: The key thing to remember is that a instance of this object
53  * is created foreach test method!!!
54  */

55 public class TestCaseBase extends TestCase {
56     /** Derived class constructor signature */
57     private static final Class JavaDoc[] CONST_SIGN = {
58         Method JavaDoc.class
59     };
60     
61     /** Empty arguments used in call test method */
62     private static final Object JavaDoc[] NO_ARGS = new Object JavaDoc[0];
63
64     /** Standard input directory */
65     private static final File JavaDoc INPUT_DIR = new File JavaDoc("input");
66
67     /** Output directory */
68     private static final File JavaDoc OUTPUT_DIR = new File JavaDoc("output");
69
70     /** Classes directory in output */
71     private static final File JavaDoc CLASSES_DIR = new File JavaDoc(OUTPUT_DIR, "classes");
72
73     /** Results directory in output */
74     private static final File JavaDoc RESULTS_DIR = new File JavaDoc(OUTPUT_DIR, "results");
75
76     /** Expected results directory */
77     private static final File JavaDoc EXPECTED_DIR = new File JavaDoc("expected");
78
79     /**
80      * Part of package name that is skipped when generating result name. This
81      * is to avoid creating a bunch of directories in results and expected
82      * that don't really do much
83      */

84     private static final String JavaDoc RESULT_PKG_SKIP = "org.enhydra.xml.";
85
86     /** Standard replacement patterns for diffing input */
87     public static final String JavaDoc INPUT_REPLACE = "${testCaseRoot}/input";
88     public static final String JavaDoc OUTPUT_REPLACE = "${testCaseRoot}/output";
89         
90     /**
91      * Class used in selecting tests to run. If an instance of this is
92      * supplied, it can be used to choose a subset of tests.
93      */

94     public interface TestSelector {
95         /** Determine if a test method should be executed */
96         public boolean select(Method JavaDoc method);
97     }
98
99     /** Method that this instace of the test will executed */
100     private Method JavaDoc fMethod;
101
102     /**
103      * Full test id, default is test case class plus method name, but
104      * this may have more info in it.
105      */

106     private String JavaDoc fTestId;
107
108     /** Writer for logging messages */
109     private PrintWriter JavaDoc fMsgWriter;
110
111     /** Write tracing if not null */
112     private PrintWriter JavaDoc fVerboseOut;
113
114     /** Should missing or miss-matched expected files be updated? */
115     private boolean fUpdateExpected;
116
117     /**
118      * Test case root directory. This is the the path to the directory
119      * containing this test case. It's either the current directory or set
120      * from a property. All files are relative to this location.
121      */

122     private File JavaDoc fTestCaseRoot;
123
124     /** Standard input directory, relative to test case root */
125     private File JavaDoc fInputRoot;
126
127     /** Output directory, relative to test case root */
128     private File JavaDoc fOutputRoot;
129
130     /** Classes directory in output */
131     private File JavaDoc fClassesRoot;
132
133     /** Results directory in output */
134     private File JavaDoc fResultsRoot;
135
136     /** Expected results directory */
137     private File JavaDoc fExpectedRoot;
138
139     /** Package directory (lazy) */
140     private File JavaDoc fPackageDir;
141
142     /** Relative result dir (lazy) */
143     private File JavaDoc fRelResultsDir;
144
145     /** Result dir (lazy) */
146     private File JavaDoc fResultsDir;
147
148     /** Expected result dir (lazy) */
149     private File JavaDoc fExpectedDir;
150
151     /** Class loader use to load compiled objects */
152     private ClassLoader JavaDoc fTestClassLoader;
153
154     /** Extra diff filters to use */
155     private ArrayList JavaDoc fExtraFilters;
156
157     /** Differ object that queues exceptions. */
158     private TestDiff fDiffer;
159
160     /** Determine if a method is a test method */
161     private static boolean isTestMethod(Method JavaDoc method) {
162         // check name an signature
163
return method.getName().startsWith("test")
164             && Modifier.isPublic(method.getModifiers())
165             && (method.getParameterTypes().length == 0)
166             && method.getReturnType().equals(Void.TYPE);
167     }
168
169     /** Determine if a selected test method */
170     private static boolean isTestMethod(Method JavaDoc method,
171                                         TestSelector selector) {
172         return (isTestMethod(method)
173                 && ((selector == null) || selector.select(method)));
174     }
175
176     /** Create a test instance */
177     private static Test createTest(Constructor JavaDoc constr,
178                                    Method JavaDoc method) {
179         try {
180             return (Test)constr.newInstance(new Object JavaDoc[]{method});
181         } catch (InstantiationException JavaDoc except) {
182             throw new TestError(except);
183         } catch (IllegalAccessException JavaDoc except) {
184             throw new TestError(except);
185         } catch (InvocationTargetException JavaDoc except) {
186             throw new TestError(except);
187         }
188     }
189
190     /**
191      * Build the test suite
192      */

193     public static Test createSuite(Class JavaDoc testCaseClass,
194                                    TestSelector selector) {
195         Constructor JavaDoc constr;
196         try {
197             constr = testCaseClass.getConstructor(CONST_SIGN);
198         } catch (NoSuchMethodException JavaDoc except) {
199             throw new TestError(except);
200         }
201         TestSuite suite = new TestSuite();
202         Method JavaDoc[] methods= testCaseClass.getDeclaredMethods();
203         
204         for (int idx = 0; idx < methods.length; idx++) {
205             if (isTestMethod(methods[idx], selector)) {
206                 suite.addTest(createTest(constr, methods[idx]));
207             }
208         }
209         return suite;
210     }
211
212     /**
213      * Constructor for a specific test instance, specifying the unqualTestId.
214      * Used when more than the test method name must identify the tests.
215      */

216     protected TestCaseBase(String JavaDoc unqualTestId,
217                            Method JavaDoc method) {
218         super(unqualTestId);
219         fMethod = method;
220         fTestId = method.getDeclaringClass().getName() + "."
221             + unqualTestId;
222         fMsgWriter = new PrintWriter JavaDoc(System.err, true);
223         if (TestProperties.getVerbose()) {
224             fVerboseOut = fMsgWriter;
225         }
226         fUpdateExpected = TestProperties.getUpdate();
227
228         // get root and files relative to it
229
fTestCaseRoot = TestProperties.getTestRoot();
230         fInputRoot = new File JavaDoc(fTestCaseRoot, INPUT_DIR.getPath());
231         fOutputRoot = new File JavaDoc(fTestCaseRoot, OUTPUT_DIR.getPath());
232         fClassesRoot = new File JavaDoc(fTestCaseRoot, CLASSES_DIR.getPath());
233         fResultsRoot = new File JavaDoc(fTestCaseRoot, RESULTS_DIR.getPath());
234         fExpectedRoot = new File JavaDoc(fTestCaseRoot, EXPECTED_DIR.getPath());
235     }
236
237     /**
238      * Constructor for a specific test instance using method name as the
239      * unqualTestId.
240      */

241     protected TestCaseBase(Method JavaDoc method) {
242         this(method.getName(), method);
243     }
244
245     /**
246      * Called by junit to run the test.
247      */

248     public void runTest() {
249         try {
250             fMethod.invoke(this, NO_ARGS);
251         } catch (IllegalAccessException JavaDoc except) {
252             throw new TestError(except);
253         } catch (InvocationTargetException JavaDoc except) {
254             Throwable JavaDoc except2 = except.getTargetException();
255             if (except2 instanceof TestException) {
256                 throw (TestException)except2;
257             }
258             if (except2 instanceof TestError) {
259                 throw (TestError)except2;
260             }
261             throw new TestException(except2);
262         }
263         // If any diff failures occured, generate an exception
264
if (fDiffer != null) {
265             fDiffer.throwPendingDiffFailures();
266         }
267     }
268
269     /** Get the full test id */
270     public String JavaDoc getTestId() {
271         return fTestId;
272     }
273
274     /** Get the unqualified test id */
275     public String JavaDoc getUnqualTestId() {
276         return getName();
277     }
278
279     /**
280      * Get the test method name.
281      */

282     public String JavaDoc getTestName() {
283         return fMethod.getName();
284     }
285     
286     /**
287      * Get writer for writing messages
288      */

289     public PrintWriter JavaDoc getMsgWriter() {
290         return fMsgWriter;
291     }
292
293     /** print a newline to the message writer */
294     public void msgPrintln() {
295         fMsgWriter.println();
296     }
297
298     /** print a message without newline */
299     public void msgPrint(String JavaDoc msg) {
300         fMsgWriter.print(msg);
301     }
302
303     /** print a message with newline */
304     public void msgPrintln(String JavaDoc msg) {
305         msgPrint(msg);
306         msgPrintln();
307     }
308
309     /** Get the verbose writer, or null if not emabled */
310     public PrintWriter JavaDoc getVerboseOut() {
311         return fVerboseOut;
312     }
313
314     /**
315      * Get root directory for the test case. All files are relative to
316      * this directory.
317      */

318     public File JavaDoc getTestCaseRoot() {
319         return fTestCaseRoot;
320     }
321
322     /**
323      * Get the test package. This is the <em>class</em> name of the
324      * concrete test case. The other directories are derived from this
325      * directory, so that overriding this method can change all of the
326      * others.
327      */

328     public String JavaDoc getTestPackage() {
329         // Need to add `Pkg' to prevent conflict with class name
330
return getClass().getName() + "Pkg";
331     }
332
333     /**
334      * Get the tail part of the package name that removes parts that are not
335      * required to keep tests unique.
336      */

337     public String JavaDoc getTestPackageTail() {
338         return getTestPackage().substring(RESULT_PKG_SKIP.length());
339     }
340
341     /**
342      * Get the root of the class tree.
343      */

344     public File JavaDoc getClassRoot() {
345         return fClassesRoot;
346     }
347
348     /** Get the test package directory, where compiled files are placed */
349     public File JavaDoc getPackageDir() {
350         if (fPackageDir == null) {
351             String JavaDoc pkgPath = getTestPackage().replace('.', File.separatorChar);
352             fPackageDir = new File JavaDoc(getClassRoot(), pkgPath);
353         }
354         return fPackageDir;
355     }
356
357     /** Get input file root dir */
358     public File JavaDoc getInputRoot() {
359         return fInputRoot;
360     }
361
362     /** Get path to an input file, give file relative to input/ */
363     public File JavaDoc getInputFile(String JavaDoc fileName) {
364         return new File JavaDoc(fInputRoot, fileName);
365     }
366     
367     /**
368      * Get path to an input file that is in another test case directory.
369      * Given the relative location of that directory and the file relative to
370      * input.
371      */

372     public File JavaDoc getOtherInputFile(String JavaDoc otherTestCaseDir,
373                                   String JavaDoc fileName) {
374         File JavaDoc otherRoot = new File JavaDoc(fTestCaseRoot, otherTestCaseDir);
375         File JavaDoc otherInput = new File JavaDoc(otherRoot, INPUT_DIR.getPath());
376
377         // Add filter for this
378
addOtherInputFileDiffFilter(otherTestCaseDir, otherRoot);
379
380         return new File JavaDoc(otherInput, fileName);
381     }
382     
383     /** Get output root dir */
384     public File JavaDoc getOutputRoot() {
385         return fOutputRoot;
386     }
387
388     /**
389      * Get the relative results directory (not including output or expected)
390      */

391     public File JavaDoc getRelResultsDir() {
392         if (fRelResultsDir == null) {
393             // Get package with several leading ones removed
394
String JavaDoc pkgPath = getTestPackageTail().replace('.', File.separatorChar);
395             fRelResultsDir = new File JavaDoc(pkgPath);
396         }
397         return fRelResultsDir;
398     }
399
400     /** Get the results directory for this test */
401     public File JavaDoc getResultsDir() {
402         if (fResultsDir == null) {
403             fResultsDir = new File JavaDoc(fResultsRoot,
404                                    getRelResultsDir().getPath());
405             fResultsDir.mkdirs(); // always create
406
}
407         return fResultsDir;
408     }
409
410     /** Get a result file path */
411     public File JavaDoc getResultFile(String JavaDoc fname,
412                               String JavaDoc suffix) {
413         return new File JavaDoc(getResultsDir(), fname + "." + suffix);
414     }
415     
416     /** Get a result file path */
417     public File JavaDoc getResultFile(String JavaDoc suffix) {
418         return getResultFile(getTestName(), suffix);
419     }
420     
421     /** Get the test expected root directory */
422     public File JavaDoc getExpectedRoot() {
423         return fExpectedRoot;
424     }
425
426     /** Get the test expected results directory */
427     public File JavaDoc getExpectedDir() {
428         if (fExpectedDir == null) {
429             fExpectedDir = new File JavaDoc(fExpectedRoot,
430                                     getRelResultsDir().getPath());
431         }
432         return fExpectedDir;
433     }
434     
435     /** Get an expected file name. */
436     public File JavaDoc getExpectedFile(String JavaDoc fname,
437                                 String JavaDoc suffix) {
438         return new File JavaDoc(getExpectedDir(), fname + "." + suffix);
439     }
440
441     /** Get an expected file name. */
442     public File JavaDoc getExpectedFile(String JavaDoc suffix) {
443         return getExpectedFile(getTestName(), suffix);
444     }
445
446     /**
447      * Add an additional diff filter for handling special-case
448      * patterns.
449      */

450     public void addDiffFilter(TestDiff.LineFilter filter) {
451         if (fExtraFilters == null) {
452             fExtraFilters = new ArrayList JavaDoc();
453         }
454         fExtraFilters.add(filter);
455     }
456
457     /**
458      * Define a diff filter for handling an input file that is coming
459      * from an another, as obtained by getOtherInputFile().
460      */

461     private void addOtherInputFileDiffFilter(String JavaDoc otherTestCaseDir,
462                                              File JavaDoc otherRoot) {
463         addDiffFilter(new SimpleDiffFilter(otherRoot.getPath(),
464                                            "${testCaseRoot}/" + otherTestCaseDir));
465     }
466
467     /**
468      * Add filters to diff object. These allow compares to not
469      * fail due to path variations in where the test is run.
470      */

471     private void addFilters(TestDiff differ) {
472         // add standard filters
473
differ.addFilter(new SimpleDiffFilter(getInputRoot().getPath(),
474                                               INPUT_REPLACE));
475         differ.addFilter(new SimpleDiffFilter(getOutputRoot().getPath(),
476                                               OUTPUT_REPLACE));
477
478         // add extra filters
479
if (fExtraFilters != null) {
480             for (int idx = 0; idx < fExtraFilters.size(); idx++) {
481                 differ.addFilter((TestDiff.LineFilter)fExtraFilters.get(idx));
482             }
483         }
484     }
485
486     /**
487      * Get the diff object for the class. Failures are queued until
488      * after the test completes. The runTest method will then throw
489      * the exception when complete. Optionally updates expected.
490      */

491     public TestDiff getDiffer() {
492         if (fDiffer == null) {
493             int flags = TestDiff.QUEUE_FAILURES;
494             if (fUpdateExpected) {
495                 flags |= TestDiff.UPDATE_EXPECTED;
496             }
497             fDiffer = new TestDiff(fMsgWriter, flags);
498             addFilters(fDiffer);
499         }
500         return fDiffer;
501     }
502
503     /**
504      * Get a new diff object. If queue failures are requested, they
505      * are not automatically thrown as with <code>getDiffer()</code>.
506      */

507     public TestDiff createDiffer(boolean queueFailures) {
508         int flags = 0;
509         if (queueFailures) {
510             flags |= TestDiff.QUEUE_FAILURES;
511         }
512         if (fUpdateExpected) {
513             flags |= TestDiff.UPDATE_EXPECTED;
514         }
515         return new TestDiff(fMsgWriter, flags);
516     }
517
518     /**
519      * Get a class loader for use in the tests We need to have own instance of
520      * the classloader, as system classloader sees to cache file searchs and
521      * doesn't see newly created classes. Note that output directory must not
522      * be on the system classpath.
523      */

524     public ClassLoader JavaDoc createClassLoader() {
525         getClassRoot().mkdirs();
526         URL JavaDoc pathUrl = TestFileOps.dirToUrl(getClassRoot());
527         return new URLClassLoader JavaDoc(new URL JavaDoc[]{pathUrl},
528                                   getClass().getClassLoader());
529     }
530
531     /**
532      * Get the test classloader, creating if it doesn't exist.
533      */

534     public ClassLoader JavaDoc getTestClassLoader() {
535         if (fTestClassLoader == null) {
536             fTestClassLoader = createClassLoader();
537         }
538         return fTestClassLoader;
539     }
540
541     /**
542      * Print information about the class for debugging.
543      */

544     public void dumpInfo(PrintWriter JavaDoc out) {
545         out.println("testCase: " + getClass().getName());
546         out.println(" getName(): " + getName());
547         out.println(" getTestId(): " + getTestId());
548         out.println(" getTestCaseRoot(): " + getTestCaseRoot());
549         out.println(" getInputRoot(): " + getInputRoot());
550         out.println(" getUnqualTestId(): " + getUnqualTestId());
551         out.println(" getTestName(): " + getTestName());
552         out.println(" getTestPackage(): " + getTestPackage());
553         out.println(" getClassRoot(): " + getClassRoot());
554         out.println(" getPackageDir(): " + getPackageDir());
555         out.println(" getRelResultsDir(): " + getRelResultsDir());
556         out.println(" getResultsDir(): " + getResultsDir());
557         out.println(" getExpectedDir(): " + getExpectedDir());
558     }
559 }
560
561
Popular Tags