Updates the AbstractComsSetup message to report JUnits multiple exceptions correctly.

Adds a simple logger to the AbstractComsSetup that prints messages to the console based on the log level.
Replaces all System.out prints with TestBench.out()

Change-Id: Ieb7acfe51aa2febe9cfd3883f8a33094c9b72a6e
This commit is contained in:
Jonathan Leitschuh
2014-07-24 14:46:29 -04:00
parent 2481e98bc8
commit 78e6cf7208

View File

@@ -6,14 +6,17 @@
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.MultipleFailureException;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
@@ -24,6 +27,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindow;
* from this class, to ensure that all of the hardware will be able to run.
*
* @author Fredric Silberberg
* @author Jonathan Leitschuh
*/
public abstract class AbstractComsSetup {
/** Stores whether network coms have been initialized */
@@ -43,7 +47,7 @@ public abstract class AbstractComsSetup {
FRCNetworkCommunicationsLibrary
.FRCNetworkCommunicationObserveUserProgramStarting();
LiveWindow.setEnabled(false);
System.out.println("Started coms");
TestBench.out().println("Started coms");
// Wait until the robot is enabled before starting the tests
int i = 0;
@@ -54,13 +58,13 @@ public abstract class AbstractComsSetup {
e.printStackTrace();
}
//Prints the message on one line overwriting itself each time
System.out.print("\rWaiting for enable: " + i++);
TestBench.out().print("\rWaiting for enable: " + i++);
}
System.out.println();
TestBench.out().println();
// Ready to go!
initialized = true;
System.out.println("Running!");
TestBench.out().println("Running!");
}
}
@@ -69,21 +73,125 @@ public abstract class AbstractComsSetup {
/** This causes a stack trace to be printed as the test is running as well as at the end */
@Rule
public TestWatcher testWatcher = new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
System.out.println();
getClassLogger().severe("" + description.getDisplayName() + " failed " + e.getMessage());
e.printStackTrace();
public final TestWatcher getTestWatcher(){
return getOverridenTestWatcher();
}
/**
* Given as a way to provide a custom test watcher for a test or set of tests
* @return the test watcher to use
*/
protected TestWatcher getOverridenTestWatcher(){
return new DefaultTestWatcher();
}
protected class DefaultTestWatcher extends TestWatcher {
/**
* Allows a failure to supply a custom status message to be displayed along with the stack trace.
*/
protected void failed(Throwable e, Description description, String status){
TestBench.out().println();
//Instance of is the best way I know to retrieve this data.
if(e instanceof MultipleFailureException){
/* MultipleFailureExceptions hold multiple exceptions in one exception. In order to properly display these stack traces
* we have to cast the throwable and work with the list of thrown exceptions stored within it.
*/
int i = 1; //Running exception count
int failureCount = ((MultipleFailureException)e).getFailures().size();
for(Throwable singleThrown : ((MultipleFailureException)e).getFailures()){
getClassLogger().logp(Level.SEVERE, description.getClassName(), description.getMethodName(), (i++) + "/" + failureCount
+ " "+ description.getDisplayName() + " failed " + singleThrown.getMessage() + "\n" + status, singleThrown);
}
} else {
getClassLogger().logp(Level.SEVERE, description.getClassName(), description.getMethodName(), description.getDisplayName() + " failed " + e.getMessage() + "\n" + status, e);
}
super.failed(e, description);
}
/* (non-Javadoc)
* @see org.junit.rules.TestWatcher#failed(java.lang.Throwable, org.junit.runner.Description)
*/
@Override
protected void starting( Description description ) {
System.out.println();
getClassLogger().info( description.getDisplayName());
protected void failed(Throwable e, Description description) {
failed(e, description, "");
}
/* (non-Javadoc)
* @see org.junit.rules.TestWatcher#starting(org.junit.runner.Description)
*/
@Override
protected void starting(Description description ) {
TestBench.out().println();
// Wait until the robot is enabled before starting the next tests
int i = 0;
while (!DriverStation.getInstance().isEnabled()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Prints the message on one line overwriting itself each time
TestBench.out().print("\rWaiting for enable: " + i++);
}
getClassLogger().logp(Level.INFO, description.getClassName(), description.getMethodName(), description.getDisplayName());
super.starting(description);
}
@Override
protected void succeeded(Description description) {
simpleLog(Level.INFO, "TEST PASSED!");
super.succeeded(description);
}
};
/**
* Logs a simple message without the logger formatting associated with it.
* @param level The level to log the message at
* @param message The message to log
*/
protected void simpleLog(Level level, String message){
if(getClassLogger().isLoggable(level)){
TestBench.out().println(message);
}
}
/**
* Provided as a replacement to lambda functions to allow for repeatable checks to see if a correct state is reached
* @author Jonathan Leitschuh
*
*/
public abstract class BooleanCheck{
public BooleanCheck(){}
/**
* Runs the enclosed code and evaluates it to determine what state it should return.
* @return true if the code provided within the method returns true
*/
abstract public boolean getAsBoolean();
};
/**
* Delays until either the correct state is reached or we reach the timeout.
* @param level The level to log the message at.
* @param timeout How long the delay should run before it should timeout and allow the test to continue
* @param message The message to accompany the delay. The message will display 'message' took 'timeout' seconds if it passed.
* @param correctState A method to determine if the test has reached a state where it is valid to continue
* @return a double representing how long the delay took to run in seconds.
*/
public double delayTillInCorrectStateWithMessage(Level level, double timeout, String message, BooleanCheck correctState){
int i = 0;
//As long as we are not in the correct state and the timeout has not been reached then continue to run this loop
for(i = 0; i < (timeout * 100) && !correctState.getAsBoolean(); i++){
Timer.delay(.01);
}
if(correctState.getAsBoolean()){
simpleLog(level, message + " took " + (i * .01) + " seconds");
} else {
simpleLog(level, message + " timed out after " + (i * .01) + " seconds");
}
return i*.01;
}
}