001    package org.junit.rules;
002    
003    import java.util.ArrayList;
004    import java.util.Collections;
005    import java.util.List;
006    
007    import org.junit.Rule;
008    import org.junit.runner.Description;
009    import org.junit.runners.model.Statement;
010    
011    /**
012     * The {@code RuleChain} can be used for creating composite rules. You create a
013     * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
014     * {@link #around(TestRule)}:
015     *
016     * <pre>
017     * public abstract class CompositeRules {
018     *   public static TestRule extendedLogging() {
019     *     return RuleChain.outerRule(new LoggingRule("outer rule"))
020     *                     .around(new LoggingRule("middle rule"))
021     *                     .around(new LoggingRule("inner rule"));
022     *   }
023     * }
024     * </pre>
025     *
026     * <pre>
027     * public class UseRuleChain {
028     *   &#064;Rule
029     *   public final TestRule extendedLogging = CompositeRules.extendedLogging();
030     *
031     *   &#064;Test
032     *   public void example() {
033     *     assertTrue(true);
034     *   }
035     * }
036     * </pre>
037     *
038     * writes the log
039     *
040     * <pre>
041     * starting outer rule
042     * starting middle rule
043     * starting inner rule
044     * finished inner rule
045     * finished middle rule
046     * finished outer rule
047     * </pre>
048     *
049     * In older versions of JUnit (before 4.13) {@code RuleChain} was used for
050     * ordering rules. We recommend to not use it for this purpose anymore. You can
051     * use the attribute {@code order} of the annotation {@link Rule#order() Rule}
052     * or {@link org.junit.ClassRule#order() ClassRule} for ordering rules.
053     *
054     * @see org.junit.Rule#order()
055     * @see org.junit.ClassRule#order()
056     * @since 4.10
057     */
058    public class RuleChain implements TestRule {
059        private static final RuleChain EMPTY_CHAIN = new RuleChain(
060                Collections.<TestRule>emptyList());
061    
062        private List<TestRule> rulesStartingWithInnerMost;
063    
064        /**
065         * Returns a {@code RuleChain} without a {@link TestRule}. This method may
066         * be the starting point of a {@code RuleChain}.
067         *
068         * @return a {@code RuleChain} without a {@link TestRule}.
069         */
070        public static RuleChain emptyRuleChain() {
071            return EMPTY_CHAIN;
072        }
073    
074        /**
075         * Returns a {@code RuleChain} with a single {@link TestRule}. This method
076         * is the usual starting point of a {@code RuleChain}.
077         *
078         * @param outerRule the outer rule of the {@code RuleChain}.
079         * @return a {@code RuleChain} with a single {@link TestRule}.
080         */
081        public static RuleChain outerRule(TestRule outerRule) {
082            return emptyRuleChain().around(outerRule);
083        }
084    
085        private RuleChain(List<TestRule> rules) {
086            this.rulesStartingWithInnerMost = rules;
087        }
088    
089        /**
090         * Create a new {@code RuleChain}, which encloses the given {@link TestRule} with
091         * the rules of the current {@code RuleChain}.
092         *
093         * @param enclosedRule the rule to enclose; must not be {@code null}.
094         * @return a new {@code RuleChain}.
095         * @throws NullPointerException if the argument {@code enclosedRule} is {@code null}
096         */
097        public RuleChain around(TestRule enclosedRule) {
098            if (enclosedRule == null) {
099                throw new NullPointerException("The enclosed rule must not be null");
100            }
101            List<TestRule> rulesOfNewChain = new ArrayList<TestRule>();
102            rulesOfNewChain.add(enclosedRule);
103            rulesOfNewChain.addAll(rulesStartingWithInnerMost);
104            return new RuleChain(rulesOfNewChain);
105        }
106    
107        /**
108         * {@inheritDoc}
109         */
110        public Statement apply(Statement base, Description description) {
111            return new RunRules(base, rulesStartingWithInnerMost, description);
112        }
113    }