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.Rule; 8 import org.junit.runner.Description; 9 import org.junit.runners.model.Statement; 10 11 /** 12 * The {@code RuleChain} can be used for creating composite rules. You create a 13 * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of 14 * {@link #around(TestRule)}: 15 * 16 * <pre> 17 * public abstract class CompositeRules { 18 * public static TestRule extendedLogging() { 19 * return RuleChain.outerRule(new LoggingRule("outer rule")) 20 * .around(new LoggingRule("middle rule")) 21 * .around(new LoggingRule("inner rule")); 22 * } 23 * } 24 * </pre> 25 * 26 * <pre> 27 * public class UseRuleChain { 28 * @Rule 29 * public final TestRule extendedLogging = CompositeRules.extendedLogging(); 30 * 31 * @Test 32 * public void example() { 33 * assertTrue(true); 34 * } 35 * } 36 * </pre> 37 * 38 * writes the log 39 * 40 * <pre> 41 * starting outer rule 42 * starting middle rule 43 * starting inner rule 44 * finished inner rule 45 * finished middle rule 46 * finished outer rule 47 * </pre> 48 * 49 * In older versions of JUnit (before 4.13) {@code RuleChain} was used for 50 * ordering rules. We recommend to not use it for this purpose anymore. You can 51 * use the attribute {@code order} of the annotation {@link Rule#order() Rule} 52 * or {@link org.junit.ClassRule#order() ClassRule} for ordering rules. 53 * 54 * @see org.junit.Rule#order() 55 * @see org.junit.ClassRule#order() 56 * @since 4.10 57 */ 58 public class RuleChain implements TestRule { 59 private static final RuleChain EMPTY_CHAIN = new RuleChain( 60 Collections.<TestRule>emptyList()); 61 62 private List<TestRule> rulesStartingWithInnerMost; 63 64 /** 65 * Returns a {@code RuleChain} without a {@link TestRule}. This method may 66 * be the starting point of a {@code RuleChain}. 67 * 68 * @return a {@code RuleChain} without a {@link TestRule}. 69 */ emptyRuleChain()70 public static RuleChain emptyRuleChain() { 71 return EMPTY_CHAIN; 72 } 73 74 /** 75 * Returns a {@code RuleChain} with a single {@link TestRule}. This method 76 * is the usual starting point of a {@code RuleChain}. 77 * 78 * @param outerRule the outer rule of the {@code RuleChain}. 79 * @return a {@code RuleChain} with a single {@link TestRule}. 80 */ outerRule(TestRule outerRule)81 public static RuleChain outerRule(TestRule outerRule) { 82 return emptyRuleChain().around(outerRule); 83 } 84 RuleChain(List<TestRule> rules)85 private RuleChain(List<TestRule> rules) { 86 this.rulesStartingWithInnerMost = rules; 87 } 88 89 /** 90 * Create a new {@code RuleChain}, which encloses the given {@link TestRule} with 91 * the rules of the current {@code RuleChain}. 92 * 93 * @param enclosedRule the rule to enclose; must not be {@code null}. 94 * @return a new {@code RuleChain}. 95 * @throws NullPointerException if the argument {@code enclosedRule} is {@code null} 96 */ around(TestRule enclosedRule)97 public RuleChain around(TestRule enclosedRule) { 98 if (enclosedRule == null) { 99 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 */ apply(Statement base, Description description)110 public Statement apply(Statement base, Description description) { 111 return new RunRules(base, rulesStartingWithInnerMost, description); 112 } 113 }