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 * <p>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.</p>
19 *
20 * <p>The flow when JUnit runs tests is that a <code>Request</code> specifies some tests to be run ->
21 * a {@link org.junit.runner.Runner} is created for each class implied by the <code>Request</code> ->
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.</p>
24 */
25public abstract class Request {
26	/**
27	 * Create a <code>Request</code> that, when processed, will run a single test.
28	 * This is done by filtering out all other tests. This method is used to support rerunning
29	 * single tests.
30	 * @param clazz the class of the test
31	 * @param methodName the name of the test
32	 * @return a <code>Request</code> that will cause a single test be run
33	 */
34	public static Request method(Class<?> clazz, String methodName) {
35		Description method= Description.createTestDescription(clazz, methodName);
36		return Request.aClass(clazz).filterWith(method);
37	}
38
39	/**
40	 * Create a <code>Request</code> that, when processed, will run all the tests
41	 * in a class. The odd name is necessary because <code>class</code> is a reserved word.
42	 * @param clazz the class containing the tests
43	 * @return a <code>Request</code> that will cause all tests in the class to be run
44	 */
45	public static Request aClass(Class<?> clazz) {
46		return new ClassRequest(clazz);
47	}
48
49	/**
50	 * Create a <code>Request</code> that, when processed, will run all the tests
51	 * in a class. If the class has a suite() method, it will be ignored.
52	 * @param clazz the class containing the tests
53	 * @return a <code>Request</code> that will cause all tests in the class to be run
54	 */
55	public static Request classWithoutSuiteMethod(Class<?> clazz) {
56		return new ClassRequest(clazz, false);
57	}
58
59	/**
60	 * Create a <code>Request</code> that, when processed, will run all the tests
61	 * in a set of classes.
62	 * @param computer Helps construct Runners from classes
63	 * @param classes the classes containing the tests
64	 * @return a <code>Request</code> that will cause all tests in the classes to be run
65	 */
66	public static Request classes(Computer computer, Class<?>... classes) {
67		try {
68			AllDefaultPossibilitiesBuilder builder= new AllDefaultPossibilitiesBuilder(true);
69			Runner suite= computer.getSuite(builder, classes);
70			return runner(suite);
71		} catch (InitializationError e) {
72			throw new RuntimeException(
73					"Bug in saff's brain: Suite constructor, called as above, should always complete");
74		}
75	}
76
77	/**
78	 * Create a <code>Request</code> that, when processed, will run all the tests
79	 * in a set of classes with the default <code>Computer</code>.
80	 * @param classes the classes containing the tests
81	 * @return a <code>Request</code> that will cause all tests in the classes to be run
82	 */
83	public static Request classes(Class<?>... classes) {
84		return classes(JUnitCore.defaultComputer(), classes);
85	}
86
87
88	/**
89	 * Not used within JUnit.  Clients should simply instantiate ErrorReportingRunner themselves
90	 */
91	@Deprecated
92	public static Request errorReport(Class<?> klass, Throwable cause) {
93		return runner(new ErrorReportingRunner(klass, cause));
94	}
95
96	/**
97	 * @param runner the runner to return
98	 * @return a <code>Request</code> that will run the given runner when invoked
99	 */
100	public static Request runner(final Runner runner) {
101		return new Request(){
102			@Override
103			public Runner getRunner() {
104				return runner;
105			}
106		};
107	}
108
109	/**
110	 * Returns a {@link Runner} for this Request
111	 * @return corresponding {@link Runner} for this Request
112	 */
113	public abstract Runner getRunner();
114
115	/**
116	 * Returns a Request that only contains those tests that should run when
117	 * <code>filter</code> is applied
118	 * @param filter The {@link Filter} to apply to this Request
119	 * @return the filtered Request
120	 */
121	public Request filterWith(Filter filter) {
122		return new FilterRequest(this, filter);
123	}
124
125	/**
126	 * Returns a Request that only runs contains tests whose {@link Description}
127	 * equals <code>desiredDescription</code>
128	 * @param desiredDescription {@link Description} of those tests that should be run
129	 * @return the filtered Request
130	 */
131	public Request filterWith(final Description desiredDescription) {
132		return filterWith(Filter.matchMethodDescription(desiredDescription));
133	}
134
135	/**
136	 * Returns a Request whose Tests can be run in a certain order, defined by
137	 * <code>comparator</code>
138	 *
139	 * For example, here is code to run a test suite in alphabetical order:
140	 *
141	 * <pre>
142	private static Comparator<Description> forward() {
143		return new Comparator<Description>() {
144			public int compare(Description o1, Description o2) {
145				return o1.getDisplayName().compareTo(o2.getDisplayName());
146			}
147		};
148	}
149
150	public static main() {
151		new JUnitCore().run(Request.aClass(AllTests.class).sortWith(forward()));
152	}
153	 * </pre>
154	 *
155	 * @param comparator definition of the order of the tests in this Request
156	 * @return a Request with ordered Tests
157	 */
158	public Request sortWith(Comparator<Description> comparator) {
159		return new SortingRequest(this, comparator);
160	}
161}
162