    001    package org.junit.rules;
    002
    003    import java.util.List;
    004
    005    import org.junit.internal.management.ManagementFactory;
    006    import org.junit.internal.management.RuntimeMXBean;
    007    import org.junit.runner.Description;
    008    import org.junit.runners.model.Statement;
    009
    010    /**
    011     * The {@code DisableOnDebug} Rule allows you to label certain rules to be
    012     * disabled when debugging.
    013     * <p>
    014     * The most illustrative use case is for tests that make use of the
    015     * {@link Timeout} rule, when ran in debug mode the test may terminate on
    016     * timeout abruptly during debugging. Developers may disable the timeout, or
    017     * increase the timeout by making a code change on tests that need debugging and
    018     * remember revert the change afterwards or rules such as {@link Timeout} that
    019     * may be disabled during debugging may be wrapped in a {@code DisableOnDebug}.
    020     * <p>
    021     * The important benefit of this feature is that you can disable such rules
    022     * without any making any modifications to your test class to remove them during
    023     * debugging.
    024     * <p>
    025     * This does nothing to tackle timeouts or time sensitive code under test when
    026     * debugging and may make this less useful in such circumstances.
    027     * <p>
    028     * Example usage:
    029     *
    030     * <pre>
    031     * public static class DisableTimeoutOnDebugSampleTest {
    032     *
    033     *     &#064;Rule
    034     *     public TestRule timeout = new DisableOnDebug(new Timeout(20));
    035     *
    036     *     &#064;Test
    037     *     public void myTest() {
    038     *         int i = 0;
    039     *         assertEquals(0, i); // suppose you had a break point here to inspect i
    040     *     }
    041     * }
    042     * </pre>
    043     *
    044     * @since 4.12
    045     */
    046    public class DisableOnDebug implements TestRule {
    047        private final TestRule rule;
    048        private final boolean debugging;
    049
    050        /**
    051         * Create a {@code DisableOnDebug} instance with the timeout specified in
    052         * milliseconds.
    053         *
    054         * @param rule to disable during debugging
    055         */
    056        public DisableOnDebug(TestRule rule) {
    057            this(rule, ManagementFactory.getRuntimeMXBean()
    058                    .getInputArguments());
    059        }
    060
    061        /**
    062         * Visible for testing purposes only.
    063         *
    064         * @param rule the rule to disable during debugging
    065         * @param inputArguments
    066         *            arguments provided to the Java runtime
    067         */
    068        DisableOnDebug(TestRule rule, List<String> inputArguments) {
    069            this.rule = rule;
    070            debugging = isDebugging(inputArguments);
    071        }
    072
    073        /**
    074         * @see TestRule#apply(Statement, Description)
    075         */
    076        public Statement apply(Statement base, Description description) {
    077            if (debugging) {
    078                return base;
    079            } else {
    080                return rule.apply(base, description);
    081            }
    082        }
    083
    084        /**
    085         * Parses arguments passed to the runtime environment for debug flags
    086         * <p>
    087         * Options specified in:
    088         * <ul>
    089         * <li>
    090         * <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/conninv.html#Invocation"
    091         * >javase-6</a></li>
    092         * <li><a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/conninv.html#Invocation"
    093         * >javase-7</a></li>
    094         * <li><a href="http://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#Invocation"
    095         * >javase-8</a></li>
    096         *
    097         *
    098         * @param arguments
    099         *            the arguments passed to the runtime environment, usually this
    100         *            will be {@link RuntimeMXBean#getInputArguments()}
    101         * @return true if the current JVM was started in debug mode, false
    102         *         otherwise.
    103         */
    104        private static boolean isDebugging(List<String> arguments) {
    105            for (final String argument : arguments) {
    106                if ("-Xdebug".equals(argument) || argument.startsWith("-agentlib:jdwp")) {
    107                    return true;
    108                }
    109            }
    110            return false;
    111        }
    112
    113        /**
    114         * Returns {@code true} if the JVM is in debug mode. This method may be used
    115         * by test classes to take additional action to disable code paths that
    116         * interfere with debugging if required.
    117         *
    118         * @return {@code true} if the current JVM is in debug mode, {@code false}
    119         *         otherwise
    120         */
    121        public boolean isDebugging() {
    122            return debugging;
    123        }
    124
    125    }