1 package org.junit.rules;
2 
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 
7 import org.junit.runner.Description;
8 import org.junit.runners.model.Statement;
9 
10 /**
11  * The RuleChain rule allows ordering of TestRules. You create a
12  * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
13  * {@link #around(TestRule)}:
14  *
15  * <pre>
16  * public static class UseRuleChain {
17  * 	&#064;Rule
18  * 	public RuleChain chain= RuleChain
19  * 	                       .outerRule(new LoggingRule("outer rule")
20  * 	                       .around(new LoggingRule("middle rule")
21  * 	                       .around(new LoggingRule("inner rule");
22  *
23  * 	&#064;Test
24  * 	public void example() {
25  * 		assertTrue(true);
26  *     }
27  * }
28  * </pre>
29  *
30  * writes the log
31  *
32  * <pre>
33  * starting outer rule
34  * starting middle rule
35  * starting inner rule
36  * finished inner rule
37  * finished middle rule
38  * finished outer rule
39  * </pre>
40  *
41  * @since 4.10
42  */
43 public class RuleChain implements TestRule {
44     private static final RuleChain EMPTY_CHAIN = new RuleChain(
45             Collections.<TestRule>emptyList());
46 
47     private List<TestRule> rulesStartingWithInnerMost;
48 
49     /**
50      * Returns a {@code RuleChain} without a {@link TestRule}. This method may
51      * be the starting point of a {@code RuleChain}.
52      *
53      * @return a {@code RuleChain} without a {@link TestRule}.
54      */
emptyRuleChain()55     public static RuleChain emptyRuleChain() {
56         return EMPTY_CHAIN;
57     }
58 
59     /**
60      * Returns a {@code RuleChain} with a single {@link TestRule}. This method
61      * is the usual starting point of a {@code RuleChain}.
62      *
63      * @param outerRule the outer rule of the {@code RuleChain}.
64      * @return a {@code RuleChain} with a single {@link TestRule}.
65      */
outerRule(TestRule outerRule)66     public static RuleChain outerRule(TestRule outerRule) {
67         return emptyRuleChain().around(outerRule);
68     }
69 
RuleChain(List<TestRule> rules)70     private RuleChain(List<TestRule> rules) {
71         this.rulesStartingWithInnerMost = rules;
72     }
73 
74     /**
75      * Create a new {@code RuleChain}, which encloses the {@code nextRule} with
76      * the rules of the current {@code RuleChain}.
77      *
78      * @param enclosedRule the rule to enclose.
79      * @return a new {@code RuleChain}.
80      */
around(TestRule enclosedRule)81     public RuleChain around(TestRule enclosedRule) {
82         List<TestRule> rulesOfNewChain = new ArrayList<TestRule>();
83         rulesOfNewChain.add(enclosedRule);
84         rulesOfNewChain.addAll(rulesStartingWithInnerMost);
85         return new RuleChain(rulesOfNewChain);
86     }
87 
88     /**
89      * {@inheritDoc}
90      */
apply(Statement base, Description description)91     public Statement apply(Statement base, Description description) {
92         for (TestRule each : rulesStartingWithInnerMost) {
93             base = each.apply(base, description);
94         }
95         return base;
96     }
97 }