001    package org.junit.rules;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import org.junit.AssumptionViolatedException;
007    import org.junit.runner.Description;
008    import org.junit.runners.model.MultipleFailureException;
009    import 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     */
046    public 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    }