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.rules;
021
022import ch.powerunit.Statement;
023import ch.powerunit.TestContext;
024import ch.powerunit.TestRule;
025import ch.powerunit.exception.AssumptionError;
026
027/**
028 * This can be use to support taking action depending on the issue of the test.
029 * <p>
030 * The purpose is here to provide an interface that can be implemented by rule
031 * implementor to do action, before, after and on some condition.
032 * <p>
033 * Rule implementer should implements this interface and then implement the
034 * required methods (which are do-nothing method by default).
035 *
036 * The order of execution is the following :
037 * <ul>
038 * <li>Before the test, the method {@link #onStart(TestContext)} is executed.</li>
039 * <li>Then the test is executed.</li>
040 * <li>In case of error/failure, one (and only one) of the next methods is
041 * executed
042 * <ol>
043 * <li>{@link #onFailure(TestContext, AssertionError)} in case of test failure.</li>
044 * <li>{@link #onError(TestContext, Throwable)} in case of test error.</li>
045 * <li>{@link #onAssumptionSkip(TestContext, AssumptionError)} in case of test
046 * skip.</li>
047 * </ol>
048 * </li>
049 * <li>In all case, after the test, and after the previous method in case of
050 * error/failure, the method {@link #onEnd(TestContext)} is executed.</li>
051 * </ul>
052 *
053 * The {@link ExternalResource} rule implements this interface to provide simple
054 * use case (action before and always after test).
055 *
056 * @author borettim
057 * @see ExternalResource
058 */
059public interface TestListenerRule extends TestRule {
060
061    /**
062     * Method used at the start of the test.
063     * <p>
064     * Default implementation is to do nothing.
065     * 
066     * @param context
067     *            the test context
068     */
069    default void onStart(TestContext<Object> context) {
070        // Do nothing as default
071    }
072
073    /**
074     * Method used when a failure happened.
075     * <p>
076     * Default implementation is to do nothing.
077     * 
078     * @param context
079     *            the test context
080     * @param af
081     *            the failure
082     */
083    default void onFailure(TestContext<Object> context, AssertionError af) {
084        // Do nothing as default
085    }
086
087    /**
088     * Method used when an error happened.
089     * <p>
090     * Default implementation is to do nothing.
091     * 
092     * @param context
093     *            the test context
094     * @param error
095     *            the error
096     */
097    default void onError(TestContext<Object> context, Throwable error) {
098        // Do nothing as default
099    }
100
101    /**
102     * Method used when an assumption error happened.
103     * <p>
104     * Default implementation is to do nothing.
105     * 
106     * @param context
107     *            the test context
108     * @param error
109     *            the assumption error
110     */
111    default void onAssumptionSkip(TestContext<Object> context,
112            AssumptionError error) {
113        // Do nothing as default
114    }
115
116    /**
117     * Method used at the end of the test.
118     * <p>
119     * Default implementation is to do nothing.
120     * 
121     * @param context
122     *            the test context
123     */
124    default void onEnd(TestContext<Object> context) {
125        // Do nothing as default
126    }
127
128    @Override
129    default Statement<TestContext<Object>, Throwable> computeStatement(
130            Statement<TestContext<Object>, Throwable> inner) {
131        return (p) -> {
132            try {
133                onStart(p);
134                inner.run(p);
135            } catch (AssertionError af) {
136                onFailure(p, af);
137                throw af;
138            } catch (InternalError ie) {
139                onError(p, ie);
140                throw ie;
141            } catch (AssumptionError ie) {
142                onAssumptionSkip(p, ie);
143                throw ie;
144            } catch (Throwable t) {
145                onError(p, t);
146                throw t;
147            } finally {
148                onEnd(p);
149            }
150        };
151    }
152}