diff --git a/src/xbot/common/command/BaseSubsystem.java b/src/xbot/common/command/BaseSubsystem.java index 8754baa6..cb460790 100644 --- a/src/xbot/common/command/BaseSubsystem.java +++ b/src/xbot/common/command/BaseSubsystem.java @@ -11,7 +11,6 @@ public void setDefaultCommand(Command command) { @Override protected void initDefaultCommand() { - // TODO Auto-generated method stub } diff --git a/src/xbot/common/injection/RobotModule.java b/src/xbot/common/injection/RobotModule.java index 918db9e3..7796bc49 100644 --- a/src/xbot/common/injection/RobotModule.java +++ b/src/xbot/common/injection/RobotModule.java @@ -4,6 +4,8 @@ import xbot.common.command.SmartDashboardCommandPutter; import xbot.common.injection.wpi_factories.RealWPIFactory; import xbot.common.injection.wpi_factories.WPIFactory; +import xbot.common.logging.RobotAssertionManager; +import xbot.common.logging.SilentRobotAssertionManager; import xbot.common.properties.DatabaseStorageBase; import xbot.common.properties.ITableProxy; import xbot.common.properties.RobotDatabaseStorage; @@ -19,6 +21,7 @@ protected void configure() { this.bind(ITableProxy.class).to(SmartDashboardTableWrapper.class); this.bind(DatabaseStorageBase.class).to(RobotDatabaseStorage.class); this.bind(SmartDashboardCommandPutter.class).to(RealSmartDashboardCommandPutter.class); + this.bind(RobotAssertionManager.class).to(SilentRobotAssertionManager.class); } } diff --git a/src/xbot/common/logging/LoudRobotAssertionManager.java b/src/xbot/common/logging/LoudRobotAssertionManager.java new file mode 100644 index 00000000..02b375cb --- /dev/null +++ b/src/xbot/common/logging/LoudRobotAssertionManager.java @@ -0,0 +1,15 @@ +package xbot.common.logging; + +public class LoudRobotAssertionManager extends RobotAssertionManager { + + @Override + protected void handlePlatformException(RuntimeException e) { + throw e; + } + + @Override + public boolean isExceptionsEnabled() { + return true; + } + +} diff --git a/src/xbot/common/logging/RobotAssertionException.java b/src/xbot/common/logging/RobotAssertionException.java new file mode 100644 index 00000000..6875e67f --- /dev/null +++ b/src/xbot/common/logging/RobotAssertionException.java @@ -0,0 +1,7 @@ +package xbot.common.logging; + +public class RobotAssertionException extends RuntimeException { + public RobotAssertionException(String failureCauseCause) { + super("Assertion error: " + failureCauseCause); + } +} diff --git a/src/xbot/common/logging/RobotAssertionManager.java b/src/xbot/common/logging/RobotAssertionManager.java new file mode 100644 index 00000000..34a6bce8 --- /dev/null +++ b/src/xbot/common/logging/RobotAssertionManager.java @@ -0,0 +1,35 @@ +package xbot.common.logging; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.apache.log4j.Logger; + +public abstract class RobotAssertionManager { + static Logger log = Logger.getLogger(RobotAssertionManager.class); + + public final void throwException(RuntimeException e) { + log.error("Safe exception encountered (exception throw " + (this.isExceptionsEnabled() ? "enabled" : "disabled") + "): " + + e.getMessage()); + log.error("Stack trace: \n " + + Arrays.stream(e.getStackTrace()) + .map(elem -> elem.toString()) + .collect(Collectors.joining("\n "))); + + handlePlatformException(e); + } + + public final void throwException(String message, Throwable cause) { + throwException(new RuntimeException(message, cause)); + } + + protected abstract void handlePlatformException(RuntimeException e); + + public abstract boolean isExceptionsEnabled(); + + public final void assertTrue(boolean value, String assertionFaliureCause) { + if(!value) { + throwException(new RobotAssertionException(assertionFaliureCause)); + } + } +} diff --git a/src/xbot/common/logging/SilentRobotAssertionManager.java b/src/xbot/common/logging/SilentRobotAssertionManager.java new file mode 100644 index 00000000..b966cb4a --- /dev/null +++ b/src/xbot/common/logging/SilentRobotAssertionManager.java @@ -0,0 +1,15 @@ +package xbot.common.logging; + +public class SilentRobotAssertionManager extends RobotAssertionManager { + + @Override + protected void handlePlatformException(RuntimeException e) { + // Don't do anything: we don't need to throw + } + + @Override + public boolean isExceptionsEnabled() { + return false; + } + +} diff --git a/tests/xbot/common/injection/BaseWPITest.java b/tests/xbot/common/injection/BaseWPITest.java index 7f8f098c..2d79ae7d 100644 --- a/tests/xbot/common/injection/BaseWPITest.java +++ b/tests/xbot/common/injection/BaseWPITest.java @@ -8,6 +8,7 @@ import com.google.inject.Injector; import xbot.common.controls.MockRobotIO; +import xbot.common.logging.RobotAssertionManager; import xbot.common.properties.PropertyManager; import edu.wpi.first.wpilibj.HLUsageReporting; import edu.wpi.first.wpilibj.MockHLUsageReporting; diff --git a/tests/xbot/common/injection/UnitTestModule.java b/tests/xbot/common/injection/UnitTestModule.java index fc23aed4..32301e8c 100644 --- a/tests/xbot/common/injection/UnitTestModule.java +++ b/tests/xbot/common/injection/UnitTestModule.java @@ -4,6 +4,8 @@ import xbot.common.command.SmartDashboardCommandPutter; import xbot.common.injection.wpi_factories.MockWPIFactory; import xbot.common.injection.wpi_factories.WPIFactory; +import xbot.common.logging.LoudRobotAssertionManager; +import xbot.common.logging.RobotAssertionManager; import xbot.common.properties.DatabaseStorageBase; import xbot.common.properties.ITableProxy; import xbot.common.properties.TableProxy; @@ -28,5 +30,7 @@ protected void configure() { this.bind(DatabaseStorageBase.class).to(OffRobotDatabaseStorage.class).in(Singleton.class); this.bind(SmartDashboardCommandPutter.class).to(MockSmartDashboardCommandPutter.class); + + this.bind(RobotAssertionManager.class).to(LoudRobotAssertionManager.class); } } \ No newline at end of file diff --git a/tests/xbot/common/logging/SafeRobotAssertionTests.java b/tests/xbot/common/logging/SafeRobotAssertionTests.java new file mode 100644 index 00000000..51f54b95 --- /dev/null +++ b/tests/xbot/common/logging/SafeRobotAssertionTests.java @@ -0,0 +1,44 @@ +package xbot.common.logging; + +import static org.junit.Assert.*; +import org.junit.Test; + +import xbot.common.injection.BaseWPITest; + +public class SafeRobotAssertionTests extends BaseWPITest { + @Test + public void testNoExceptionOnRobot() { + RobotAssertionManager assertMan = new SilentRobotAssertionManager(); + + assertMan.throwException(new RuntimeException("Something really bad happened (...but robots never die)")); + } + + @Test(expected=RuntimeException.class) + public void testExceptionThrownInTests() { + RobotAssertionManager assertMan = new LoudRobotAssertionManager(); + + assertMan.throwException(new RuntimeException("Something really bad happened (tests are free to die as necessary)")); + } + + @Test + public void testAssertionContinuesOnRobot() { + RobotAssertionManager assertMan = new SilentRobotAssertionManager(); + + assertMan.assertTrue(true, "The world is ending"); + assertMan.assertTrue(false, "false != true"); + } + + @Test(expected=RobotAssertionException.class) + public void testAssertionFailedInTests() { + RobotAssertionManager assertMan = new LoudRobotAssertionManager(); + + assertMan.assertTrue(false, "false != true"); + } + + @Test() + public void testAssertionPassedInTests() { + RobotAssertionManager assertMan = new LoudRobotAssertionManager(); + + assertMan.assertTrue(true, "The world is ending"); + } +}