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.runner.Description;
008    import org.junit.runners.model.Statement;
009    
010    /**
011     * The RuleChain rule allows ordering of TestRules. You create a
012     * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
013     * {@link #around(TestRule)}:
014     *
015     * <pre>
016     * public static class UseRuleChain {
017     *      &#064;Rule
018     *      public RuleChain chain= RuleChain
019     *                             .outerRule(new LoggingRule("outer rule")
020     *                             .around(new LoggingRule("middle rule")
021     *                             .around(new LoggingRule("inner rule");
022     *
023     *      &#064;Test
024     *      public void example() {
025     *              assertTrue(true);
026     *     }
027     * }
028     * </pre>
029     *
030     * writes the log
031     *
032     * <pre>
033     * starting outer rule
034     * starting middle rule
035     * starting inner rule
036     * finished inner rule
037     * finished middle rule
038     * finished outer rule
039     * </pre>
040     *
041     * @since 4.10
042     */
043    public class RuleChain implements TestRule {
044        private static final RuleChain EMPTY_CHAIN = new RuleChain(
045                Collections.<TestRule>emptyList());
046    
047        private List<TestRule> rulesStartingWithInnerMost;
048    
049        /**
050         * Returns a {@code RuleChain} without a {@link TestRule}. This method may
051         * be the starting point of a {@code RuleChain}.
052         *
053         * @return a {@code RuleChain} without a {@link TestRule}.
054         */
055        public static RuleChain emptyRuleChain() {
056            return EMPTY_CHAIN;
057        }
058    
059        /**
060         * Returns a {@code RuleChain} with a single {@link TestRule}. This method
061         * is the usual starting point of a {@code RuleChain}.
062         *
063         * @param outerRule the outer rule of the {@code RuleChain}.
064         * @return a {@code RuleChain} with a single {@link TestRule}.
065         */
066        public static RuleChain outerRule(TestRule outerRule) {
067            return emptyRuleChain().around(outerRule);
068        }
069    
070        private RuleChain(List<TestRule> rules) {
071            this.rulesStartingWithInnerMost = rules;
072        }
073    
074        /**
075         * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
076         * the rules of the current {@code RuleChain}.
077         *
078         * @param enclosedRule the rule to enclose.
079         * @return a new {@code RuleChain}.
080         */
081        public RuleChain around(TestRule enclosedRule) {
082            List<TestRule> rulesOfNewChain = new ArrayList<TestRule>();
083            rulesOfNewChain.add(enclosedRule);
084            rulesOfNewChain.addAll(rulesStartingWithInnerMost);
085            return new RuleChain(rulesOfNewChain);
086        }
087    
088        /**
089         * {@inheritDoc}
090         */
091        public Statement apply(Statement base, Description description) {
092            for (TestRule each : rulesStartingWithInnerMost) {
093                base = each.apply(base, description);
094            }
095            return base;
096        }
097    }