001package org.junit.rules;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.junit.AssumptionViolatedException;
007import org.junit.runner.Description;
008import org.junit.runners.model.MultipleFailureException;
009import org.junit.runners.model.Statement;
010
011/**
012 * TestWatcher is a base class for Rules that take note of the testing
013 * action, without modifying it. For example, this class will keep a log of each
014 * passing and failing test:
015 *
016 * <pre>
017 * public static class WatchmanTest {
018 *  private static String watchedLog;
019 *
020 *  &#064;Rule
021 *  public TestWatcher watchman= new TestWatcher() {
022 *      &#064;Override
023 *      protected void failed(Throwable e, Description description) {
024 *          watchedLog+= description + &quot;\n&quot;;
025 *      }
026 *
027 *      &#064;Override
028 *      protected void succeeded(Description description) {
029 *          watchedLog+= description + &quot; &quot; + &quot;success!\n&quot;;
030 *         }
031 *     };
032 *
033 *  &#064;Test
034 *  public void fails() {
035 *      fail();
036 *  }
037 *
038 *  &#064;Test
039 *  public void succeeds() {
040 *     }
041 * }
042 * </pre>
043 *
044 * @since 4.9
045 */
046public abstract class TestWatcher implements TestRule {
047    public Statement apply(final Statement base, final Description description) {
048        return new Statement() {
049            @Override
050            public void evaluate() throws Throwable {
051                List<Throwable> errors = new ArrayList<Throwable>();
052
053                startingQuietly(description, errors);
054                try {
055                    base.evaluate();
056                    succeededQuietly(description, errors);
057                } catch (@SuppressWarnings("deprecation") org.junit.internal.AssumptionViolatedException  e) {
058                    errors.add(e);
059                    skippedQuietly(e, description, errors);
060                } catch (Throwable e) {
061                    errors.add(e);
062                    failedQuietly(e, description, errors);
063                } finally {
064                    finishedQuietly(description, errors);
065                }
066
067                MultipleFailureException.assertEmpty(errors);
068            }
069        };
070    }
071
072    private void succeededQuietly(Description description,
073            List<Throwable> errors) {
074        try {
075            succeeded(description);
076        } catch (Throwable e) {
077            errors.add(e);
078        }
079    }
080
081    private void failedQuietly(Throwable e, Description description,
082            List<Throwable> errors) {
083        try {
084            failed(e, description);
085        } catch (Throwable e1) {
086            errors.add(e1);
087        }
088    }
089
090    @SuppressWarnings("deprecation")
091    private void skippedQuietly(
092            org.junit.internal.AssumptionViolatedException e, Description description,
093            List<Throwable> errors) {
094        try {
095            if (e instanceof AssumptionViolatedException) {
096                skipped((AssumptionViolatedException) e, description);
097            } else {
098                skipped(e, description);
099            }
100        } catch (Throwable e1) {
101            errors.add(e1);
102        }
103    }
104
105    private void startingQuietly(Description description,
106            List<Throwable> errors) {
107        try {
108            starting(description);
109        } catch (Throwable e) {
110            errors.add(e);
111        }
112    }
113
114    private void finishedQuietly(Description description,
115            List<Throwable> errors) {
116        try {
117            finished(description);
118        } catch (Throwable e) {
119            errors.add(e);
120        }
121    }
122
123    /**
124     * Invoked when a test succeeds
125     */
126    protected void succeeded(Description description) {
127    }
128
129    /**
130     * Invoked when a test fails
131     */
132    protected void failed(Throwable e, Description description) {
133    }
134
135    /**
136     * Invoked when a test is skipped due to a failed assumption.
137     */
138    @SuppressWarnings("deprecation")
139    protected void skipped(AssumptionViolatedException e, Description description) {
140        // For backwards compatibility with JUnit 4.11 and earlier, call the legacy version
141        org.junit.internal.AssumptionViolatedException asInternalException = e;
142        skipped(asInternalException, description);
143    }
144
145    /**
146     * Invoked when a test is skipped due to a failed assumption.
147     *
148     * @deprecated use {@link #skipped(AssumptionViolatedException, Description)}
149     */
150    @Deprecated
151    protected void skipped(
152            org.junit.internal.AssumptionViolatedException e, Description description) {
153    }
154
155    /**
156     * Invoked when a test is about to start
157     */
158    protected void starting(Description description) {
159    }
160
161    /**
162     * Invoked when a test method finishes (whether passing or failing)
163     */
164    protected void finished(Description description) {
165    }
166}