Sample

Schnappinger/junit4/org.junit.rules.Stopwatch

Human rating uses the original dataset scale.

Human3.46
Lines174

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett0.9280–1; higher is more readable
88.0Δ 48.9
Scalabrino0.8540–1; higher is more readable
77.4Δ 38.3
Dorn0.5860–1; higher is more readable
66.3Δ 27.2
Mi0.4570–1; higher is more readable
28.4Δ 10.7
LLOC35Logical lines; fewer is more readable
47.0Δ 7.9
DeepSeek V4 Pro17.670–20; mean of three runs
83.0Δ 43.9
GPT-6.1 Sol180–20; mean of three runs
73.8Δ 34.7
BTTF0.6350–1; higher is more readable
64.0Δ 24.9
Human3.461–4; original rating
39.1

Views

Source code

package org.junit.rules; import org.junit.internal.AssumptionViolatedException; import org.junit.runner.Description; import java.util.concurrent.TimeUnit; /** * The Stopwatch Rule notifies one of its own protected methods of the time spent by a test.<p/> * Override them to get the time in nanoseconds. For example, this class will keep logging the * time spent by each passed, failed, skipped, and finished test: * * <pre> * public static class StopwatchTest { * private static final Logger logger= Logger.getLogger(&quot;&quot;); * * private static void logInfo(String testName, String status, long nanos) { * logger.info(String.format(&quot;Test %s %s, spent %d microseconds&quot;, * testName, status, Stopwatch.toMicros(nanos))); * } * * &#064;Rule * public Stopwatch stopwatch= new Stopwatch() { * &#064;Override * protected void succeeded(long nanos, Description description) { * logInfo(description.getMethodName(), &quot;succeeded&quot;, nanos); * } * * &#064;Override * protected void failed(long nanos, Throwable e, Description description) { * logInfo(description.getMethodName(), &quot;failed&quot;, nanos); * } * * &#064;Override * protected void skipped(long nanos, AssumptionViolatedException e, Description description) { * logInfo(description.getMethodName(), &quot;skipped&quot;, nanos); * } * * &#064;Override * protected void finished(long nanos, Description description) { * logInfo(description.getMethodName(), &quot;finished&quot;, nanos); * } * }; * * &#064;Test * public void succeeds() { * } * * &#064;Test * public void fails() { * fail(); * } * * &#064;Test * public void skips() { * assumeTrue(false); * } * } * </pre> * * An example to assert runtime: * <pre> * &#064;Test * public void performanceTest() throws InterruptedException { * long delta= 30; * Thread.sleep(300L); * assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta); * Thread.sleep(500L); * assertEquals(800d, stopwatch.runtime(MILLISECONDS), delta); * } * </pre> * * @author tibor17 * @since 4.12 */ public class Stopwatch extends TestWatcher { private long fStartNanos; private long fEndNanos; /** * @param unit time unit for returned runtime * @return runtime measured during the test */ public long runtime(TimeUnit unit) { return unit.convert(currentNanoTime() - fStartNanos, TimeUnit.NANOSECONDS); } /** * Invoked when a test succeeds */ protected void succeeded(long nanos, Description description) { } /** * Invoked when a test fails */ protected void failed(long nanos, Throwable e, Description description) { } /** * Invoked when a test is skipped due to a failed assumption. */ protected void skipped(long nanos, AssumptionViolatedException e, Description description) { } /** * Invoked when a test method finishes (whether passing or failing) */ protected void finished(long nanos, Description description) { } /** * @param nanos time in nanoseconds * @return time converted to microseconds */ public static long toMicros(long nanos) { return TimeUnit.NANOSECONDS.toMicros(nanos); } /** * @param nanos time in nanoseconds * @return time converted to milliseconds */ public static long toMillis(long nanos) { return TimeUnit.NANOSECONDS.toMillis(nanos); } /** * @param nanos time in nanoseconds * @return time converted to seconds */ public static long toSeconds(long nanos) { return TimeUnit.NANOSECONDS.toSeconds(nanos); } private long getNanos() { return fEndNanos - fStartNanos; } private void starting() { fStartNanos= currentNanoTime(); } private void stopping() { fEndNanos= currentNanoTime(); } private long currentNanoTime() { return System.nanoTime(); } @Override final protected void succeeded(Description description) { stopping(); succeeded(getNanos(), description); } @Override final protected void failed(Throwable e, Description description) { stopping(); failed(getNanos(), e, description); } @Override final protected void skipped(AssumptionViolatedException e, Description description) { stopping(); skipped(getNanos(), e, description); } @Override final protected void starting(Description description) { starting(); } @Override final protected void finished(Description description) { finished(getNanos(), description); } }

Loading feature diagnosis…

Source regions

Feature contributions

Feature contributions

FeatureValueContribution
(log-odds)
Source linesThe number of non-empty source lines.174+69.6
Halstead volumeHow much symbolic information the code contains. It combines the total number of operators and values with the number of distinct ones.2091.299−69.013
Byte entropyHow varied the bytes in the source text are. Repeated bytes give a lower value; a more even mixture gives a higher value.4.602−6.904

Intercept 8.87 + feature contributions = 2.553 (log-odds).
Score = sigmoid(2.553) = 0.928.

Score0.854

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.175−5.16
Indentation frequencyHow rapidly indentation changes from line to line.87+2.272
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.173.875+2.021
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.102.914+0.856
Identifier layout (horizontal)How rapidly the visual pattern of identifier characters changes from left to right. It measures spatial frequency, not the meaning of the names.102.971−0.696
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.036+0.589
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.1+0.398

Intercept 0.07 + feature contributions = 0.349 (log-odds).
Score = sigmoid(0.349) = 0.586.

Score0.457
Score35
Run 1

The code is well-structured with clear separation of public API, protected hooks, and private helpers. Nesting is minimal and flat. Intent is clear through descriptive method names and Javadoc, though the Javadoc example is somewhat long. Action granularity is generally one action per line, but some fields/assignments (e.g., `private long fStartNanos;`) could be spaced better. The naming convention `fStartNanos` is slightly dated and inconsistent with typical Java style, which mildly impacts clarity. Reading flow is natural, though the method `starting()` has the same name as an inner private method and an overridden protected method, which can cause confusion. Overall, the code is highly readable with minor stylistic issues.

Run 2

The code is highly readable. It has a clear logical structure with a comprehensive Javadoc that includes examples. Nesting is minimal, with straightforward method bodies. Intent is obvious: the Stopwatch rule measures test execution time and provides hooks for different outcomes. Code length is appropriate, avoiding unnecessary verbosity while maintaining completeness. Each method generally performs one action, contributing to good action granularity. The reading flow is natural, with clear separation of public API, protected overridable methods, and private helpers. Minor drawbacks include the redundant `starting()` method (which overrides a final method and simply calls a private method of the same name) and the slight inconsistency in how `finished` is handled compared to `succeeded`/`failed`/`skipped` (which call `stopping`). Overall, the code is exemplary in readability.

Run 3

The code is well-structured, with a clear class hierarchy and logical grouping of related methods. The Javadoc examples significantly aid comprehension. Methods are concise and focused on a single action. Nesting is minimal; the only deep nesting appears in the included example (a separate usage scenario). Intent is explicit via descriptive method names like 'starting', 'stopping', 'succeeded', 'failed', etc. The code avoids redundancy by delegating to private helpers. The reading flow follows a natural progression from public API to private utilities. Minor deductions: the 'fStartNanos'/'fEndNanos' prefix is slightly dated, and the 'succeeded(Description)' override final methods could benefit from a brief comment distinguishing them from the overloaded callbacks. Overall, highly readable.

Run 1

Code Structure: Well-organized class with distinct runtime access, extension hooks, conversion utilities, and lifecycle overrides, although related overloads are separated. Nesting: Almost entirely flat, with short methods and no complex branching. Clarity of intent: Descriptive method names and documentation clearly communicate test timing behavior; overloaded lifecycle names and prefixed fields introduce minor ambiguity. Code length: Implementation is concise, but extensive examples and repetitive callback wrappers increase reading length. Action granularity: Statements generally perform one action per line, making state updates and callback delegation easy to follow. Reading flow: Consistent method patterns provide predictable flow, though tracing lifecycle behavior requires jumping between overrides and helpers. Unconventional modifier ordering and assignment spacing slightly reduce polish.

Run 2

Code Structure: Well organized into timing state, extension hooks, conversion utilities, and lifecycle overrides, although grouping related overloads could improve navigation. Nesting: Almost entirely flat, with short methods and no complex branching. Clarity of intent: Descriptive method names and documented callbacks make the purpose clear; prefixed fields and overloaded lifecycle methods add minor cognitive overhead. Code length: Implementation is concise, though extensive examples and repetitive wrappers increase overall length. Action granularity: Statements generally perform one action per line, and lifecycle overrides clearly separate stopping from notification. Reading flow: Consistent formatting and straightforward delegation support natural reading, but unconventional modifier ordering, assignment spacing, and similarly named helper methods slightly interrupt the flow.

Run 3

Code Structure: Well organized into timing state, extension callbacks, conversion utilities, and lifecycle overrides, though grouping related overloads could improve navigation. Nesting: Almost entirely flat, with short methods and no complex control flow. Clarity of intent: Descriptive method names and Javadoc clearly explain the stopwatch and callback API; prefixed field names and overloaded lifecycle methods add minor friction. Code length: Implementation is concise, although extensive examples and repetitive callback wrappers increase overall length. Action granularity: Statements generally perform one action per line, making timing updates and callback dispatch easy to follow. Reading flow: Consistent formatting and straightforward methods support natural reading, but unusual modifier ordering, annotation placement, and inconsistent spacing around assignments slightly reduce polish.