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 }