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 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 * {@code RuleChain} cannot be used to define the order of existing rules. 042 * For example in the below snippet the LoggingRule {@code middle} would be 043 * executed outside as well as inside the {@code RuleChain}: 044 * 045 * <pre> 046 * @Rule 047 * public LoggingRule middle = new LoggingRule("middle rule"); 048 * 049 * @Rule 050 * public RuleChain chain = RuleChain 051 * .outerRule(new LoggingRule("outer rule")) 052 * .around(middle) 053 * .around(new LoggingRule("inner rule")); 054 * </pre> 055 * 056 * @deprecated Since 4.13 ordering of rules can be naturally specified with an annotation attribute. 057 * @see org.junit.Rule#order() 058 * @see org.junit.ClassRule#order() 059 * @since 4.10 060 */ 061 @Deprecated 062 public class RuleChain implements TestRule { 063 private static final RuleChain EMPTY_CHAIN = new RuleChain( 064 Collections.<TestRule>emptyList()); 065 066 private List<TestRule> rulesStartingWithInnerMost; 067 068 /** 069 * Returns a {@code RuleChain} without a {@link TestRule}. This method may 070 * be the starting point of a {@code RuleChain}. 071 * 072 * @return a {@code RuleChain} without a {@link TestRule}. 073 */ 074 public static RuleChain emptyRuleChain() { 075 return EMPTY_CHAIN; 076 } 077 078 /** 079 * Returns a {@code RuleChain} with a single {@link TestRule}. This method 080 * is the usual starting point of a {@code RuleChain}. 081 * 082 * @param outerRule the outer rule of the {@code RuleChain}. 083 * @return a {@code RuleChain} with a single {@link TestRule}. 084 */ 085 public static RuleChain outerRule(TestRule outerRule) { 086 return emptyRuleChain().around(outerRule); 087 } 088 089 private RuleChain(List<TestRule> rules) { 090 this.rulesStartingWithInnerMost = rules; 091 } 092 093 /** 094 * Create a new {@code RuleChain}, which encloses the given {@link TestRule} with 095 * the rules of the current {@code RuleChain}. 096 * 097 * @param enclosedRule the rule to enclose; must not be {@code null}. 098 * @return a new {@code RuleChain}. 099 * @throws NullPointerException if the argument {@code enclosedRule} is {@code null} 100 */ 101 public RuleChain around(TestRule enclosedRule) { 102 if (enclosedRule == null) { 103 throw new NullPointerException("The enclosed rule must not be null"); 104 } 105 List<TestRule> rulesOfNewChain = new ArrayList<TestRule>(); 106 rulesOfNewChain.add(enclosedRule); 107 rulesOfNewChain.addAll(rulesStartingWithInnerMost); 108 return new RuleChain(rulesOfNewChain); 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 public Statement apply(Statement base, Description description) { 115 return new RunRules(base, rulesStartingWithInnerMost, description); 116 } 117 }