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 * @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 * @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 }