001package org.junit.rules;
002
003import org.junit.internal.AssumptionViolatedException;
004import org.junit.runner.Description;
005
006import java.util.concurrent.TimeUnit;
007
008/**
009 * The Stopwatch Rule notifies one of its own protected methods of the time spent by a test.<p/>
010 * Override them to get the time in nanoseconds. For example, this class will keep logging the
011 * time spent by each passed, failed, skipped, and finished test:
012 *
013 * <pre>
014 * public static class StopwatchTest {
015 *     private static final Logger logger= Logger.getLogger(&quot;&quot;);
016 *
017 *     private static void logInfo(String testName, String status, long nanos) {
018 *         logger.info(String.format(&quot;Test %s %s, spent %d microseconds&quot;,
019 *                                     testName, status, Stopwatch.toMicros(nanos)));
020 *     }
021 *
022 *     &#064;Rule
023 *     public Stopwatch stopwatch= new Stopwatch() {
024 *         &#064;Override
025 *         protected void succeeded(long nanos, Description description) {
026 *             logInfo(description.getMethodName(), &quot;succeeded&quot;, nanos);
027 *         }
028 *
029 *         &#064;Override
030 *         protected void failed(long nanos, Throwable e, Description description) {
031 *             logInfo(description.getMethodName(), &quot;failed&quot;, nanos);
032 *         }
033 *
034 *         &#064;Override
035 *         protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
036 *             logInfo(description.getMethodName(), &quot;skipped&quot;, nanos);
037 *         }
038 *
039 *         &#064;Override
040 *         protected void finished(long nanos, Description description) {
041 *             logInfo(description.getMethodName(), &quot;finished&quot;, nanos);
042 *         }
043 *     };
044 *
045 *     &#064;Test
046 *     public void succeeds() {
047 *     }
048 *
049 *     &#064;Test
050 *     public void fails() {
051 *         fail();
052 *     }
053 *
054 *     &#064;Test
055 *     public void skips() {
056 *         assumeTrue(false);
057 *     }
058 * }
059 * </pre>
060 *
061 * An example to assert runtime:
062 * <pre>
063 * &#064;Test
064 * public void performanceTest() throws InterruptedException {
065 *     long delta= 30;
066 *     Thread.sleep(300L);
067 *     assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta);
068 *     Thread.sleep(500L);
069 *     assertEquals(800d, stopwatch.runtime(MILLISECONDS), delta);
070 * }
071 * </pre>
072 *
073 * @author tibor17
074 * @since 4.12
075 */
076public class Stopwatch extends TestWatcher {
077    private long fStartNanos;
078    private long fEndNanos;
079
080    /**
081     * @param unit time unit for returned runtime
082     * @return runtime measured during the test
083     */
084    public long runtime(TimeUnit unit) {
085        return unit.convert(currentNanoTime() - fStartNanos, TimeUnit.NANOSECONDS);
086    }
087
088    /**
089     * Invoked when a test succeeds
090     */
091    protected void succeeded(long nanos, Description description) {
092    }
093
094    /**
095     * Invoked when a test fails
096     */
097    protected void failed(long nanos, Throwable e, Description description) {
098    }
099
100    /**
101     * Invoked when a test is skipped due to a failed assumption.
102     */
103    protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
104    }
105
106    /**
107     * Invoked when a test method finishes (whether passing or failing)
108     */
109    protected void finished(long nanos, Description description) {
110    }
111
112    /**
113     * @param nanos time in nanoseconds
114     * @return time converted to microseconds
115     */
116    public static long toMicros(long nanos) {
117        return TimeUnit.NANOSECONDS.toMicros(nanos);
118    }
119
120    /**
121     * @param nanos time in nanoseconds
122     * @return time converted to milliseconds
123     */
124    public static long toMillis(long nanos) {
125        return TimeUnit.NANOSECONDS.toMillis(nanos);
126    }
127
128    /**
129     * @param nanos time in nanoseconds
130     * @return time converted to seconds
131     */
132    public static long toSeconds(long nanos) {
133        return TimeUnit.NANOSECONDS.toSeconds(nanos);
134    }
135
136    private long getNanos() {
137        return fEndNanos - fStartNanos;
138    }
139
140    private void starting() {
141        fStartNanos= currentNanoTime();
142    }
143
144    private void stopping() {
145        fEndNanos= currentNanoTime();
146    }
147
148    private long currentNanoTime() {
149        return System.nanoTime();
150    }
151
152    @Override final protected void succeeded(Description description) {
153        stopping();
154        succeeded(getNanos(), description);
155    }
156
157    @Override final protected void failed(Throwable e, Description description) {
158        stopping();
159        failed(getNanos(), e, description);
160    }
161
162    @Override final protected void skipped(AssumptionViolatedException e, Description description) {
163        stopping();
164        skipped(getNanos(), e, description);
165    }
166
167    @Override final protected void starting(Description description) {
168        starting();
169    }
170
171    @Override final protected void finished(Description description) {
172        finished(getNanos(), description);
173    }
174}