001    package org.junit.runner.manipulation;
002    
003    import org.junit.runner.Description;
004    import org.junit.runner.Request;
005    
006    /**
007     * The canonical case of filtering is when you want to run a single test method in a class. Rather
008     * than introduce runner API just for that one case, JUnit provides a general filtering mechanism.
009     * If you want to filter the tests to be run, extend <code>Filter</code> and apply an instance of
010     * your filter to the {@link org.junit.runner.Request} before running it (see
011     * {@link org.junit.runner.JUnitCore#run(Request)}. Alternatively, apply a <code>Filter</code> to
012     * a {@link org.junit.runner.Runner} before running tests (for example, in conjunction with
013     * {@link org.junit.runner.RunWith}.
014     *
015     * @since 4.0
016     */
017    public abstract class Filter {
018        /**
019         * A null <code>Filter</code> that passes all tests through.
020         */
021        public static final Filter ALL = new Filter() {
022            @Override
023            public boolean shouldRun(Description description) {
024                return true;
025            }
026    
027            @Override
028            public String describe() {
029                return "all tests";
030            }
031    
032            @Override
033            public void apply(Object child) throws NoTestsRemainException {
034                // do nothing
035            }
036    
037            @Override
038            public Filter intersect(Filter second) {
039                return second;
040            }
041        };
042    
043        /**
044         * Returns a {@code Filter} that only runs the single method described by
045         * {@code desiredDescription}
046         */
047        public static Filter matchMethodDescription(final Description desiredDescription) {
048            return new Filter() {
049                @Override
050                public boolean shouldRun(Description description) {
051                    if (description.isTest()) {
052                        return desiredDescription.equals(description);
053                    }
054    
055                    // explicitly check if any children want to run
056                    for (Description each : description.getChildren()) {
057                        if (shouldRun(each)) {
058                            return true;
059                        }
060                    }
061                    return false;
062                }
063    
064                @Override
065                public String describe() {
066                    return String.format("Method %s", desiredDescription.getDisplayName());
067                }
068            };
069        }
070    
071    
072        /**
073         * @param description the description of the test to be run
074         * @return <code>true</code> if the test should be run
075         */
076        public abstract boolean shouldRun(Description description);
077    
078        /**
079         * Returns a textual description of this Filter
080         *
081         * @return a textual description of this Filter
082         */
083        public abstract String describe();
084    
085        /**
086         * Invoke with a {@link org.junit.runner.Runner} to cause all tests it intends to run
087         * to first be checked with the filter. Only those that pass the filter will be run.
088         *
089         * @param child the runner to be filtered by the receiver
090         * @throws NoTestsRemainException if the receiver removes all tests
091         */
092        public void apply(Object child) throws NoTestsRemainException {
093            if (!(child instanceof Filterable)) {
094                return;
095            }
096            Filterable filterable = (Filterable) child;
097            filterable.filter(this);
098        }
099    
100        /**
101         * Returns a new Filter that accepts the intersection of the tests accepted
102         * by this Filter and {@code second}
103         */
104        public Filter intersect(final Filter second) {
105            if (second == this || second == ALL) {
106                return this;
107            }
108            final Filter first = this;
109            return new Filter() {
110                @Override
111                public boolean shouldRun(Description description) {
112                    return first.shouldRun(description)
113                            && second.shouldRun(description);
114                }
115    
116                @Override
117                public String describe() {
118                    return first.describe() + " and " + second.describe();
119                }
120            };
121        }
122    }