1package org.junit.rules;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import org.junit.AssumptionViolatedException;
7import org.junit.runner.Description;
8import org.junit.runners.model.MultipleFailureException;
9import org.junit.runners.model.Statement;
10
11/**
12 * TestWatcher is a base class for Rules that take note of the testing
13 * action, without modifying it. For example, this class will keep a log of each
14 * passing and failing test:
15 *
16 * <pre>
17 * public static class WatchmanTest {
18 *  private static String watchedLog;
19 *
20 *  &#064;Rule
21 *  public TestWatcher watchman= new TestWatcher() {
22 *      &#064;Override
23 *      protected void failed(Throwable e, Description description) {
24 *          watchedLog+= description + &quot;\n&quot;;
25 *      }
26 *
27 *      &#064;Override
28 *      protected void succeeded(Description description) {
29 *          watchedLog+= description + &quot; &quot; + &quot;success!\n&quot;;
30 *         }
31 *     };
32 *
33 *  &#064;Test
34 *  public void fails() {
35 *      fail();
36 *  }
37 *
38 *  &#064;Test
39 *  public void succeeds() {
40 *     }
41 * }
42 * </pre>
43 *
44 * @since 4.9
45 */
46public abstract class TestWatcher implements TestRule {
47    public Statement apply(final Statement base, final Description description) {
48        return new Statement() {
49            @Override
50            public void evaluate() throws Throwable {
51                List<Throwable> errors = new ArrayList<Throwable>();
52
53                startingQuietly(description, errors);
54                try {
55                    base.evaluate();
56                    succeededQuietly(description, errors);
57                } catch (@SuppressWarnings("deprecation") org.junit.internal.AssumptionViolatedException  e) {
58                    errors.add(e);
59                    skippedQuietly(e, description, errors);
60                } catch (Throwable e) {
61                    errors.add(e);
62                    failedQuietly(e, description, errors);
63                } finally {
64                    finishedQuietly(description, errors);
65                }
66
67                MultipleFailureException.assertEmpty(errors);
68            }
69        };
70    }
71
72    private void succeededQuietly(Description description,
73            List<Throwable> errors) {
74        try {
75            succeeded(description);
76        } catch (Throwable e) {
77            errors.add(e);
78        }
79    }
80
81    private void failedQuietly(Throwable e, Description description,
82            List<Throwable> errors) {
83        try {
84            failed(e, description);
85        } catch (Throwable e1) {
86            errors.add(e1);
87        }
88    }
89
90    @SuppressWarnings("deprecation")
91    private void skippedQuietly(
92            org.junit.internal.AssumptionViolatedException e, Description description,
93            List<Throwable> errors) {
94        try {
95            if (e instanceof AssumptionViolatedException) {
96                skipped((AssumptionViolatedException) e, description);
97            } else {
98                skipped(e, description);
99            }
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}
167