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}