001    package groovy.util;
002    
003    import groovy.lang.GroovyClassLoader;
004    import groovy.lang.Script;
005    import junit.framework.Test;
006    import junit.framework.TestSuite;
007    import org.codehaus.groovy.control.CompilationFailedException;
008    import org.codehaus.groovy.runtime.ScriptTestAdapter;
009    
010    import java.io.File;
011    import java.io.IOException;
012    import java.util.Collection;
013    import java.util.Iterator;
014    import java.util.logging.Logger;
015    
016    /**
017     * AllTestSuite can be used in extension of GroovyTestSuite to execute TestCases written in Groovy
018     * from inside a Java IDE.
019     * AllTestSuite collects all files below a given directory that comply to a given pattern.
020     * From these files, a TestSuite is constructed that can be run via an IDE graphical Test runner.
021     * The files are assumed to be Groovy source files and be either a TestCase or a Script that can
022     * be wrapped transparently into a TestCase.
023     * The directory and the pattern can be set via System properties (see this classes' constants for details.)
024     *
025     * When setting the loglevel of this class to FINEST, all file loading will be logged.
026     *
027     * See also groovy.util.AllTestSuiteTest.groovy
028     * @author Dierk Koenig based on a prototype by Andrew Glover
029     * todo: dk: make FileNameFinder injectable
030     */
031    public class AllTestSuite extends TestSuite {
032    
033        /** The System Property to set as base directory for collection of Test Cases.
034         * The pattern will be used as an Ant fileset include basedir.
035         * Key is "groovy.test.dir".
036         * Default value is "./test/".
037         */
038        public static final String SYSPROP_TEST_DIR = "groovy.test.dir";
039    
040        /** The System Property to set as the filename pattern for collection of Test Cases.
041         * The pattern will be used as Regualar Expression pattern applied with the find
042         * operator agains each candidate file.path.
043         * Key is "groovy.test.pattern".
044         * Default value is "Test.groovy".
045         */
046        public static final String SYSPROP_TEST_PATTERN = "groovy.test.pattern";
047    
048        private static Logger LOG = Logger.getLogger(AllTestSuite.class.getName());
049        private static ClassLoader JAVA_LOADER = AllTestSuite.class.getClassLoader();
050        private static GroovyClassLoader GROOVY_LOADER = new GroovyClassLoader(JAVA_LOADER);
051    
052        private static final String[] EMPTY_ARGS = new String[]{};
053        private static IFileNameFinder FINDER = null;
054    
055        static { // this is only needed since the Groovy Build compiles *.groovy files after *.java files
056            try {
057                Class finderClass = Class.forName("groovy.util.FileNameFinder");
058                FINDER = (IFileNameFinder) finderClass.newInstance();
059            } catch (Exception e) {
060                throw new RuntimeException("Cannot find and instantiate class FileNameFinder", e);
061            }
062        }
063    
064        public static Test suite() {
065            String basedir = System.getProperty(SYSPROP_TEST_DIR, "./test/");
066            String pattern = System.getProperty(SYSPROP_TEST_PATTERN, "**/*Test.groovy");
067            return suite(basedir, pattern);
068        }    
069    
070        public static Test suite(String basedir, String pattern) {
071            AllTestSuite suite = new AllTestSuite();
072            String fileName = "";
073            try {
074                Collection filenames = FINDER.getFileNames(basedir, pattern);
075                for (Iterator iter = filenames.iterator(); iter.hasNext();) {
076                    fileName = (String) iter.next();
077                    LOG.finest("trying to load "+ fileName);
078                    suite.loadTest(fileName);
079                }
080            } catch (CompilationFailedException e1) {
081                e1.printStackTrace();
082                throw new RuntimeException("CompilationFailedException when loading "+fileName, e1);
083            } catch (IOException e2) {
084                throw new RuntimeException("IOException when loading "+fileName, e2);
085            }
086            return suite;
087        }
088    
089        protected void loadTest(String fileName) throws CompilationFailedException, IOException {
090            Class type = compile(fileName);
091            if (!Test.class.isAssignableFrom(type) && Script.class.isAssignableFrom(type)) {
092                addTest(new ScriptTestAdapter(type, EMPTY_ARGS));
093            } else {
094                addTestSuite(type);
095            }
096        }
097    
098        protected Class compile(String fileName) throws CompilationFailedException, IOException {
099            return GROOVY_LOADER.parseClass(new File(fileName));
100        }
101    }