1package org.junit.runner.manipulation;
2
3import org.junit.runner.Description;
4import org.junit.runner.Request;
5
6/**
7 * The canonical case of filtering is when you want to run a single test method in a class. Rather
8 * than introduce runner API just for that one case, JUnit provides a general filtering mechanism.
9 * If you want to filter the tests to be run, extend <code>Filter</code> and apply an instance of
10 * your filter to the {@link org.junit.runner.Request} before running it (see
11 * {@link org.junit.runner.JUnitCore#run(Request)}. Alternatively, apply a <code>Filter</code> to
12 * a {@link org.junit.runner.Runner} before running tests (for example, in conjunction with
13 * {@link org.junit.runner.RunWith}.
14 */
15public abstract class Filter {
16	/**
17	 * A null <code>Filter</code> that passes all tests through.
18	 */
19	public static Filter ALL= new Filter() {
20		@Override
21		public boolean shouldRun(Description description) {
22			return true;
23		}
24
25		@Override
26		public String describe() {
27			return "all tests";
28		}
29
30		@Override
31		public void apply(Object child) throws NoTestsRemainException {
32			// do nothing
33		}
34
35		@Override
36		public Filter intersect(Filter second) {
37			return second;
38		}
39	};
40
41	/**
42	 * Returns a {@code Filter} that only runs the single method described by
43	 * {@code desiredDescription}
44	 */
45	public static Filter matchMethodDescription(final Description desiredDescription) {
46		return new Filter() {
47			@Override
48			public boolean shouldRun(Description description) {
49				if (description.isTest())
50					return desiredDescription.equals(description);
51
52				// explicitly check if any children want to run
53				for (Description each : description.getChildren())
54					if (shouldRun(each))
55						return true;
56				return false;
57			}
58
59			@Override
60			public String describe() {
61				return String.format("Method %s", desiredDescription.getDisplayName());
62			}
63		};
64	}
65
66
67	/**
68	 * @param description the description of the test to be run
69	 * @return <code>true</code> if the test should be run
70	 */
71	public abstract boolean shouldRun(Description description);
72
73	/**
74	 * Returns a textual description of this Filter
75	 * @return a textual description of this Filter
76	 */
77	public abstract String describe();
78
79	/**
80	 * Invoke with a {@link org.junit.runner.Runner} to cause all tests it intends to run
81	 * to first be checked with the filter. Only those that pass the filter will be run.
82	 * @param child the runner to be filtered by the receiver
83	 * @throws NoTestsRemainException if the receiver removes all tests
84	 */
85	public void apply(Object child) throws NoTestsRemainException {
86		if (!(child instanceof Filterable))
87			return;
88		Filterable filterable= (Filterable) child;
89		filterable.filter(this);
90	}
91
92	/**
93	 * Returns a new Filter that accepts the intersection of the tests accepted
94	 * by this Filter and {@code second}
95	 */
96	public Filter intersect(final Filter second) {
97		if (second == this || second == ALL) {
98			return this;
99		}
100		final Filter first= this;
101		return new Filter() {
102			@Override
103			public boolean shouldRun(Description description) {
104				return first.shouldRun(description)
105						&& second.shouldRun(description);
106			}
107
108			@Override
109			public String describe() {
110				return first.describe() + " and " + second.describe();
111			}
112		};
113	}
114}
115