001 package org.junit.rules; 002 003 import java.lang.management.ManagementFactory; 004 import java.lang.management.RuntimeMXBean; 005 import java.util.List; 006 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)) { 107 return true; 108 } else if (argument.startsWith("-agentlib:jdwp")) { 109 return true; 110 } 111 } 112 return false; 113 } 114 115 /** 116 * Returns {@code true} if the JVM is in debug mode. This method may be used 117 * by test classes to take additional action to disable code paths that 118 * interfere with debugging if required. 119 * 120 * @return {@code true} if the current JVM is in debug mode, {@code false} 121 * otherwise 122 */ 123 public boolean isDebugging() { 124 return debugging; 125 } 126 127 }