001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit;
021
022import java.util.function.Consumer;
023import java.util.function.Supplier;
024
025import org.mockito.MockitoAnnotations;
026
027/**
028 * Definition of a test rule (modification of a test statement).
029 * <p>
030 * TestRule are the only way (outside of the &#64;Parameters concept) to
031 * provides test fixtures, action before and after tests, etc. Only one
032 * <code>TestRule</code> chain is allowed for a test class. If a test class
033 * extends another one, one chain is allowed for each test class and they will
034 * be chained from the upper class to the lower one.
035 * <p>
036 * Conceptually, a test rule, at execution time, will receive a test statement
037 * as parameter and compute another test statement.
038 * <h3>Test Rule chain</h3>
039 * A test rule chain is public final, non static, field, of type
040 * <code>TestRule</code>. Once you have the outer test rule, it is possible to
041 * chain them by using the {@link #around(TestRule)} or
042 * {@link #around(Supplier)} methods. One single TestRule (which can be used as
043 * a start of the chain, or later), can be builded by :
044 * <ul>
045 * <li>Simply using the constructor (or other way) provided by the rule itself
046 * (for instance see the {@link ch.powerunit.rules.TestContextRule
047 * TestContextRule} rule.</li>
048 * <li>Use the <code>before</code> method that will produce a rule to be
049 * executed before a test ; The <code>after</code> method will do the same, but
050 * with a code to be executed after a test.</li>
051 * </ul>
052 *
053 * <h3>Example</h3>
054 * For instance, for this class:
055 *
056 * <pre>
057 * import org.mockito.Mock;
058 * import org.mockito.Mockito;
059 * import ch.powerunit.Rule;
060 * import ch.powerunit.Test;
061 * import ch.powerunit.TestRule;
062 * import ch.powerunit.TestSuite;
063 * 
064 * public class MockitoRuleTest implements TestSuite {
065 *     public interface Mockable {
066 *         void run();
067 *     }
068 * 
069 *     &#064;Mock
070 *     private Mockable mock;
071 * 
072 *     &#064;Rule
073 *     public final TestRule testRule = mockitoRule()
074 *             .around(before(this::prepare));
075 * 
076 *     public void prepare() {
077 *         Mockito.doThrow(new RuntimeException(&quot;test&quot;)).when(mock).run();
078 *     }
079 * 
080 *     &#064;Test
081 *     public void testException() {
082 *         assertWhen((p) -&gt; mock.run()).throwException(
083 *                 isA(RuntimeException.class));
084 *     }
085 * 
086 * }
087 * </pre>
088 *
089 * In this case, the defined chain, will first apply the rule provided by
090 * <code>mockitoRule</code>, and then apply the rule included inside the
091 * <code>around</code>. The <code>before</code> method usage inside the
092 * <code>around</code> will ensure the method <code>prepare</code> is executed
093 * before each test.
094 * <p>
095 * The sequence of execution, will be :
096 * <ol>
097 * <li>Execute the Mockito initialization.</li>
098 * <li>Execute the method <code>prepare</code>.</li>
099 * <li>Execute the test method <code>testException</code>.</li>
100 * </ol>
101 *
102 * @author borettim
103 *
104 */
105@FunctionalInterface
106public interface TestRule {
107    /**
108     * The default implementation of test rule.
109     * <p>
110     * The goal of this method is to compute another test statement that will be
111     * the one to be runned.
112     * 
113     * @param inner
114     *            the inner statement
115     * @return the new statement, as modified by this rule.
116     */
117    Statement<TestContext<Object>, Throwable> computeStatement(
118            Statement<TestContext<Object>, Throwable> inner);
119
120    /**
121     * Build a before testrule.
122     * <p>
123     * The passed piece of code (which can for instance an inline definition or
124     * a reference to a method) that must be executed before the test itself.
125     * 
126     * @param before
127     *            the code to be used before
128     * @return the rule chain.
129     */
130    static TestRule before(Runnable before) {
131        return (i) -> (p) -> {
132            before.run();// NOSONAR - It is OK to run here
133            i.run(p);
134        };
135    }
136    
137    /**
138     * Build a before testrule.
139     * <p>
140     * The passed piece of code (which can for instance an inline definition or
141     * a reference to a method) that must be executed before the test itself.
142     * 
143     * @param before
144     *            the code to be used before
145     * @return the rule chain.
146     * @since 0.4.0
147     */
148    static TestRule before(Consumer<TestContext<Object>> before) {
149        return (i) -> (p) -> {
150            before.accept(p);
151            i.run(p);// NOSONAR - It is OK to run here
152        };
153    }
154
155    /**
156     * Build a after testrule.
157     * <p>
158     * The passed piece of code (which can for instance an inline definition or
159     * a reference to a method) that must be executed after the test itself.
160     * 
161     * @param after
162     *            the code to be used after
163     * @return the rule chain.
164     */
165    static TestRule after(Runnable after) {
166        return (i) -> (p) -> {
167            try {
168                i.run(p);// NOSONAR - It is OK to run here
169            } finally {
170                after.run();// NOSONAR - It is OK to run here
171            }
172        };
173    }
174    
175    /**
176     * Build a after testrule.
177     * <p>
178     * The passed piece of code (which can for instance an inline definition or
179     * a reference to a method) that must be executed after the test itself.
180     * 
181     * @param after
182     *            the code to be used after
183     * @return the rule chain.
184     * @since 0.4.0
185     */
186    static TestRule after(Consumer<TestContext<Object>> after) {
187        return (i) -> (p) -> {
188            try {
189                i.run(p);// NOSONAR - It is OK to run here
190            } finally {
191                after.accept(p);
192            }
193        };
194    }
195
196    /**
197     * Add an inner rule.
198     * 
199     * @param inner
200     *            the inner rule
201     * @return the rule chain.
202     */
203    default TestRule around(TestRule inner) {
204        return around(() -> inner);
205    }
206
207    /**
208     * Add an inner rule.
209     * <p>
210     * This inner rule is created just before usage, thanks to the
211     * {@link Supplier} object. This can be used for the case when one rule
212     * depend on the outcome of a previous one.
213     * 
214     * @param inner
215     *            the supplier of the inner rule
216     * @return the rule chain.
217     */
218    default TestRule around(Supplier<TestRule> inner) {
219        return (i) -> computeStatement((p) -> inner.get().computeStatement(i)
220                .run(p));
221    }
222
223    /**
224     * Create a rule to support mockito.
225     * 
226     * @return the mockitor rule
227     */
228    static TestRule mockitoRule() {
229        return (i) -> Statement.around(i, (p) -> {
230            MockitoAnnotations.initMocks(p.getTestSuiteObject());
231        }, (p) -> {
232            // Do nothing as default
233            });
234    }
235}