1package org.junit.runner;
2
3import java.util.Comparator;
4
5import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
6import org.junit.internal.requests.ClassRequest;
7import org.junit.internal.requests.FilterRequest;
8import org.junit.internal.requests.SortingRequest;
9import org.junit.internal.runners.ErrorReportingRunner;
10import org.junit.runner.manipulation.Filter;
11import org.junit.runners.model.InitializationError;
12
13/**
14 * A <code>Request</code> is an abstract description of tests to be run. Older versions of
15 * JUnit did not need such a concept--tests to be run were described either by classes containing
16 * tests or a tree of {@link  org.junit.Test}s. However, we want to support filtering and sorting,
17 * so we need a more abstract specification than the tests themselves and a richer
18 * specification than just the classes.
19 *
20 * <p>The flow when JUnit runs tests is that a <code>Request</code> specifies some tests to be run -&gt;
21 * a {@link org.junit.runner.Runner} is created for each class implied by the <code>Request</code> -&gt;
22 * the {@link org.junit.runner.Runner} returns a detailed {@link org.junit.runner.Description}
23 * which is a tree structure of the tests to be run.
24 *
25 * @since 4.0
26 */
27public abstract class Request {
28    /**
29     * Create a <code>Request</code> that, when processed, will run a single test.
30     * This is done by filtering out all other tests. This method is used to support rerunning
31     * single tests.
32     *
33     * @param clazz the class of the test
34     * @param methodName the name of the test
35     * @return a <code>Request</code> that will cause a single test be run
36     */
37    public static Request method(Class<?> clazz, String methodName) {
38        Description method = Description.createTestDescription(clazz, methodName);
39        return Request.aClass(clazz).filterWith(method);
40    }
41
42    /**
43     * Create a <code>Request</code> that, when processed, will run all the tests
44     * in a class. The odd name is necessary because <code>class</code> is a reserved word.
45     *
46     * @param clazz the class containing the tests
47     * @return a <code>Request</code> that will cause all tests in the class to be run
48     */
49    public static Request aClass(Class<?> clazz) {
50        return new ClassRequest(clazz);
51    }
52
53    /**
54     * Create a <code>Request</code> that, when processed, will run all the tests
55     * in a class. If the class has a suite() method, it will be ignored.
56     *
57     * @param clazz the class containing the tests
58     * @return a <code>Request</code> that will cause all tests in the class to be run
59     */
60    public static Request classWithoutSuiteMethod(Class<?> clazz) {
61        return new ClassRequest(clazz, false);
62    }
63
64    /**
65     * Create a <code>Request</code> that, when processed, will run all the tests
66     * in a set of classes.
67     *
68     * @param computer Helps construct Runners from classes
69     * @param classes the classes containing the tests
70     * @return a <code>Request</code> that will cause all tests in the classes to be run
71     */
72    public static Request classes(Computer computer, Class<?>... classes) {
73        try {
74            AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true);
75            Runner suite = computer.getSuite(builder, classes);
76            return runner(suite);
77        } catch (InitializationError e) {
78            throw new RuntimeException(
79                    "Bug in saff's brain: Suite constructor, called as above, should always complete");
80        }
81    }
82
83    /**
84     * Create a <code>Request</code> that, when processed, will run all the tests
85     * in a set of classes with the default <code>Computer</code>.
86     *
87     * @param classes the classes containing the tests
88     * @return a <code>Request</code> that will cause all tests in the classes to be run
89     */
90    public static Request classes(Class<?>... classes) {
91        return classes(JUnitCore.defaultComputer(), classes);
92    }
93
94
95    /**
96     * Creates a {@link Request} that, when processed, will report an error for the given
97     * test class with the given cause.
98     */
99    public static Request errorReport(Class<?> klass, Throwable cause) {
100        return runner(new ErrorReportingRunner(klass, cause));
101    }
102
103    /**
104     * @param runner the runner to return
105     * @return a <code>Request</code> that will run the given runner when invoked
106     */
107    public static Request runner(final Runner runner) {
108        return new Request() {
109            @Override
110            public Runner getRunner() {
111                return runner;
112            }
113        };
114    }
115
116    /**
117     * Returns a {@link Runner} for this Request
118     *
119     * @return corresponding {@link Runner} for this Request
120     */
121    public abstract Runner getRunner();
122
123    /**
124     * Returns a Request that only contains those tests that should run when
125     * <code>filter</code> is applied
126     *
127     * @param filter The {@link Filter} to apply to this Request
128     * @return the filtered Request
129     */
130    public Request filterWith(Filter filter) {
131        return new FilterRequest(this, filter);
132    }
133
134    /**
135     * Returns a Request that only runs contains tests whose {@link Description}
136     * equals <code>desiredDescription</code>
137     *
138     * @param desiredDescription {@link Description} of those tests that should be run
139     * @return the filtered Request
140     */
141    public Request filterWith(final Description desiredDescription) {
142        return filterWith(Filter.matchMethodDescription(desiredDescription));
143    }
144
145    /**
146     * Returns a Request whose Tests can be run in a certain order, defined by
147     * <code>comparator</code>
148     * <p>
149     * For example, here is code to run a test suite in alphabetical order:
150     * <pre>
151     * private static Comparator&lt;Description&gt; forward() {
152     * return new Comparator&lt;Description&gt;() {
153     * public int compare(Description o1, Description o2) {
154     * return o1.getDisplayName().compareTo(o2.getDisplayName());
155     * }
156     * };
157     * }
158     *
159     * public static main() {
160     * new JUnitCore().run(Request.aClass(AllTests.class).sortWith(forward()));
161     * }
162     * </pre>
163     *
164     * @param comparator definition of the order of the tests in this Request
165     * @return a Request with ordered Tests
166     */
167    public Request sortWith(Comparator<Description> comparator) {
168        return new SortingRequest(this, comparator);
169    }
170}
171