001package org.junit.runner;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import junit.runner.Version;
007import org.junit.internal.JUnitSystem;
008import org.junit.internal.RealSystem;
009import org.junit.internal.TextListener;
010import org.junit.internal.runners.JUnit38ClassRunner;
011import org.junit.runner.notification.Failure;
012import org.junit.runner.notification.RunListener;
013import org.junit.runner.notification.RunNotifier;
014
015/**
016 * <code>JUnitCore</code> is a facade for running tests. It supports running JUnit 4 tests,
017 * JUnit 3.8.x tests, and mixtures. To run tests from the command line, run
018 * <code>java org.junit.runner.JUnitCore TestClass1 TestClass2 ...</code>.
019 * For one-shot test runs, use the static method {@link #runClasses(Class[])}.
020 * If you want to add special listeners,
021 * create an instance of {@link org.junit.runner.JUnitCore} first and use it to run the tests.
022 *
023 * @see org.junit.runner.Result
024 * @see org.junit.runner.notification.RunListener
025 * @see org.junit.runner.Request
026 * @since 4.0
027 */
028public class JUnitCore {
029    private final RunNotifier fNotifier = new RunNotifier();
030
031    /**
032     * Run the tests contained in the classes named in the <code>args</code>.
033     * If all tests run successfully, exit with a status of 0. Otherwise exit with a status of 1.
034     * Write feedback while tests are running and write
035     * stack traces for all failed tests after the tests all complete.
036     *
037     * @param args names of classes in which to find tests to run
038     */
039    public static void main(String... args) {
040        runMainAndExit(new RealSystem(), args);
041    }
042
043    /**
044     * Runs main and exits
045     */
046    private static void runMainAndExit(JUnitSystem system, String... args) {
047        Result result = new JUnitCore().runMain(system, args);
048        System.exit(result.wasSuccessful() ? 0 : 1);
049    }
050
051    /**
052     * Run the tests contained in <code>classes</code>. Write feedback while the tests
053     * are running and write stack traces for all failed tests after all tests complete. This is
054     * similar to {@link #main(String[])}, but intended to be used programmatically.
055     *
056     * @param computer Helps construct Runners from classes
057     * @param classes Classes in which to find tests
058     * @return a {@link Result} describing the details of the test run and the failed tests.
059     */
060    public static Result runClasses(Computer computer, Class<?>... classes) {
061        return new JUnitCore().run(computer, classes);
062    }
063
064    /**
065     * Run the tests contained in <code>classes</code>. Write feedback while the tests
066     * are running and write stack traces for all failed tests after all tests complete. This is
067     * similar to {@link #main(String[])}, but intended to be used programmatically.
068     *
069     * @param classes Classes in which to find tests
070     * @return a {@link Result} describing the details of the test run and the failed tests.
071     */
072    public static Result runClasses(Class<?>... classes) {
073        return new JUnitCore().run(defaultComputer(), classes);
074    }
075
076    /**
077     * @param system
078     * @args args from main()
079     */
080    private Result runMain(JUnitSystem system, String... args) {
081        system.out().println("JUnit version " + Version.id());
082        List<Class<?>> classes = new ArrayList<Class<?>>();
083        List<Failure> missingClasses = new ArrayList<Failure>();
084        for (String each : args) {
085            try {
086                classes.add(Class.forName(each));
087            } catch (ClassNotFoundException e) {
088                system.out().println("Could not find class: " + each);
089                Description description = Description.createSuiteDescription(each);
090                Failure failure = new Failure(description, e);
091                missingClasses.add(failure);
092            }
093        }
094        RunListener listener = new TextListener(system);
095        addListener(listener);
096        Result result = run(classes.toArray(new Class[0]));
097        for (Failure each : missingClasses) {
098            result.getFailures().add(each);
099        }
100        return result;
101    }
102
103    /**
104     * @return the version number of this release
105     */
106    public String getVersion() {
107        return Version.id();
108    }
109
110    /**
111     * Run all the tests in <code>classes</code>.
112     *
113     * @param classes the classes containing tests
114     * @return a {@link Result} describing the details of the test run and the failed tests.
115     */
116    public Result run(Class<?>... classes) {
117        return run(Request.classes(defaultComputer(), classes));
118    }
119
120    /**
121     * Run all the tests in <code>classes</code>.
122     *
123     * @param computer Helps construct Runners from classes
124     * @param classes the classes containing tests
125     * @return a {@link Result} describing the details of the test run and the failed tests.
126     */
127    public Result run(Computer computer, Class<?>... classes) {
128        return run(Request.classes(computer, classes));
129    }
130
131    /**
132     * Run all the tests contained in <code>request</code>.
133     *
134     * @param request the request describing tests
135     * @return a {@link Result} describing the details of the test run and the failed tests.
136     */
137    public Result run(Request request) {
138        return run(request.getRunner());
139    }
140
141    /**
142     * Run all the tests contained in JUnit 3.8.x <code>test</code>. Here for backward compatibility.
143     *
144     * @param test the old-style test
145     * @return a {@link Result} describing the details of the test run and the failed tests.
146     */
147    public Result run(junit.framework.Test test) {
148        return run(new JUnit38ClassRunner(test));
149    }
150
151    /**
152     * Do not use. Testing purposes only.
153     */
154    public Result run(Runner runner) {
155        Result result = new Result();
156        RunListener listener = result.createListener();
157        fNotifier.addFirstListener(listener);
158        try {
159            fNotifier.fireTestRunStarted(runner.getDescription());
160            runner.run(fNotifier);
161            fNotifier.fireTestRunFinished(result);
162        } finally {
163            removeListener(listener);
164        }
165        return result;
166    }
167
168    /**
169     * Add a listener to be notified as the tests run.
170     *
171     * @param listener the listener to add
172     * @see org.junit.runner.notification.RunListener
173     */
174    public void addListener(RunListener listener) {
175        fNotifier.addListener(listener);
176    }
177
178    /**
179     * Remove a listener.
180     *
181     * @param listener the listener to remove
182     */
183    public void removeListener(RunListener listener) {
184        fNotifier.removeListener(listener);
185    }
186
187    static Computer defaultComputer() {
188        return new Computer();
189    }
190
191}