package junit.extensions.abbot; import java.io.File; import java.lang.reflect.Constructor; import java.util.*; import junit.framework.*; import abbot.Log; import abbot.script.Script; //import junit.ui.TestRunner; //import junit.swingui; /** Similar to TestSuite, except that it auto-generates a suite based on test * scripts matching certain criteria. * <p> * By default, generate a suite of all scripts found in a given directory for * which the accept method returns true. Note that there is no guarantee of * the order of the scripts. * <p> * The ScriptTestSuite constructors which require a class argument provide a * means for using custom fixtures derived from * <a href="ScriptFixture.html">ScriptFixture</a>. The default fixture * preserves existing environment windows (e.g. the JUnit Swing UI TestRunner) * and disposes of all windows generated by the code under test. Derived * fixtures may provide arbitrary code in their setUp/tearDown methods (such * as install/uninstall a custom security manager, set system properties, * etc), the same as you would do in any other derivation of * junit.framework.TestCase. * <p> * <h3>Example 1</h3> * Following is a ScriptTestSuite which will aggregate all tests in the * directory "src/example", whose filenames begin with "MyCode-" and end with * ".xml":<br> * <pre><code> * public class MyCodeTest extends ScriptFixture { * public MyCodeTest(String name) { super(name); } * public static Test suite() { * return new ScriptTestSuite(MyCodeTest.class, "src/example") { * public boolean accept(File file) { * String name = file.getName(); * return name.startsWith("MyCode-") && name.endsWith(".xml"); * } * }; * } * } * </code></pre> */ public class ScriptTestSuite extends TestSuite { private File primaryDirectory; /** Constructs a suite of tests from all the scripts found in the directory specified by the system property "abbot.testsuite.path". The most common use for this constructor would be from an Ant 'junit' task, where the system property is defined for a given run. The suite will recurse directories if "abbot.testsuite.path.recurse" is set to true. */ public ScriptTestSuite() { this(ScriptFixture.class, System.getProperty("abbot.testsuite.path", System.getProperty("user.dir")), Boolean.getBoolean("abbot.testsuite.path.recurse")); } /** Constructs a suite of tests from all the scripts found in the current * directory. Does not recurse to subdirectories. The Class argument * must be a subclass of junit.extensions.abbot.ScriptFixture. */ public ScriptTestSuite(Class fixtureClass) { this(fixtureClass, System.getProperty("user.dir"), false); } /** Constructs a suite of tests from all the scripts found in the given * directory. Does not recurse to subdirectories. The Class argument * must be a subclass of junit.extensions.abbot.ScriptFixture. */ public ScriptTestSuite(Class fixtureClass, String dirname) { this(fixtureClass, dirname, false); } /** Constructs an ScriptTestSuite from all the scripts in the given * directory, recursing if recurse is true. The Class argument * must be a class derived from junit.extensions.abbot.ScriptFixture. */ public ScriptTestSuite(Class fixtureClass, String dirname, boolean recurse) { this(fixtureClass, findFilenames(dirname, recurse)); primaryDirectory = new File(dirname); if (!primaryDirectory.exists() || !primaryDirectory.isDirectory()) { String msg = "Directory '" + dirname + "' did not exist" + " when scanning for test scripts"; addTest(warnings(msg)); } } /** Constructs a suite of tests for each script given in the argument * list. */ public ScriptTestSuite(String[] filenames) { this(ScriptFixture.class, filenames); } /** Constructs a suite of tests for each script given in the argument * list, using the given class derived from ScriptFixture to wrap each * script. */ public ScriptTestSuite(Class fixtureClass, String[] filenames) { super(fixtureClass.getName()); primaryDirectory = new File(System.getProperty("user.dir")); Log.debug("Loading " + fixtureClass + ", with " + filenames.length + " files"); for (int i=0;i < filenames.length;i++) { File file = new File(filenames[i]); // Filter for desired files only if (!accept(file)) continue; try { Log.debug("Attempting to create " + fixtureClass); Constructor ctor = fixtureClass.getConstructor(new Class[] { String.class }); Test test = (Test)ctor.newInstance(new Object[] { file.getAbsolutePath() }); Log.debug("Created an instance of " + fixtureClass); addTest(test); } catch(Throwable thr) { Log.warn(thr); addTest(warnings("Could not construct an instance of " + fixtureClass)); break; } } if (testCount() == 0) { addTest(warnings("No scripts found")); } } public File getDirectory() { return primaryDirectory; } /** Return whether to accept the given file. The default implementation * omits common backup files. */ public boolean accept(File file) { String name = file.getName(); return !name.startsWith(".#") && !name.endsWith("~") && !name.endsWith(".bak"); } /** * Returns a test which will fail and log a warning message. */ private Test warnings(final String message) { return new TestCase("warning") { protected void runTest() { fail(message); } }; } /** Add all test scripts in the given directory, optionally recursing to * subdirectories. Returns a list of absolute paths. */ protected static List findTestScripts(File dir, List files, boolean recurse) { File[] flist = dir.listFiles(); for (int i=0;flist != null && i < flist.length;i++) { //Log.debug("Examining " + flist[i]); if (flist[i].isDirectory()) { if (recurse) findTestScripts(flist[i], files, recurse); } else if (Script.isScript(flist[i])) { String filename = flist[i].getAbsolutePath(); if (!files.contains(filename)) { Log.debug("Adding " + filename); files.add(filename); } } } return files; } /** Scan for test scripts and return an array of filenames for all scripts found. */ static String[] findFilenames(String dirname, boolean recurse) { File dir = new File(dirname); ArrayList list = new ArrayList(); if (dir.exists() && dir.isDirectory()) { findTestScripts(dir, list, recurse); } return (String[])list.toArray(new String[list.size()]); } /** Run all scripts on the command line as a single suite. */ public static void main(String[] args) { args = Log.init(args); ScriptTestSuite suite = new ScriptTestSuite(args); junit.textui.TestRunner runner = new junit.textui.TestRunner(); try { TestResult r = runner.doRun(suite, false); if (!r.wasSuccessful()) System.exit(-1); System.exit(0); } catch(Throwable thr) { System.err.println(thr.getMessage()); System.exit(-2); } } }