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 * @Rule
034 * public TestRule timeout = new DisableOnDebug(new Timeout(20));
035 *
036 * @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 }