    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    }