WPILib Reorganization

This is a major restructuring of the WPILib repository to simply build
procedures and remove the remnants of Maven from everything except the
eclipse plugins. Gradle files have been largely simplified or rewritten,
taking advantage of splitting up parts of the build into separate build
files for ease of reading.

The eclipse plugins are now in a separate project, as is ntcore. All
dependencies are resolved via Maven dependencies, with the
Jenkins-maintained WPILib repo. Project structures have also been
simplified: we no longer have separate subprojects inside wpilibc and
wpilibj. Where possible, these changes hav been done with git renames,
to make sure we still have full history for all repositories. Other
unrelated subprojects have also been broken out: OutlineViewer is now a
separate project.

Change-Id: Ib4e2a6e1a2f66427a14f16612b0e0d69ed661878
This commit is contained in:
Fredric Silberberg
2015-09-24 20:26:49 -04:00
parent c20d34c2b6
commit 6d854afb0e
1769 changed files with 2278 additions and 333177 deletions

View File

@@ -0,0 +1,255 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.After;
import org.junit.Test;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* This class should not be run as a test explicitly. Instead it should be
* extended by tests that use the InterruptableSensorBase
*
* @author jonathanleitschuh
*
*/
public abstract class AbstractInterruptTest extends AbstractComsSetup {
private InterruptableSensorBase interruptable = null;
private InterruptableSensorBase getInterruptable() {
if (interruptable == null) {
interruptable = giveInterruptableSensorBase();
}
return interruptable;
}
@After
public void interruptTeardown() {
if (interruptable != null) {
freeInterruptableSensorBase();
interruptable = null;
}
}
/**
* Give the interruptible sensor base that interrupts can be attached to.
*$
* @return
*/
abstract InterruptableSensorBase giveInterruptableSensorBase();
/**
* Cleans up the interruptible sensor base. This is only called if
* {@link #giveInterruptableSensorBase()} is called.
*/
abstract void freeInterruptableSensorBase();
/**
* Perform whatever action is required to set the interrupt high.
*/
abstract void setInterruptHigh();
/**
* Perform whatever action is required to set the interrupt low.
*/
abstract void setInterruptLow();
private class InterruptCounter {
private final AtomicInteger count = new AtomicInteger();
void increment() {
count.addAndGet(1);
}
int getCount() {
return count.get();
}
};
private class TestInterruptHandlerFunction extends InterruptHandlerFunction<InterruptCounter> {
protected final AtomicBoolean exceptionThrown = new AtomicBoolean(false);
/** Stores the time that the interrupt fires */
final AtomicLong interruptFireTime = new AtomicLong();
/** Stores if the interrupt has completed at least once */
final AtomicBoolean interruptComplete = new AtomicBoolean(false);
protected Exception ex;
final InterruptCounter counter;
TestInterruptHandlerFunction(InterruptCounter counter) {
this.counter = counter;
}
@Override
public void interruptFired(int interruptAssertedMask, InterruptCounter param) {
interruptFireTime.set(Utility.getFPGATime());
counter.increment();
try {
// This won't cause the test to fail
assertSame(counter, param);
} catch (Exception ex) {
// So we must throw the exception within the test
exceptionThrown.set(true);
this.ex = ex;
}
interruptComplete.set(true);
};
@Override
public InterruptCounter overridableParameter() {
return counter;
}
};
@Test(timeout = 1000)
public void testSingleInterruptsTriggering() throws Exception {
// Given
final InterruptCounter counter = new InterruptCounter();
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
// When
getInterruptable().requestInterrupts(function);
getInterruptable().enableInterrupts();
setInterruptLow();
Timer.delay(0.01);
// Note: Utility.getFPGATime() is used because double values can turn over
// after the robot has been running for a long time
final long interruptTriggerTime = Utility.getFPGATime();
setInterruptHigh();
// Delay until the interrupt is complete
while (!function.interruptComplete.get()) {
Timer.delay(.005);
}
// Then
assertEquals("The interrupt did not fire the expected number of times", 1, counter.getCount());
// If the test within the interrupt failed
if (function.exceptionThrown.get()) {
throw function.ex;
}
final long range = 10000; // in microseconds
assertThat(
"The interrupt did not fire within the expected time period (values in milliseconds)",
function.interruptFireTime.get(),
both(greaterThan(interruptTriggerTime - range)).and(lessThan(interruptTriggerTime + range)));
assertThat(
"The readRisingTimestamp() did not return the correct value (values in seconds)",
getInterruptable().readRisingTimestamp(),
both(greaterThan((interruptTriggerTime - range) / 1e6)).and(
lessThan((interruptTriggerTime + range) / 1e6)));
}
@Test(timeout = 2000)
public void testMultipleInterruptsTriggering() throws Exception {
// Given
final InterruptCounter counter = new InterruptCounter();
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
// When
getInterruptable().requestInterrupts(function);
getInterruptable().enableInterrupts();
final int fireCount = 50;
for (int i = 0; i < fireCount; i++) {
setInterruptLow();
setInterruptHigh();
// Wait for the interrupt to complete before moving on
while (!function.interruptComplete.getAndSet(false)) {
Timer.delay(.005);
}
}
// Then
assertEquals("The interrupt did not fire the expected number of times", fireCount,
counter.getCount());
}
/** The timeout length for this test in seconds */
private static final int synchronousTimeout = 5;
@Test(timeout = (long) (synchronousTimeout * 1e3))
public void testSynchronousInterruptsTriggering() {
// Given
getInterruptable().requestInterrupts();
final double synchronousDelay = synchronousTimeout / 2.;
Runnable r = new Runnable() {
@Override
public void run() {
Timer.delay(synchronousDelay);
setInterruptLow();
setInterruptHigh();
}
};
// When
// Note: the long time value is used because doubles can flip if the robot
// is left running for long enough
final long startTimeStamp = Utility.getFPGATime();
new Thread(r).start();
// Delay for twice as long as the timeout so the test should fail first
getInterruptable().waitForInterrupt(synchronousTimeout * 2);
final long stopTimeStamp = Utility.getFPGATime();
// Then
// The test will not have timed out and:
final double interruptRunTime = (stopTimeStamp - startTimeStamp) * 1e-6;
assertEquals("The interrupt did not run for the expected amount of time (units in seconds)",
synchronousDelay, interruptRunTime, .1);
}
@Test(timeout = 4000)
public void testDisableStopsInterruptFiring() {
final InterruptCounter counter = new InterruptCounter();
TestInterruptHandlerFunction function = new TestInterruptHandlerFunction(counter);
// When
getInterruptable().requestInterrupts(function);
getInterruptable().enableInterrupts();
final int fireCount = 50;
for (int i = 0; i < fireCount; i++) {
setInterruptLow();
setInterruptHigh();
// Wait for the interrupt to complete before moving on
while (!function.interruptComplete.getAndSet(false)) {
Timer.delay(.005);
}
}
getInterruptable().disableInterrupts();
// TestBench.out().println("Finished disabling the robot");
for (int i = 0; i < fireCount; i++) {
setInterruptLow();
setInterruptHigh();
// Just wait because the interrupt should not fire
Timer.delay(.005);
}
// Then
assertEquals("The interrupt did not fire the expected number of times", fireCount,
counter.getCount());
}
}

View File

@@ -0,0 +1,152 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import org.junit.runners.model.InitializationError;
import edu.wpi.first.wpilibj.test.AbstractTestSuite.ClassMethodPair;
/**
* @author jonathanleitschuh
*
*/
public class AbstractTestSuiteTest {
@Ignore("Prevents ANT from trying to run these as tests")
@RunWith(Suite.class)
@SuiteClasses({FirstSampleTest.class, SecondSampleTest.class, ThirdSampleTest.class,
FourthSampleTest.class, UnusualTest.class, ExampleSubSuite.class, EmptySuite.class})
class TestForAbstractTestSuite extends AbstractTestSuite {
}
TestForAbstractTestSuite testSuite;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
testSuite = new TestForAbstractTestSuite();
}
@Test
public void testGetTestsMatchingAll() throws InitializationError {
// when
List<Class<?>> collectedTests = testSuite.getAllClassMatching(".*");
// then
assertEquals(7, collectedTests.size());
}
@Test
public void testGetTestsMatchingSample() throws InitializationError {
// when
List<Class<?>> collectedTests = testSuite.getAllClassMatching(".*Sample.*");
// then
assertEquals(4, collectedTests.size());
}
@Test
public void testGetTestsMatchingUnusual() throws InitializationError {
// when
List<Class<?>> collectedTests = testSuite.getAllClassMatching(".*Unusual.*");
// then
assertEquals(1, collectedTests.size());
assertEquals(UnusualTest.class, collectedTests.get(0));
}
@Test
public void testGetTestsFromSuiteMatchingAll() throws InitializationError {
// when
List<Class<?>> collectedTests = testSuite.getSuiteOrTestMatchingRegex(".*");
// then
assertEquals(7, collectedTests.size());
}
@Test
public void testGetTestsFromSuiteMatchingTest() throws InitializationError {
// when
List<Class<?>> collectedTests = testSuite.getSuiteOrTestMatchingRegex(".*Test.*");
// then
assertEquals(7, collectedTests.size());
assertThat(collectedTests, hasItems(new Class<?>[] {FirstSubSuiteTest.class,
SecondSubSuiteTest.class, UnusualTest.class}));
assertThat(collectedTests,
not(hasItems(new Class<?>[] {ExampleSubSuite.class, EmptySuite.class})));
}
@Test
public void testGetMethodFromTest() {
// when
List<ClassMethodPair> pairs = testSuite.getMethodMatching(".*Method.*");
// then
assertEquals(1, pairs.size());
assertEquals(FirstSubSuiteTest.class, pairs.get(0).methodClass);
assertEquals(FirstSubSuiteTest.METHODNAME, pairs.get(0).methodName);
}
}
class FirstSampleTest {
}
class SecondSampleTest {
}
class ThirdSampleTest {
}
class FourthSampleTest {
}
class UnusualTest {
} // This is a member of both suites
@Ignore("Prevents ANT from trying to run these as tests")
class FirstSubSuiteTest {
public static final String METHODNAME = "aTestMethod";
@Test
public void aTestMethod() {}
}
class SecondSubSuiteTest {
}
@RunWith(Suite.class)
@SuiteClasses({FirstSubSuiteTest.class, SecondSubSuiteTest.class, UnusualTest.class})
@Ignore("Prevents ANT from trying to run these as tests")
class ExampleSubSuite extends AbstractTestSuite {
}
@Ignore("Prevents ANT from trying to run these as tests")
@RunWith(Suite.class)
@SuiteClasses({})
class EmptySuite extends AbstractTestSuite {
}

View File

@@ -0,0 +1,212 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
import edu.wpi.first.wpilibj.fixtures.AnalogCrossConnectFixture;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* @author jonathanleitschuh
*
*/
public class AnalogCrossConnectTest extends AbstractInterruptTest {
private static final Logger logger = Logger.getLogger(AnalogCrossConnectTest.class.getName());
private static AnalogCrossConnectFixture analogIO;
static final double kDelayTime = 0.01;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
analogIO = TestBench.getAnalogCrossConnectFixture();
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
analogIO.teardown();
analogIO = null;
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
analogIO.setup();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
@Test
public void testAnalogOuput() {
for (int i = 0; i < 50; i++) {
analogIO.getOutput().setVoltage(i / 10.0f);
Timer.delay(kDelayTime);
assertEquals(analogIO.getOutput().getVoltage(), analogIO.getInput().getVoltage(), 0.01);
}
}
@Test
public void testAnalogTriggerBelowWindow() {
// Given
AnalogTrigger trigger = new AnalogTrigger(analogIO.getInput());
trigger.setLimitsVoltage(2.0f, 3.0f);
// When the output voltage is than less the lower limit
analogIO.getOutput().setVoltage(1.0f);
Timer.delay(kDelayTime);
// Then the analog trigger is not in the window and the trigger state is off
assertFalse("Analog trigger is in the window (2V, 3V)", trigger.getInWindow());
assertFalse("Analog trigger is on", trigger.getTriggerState());
trigger.free();
}
@Test
public void testAnalogTriggerInWindow() {
// Given
AnalogTrigger trigger = new AnalogTrigger(analogIO.getInput());
trigger.setLimitsVoltage(2.0f, 3.0f);
// When the output voltage is within the lower and upper limits
analogIO.getOutput().setVoltage(2.5f);
Timer.delay(kDelayTime);
// Then the analog trigger is in the window and the trigger state is off
assertTrue("Analog trigger is not in the window (2V, 3V)", trigger.getInWindow());
assertFalse("Analog trigger is on", trigger.getTriggerState());
trigger.free();
}
@Test
public void testAnalogTriggerAboveWindow() {
// Given
AnalogTrigger trigger = new AnalogTrigger(analogIO.getInput());
trigger.setLimitsVoltage(2.0f, 3.0f);
// When the output voltage is greater than the upper limit
analogIO.getOutput().setVoltage(4.0f);
Timer.delay(kDelayTime);
// Then the analog trigger is not in the window and the trigger state is on
assertFalse("Analog trigger is in the window (2V, 3V)", trigger.getInWindow());
assertTrue("Analog trigger is not on", trigger.getTriggerState());
trigger.free();
}
@Test
public void testAnalogTriggerCounter() {
// Given
AnalogTrigger trigger = new AnalogTrigger(analogIO.getInput());
trigger.setLimitsVoltage(2.0f, 3.0f);
Counter counter = new Counter(trigger);
// When the analog output is turned low and high 50 times
for (int i = 0; i < 50; i++) {
analogIO.getOutput().setVoltage(1.0);
Timer.delay(kDelayTime);
analogIO.getOutput().setVoltage(4.0);
Timer.delay(kDelayTime);
}
// Then the counter should be at 50
assertEquals("Analog trigger counter did not count 50 ticks", 50, counter.get());
}
@Test(expected = RuntimeException.class)
public void testRuntimeExceptionOnInvalidAccumulatorPort() {
analogIO.getInput().getAccumulatorCount();
}
private AnalogTrigger interruptTrigger;
private AnalogTriggerOutput interruptTriggerOutput;
/*
* (non-Javadoc)
*$
* @see
* edu.wpi.first.wpilibj.AbstractInterruptTest#giveInterruptableSensorBase()
*/
@Override
InterruptableSensorBase giveInterruptableSensorBase() {
interruptTrigger = new AnalogTrigger(analogIO.getInput());
interruptTrigger.setLimitsVoltage(2.0f, 3.0f);
interruptTriggerOutput = new AnalogTriggerOutput(interruptTrigger, AnalogTriggerType.kState);
return interruptTriggerOutput;
}
/*
* (non-Javadoc)
*$
* @see
* edu.wpi.first.wpilibj.AbstractInterruptTest#freeInterruptableSensorBase()
*/
@Override
void freeInterruptableSensorBase() {
interruptTriggerOutput.cancelInterrupts();
interruptTriggerOutput.free();
interruptTriggerOutput = null;
interruptTrigger.free();
interruptTrigger = null;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptHigh()
*/
@Override
void setInterruptHigh() {
analogIO.getOutput().setVoltage(4.0);
Timer.delay(kDelayTime);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptLow()
*/
@Override
void setInterruptLow() {
analogIO.getOutput().setVoltage(1.0);
Timer.delay(kDelayTime);
}
}

View File

@@ -0,0 +1,76 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import edu.wpi.first.wpilibj.fixtures.AnalogCrossConnectFixture;
import edu.wpi.first.wpilibj.mockhardware.FakePotentiometerSource;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* @author jonathanleitschuh
*
*/
public class AnalogPotentiometerTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(AnalogPotentiometerTest.class.getName());
private AnalogCrossConnectFixture analogIO;
private FakePotentiometerSource potSource;
private AnalogPotentiometer pot;
private static final double DOUBLE_COMPARISON_DELTA = 2.0;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
analogIO = TestBench.getAnalogCrossConnectFixture();
potSource = new FakePotentiometerSource(analogIO.getOutput(), 360);
pot = new AnalogPotentiometer(analogIO.getInput(), 360.0, 0);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
potSource.reset();
pot.free();
analogIO.teardown();
}
@Override
protected Logger getClassLogger() {
return logger;
}
@Test
public void testInitialSettings() {
assertEquals(0, pot.get(), DOUBLE_COMPARISON_DELTA);
}
@Test
public void testRangeValues() {
for (double i = 0.0; i < 360.0; i = i + 1.0) {
potSource.setAngle(i);
potSource.setMaxVoltage(ControllerPower.getVoltage5V());
Timer.delay(.02);
assertEquals(i, pot.get(), DOUBLE_COMPARISON_DELTA);
}
}
}

View File

@@ -0,0 +1,68 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
@RunWith(Parameterized.class)
public class BuiltInAccelerometerTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(BuiltInAccelerometerTest.class.getName());
private static final double kAccelerationTolerance = 0.1;
private final BuiltInAccelerometer m_accelerometer;
public BuiltInAccelerometerTest(Accelerometer.Range range) {
m_accelerometer = new BuiltInAccelerometer(range);
}
@BeforeClass
public static void waitASecond() {
/*
* The testbench sometimes shakes a little from a previous test. Give it
* some time.
*/
Timer.delay(1.0);
}
/**
* Test with all valid ranges to make sure unpacking is always done correctly.
*/
@Parameters
public static Collection<Accelerometer.Range[]> generateData() {
return Arrays.asList(new Accelerometer.Range[][] { {Accelerometer.Range.k2G},
{Accelerometer.Range.k4G}, {Accelerometer.Range.k8G},});
}
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* There's not much we can automatically test with the on-board accelerometer,
* but checking for gravity is probably good enough to tell that it's working.
*/
@Test
public void testAccelerometer() {
assertEquals(0.0, m_accelerometer.getX(), kAccelerationTolerance);
assertEquals(1.0, m_accelerometer.getY(), kAccelerationTolerance);
assertEquals(0.0, m_accelerometer.getZ(), kAccelerationTolerance);
}
}

View File

@@ -0,0 +1,135 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertTrue;
import java.util.logging.Logger;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.fixtures.SampleFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.hal.CanTalonSRX;
import edu.wpi.first.wpilibj.hal.CanTalonJNI;
import edu.wpi.first.wpilibj.hal.SWIGTYPE_p_double;
/**
* Basic test (borrowed straight from SampleTest) for running the CAN TalonSRX.
*/
public class CANTalonTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(SampleTest.class.getName());
static SampleFixture fixture = new SampleFixture();
protected Logger getClassLogger() {
return logger;
}
@BeforeClass
public static void classSetup() {
// Set up the fixture before the test is created
fixture.setup();
}
@Before
public void setUp() {
// Reset the fixture elements before every test
fixture.reset();
}
@AfterClass
public static void tearDown() {
// Clean up the fixture after the test
fixture.teardown();
}
private String errorMessage(double actual, double expected) {
String start = "Actual value was: ";
start += actual;
start += " Expected: ";
start += expected;
return start;
}
/**
* Briefly run a CAN Talon and assert true.
*/
@Test
public void throttle() {
double throttle = 0.1;
CANTalon tal = new CANTalon(0);
tal.set(throttle);
Timer.delay(5.0);
assertTrue(errorMessage(tal.get(), throttle), Math.abs(throttle - tal.get()) < 1e-2);
tal.set(-throttle);
Timer.delay(1.25);
assertTrue(errorMessage(tal.get(), -throttle), Math.abs(throttle + tal.get()) < 1e-2);
tal.reverseOutput(true);
tal.set(-throttle);
Timer.delay(1.25);
assertTrue(errorMessage(tal.get(), -throttle), Math.abs(throttle + tal.get()) < 1e-2);
tal.disable();
Timer.delay(0.2);
assertTrue(errorMessage(tal.get(), 0.0), Math.abs(tal.get()) < 1e-10);
}
@Test
public void SetGetPID() {
CANTalon talon = new CANTalon(0);
talon.changeControlMode(CANTalon.TalonControlMode.Position);
double p = 0.05, i = 0.098, d = 1.23;
talon.setPID(p, i, d);
assertTrue(errorMessage(talon.getP(), p), Math.abs(p - talon.getP()) < 1e-5);
assertTrue(errorMessage(talon.getI(), i), Math.abs(i - talon.getI()) < 1e-5);
assertTrue(errorMessage(talon.getD(), d), Math.abs(d - talon.getD()) < 1e-5);
// Test with new values in case the talon was already set to the previous
// ones.
p = 0.15;
i = 0.198;
d = 1.03;
talon.setPID(p, i, d);
assertTrue(errorMessage(talon.getP(), p), Math.abs(p - talon.getP()) < 1e-5);
assertTrue(errorMessage(talon.getI(), i), Math.abs(i - talon.getI()) < 1e-5);
assertTrue(errorMessage(talon.getD(), d), Math.abs(d - talon.getD()) < 1e-5);
}
@Test
public void positionModeWorks() {
CANTalon talon = new CANTalon(0);
talon.changeControlMode(CANTalon.TalonControlMode.Position);
talon.setFeedbackDevice(CANTalon.FeedbackDevice.AnalogPot);
Timer.delay(0.2);
double p = 1.0, i = 0.0, d = 0.00;
talon.setPID(p, i, d);
talon.set(100);
Timer.delay(5.0);
talon.reverseOutput(true);
Timer.delay(5.0);
// assertTrue(errorMessage(talon.get(), 100), Math.abs(100 - talon.get()) <
// 10);
assertTrue(true);
}
@Test
public void testBrake() {
CANTalon talon = new CANTalon(0);
for (int i = 0; i < 5; i++) {
talon.enableBrakeMode(true);
Timer.delay(0.5);
talon.enableBrakeMode(false);
Timer.delay(0.5);
}
}
}

View File

@@ -0,0 +1,125 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.fixtures.FakeCounterFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Tests to see if the Counter is working properly
*$
* @author Jonathan Leitschuh
*
*/
@RunWith(Parameterized.class)
public class CounterTest extends AbstractComsSetup {
private static FakeCounterFixture counter = null;
private static final Logger logger = Logger.getLogger(CounterTest.class.getName());
Integer input;
Integer output;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* Constructs a Counter Test with the given inputs
*$
* @param input The input Port
* @param output The output Port
*/
public CounterTest(Integer input, Integer output) {
assert input != null;
assert output != null;
this.input = input;
this.output = output;
// System.out.println("Counter Test: Input: " + input + " Output: " +
// output);
if (counter != null)
counter.teardown();
counter = new FakeCounterFixture(input, output);
}
/**
* Test data generator. This method is called the the JUnit parameterized test
* runner and returns a Collection of Arrays. For each Array in the
* Collection, each array element corresponds to a parameter in the
* constructor.
*/
@Parameters
public static Collection<Integer[]> generateData() {
// In this example, the parameter generator returns a List of
// arrays. Each array has two elements: { Digital input port, Digital output
// port}.
// These data are hard-coded into the class, but they could be
// generated or loaded in any way you like.
return TestBench.getInstance().getDIOCrossConnectCollection();
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
counter.teardown();
counter = null;
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
counter.setup();
}
/**
* Tests the default state of the counter immediately after reset
*/
@Test
public void testDefault() {
assertTrue("Counter did not reset to 0", counter.getCounter().get() == 0);
}
@Test(timeout = 5000)
public void testCount() {
int goal = 100;
counter.getFakeCounterSource().setCount(goal);
counter.getFakeCounterSource().execute();
int count = counter.getCounter().get();
assertTrue("Fake Counter, Input: " + input + ", Output: " + output + ", did not return " + goal
+ " instead got: " + count, count == goal);
}
}

View File

@@ -0,0 +1,153 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.fixtures.DIOCrossConnectFixture;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Tests to see if the Digital ports are working properly
*$
* @author jonathanleitschuh
*/
@RunWith(Parameterized.class)
public class DIOCrossConnectTest extends AbstractInterruptTest {
private static final Logger logger = Logger.getLogger(DIOCrossConnectTest.class.getName());
private static DIOCrossConnectFixture dio = null;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* Default constructor for the DIOCrossConnectTest This test is parameterized
* in order to allow it to be tested using a variety of different input/output
* pairs without duplicate code.<br>
* This class takes Integer port values instead of DigitalClasses because it
* would force them to be instantiated at the same time which could (untested)
* cause port binding errors.
*$
* @param input The port for the input wire
* @param output The port for the output wire
*/
public DIOCrossConnectTest(Integer input, Integer output) {
if (dio != null) {
dio.teardown();
}
dio = new DIOCrossConnectFixture(input, output);
}
/**
* Test data generator. This method is called the the JUnit parameterized test
* runner and returns a Collection of Arrays. For each Array in the
* Collection, each array element corresponds to a parameter in the
* constructor.
*/
@Parameters(name = "{index}: Input Port: {0} Output Port: {1}")
public static Collection<Integer[]> generateData() {
// In this example, the parameter generator returns a List of
// arrays. Each array has two elements: { Digital input port, Digital output
// port}.
// These data are hard-coded into the class, but they could be
// generated or loaded in any way you like.
return TestBench.getInstance().getDIOCrossConnectCollection();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
dio.teardown();
dio = null;
}
@After
public void tearDown() throws Exception {
dio.reset();
}
/**
* Tests to see if the DIO can create and recognize a high value
*/
@Test
public void testSetHigh() {
dio.getOutput().set(true);
assertTrue("DIO Not High after no delay", dio.getInput().get());
Timer.delay(.02);
assertTrue("DIO Not High after .05s delay", dio.getInput().get());
}
/**
* Tests to see if the DIO can create and recognize a low value
*/
@Test
public void testSetLow() {
dio.getOutput().set(false);
assertFalse("DIO Not Low after no delay", dio.getInput().get());
Timer.delay(.02);
assertFalse("DIO Not Low after .05s delay", dio.getInput().get());
}
/*
* (non-Javadoc)
*$
* @see
* edu.wpi.first.wpilibj.AbstractInterruptTest#giveInterruptableSensorBase()
*/
@Override
InterruptableSensorBase giveInterruptableSensorBase() {
return dio.getInput();
}
/*
* (non-Javadoc)
*$
* @see
* edu.wpi.first.wpilibj.AbstractInterruptTest#freeInterruptableSensorBase()
*/
@Override
void freeInterruptableSensorBase() {
// Handled in the fixture
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptHigh()
*/
@Override
void setInterruptHigh() {
dio.getOutput().set(true);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.AbstractInterruptTest#setInterruptLow()
*/
@Override
void setInterruptLow() {
dio.getOutput().set(false);
}
}

View File

@@ -0,0 +1,162 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.fixtures.FakeEncoderFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Test to see if the FPGA properly recognizes a mock Encoder input
*$
* @author Jonathan Leitschuh
*
*/
@RunWith(Parameterized.class)
public class EncoderTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(EncoderTest.class.getName());
private static FakeEncoderFixture encoder = null;
private final boolean flip; // Does this test need to flip the inputs
private final int inputA;
private final int inputB;
private final int outputA;
private final int outputB;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* Test data generator. This method is called the the JUnit parameterized test
* runner and returns a Collection of Arrays. For each Array in the
* Collection, each array element corresponds to a parameter in the
* constructor.
*/
@Parameters
public static Collection<Integer[]> generateData() {
return TestBench.getInstance().getEncoderDIOCrossConnectCollection();
}
/**
* Constructs a parameterized Encoder Test
*$
* @param inputA The port number for inputA
* @param outputA The port number for outputA
* @param inputB The port number for inputB
* @param outputB The port number for outputB
* @param flip whether or not these set of values require the encoder to be
* reversed (0 or 1)
*/
public EncoderTest(int inputA, int outputA, int inputB, int outputB, int flip) {
this.inputA = inputA;
this.inputB = inputB;
this.outputA = outputA;
this.outputB = outputB;
// If the encoder from a previous test is allocated then we must free its
// members
if (encoder != null)
encoder.teardown();
this.flip = flip == 0;
encoder = new FakeEncoderFixture(inputA, outputA, inputB, outputB);
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
encoder.teardown();
encoder = null;
}
/**
* Sets up the test and verifies that the test was reset to the default state
*$
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
encoder.setup();
testDefaultState();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
encoder.reset();
}
/**
* Tests to see if Encoders initialize to zero
*/
@Test
public void testDefaultState() {
int value = encoder.getEncoder().get();
assertTrue(errorMessage(0, value), value == 0);
}
/**
* Tests to see if Encoders can count up sucsessfully
*/
@Test
public void testCountUp() {
int goal = 100;
encoder.getFakeEncoderSource().setCount(goal);
encoder.getFakeEncoderSource().setForward(flip);
encoder.getFakeEncoderSource().execute();
int value = encoder.getEncoder().get();
assertTrue(errorMessage(goal, value), value == goal);
}
/**
* Tests to see if Encoders can count down sucsessfully
*/
@Test
public void testCountDown() {
int goal = -100;
encoder.getFakeEncoderSource().setCount(goal); // Goal has to be positive
encoder.getFakeEncoderSource().setForward(!flip);
encoder.getFakeEncoderSource().execute();
int value = encoder.getEncoder().get();
assertTrue(errorMessage(goal, value), value == goal);
}
/**
* Creates a simple message with the error that was encounterd for the
* Encoders
*$
* @param goal The goal that was trying to be reached
* @param trueValue The actual value that was reached by the test
* @return A fully constructed message with data about where and why the the
* test failed
*/
private String errorMessage(int goal, int trueValue) {
return "Encoder ({In,Out}): {" + inputA + ", " + outputA + "},{" + inputB + ", " + outputB
+ "} Returned: " + trueValue + ", Wanted: " + goal;
}
}

View File

@@ -0,0 +1,105 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import edu.wpi.first.wpilibj.fixtures.TiltPanCameraFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
public class GyroTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(GyroTest.class.getName());
public static final double TEST_ANGLE = 90.0;
private TiltPanCameraFixture tpcam;
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() throws Exception {
logger.fine("Setup: TiltPan camera");
tpcam = TestBench.getInstance().getTiltPanCam();
tpcam.setup();
}
@After
public void tearDown() throws Exception {
tpcam.reset();
tpcam.teardown();
}
@Test
public void testInitial() {
double angle = tpcam.getGyro().getAngle();
assertEquals(errorMessage(angle, 0), 0, angle, .5);
}
/**
* Test to see if the Servo and the gyroscope is turning 90 degrees Note servo
* on TestBench is not the same type of servo that servo class was designed
* for so setAngle is significantly off. This has been calibrated for the
* servo on the rig.
*/
@Test
public void testGyroAngle() {
// Set angle
for (int i = 0; i < 5; i++) {
tpcam.getPan().set(0);
Timer.delay(.1);
}
Timer.delay(0.5);
// Reset for setup
tpcam.getGyro().reset();
Timer.delay(0.5);
// Perform test
for (int i = 0; i < 53; i++) {
tpcam.getPan().set(i / 100.0);
Timer.delay(0.05);
}
Timer.delay(1.2);
double angle = tpcam.getGyro().getAngle();
double difference = TEST_ANGLE - angle;
double diff = Math.abs(difference);
assertEquals(errorMessage(diff, TEST_ANGLE), TEST_ANGLE, angle, 10);
}
@Test
public void testDeviationOverTime() {
// Make sure that the test isn't influenced by any previous motions.
Timer.delay(0.25);
tpcam.getGyro().reset();
Timer.delay(0.25);
double angle = tpcam.getGyro().getAngle();
assertEquals(errorMessage(angle, 0), 0, angle, .5);
Timer.delay(5);
angle = tpcam.getGyro().getAngle();
assertEquals("After 5 seconds " + errorMessage(angle, 0), 0, angle, 1);
}
private String errorMessage(double difference, double target) {
return "Gyro angle skewed " + difference + " deg away from target " + target;
}
}

View File

@@ -0,0 +1,230 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
@RunWith(Parameterized.class)
public class MotorEncoderTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(MotorEncoderTest.class.getName());
private static final double MOTOR_RUNTIME = .25;
// private static final List<MotorEncoderFixture> pairs = new
// ArrayList<MotorEncoderFixture>();
private static MotorEncoderFixture<?> me = null;
@Override
protected Logger getClassLogger() {
return logger;
}
public MotorEncoderTest(MotorEncoderFixture<?> mef) {
logger.fine("Constructor with: " + mef.getType());
if (me != null && !me.equals(mef))
me.teardown();
me = mef;
}
@Parameters(name = "{index}: {0}")
public static Collection<MotorEncoderFixture<?>[]> generateData() {
// logger.fine("Loading the MotorList");
return Arrays.asList(new MotorEncoderFixture<?>[][] { {TestBench.getInstance().getTalonPair()},
{TestBench.getInstance().getVictorPair()}, {TestBench.getInstance().getJaguarPair()}});
}
@Before
public void setUp() {
double initialSpeed = me.getMotor().get();
assertTrue(me.getType() + " Did not start with an initial speeed of 0 instead got: "
+ initialSpeed, Math.abs(initialSpeed) < 0.001);
me.setup();
}
@After
public void tearDown() throws Exception {
me.reset();
encodersResetCheck(me);
}
@AfterClass
public static void tearDownAfterClass() {
// Clean up the fixture after the test
me.teardown();
me = null;
}
/**
* Test to ensure that the isMotorWithinRange method is functioning properly.
* Really only needs to run on one MotorEncoderFixture to ensure that it is
* working correctly.
*/
@Test
public void testIsMotorWithinRange() {
double range = 0.01;
assertTrue(me.getType() + " 1", me.isMotorSpeedWithinRange(0.0, range));
assertTrue(me.getType() + " 2", me.isMotorSpeedWithinRange(0.0, -range));
assertFalse(me.getType() + " 3", me.isMotorSpeedWithinRange(1.0, range));
assertFalse(me.getType() + " 4", me.isMotorSpeedWithinRange(-1.0, range));
}
/**
* This test is designed to see if the values of different motors will
* increment when spun forward
*/
@Test
public void testIncrement() {
int startValue = me.getEncoder().get();
me.getMotor().set(.75);
Timer.delay(MOTOR_RUNTIME);
int currentValue = me.getEncoder().get();
assertTrue(me.getType() + " Encoder not incremented: start: " + startValue + "; current: "
+ currentValue, startValue < currentValue);
}
/**
* This test is designed to see if the values of different motors will
* decrement when spun in reverse
*/
@Test
public void testDecrement() {
int startValue = me.getEncoder().get();
me.getMotor().set(-.75);
Timer.delay(MOTOR_RUNTIME);
int currentValue = me.getEncoder().get();
assertTrue(me.getType() + " Encoder not decremented: start: " + startValue + "; current: "
+ currentValue, startValue > currentValue);
}
/**
* This method test if the counters count when the motors rotate
*/
@Test
public void testCounter() {
int counter1Start = me.getCounters()[0].get();
int counter2Start = me.getCounters()[1].get();
me.getMotor().set(.75);
Timer.delay(MOTOR_RUNTIME);
int counter1End = me.getCounters()[0].get();
int counter2End = me.getCounters()[1].get();
assertTrue(me.getType() + " Counter not incremented: start: " + counter1Start + "; current: "
+ counter1End, counter1Start < counter1End);
assertTrue(me.getType() + " Counter not incremented: start: " + counter1Start + "; current: "
+ counter2End, counter2Start < counter2End);
me.reset();
encodersResetCheck(me);
}
/**
* Tests to see if you set the speed to something not <= 1.0 if the code
* appropriately throttles the value
*/
@Test
public void testSetHighForwardSpeed() {
me.getMotor().set(15);
assertTrue(me.getType() + " Motor speed was not close to 1.0, was: " + me.getMotor().get(),
me.isMotorSpeedWithinRange(1.0, 0.001));
}
/**
* Tests to see if you set the speed to something not >= -1.0 if the code
* appropriately throttles the value
*/
@Test
public void testSetHighReverseSpeed() {
me.getMotor().set(-15);
assertTrue(me.getType() + " Motor speed was not close to 1.0, was: " + me.getMotor().get(),
me.isMotorSpeedWithinRange(-1.0, 0.001));
}
@Test
public void testPositionPIDController() {
me.getEncoder().setPIDSourceType(PIDSourceType.kDisplacement);
PIDController pid = new PIDController(0.003, 0.001, 0, me.getEncoder(), me.getMotor());
pid.setAbsoluteTolerance(50);
pid.setOutputRange(-0.2, 0.2);
pid.setSetpoint(2500);
pid.enable();
Timer.delay(10.0);
pid.disable();
assertTrue(
"PID loop did not reach setpoint within 10 seconds. The error was: " + pid.getError(),
pid.onTarget());
pid.free();
}
@Test
public void testVelocityPIDController() {
me.getEncoder().setPIDSourceType(PIDSourceType.kRate);
PIDController pid =
new PIDController(1e-5, 0.0, 3e-5, 8e-5, me.getEncoder(), me.getMotor());
pid.setAbsoluteTolerance(200);
pid.setToleranceBuffer(50);
pid.setOutputRange(-0.3, 0.3);
pid.setSetpoint(2000);
pid.enable();
Timer.delay(10.0);
pid.disable();
assertTrue(
"PID loop did not reach setpoint within 10 seconds. The error was: " + pid.getAvgError(),
pid.onTarget());
pid.free();
}
/**
* Checks to see if the encoders and counters are appropriately reset to zero
* when reset
*$
* @param me The MotorEncoderFixture under test
*/
private void encodersResetCheck(MotorEncoderFixture<?> me) {
assertEquals(me.getType() + " Encoder value was incorrect after reset.", me.getEncoder().get(),
0);
assertEquals(me.getType() + " Motor value was incorrect after reset.", me.getMotor().get(), 0,
0);
assertEquals(me.getType() + " Counter1 value was incorrect after reset.",
me.getCounters()[0].get(), 0);
assertEquals(me.getType() + " Counter2 value was incorrect after reset.",
me.getCounters()[1].get(), 0);
Timer.delay(0.5); // so this doesn't fail with the 0.5 second default
// timeout on the encoders
assertTrue(me.getType() + " Encoder.getStopped() returned false after the motor was reset.", me
.getEncoder().getStopped());
}
}

View File

@@ -0,0 +1,120 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
/**
* Tests Inversion of motors using the SpeedController setInverted
*/
@RunWith(Parameterized.class)
public class MotorInvertingTest extends AbstractComsSetup {
static MotorEncoderFixture<?> fixture = null;
private static final double motorspeed = 0.35;
private static final double delaytime = 0.3;
public MotorInvertingTest(MotorEncoderFixture<?> afixture) {
logger.fine("Constructor with: " + afixture.getType());
if (fixture != null && !fixture.equals(afixture))
fixture.teardown();
fixture = afixture;
fixture.setup();
}
@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<MotorEncoderFixture<?>[]> generateData() {
// logger.fine("Loading the MotorList");
return Arrays.asList(new MotorEncoderFixture<?>[][] { {TestBench.getInstance().getTalonPair()},
{TestBench.getInstance().getVictorPair()}, {TestBench.getInstance().getJaguarPair()}});
}
private static final Logger logger = Logger.getLogger(MotorInvertingTest.class.getName());
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() {
// Reset the fixture elements before every test
fixture.reset();
}
@AfterClass
public static void tearDown() {
fixture.getMotor().setInverted(false);
// Clean up the fixture after the test
fixture.teardown();
}
@Test
public void testInvertingPositive() {
fixture.getMotor().setInverted(false);
fixture.getMotor().set(motorspeed);
Timer.delay(delaytime);
boolean initDirection = fixture.getEncoder().getDirection();
fixture.getMotor().setInverted(true);
fixture.getMotor().set(motorspeed);
Timer.delay(delaytime);
assertFalse("Inverting with Positive value does not change direction", fixture.getEncoder()
.getDirection() == initDirection);
fixture.getMotor().set(0);
}
@Test
public void testInvertingNegative() {
fixture.getMotor().setInverted(false);
fixture.getMotor().set(-motorspeed);
Timer.delay(delaytime);
boolean initDirection = fixture.getEncoder().getDirection();
fixture.getMotor().setInverted(true);
fixture.getMotor().set(-motorspeed);
Timer.delay(delaytime);
assertFalse("Inverting with Negative value does not change direction", fixture.getEncoder()
.getDirection() == initDirection);
fixture.getMotor().set(0);
}
@Test
public void testInvertingSwitchingPosToNeg() {
fixture.getMotor().setInverted(false);
fixture.getMotor().set(motorspeed);
Timer.delay(delaytime);
boolean initDirection = fixture.getEncoder().getDirection();
fixture.getMotor().setInverted(true);
fixture.getMotor().set(-motorspeed);
Timer.delay(delaytime);
assertTrue("Inverting with Switching value does change direction", fixture.getEncoder()
.getDirection() == initDirection);
fixture.getMotor().set(0);
}
@Test
public void testInvertingSwitchingNegToPos() {
fixture.getMotor().setInverted(false);
fixture.getMotor().set(-motorspeed);
Timer.delay(delaytime);
boolean initDirection = fixture.getEncoder().getDirection();
fixture.getMotor().setInverted(true);
fixture.getMotor().set(motorspeed);
Timer.delay(delaytime);
assertTrue("Inverting with Switching value does change direction", fixture.getEncoder()
.getDirection() == initDirection);
fixture.getMotor().set(0);
}
}

View File

@@ -0,0 +1,179 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.*;
import java.util.concurrent.Delayed;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* @author Kacper Puczydlowski
*
*/
public class PCMTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(PCMTest.class.getName());
/*
* The PCM switches the compressor up to 2 seconds after the pressure switch
* changes.
*/
protected static final double kCompressorDelayTime = 2.0;
/* Solenoids should change much more quickly */
protected static final double kSolenoidDelayTime = 1.0;
/*
* The voltage divider on the test bench should bring the compressor output to
* around these values.
*/
protected static final double kCompressorOnVoltage = 5.00;
protected static final double kCompressorOffVoltage = 1.68;
private static Compressor compressor;
private static DigitalOutput fakePressureSwitch;
private static AnalogInput fakeCompressor;
private static DigitalInput fakeSolenoid1, fakeSolenoid2;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
compressor = new Compressor();
fakePressureSwitch = new DigitalOutput(11);
fakeCompressor = new AnalogInput(1);
fakeSolenoid1 = new DigitalInput(12);
fakeSolenoid2 = new DigitalInput(13);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
compressor.free();
fakePressureSwitch.free();
fakeCompressor.free();
fakeSolenoid1.free();
fakeSolenoid2.free();
}
@Before
public void setUp() throws Exception {}
@Before
public void reset() throws Exception {
compressor.stop();
fakePressureSwitch.set(false);
}
@After
public void tearDown() throws Exception {}
/**
* Test if the compressor turns on and off when the pressure switch is toggled
*/
@Test
public void testPressureSwitch() throws Exception {
double range = 0.1;
reset();
compressor.setClosedLoopControl(true);
// Turn on the compressor
fakePressureSwitch.set(true);
Timer.delay(kCompressorDelayTime);
assertEquals("Compressor did not turn on when the pressure switch turned on.",
kCompressorOnVoltage, fakeCompressor.getVoltage(), range);
// Turn on the compressor
fakePressureSwitch.set(false);
Timer.delay(kCompressorDelayTime);
assertEquals("Compressor did not turn off when the pressure switch turned off.",
kCompressorOffVoltage, fakeCompressor.getVoltage(), range);
}
/**
* Test if the correct solenoids turn on and off when they should
*/
@Test
public void testSolenoid() throws Exception {
reset();
Solenoid solenoid1 = new Solenoid(0);
Solenoid solenoid2 = new Solenoid(1);
solenoid1.set(false);
solenoid2.set(false);
Timer.delay(kSolenoidDelayTime);
assertTrue("Solenoid #1 did not turn on", fakeSolenoid1.get());
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
// Turn Solenoid #1 on, and turn Solenoid #2 off
solenoid1.set(true);
solenoid2.set(false);
Timer.delay(kSolenoidDelayTime);
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
// Turn Solenoid #1 off, and turn Solenoid #2 on
solenoid1.set(false);
solenoid2.set(true);
Timer.delay(kSolenoidDelayTime);
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
// Turn both Solenoids on
solenoid1.set(true);
solenoid2.set(true);
Timer.delay(kSolenoidDelayTime);
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
solenoid1.free();
solenoid2.free();
}
/**
* Test if the correct solenoids turn on and off when they should when used
* with the DoubleSolenoid class.
*/
@Test
public void doubleSolenoid() {
DoubleSolenoid solenoid = new DoubleSolenoid(0, 1);
solenoid.set(DoubleSolenoid.Value.kOff);
Timer.delay(kSolenoidDelayTime);
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
solenoid.set(DoubleSolenoid.Value.kForward);
Timer.delay(kSolenoidDelayTime);
assertFalse("Solenoid #1 did not turn on", fakeSolenoid1.get());
assertTrue("Solenoid #2 did not turn off", fakeSolenoid2.get());
solenoid.set(DoubleSolenoid.Value.kReverse);
Timer.delay(kSolenoidDelayTime);
assertTrue("Solenoid #1 did not turn off", fakeSolenoid1.get());
assertFalse("Solenoid #2 did not turn on", fakeSolenoid2.get());
solenoid.free();
}
protected Logger getClassLogger() {
return logger;
}
}

View File

@@ -0,0 +1,104 @@
package edu.wpi.first.wpilibj;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.can.CANMessageNotFoundException;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
@RunWith(Parameterized.class)
public class PDPTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(PCMTest.class.getName());
private static PowerDistributionPanel pdp;
private static MotorEncoderFixture<?> me;
private final double expectedStoppedCurrentDraw;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
pdp = new PowerDistributionPanel();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
pdp.free();
pdp = null;
me.teardown();
me = null;
}
public PDPTest(MotorEncoderFixture<?> mef, Double expectedCurrentDraw) {
logger.fine("Constructor with: " + mef.getType());
if (me != null && !me.equals(mef))
me.teardown();
me = mef;
me.setup();
this.expectedStoppedCurrentDraw = expectedCurrentDraw;
}
@Parameters(name = "{index}: {0}, Expected Stopped Current Draw: {1}")
public static Collection<Object[]> generateData() {
// logger.fine("Loading the MotorList");
return Arrays.asList(new Object[][] {
{TestBench.getInstance().getTalonPair(), new Double(0.0)},
{TestBench.getInstance().getVictorPair(), new Double(0.0)},
{TestBench.getInstance().getJaguarPair(), new Double(0.0)}});
}
@After
public void tearDown() throws Exception {
me.reset();
}
/**
* Test if the current changes when the motor is driven using a talon
*/
@Test
public void CheckStoppedCurrentForSpeedController() throws CANMessageNotFoundException {
Timer.delay(0.25);
/* The Current should be 0 */
assertEquals("The low current was not within the expected range.", expectedStoppedCurrentDraw,
pdp.getCurrent(me.getPDPChannel()), 0.001);
}
/**
* Test if the current changes when the motor is driven using a talon
*/
@Test
public void CheckRunningCurrentForSpeedController() throws CANMessageNotFoundException {
/* Set the motor to full forward */
me.getMotor().set(1.0);
Timer.delay(0.25);
/* The current should now be greater than the low current */
assertThat("The driven current is not greater than the resting current.",
pdp.getCurrent(me.getPDPChannel()), is(greaterThan(expectedStoppedCurrentDraw)));
}
@Override
protected Logger getClassLogger() {
return logger;
}
}

View File

@@ -0,0 +1,206 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
import edu.wpi.first.wpilibj.networktables.NetworkTable;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* @author Kacper Puczydlowski
* @author Jonathan Leitschuh
*
*/
@RunWith(Parameterized.class)
public class PIDTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(PIDTest.class.getName());
private NetworkTable table;
private static final double absoluteTolerance = 50;
private static final double outputRange = 0.3;
private PIDController controller = null;
private static MotorEncoderFixture me = null;
private final Double k_p, k_i, k_d;
@Override
protected Logger getClassLogger() {
return logger;
}
public PIDTest(Double p, Double i, Double d, MotorEncoderFixture mef) {
logger.fine("Constructor with: " + mef.getType());
if (PIDTest.me != null && !PIDTest.me.equals(mef))
PIDTest.me.teardown();
PIDTest.me = mef;
this.k_p = p;
this.k_i = i;
this.k_d = d;
}
@Parameters
public static Collection<Object[]> generateData() {
// logger.fine("Loading the MotorList");
Collection<Object[]> data = new ArrayList<Object[]>();
double kp = 0.001;
double ki = 0.0005;
double kd = 0.0;
for (int i = 0; i < 1; i++) {
data.addAll(Arrays.asList(new Object[][] {
{kp, ki, kd, TestBench.getInstance().getTalonPair()},
{kp, ki, kd, TestBench.getInstance().getVictorPair()},
{kp, ki, kd, TestBench.getInstance().getJaguarPair()}}));
}
return data;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
logger.fine("TearDownAfterClass: " + me.getType());
me.teardown();
me = null;
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
logger.fine("Setup: " + me.getType());
me.setup();
table = NetworkTable.getTable("TEST_PID");
controller = new PIDController(k_p, k_i, k_d, me.getEncoder(), me.getMotor());
controller.initTable(table);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
logger.fine("Teardown: " + me.getType());
controller.disable();
controller.free();
controller = null;
me.reset();
}
private void setupAbsoluteTolerance() {
controller.setAbsoluteTolerance(absoluteTolerance);
}
private void setupOutputRange() {
controller.setOutputRange(-outputRange, outputRange);
}
@Test
public void testInitialSettings() {
setupAbsoluteTolerance();
setupOutputRange();
double setpoint = 2500.0;
controller.setSetpoint(setpoint);
assertFalse("PID did not begin disabled", controller.isEnable());
assertEquals("PID.getError() did not start at " + setpoint, setpoint, controller.getError(), 0);
assertEquals(k_p, table.getNumber("p"), 0);
assertEquals(k_i, table.getNumber("i"), 0);
assertEquals(k_d, table.getNumber("d"), 0);
assertEquals(setpoint, table.getNumber("setpoint"), 0);
assertFalse(table.getBoolean("enabled"));
}
@Test
public void testRestartAfterEnable() {
setupAbsoluteTolerance();
setupOutputRange();
double setpoint = 2500.0;
controller.setSetpoint(setpoint);
controller.enable();
Timer.delay(.5);
assertTrue(table.getBoolean("enabled"));
assertTrue(controller.isEnable());
assertThat(0.0, is(not(me.getMotor().get())));
controller.reset();
assertFalse(table.getBoolean("enabled"));
assertFalse(controller.isEnable());
assertEquals(0, me.getMotor().get(), 0);
}
@Test
public void testSetSetpoint() {
setupAbsoluteTolerance();
setupOutputRange();
Double setpoint = 2500.0;
controller.disable();
controller.setSetpoint(setpoint);
controller.enable();
assertEquals("Did not correctly set set-point", setpoint, new Double(controller.getSetpoint()));
}
@Test(timeout = 10000)
public void testRotateToTarget() {
setupAbsoluteTolerance();
setupOutputRange();
double setpoint = 2500.0;
assertEquals(pidData() + "did not start at 0", 0, controller.get(), 0);
controller.setSetpoint(setpoint);
assertEquals(pidData() + "did not have an error of " + setpoint, setpoint,
controller.getError(), 0);
controller.enable();
Timer.delay(5);
controller.disable();
assertTrue(pidData() + "Was not on Target. Controller Error: " + controller.getError(),
controller.onTarget());
}
private String pidData() {
return me.getType() + " PID {P:" + controller.getP() + " I:" + controller.getI() + " D:"
+ controller.getD() + "} ";
}
@Test(expected = RuntimeException.class)
public void testOnTargetNoToleranceSet() {
setupOutputRange();
controller.onTarget();
}
}

View File

@@ -0,0 +1,123 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import edu.wpi.first.wpilibj.networktables.NetworkTable;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* @author jonathanleitschuh
*
*/
public class PreferencesTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(PreferencesTest.class.getName());
private NetworkTable prefTable;
private Preferences pref;
private long check;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
NetworkTable.shutdown();
try {
File file = new File("networktables.ini");
file.mkdirs();
if (file.exists()) {
file.delete();
}
file.createNewFile();
OutputStream output = new FileOutputStream(file);
output
.write("[NetworkTables Storage 3.0]\ndouble \"/Preferences/checkedValueInt\"=2\ndouble \"/Preferences/checkedValueDouble\"=.2\ndouble \"/Preferences/checkedValueFloat\"=3.14\ndouble \"/Preferences/checkedValueLong\"=172\nstring \"/Preferences/checkedValueString\"=\"hello \\nHow are you ?\"\nboolean \"/Preferences/checkedValueBoolean\"=false\n"
.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
NetworkTable.initialize();
pref = Preferences.getInstance();
prefTable = NetworkTable.getTable("Preferences");
check = System.currentTimeMillis();
}
public void remove() {
pref.remove("checkedValueLong");
pref.remove("checkedValueDouble");
pref.remove("checkedValueString");
pref.remove("checkedValueInt");
pref.remove("checkedValueFloat");
pref.remove("checkedValueBoolean");
}
public void addCheckedValue() {
pref.putLong("checkedValueLong", check);
pref.putDouble("checkedValueDouble", 1);
pref.putString("checkedValueString", "checked");
pref.putInt("checkedValueInt", 1);
pref.putFloat("checkedValueFloat", 1);
pref.putBoolean("checkedValueBoolean", true);
}
@Test
public void testAddRemoveSave() {
assertEquals(pref.getLong("checkedValueLong", 0), 172L);
assertEquals(pref.getDouble("checkedValueDouble", 0), .2, 0);
assertEquals(pref.getString("checkedValueString", ""), "hello \nHow are you ?");
assertEquals(pref.getInt("checkedValueInt", 0), 2);
assertEquals(pref.getFloat("checkedValueFloat", 0), 3.14, .001);
assertFalse(pref.getBoolean("checkedValueBoolean", true));
remove();
assertEquals(pref.getLong("checkedValueLong", 0), 0);
assertEquals(pref.getDouble("checkedValueDouble", 0), 0, 0);
assertEquals(pref.getString("checkedValueString", ""), "");
assertEquals(pref.getInt("checkedValueInt", 0), 0);
assertEquals(pref.getFloat("checkedValueFloat", 0), 0, 0);
assertFalse(pref.getBoolean("checkedValueBoolean", false));
addCheckedValue();
pref.save();
assertEquals(check, pref.getLong("checkedValueLong", 0));
assertEquals(pref.getDouble("checkedValueDouble", 0), 1, 0);
assertEquals(pref.getString("checkedValueString", ""), "checked");
assertEquals(pref.getInt("checkedValueInt", 0), 1);
assertEquals(pref.getFloat("checkedValueFloat", 0), 1, 0);
assertTrue(pref.getBoolean("checkedValueBoolean", false));
}
@Test
public void testPreferencesToNetworkTables() {
String networkedNumber = "networkCheckedValue";
int networkNumberValue = 100;
pref.putInt(networkedNumber, networkNumberValue);
assertEquals(networkNumberValue, (int)(prefTable.getNumber(networkedNumber)));
pref.remove(networkedNumber);
}
}

View File

@@ -0,0 +1,118 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.Relay.Direction;
import edu.wpi.first.wpilibj.Relay.InvalidValueException;
import edu.wpi.first.wpilibj.Relay.Value;
import edu.wpi.first.wpilibj.fixtures.RelayCrossConnectFixture;
import edu.wpi.first.wpilibj.networktables.NetworkTable;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* @author jonathanleitschuh
*
*/
public class RelayCrossConnectTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(RelayCrossConnectTest.class.getName());
private static final NetworkTable table = NetworkTable.getTable("_RELAY_CROSS_CONNECT_TEST_");
private RelayCrossConnectFixture relayFixture;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
relayFixture = TestBench.getRelayCrossConnectFixture();
relayFixture.setup();
relayFixture.getRelay().initTable(table);
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
relayFixture.reset();
relayFixture.teardown();
}
@Test
public void testBothHigh() {
relayFixture.getRelay().setDirection(Direction.kBoth);
relayFixture.getRelay().set(Value.kOn);
relayFixture.getRelay().updateTable();
assertTrue("Input one was not high when relay set both high", relayFixture.getInputOne().get());
assertTrue("Input two was not high when relay set both high", relayFixture.getInputTwo().get());
assertEquals("On", table.getString("Value"));
}
@Test
public void testFirstHigh() {
relayFixture.getRelay().setDirection(Direction.kBoth);
relayFixture.getRelay().set(Value.kForward);
relayFixture.getRelay().updateTable();
assertFalse("Input one was not low when relay set Value.kForward", relayFixture.getInputOne()
.get());
assertTrue("Input two was not high when relay set Value.kForward", relayFixture.getInputTwo()
.get());
assertEquals("Forward", table.getString("Value"));
}
@Test
public void testSecondHigh() {
relayFixture.getRelay().setDirection(Direction.kBoth);
relayFixture.getRelay().set(Value.kReverse);
relayFixture.getRelay().updateTable();
assertTrue("Input one was not high when relay set Value.kReverse", relayFixture.getInputOne()
.get());
assertFalse("Input two was not low when relay set Value.kReverse", relayFixture.getInputTwo()
.get());
assertEquals("Reverse", table.getString("Value"));
}
@Test(expected = InvalidValueException.class)
public void testSetValueForwardWithDirectionReverseThrowingException() {
relayFixture.getRelay().setDirection(Direction.kForward);
relayFixture.getRelay().set(Value.kReverse);
}
@Test(expected = InvalidValueException.class)
public void testSetValueReverseWithDirectionForwardThrowingException() {
relayFixture.getRelay().setDirection(Direction.kReverse);
relayFixture.getRelay().set(Value.kForward);
}
@Test
public void testInitialSettings() {
assertEquals(Value.kOff, relayFixture.getRelay().get());
// Initially both outputs should be off
assertFalse(relayFixture.getInputOne().get());
assertFalse(relayFixture.getInputTwo().get());
assertEquals("Off", table.getString("Value"));
}
@Override
protected Logger getClassLogger() {
return logger;
}
}

View File

@@ -0,0 +1,73 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertTrue;
import java.util.logging.Logger;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.fixtures.SampleFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.hal.CanTalonSRX;
import edu.wpi.first.wpilibj.hal.SWIGTYPE_p_UINT8;
/**
* Sample test for a sample PID controller. This demonstrates the general
* pattern of how to create a test and use testing fixtures and categories.
*$
* All tests must extend from {@link AbstractComsSetup} in order to ensure that
* Network Communications are set up before the tests are run.
*$
* @author Fredric Silberberg
*/
public class SampleTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(SampleTest.class.getName());
static SampleFixture fixture = new SampleFixture();
protected Logger getClassLogger() {
return logger;
}
@BeforeClass
public static void classSetup() {
// Set up the fixture before the test is created
fixture.setup();
}
@Before
public void setUp() {
// Reset the fixture elements before every test
fixture.reset();
}
@AfterClass
public static void tearDown() {
// Clean up the fixture after the test
fixture.teardown();
}
/**
* This is just a sample test that asserts true. Any traditional junit code
* can be used, these are ordinary junit tests!
*/
@Test
public void test() {
CanTalonSRX cantalon = new CanTalonSRX();
cantalon.Set(0.5);
Timer.delay(0.5);
cantalon.Set(0.0);
assertTrue(true);
}
}

View File

@@ -0,0 +1,44 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import static org.junit.Assert.assertEquals;
import java.util.logging.Logger;
import org.junit.Test;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
public class TimerTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(TimerTest.class.getName());
private static final long TIMER_TOLERANCE = (long) (2.5 * 1000);
private static final long TIMER_RUNTIME = 5 * 1000000;
@Override
protected Logger getClassLogger() {
return logger;
}
@Test
public void delayTest() {
// Given
long startTime = Utility.getFPGATime();
// When
Timer.delay(TIMER_RUNTIME / 1000000);
long endTime = Utility.getFPGATime();
long difference = endTime - startTime;
// Then
long offset = difference - TIMER_RUNTIME;
assertEquals("Timer.delay ran " + offset + " microseconds too long", TIMER_RUNTIME, difference,
TIMER_TOLERANCE);
}
}

View File

@@ -0,0 +1,27 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import edu.wpi.first.wpilibj.test.AbstractTestSuite;
/**
* @author Jonathan Leitschuh Holds all of the tests in the root wpilibj
* directory Please list alphabetically so that it is easy to determine
* if a test is missing from the list
*/
@RunWith(Suite.class)
@SuiteClasses({AnalogCrossConnectTest.class, AnalogPotentiometerTest.class,
BuiltInAccelerometerTest.class, CANTalonTest.class, CounterTest.class,
DIOCrossConnectTest.class, EncoderTest.class, GyroTest.class, MotorEncoderTest.class,
MotorInvertingTest.class, PCMTest.class, PDPTest.class, PIDTest.class, PreferencesTest.class,
RelayCrossConnectTest.class, SampleTest.class, TimerTest.class})
public class WpiLibJTestSuite extends AbstractTestSuite {
}

View File

@@ -0,0 +1,108 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import org.junit.After;
import org.junit.Before;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.fixtures.CANMotorEncoderFixture;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Provides a base implementation for CAN Tests that forces a test of a
* particular mode to provide tests of a certain type. This also allows for a
* standardized base setup for each test.
*$
* @author jonathanleitschuh
*
*/
public abstract class AbstractCANTest extends AbstractComsSetup {
public static final double kMotorStopTime = 2;
public static final double kMotorTime = 3;
public static final double kMotorTimeSettling = 10;
public static final double kPotentiometerSettlingTime = 10.0;
public static final double kEncoderSettlingTime = 0.50;
public static final double kEncoderSpeedTolerance = 20.0;
public static final double kLimitSettlingTime = 20.0; // timeout in seconds
public static final double kStartupTime = 0.50;
public static final double kEncoderPositionTolerance = .75;
public static final double kPotentiometerPositionTolerance = 10.0 / 360.0; // +/-10
// degrees
public static final double kCurrentTolerance = 0.1;
/**
* Stores the status value for the previous test. This is set immediately
* after a failure or success and before the me is torn down.
*/
private String status = "";
/**
* Extends the default test watcher in order to provide more information about
* a tests failure at runtime.
*$
* @author jonathanleitschuh
*
*/
public class CANTestWatcher extends DefaultTestWatcher {
@Override
protected void failed(Throwable e, Description description) {
super.failed(e, description, status);
}
}
@Override
protected TestWatcher getOverridenTestWatcher() {
return new CANTestWatcher();
}
/** The Fixture under test */
private CANMotorEncoderFixture me;
/**
* Retrieves the CANMotorEncoderFixture
*$
* @return the CANMotorEncoderFixture for this test.
*/
public CANMotorEncoderFixture getME() {
return me;
}
/**
* This runs BEFORE the setup of the inherited class
*/
@Before
public final void preSetup() {
status = "";
me = TestBench.getInstance().getCanJaguarPair();
me.setup();
me.getMotor().setSafetyEnabled(false);
}
@After
public final void tearDown() throws Exception {
try {
// Stores the status data before tearing it down.
// If the test fails unexpectedly then this could cause an exception.
status = me.printStatus();
} finally {
me.teardown();
}
me = null;
}
protected void setCANJaguar(double seconds, double value) {
for (int i = 0; i < 50; i++) {
getME().getMotor().set(value);
Timer.delay(seconds / 50.0);
}
}
}

View File

@@ -0,0 +1,107 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.junit.Assert.assertEquals;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import org.junit.Ignore;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANCurrentQuadEncoderModeTest extends AbstractCANTest {
private static Logger logger = Logger.getLogger(CANCurrentQuadEncoderModeTest.class.getName());
private static final double kStoppedValue = 0;
private static final double kRunningValue = 3.0;
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#stopMotor()
*/
protected void stopMotor() {
getME().getMotor().set(kStoppedValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorForward()
*/
protected void runMotorForward() {
getME().getMotor().set(kRunningValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorReverse()
*/
protected void runMotorReverse() {
getME().getMotor().set(-kRunningValue);
}
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() throws Exception {
getME().getMotor().setCurrentMode(CANJaguar.kQuadEncoder, 360, 10.0, 4.0, 1.0);
getME().getMotor().enableControl();
getME().getMotor().set(0.0f);
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
@Ignore
@Test
public void testDriveToCurrentPositive() {
double setpoint = 1.6f;
/* It should get to the setpoint within 10 seconds */
for (int i = 0; i < 10; i++) {
setCANJaguar(1.0, setpoint);
if (Math.abs(getME().getMotor().getOutputCurrent() - setpoint) <= kCurrentTolerance) {
break;
}
}
assertEquals("The desired output current was not reached", setpoint, getME().getMotor()
.getOutputCurrent(), kCurrentTolerance);
}
@Ignore
@Test
public void testDriveToCurrentNegative() {
double setpoint = -1.6f;
/* It should get to the setpoint within 10 seconds */
for (int i = 0; i < 10; i++) {
setCANJaguar(1.0, setpoint);
if (Math.abs(getME().getMotor().getOutputCurrent() - Math.abs(setpoint)) <= kCurrentTolerance) {
break;
}
}
assertEquals("The desired output current was not reached", Math.abs(setpoint), getME()
.getMotor().getOutputCurrent(), kCurrentTolerance);
}
}

View File

@@ -0,0 +1,233 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import com.googlecode.junittoolbox.PollingWait;
import com.googlecode.junittoolbox.RunnableAssert;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANDefaultTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANDefaultTest.class.getName());
private final PollingWait wait = new PollingWait().timeoutAfter(65, TimeUnit.MILLISECONDS)
.pollEvery(10, TimeUnit.MILLISECONDS);
private static final double kSpikeTime = .5;
@Override
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
getME().getMotor().enableControl();
getME().getMotor().set(0.0f);
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime / 2);
}
@Test
public void testDefaultGet() {
wait.until(new RunnableAssert("Waiting for CAN Jaguar get to return 0") {
@Override
public void run() {
assertEquals("CAN Jaguar did not initialize stopped", 0.0, getME().getMotor().get(), .01f);
}
});
}
@Test
public void testDefaultBusVoltage() {
wait.until(new RunnableAssert("Waiting for default bus voltage to be correct") {
@Override
public void run() {
assertEquals("CAN Jaguar did not start at 14 volts", 14.0f, getME().getMotor()
.getBusVoltage(), 2.0f);
}
});
}
@Test
public void testDefaultOutputVoltage() {
wait.until(new RunnableAssert("Waiting for output voltage to be correct") {
@Override
public void run() {
assertEquals("CAN Jaguar did not start with an output voltage of 0", 0.0f, getME()
.getMotor().getOutputVoltage(), 0.3f);
}
});
}
@Test
public void testDefaultOutputCurrent() {
wait.until(new RunnableAssert("Waiting for output current to be correct") {
@Override
public void run() {
assertEquals("CAN Jaguar did not start with an output current of 0", 0.0f, getME()
.getMotor().getOutputCurrent(), 0.3f);
}
});
}
@Test
public void testDefaultTemperature() {
final double room_temp = 18.0f;
wait.until(new RunnableAssert("Waiting for temperature to be correct") {
@Override
public void run() {
assertThat(
"CAN Jaguar did not start with an initial temperature greater than " + room_temp,
getME().getMotor().getTemperature(), is(greaterThan(room_temp)));
}
});
}
@Test
public void testDefaultForwardLimit() {
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
wait.until(new RunnableAssert("Waiting for forward limit to not be set") {
@Override
public void run() {
getME().getMotor().set(0);
assertTrue("CAN Jaguar did not start with the Forward Limit Switch Off", getME().getMotor()
.getForwardLimitOK());
}
});
}
@Test
public void testDefaultReverseLimit() {
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
wait.until(new RunnableAssert("Waiting for reverse limit to not be set") {
@Override
public void run() {
getME().getMotor().set(0);
assertTrue("CAN Jaguar did not start with the Reverse Limit Switch Off", getME().getMotor()
.getReverseLimitOK());
}
});
}
@Test
public void testDefaultNoFaults() {
wait.until(new RunnableAssert("Waiting for no faults") {
@Override
public void run() {
assertEquals("CAN Jaguar initialized with Faults", 0, getME().getMotor().getFaults());
}
});
}
@Test
public void testFakeLimitSwitchForwards() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getMotor().enableControl();
// When
getME().getForwardLimit().set(true);
// Then
PollingWait wait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("Setting the CANJAguar forward limit switch high") {
@Override
public void run() throws Exception {
getME().getMotor().set(0);
assertFalse(
"Setting the forward limit switch high did not cause the forward limit switch to trigger",
getME().getMotor().getForwardLimitOK());
}
});
}
@Test
public void testFakeLimitSwitchReverse() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getMotor().enableControl();
// When
getME().getReverseLimit().set(true);
// Then
PollingWait wait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("Setting the CANJAguar reverse limit switch high") {
@Override
public void run() throws Exception {
getME().getMotor().set(0);
assertFalse(
"Setting the reverse limit switch high did not cause the forward limit switch to trigger",
getME().getMotor().getReverseLimitOK());
}
});
}
@Test
public void testPositionModeVerifiesOnBrownOut() {
final double setpoint = 1.0;
// Given
getME().getMotor().setPositionMode(CANJaguar.kQuadEncoder, 360, 10.0, 0.1, 0.0);
getME().getMotor().enableControl();
setCANJaguar(kMotorTime, 0.0);
getME().powerOn();
// When
/* Turn the spike off and on again */
getME().powerOff();
Timer.delay(kSpikeTime);
getME().powerOn();
Timer.delay(kSpikeTime);
PollingWait wait =
new PollingWait().timeoutAfter(15, TimeUnit.SECONDS).pollEvery(1, TimeUnit.MILLISECONDS);
/*
* The jaguar should automatically get set to quad encoder position mode, so
* it should be able to reach a setpoint in a couple seconds.
*/
wait.until(new RunnableAssert("Waiting for CANJaguar to reach set-point") {
@Override
public void run() throws Exception {
getME().getMotor().set(setpoint);
assertEquals("CANJaguar should have resumed PID control after power cycle", setpoint,
getME().getMotor().getPosition(), kEncoderPositionTolerance);
}
});
}
}

View File

@@ -0,0 +1,78 @@
package edu.wpi.first.wpilibj.can;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import java.util.logging.Logger;
/**
* Created by Patrick Murphy on 3/30/15.
*/
public class CANJaguarInversionTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANJaguarInversionTest.class.getName());
private static final double motorVoltage = 5.0;
private static final double motorPercent = 0.5;
private static final double motorSpeed = 100;
private static final double delayTime = 0.75;
private static final double speedModeDelayTime = 2.0;
@Override
protected Logger getClassLogger() {
return logger;
}
@Test
public void testInvertingVoltageMode() {
getME().getMotor().setVoltageMode(CANJaguar.kQuadEncoder, 360);
InversionTest(motorVoltage, delayTime);
}
@Test
public void testInvertingPercentMode() {
getME().getMotor().setPercentMode(CANJaguar.kQuadEncoder, 360);
InversionTest(motorPercent, delayTime);
}
@Test
public void testInvertingSpeedMode() {
getME().getMotor().setSpeedMode(CANJaguar.kQuadEncoder, 360, 0.1, 0.003, 0.01);
InversionTest(motorSpeed, speedModeDelayTime);
}
/**
* Runs an inversion test To use set the jaguar to the proper
* mode(PercentVbus, voltage, speed)
*$
* @param setpoint the speed/voltage/percent to set the motor to
* @param delayTime the amount of time to delay between starting a motor and
* checking the encoder
*/
private void InversionTest(double setpoint, double delayTime) {
CANJaguar jag = this.getME().getMotor();
jag.enableControl();
jag.setInverted(false);
jag.set(setpoint);
Timer.delay(delayTime);
double initialSpeed = jag.getSpeed();
jag.set(0.0);
jag.setInverted(true);
jag.set(setpoint);
Timer.delay(delayTime);
jag.set(0.0);
double finalSpeed = jag.getSpeed();
assertTrue("Inverting with Positive value does not invert direction",
Math.signum(initialSpeed) != Math.signum(finalSpeed));
jag.set(-setpoint);
Timer.delay(delayTime);
initialSpeed = jag.getSpeed();
jag.set(0.0);
jag.setInverted(false);
jag.set(-setpoint);
Timer.delay(delayTime);
finalSpeed = jag.getSpeed();
jag.set(0.0);
assertTrue("Inverting with Negative value does not invert direction",
Math.signum(initialSpeed) != Math.signum(finalSpeed));
}
}

View File

@@ -0,0 +1,399 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import com.googlecode.junittoolbox.PollingWait;
import com.googlecode.junittoolbox.RunnableAssert;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANPercentQuadEncoderModeTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANPercentQuadEncoderModeTest.class
.getName());
private static final double kStoppedValue = 0;
private static final double kRunningValue = 1;
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#stopMotor()
*/
protected void stopMotor() {
getME().getMotor().set(kStoppedValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorForward()
*/
protected void runMotorForward() {
getME().getMotor().set(kRunningValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorReverse()
*/
protected void runMotorReverse() {
getME().getMotor().set(-kRunningValue);
}
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() {
getME().getMotor().setPercentMode(CANJaguar.kQuadEncoder, 360);
getME().getMotor().enableControl();
getME().getMotor().set(0.0f);
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
@Test
public void testDisableStopsTheMotor() {
// given
getME().getMotor().enableControl();
setCANJaguar(kMotorTime / 2, 1);
getME().getMotor().disableControl();
// when
simpleLog(Level.FINER, "The motor should stop running now");
setCANJaguar(kMotorTime / 2, 1);
final double initialPosition = getME().getMotor().getPosition();
setCANJaguar(kMotorTime / 2, 1);
// then
assertEquals("Speed did not go to zero when disabled in percent mode", 0, getME().getMotor()
.getSpeed(), kEncoderSpeedTolerance);
assertEquals(initialPosition, getME().getMotor().getPosition(), 10);
}
@Test
public void testRotateForward() {
// Given
getME().getMotor().enableControl();
final double initialPosition = getME().getMotor().getPosition();
// When
/* Drive the speed controller briefly to move the encoder */
runMotorForward();
// Then
PollingWait wait =
new PollingWait().timeoutAfter((long) kMotorTimeSettling, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("CANJaguar position incrementing") {
@Override
public void run() throws Exception {
runMotorForward();
assertThat("CANJaguar position should have increased after the motor moved", getME()
.getMotor().getPosition(), is(greaterThan(initialPosition)));
}
});
stopMotor();
}
@Test
public void testRotateReverse() {
// Given
getME().getMotor().enableControl();
final double initialPosition = getME().getMotor().getPosition();
// When
/* Drive the speed controller briefly to move the encoder */
runMotorReverse();
// Then
PollingWait wait =
new PollingWait().timeoutAfter((long) kMotorTimeSettling, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("CANJaguar position decrementing") {
@Override
public void run() throws Exception {
runMotorReverse();
assertThat("CANJaguar position should have decreased after the motor moved", getME()
.getMotor().getPosition(), is(lessThan(initialPosition)));
}
});
stopMotor();
}
/**
* Test if we can limit the Jaguar to not rotate forwards when the fake limit
* switch is tripped
*/
@Test
public void shouldNotRotateForwards_WhenFakeLimitSwitchForwardsIsTripped() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getForwardLimit().set(true);
getME().getReverseLimit().set(false);
getME().getMotor().enableControl();
stopMotor();
Timer.delay(kEncoderSettlingTime);
PollingWait wait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
/* Wait until the limits are recognized by the CANJaguar. */
wait.until(new RunnableAssert(
"Waiting for the forward and reverse limit switches to be in the correct state") {
@Override
public void run() throws Exception {
stopMotor();
assertFalse("[TEST SETUP] The forward limit switch is not in the correct state", getME()
.getMotor().getForwardLimitOK());
assertTrue("[TEST SETUP]The reverse limit switch is not in the correct state", getME()
.getMotor().getReverseLimitOK());
}
});
final double initialPosition = getME().getMotor().getPosition();
// When
/*
* Drive the speed controller briefly to move the encoder. If the limit
* switch is recognized, it shouldn't actually move.
*/
setCANJaguar(kMotorTime, 1);
stopMotor();
// Then
/* The position should be the same, since the limit switch was on. */
assertEquals("CAN Jaguar should not have moved with the forward limit switch pressed",
initialPosition, getME().getMotor().getPosition(), kEncoderPositionTolerance);
}
/**
* Test if we can rotate in reverse when the limit switch
*/
@Test
public void shouldRotateReverse_WhenFakeLimitSwitchForwardsIsTripped() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getForwardLimit().set(true);
getME().getReverseLimit().set(false);
getME().getMotor().enableControl();
stopMotor();
Timer.delay(kEncoderSettlingTime);
PollingWait limitWait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
/* Wait until the limits are recognized by the CANJaguar. */
limitWait.until(new RunnableAssert(
"Waiting for the forward and reverse limit switches to be in the correct state") {
@Override
public void run() throws Exception {
stopMotor();
assertFalse("[TEST SETUP] The forward limit switch is not in the correct state", getME()
.getMotor().getForwardLimitOK());
assertTrue("[TEST SETUP] The reverse limit switch is not in the correct state", getME()
.getMotor().getReverseLimitOK());
}
});
final double initialPosition = getME().getMotor().getPosition();
// When
/*
* Drive the speed controller in the other direction. It should actually
* move, since only the forward switch is activated.
*/
setCANJaguar(kMotorTime, -1);
// Then
PollingWait wait =
new PollingWait().timeoutAfter((long) kMotorTimeSettling, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("Waiting for the encoder to update") {
@Override
public void run() throws Exception {
runMotorReverse();
assertThat("CAN Jaguar should have moved in reverse while the forward limit was on",
getME().getMotor().getPosition(), is(lessThan(initialPosition)));
}
});
stopMotor();
}
/**
* Test if we can limit the Jaguar to only moving forwards with a fake limit
* switch.
*/
@Test
public void shouldNotRotateReverse_WhenFakeLimitSwitchReversesIsTripped() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getForwardLimit().set(false);
getME().getReverseLimit().set(true);
getME().getMotor().enableControl();
stopMotor();
Timer.delay(kEncoderSettlingTime);
PollingWait wait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
/* Wait until the limits are recognized by the CANJaguar. */
wait.until(new RunnableAssert(
"Waiting for the forward and reverse limit switches to be in the correct state") {
@Override
public void run() throws Exception {
stopMotor();
assertTrue("[TEST SETUP] The forward limit switch is not in the correct state", getME()
.getMotor().getForwardLimitOK());
assertFalse("[TEST SETUP] The reverse limit switch is not in the correct state", getME()
.getMotor().getReverseLimitOK());
}
});
final double initialPosition = getME().getMotor().getPosition();
// When
/*
* Drive the speed controller backwards briefly to move the encoder. If the
* limit switch is recognized, it shouldn't actually move.
*/
setCANJaguar(kMotorTime, -1);
stopMotor();
// Then
/* The position should be the same, since the limit switch was on. */
assertEquals("CAN Jaguar should not have moved with the limit switch pressed", initialPosition,
getME().getMotor().getPosition(), kEncoderPositionTolerance);
}
/**
* Test if we can limit the Jaguar to only moving forwards with a fake limit
* switch.
*/
/**
*$
*/
@Test
public void shouldRotateForward_WhenFakeLimitSwitchReversesIsTripped() {
// Given
getME().getMotor().configLimitMode(CANJaguar.LimitMode.SwitchInputsOnly);
getME().getForwardLimit().set(false);
getME().getReverseLimit().set(true);
getME().getMotor().enableControl();
PollingWait limitWait =
new PollingWait().timeoutAfter((long) kLimitSettlingTime, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
/* Wait until the limits are recognized by the CANJaguar. */
limitWait.until(new RunnableAssert(
"Waiting for the forward and reverse limit switches to be in the correct state") {
@Override
public void run() throws Exception {
stopMotor();
assertTrue("[TEST SETUP] The forward limit switch is not in the correct state", getME()
.getMotor().getForwardLimitOK());
assertFalse("[TEST SETUP] The reverse limit switch is not in the correct state", getME()
.getMotor().getReverseLimitOK());
}
});
final double initialPosition = getME().getMotor().getPosition();
// When
/*
* Drive the speed controller in the other direction. It should actually
* move, since only the reverse switch is activated.
*/
setCANJaguar(kMotorTime, 1);
// Then
/* The position should have increased */
PollingWait wait =
new PollingWait().timeoutAfter((long) kMotorTimeSettling, TimeUnit.SECONDS).pollEvery(1,
TimeUnit.MILLISECONDS);
wait.until(new RunnableAssert("Waiting for the encoder to update") {
@Override
public void run() throws Exception {
runMotorForward();
assertThat("CAN Jaguar should have moved forwards while the reverse limit was on", getME()
.getMotor().getPosition(), is(greaterThan(initialPosition)));
}
});
stopMotor();
}
@Ignore("Encoder is not yet wired to the FPGA")
@Test
public void testRotateForwardEncoderToFPGA() {
getME().getMotor().enableControl();
final double jagInitialPosition = getME().getMotor().getPosition();
final double encoderInitialPosition = getME().getEncoder().get();
getME().getMotor().set(1);
Timer.delay(kMotorStopTime);
getME().getMotor().set(0);
delayTillInCorrectStateWithMessage(Level.FINE, kEncoderSettlingTime,
"Forward Encodeder settling", new BooleanCheck() {
@Override
public boolean getAsBoolean() {
return Math.abs((getME().getMotor().getPosition() - jagInitialPosition)
- (getME().getEncoder().get() - encoderInitialPosition)) < kEncoderPositionTolerance;
}
});
assertEquals(getME().getMotor().getPosition() - jagInitialPosition, getME().getEncoder().get()
- encoderInitialPosition, kEncoderPositionTolerance);
}
@Ignore("Encoder is not yet wired to the FPGA")
@Test
public void testRotateReverseEncoderToFPGA() {
getME().getMotor().enableControl();
final double jagInitialPosition = getME().getMotor().getPosition();
final double encoderInitialPosition = getME().getEncoder().get();
getME().getMotor().set(-1);
Timer.delay(kMotorStopTime);
getME().getMotor().set(0);
delayTillInCorrectStateWithMessage(Level.FINE, kEncoderSettlingTime,
"Forward Encodeder settling", new BooleanCheck() {
@Override
public boolean getAsBoolean() {
return Math.abs((getME().getMotor().getPosition() - jagInitialPosition)
- (getME().getEncoder().get() - encoderInitialPosition)) < kEncoderPositionTolerance;
}
});
assertEquals(getME().getMotor().getPosition() - jagInitialPosition, getME().getEncoder().get()
- encoderInitialPosition, kEncoderPositionTolerance);
}
}

View File

@@ -0,0 +1,170 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import com.googlecode.junittoolbox.PollingWait;
import com.googlecode.junittoolbox.RunnableAssert;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
/**
* @author jonathanleitschuh
*
*/
public class CANPositionPotentiometerModeTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANPositionPotentiometerModeTest.class
.getName());
private static final double kStoppedValue = 0;
private static final int defaultPotAngle = 180;
private static final double maxPotVoltage = 3.0;
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#stopMotor()
*/
protected void stopMotor() {
getME().getMotor().set(.5);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorForward()
*/
protected void runMotorForward() {
getME().getMotor().set(1);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorReverse()
*/
protected void runMotorReverse() {
getME().getMotor().set(0);
}
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() throws Exception {
getME().getMotor().setPositionMode(CANJaguar.kPotentiometer, 5.0, 0.1, 2.0);
// getME().getMotor().configPotentiometerTurns(rotationRange);
getME().getFakePot().setMaxVoltage(maxPotVoltage);
getME().getFakePot().setVoltage(1.5);
stopMotor();
getME().getMotor().enableControl();
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
/**
* NOTICE: This is using the {@link MotorEncoderFixture#getEncoder()} instead
* of the one built into the CAN Jaguar
*/
@Ignore("Encoder is not yet wired to the FPGA")
@Test
public void testRotateForward() {
int initialPosition = getME().getEncoder().get();
/* Drive the speed controller briefly to move the encoder */
getME().getMotor().set(kStoppedValue);
Timer.delay(kMotorTimeSettling);
getME().getMotor().set(defaultPotAngle);
/* The position should have increased */
assertThat("CAN Jaguar position should have increased after the motor moved", getME()
.getEncoder().get(), is(greaterThan(initialPosition)));
}
/**
* NOTICE: This is using the {@link MotorEncoderFixture#getEncoder()} instead
* of the one built into the CAN Jaguar
*/
@Ignore("Encoder is not yet wired to the FPGA")
@Test
public void testRotateReverse() {
int initialPosition = getME().getEncoder().get();
/* Drive the speed controller briefly to move the encoder */
getME().getMotor().set(kStoppedValue);
Timer.delay(kMotorTimeSettling);
getME().getMotor().set(defaultPotAngle);
/* The position should have increased */
assertThat("CAN Jaguar position should have increased after the motor moved", getME()
.getEncoder().get(), is(greaterThan(initialPosition)));
}
/**
* Test if we can get a position in potentiometer mode, using an analog output
* as a fake potentiometer.
*/
@Test
public void testFakePotentiometerPosition() {
// TODO When https://github.com/Pragmatists/JUnitParams/issues/5 is resolved
// make this test parameterized
// Given
PollingWait wait =
new PollingWait().timeoutAfter((long) kPotentiometerSettlingTime, TimeUnit.SECONDS)
.pollEvery(1, TimeUnit.MILLISECONDS);
RunnableAssert assertion =
new RunnableAssert("Waiting for potentiometer position to be correct") {
@Override
public void run() throws Exception {
getME().getMotor().set(0);
assertEquals(
"CAN Jaguar should have returned the potentiometer position set by the analog output",
getME().getFakePot().getVoltage(), getME().getMotor().getPosition() * 3,
kPotentiometerPositionTolerance * 3);
}
};
// When
getME().getFakePot().setVoltage(0.0);
// Then
wait.until(assertion);
// When
getME().getFakePot().setVoltage(1.0);
// Then
wait.until(assertion);
// When
getME().getFakePot().setVoltage(2.0);
// Then
wait.until(assertion);
// When
getME().getFakePot().setVoltage(3.0);
// Then
wait.until(assertion);
}
}

View File

@@ -0,0 +1,120 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.junit.Assert.assertEquals;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANPositionQuadEncoderModeTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANPositionQuadEncoderModeTest.class
.getName());
@Override
protected Logger getClassLogger() {
return logger;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorForward()
*/
protected void runMotorForward() {
double postion = getME().getMotor().getPosition();
getME().getMotor().set(postion + 100);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorReverse()
*/
protected void runMotorReverse() {
double postion = getME().getMotor().getPosition();
getME().getMotor().set(postion - 100);
}
@Before
public void setUp() throws Exception {
getME().getMotor().setPositionMode(CANJaguar.kQuadEncoder, 360, 10.0f, 0.01f, 0.0f);
getME().getMotor().enableControl(0);
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
@Ignore("The encoder initial position is not validated so is sometimes not set properly")
@Test
public void testSetEncoderInitialPositionWithEnable() {
// given
final double encoderValue = 4823;
// when
getME().getMotor().enableControl(encoderValue);
getME().getMotor().disableControl();
delayTillInCorrectStateWithMessage(Level.FINE, kEncoderSettlingTime, "Encoder value settling",
new BooleanCheck() {
@Override
public boolean getAsBoolean() {
getME().getMotor().set(getME().getMotor().getPosition());
return Math.abs(getME().getMotor().getPosition() - encoderValue) < 40;
}
});
// then
assertEquals(encoderValue, getME().getMotor().getPosition(), 40);
}
/**
* Test if we can set a position and reach that position with PID control on
* the Jaguar.
*/
@Test
public void testEncoderPositionPIDForward() {
double setpoint = getME().getMotor().getPosition() + 1.0f;
/* It should get to the setpoint within 10 seconds */
getME().getMotor().set(setpoint);
setCANJaguar(kMotorTimeSettling, setpoint);
assertEquals("CAN Jaguar should have reached setpoint with PID control", setpoint, getME()
.getMotor().getPosition(), kEncoderPositionTolerance);
}
/**
* Test if we can set a position and reach that position with PID control on
* the Jaguar.
*/
@Test
public void testEncoderPositionPIDReverse() {
double setpoint = getME().getMotor().getPosition() - 1.0f;
/* It should get to the setpoint within 10 seconds */
getME().getMotor().set(setpoint);
setCANJaguar(kMotorTimeSettling, setpoint);
assertEquals("CAN Jaguar should have reached setpoint with PID control", setpoint, getME()
.getMotor().getPosition(), kEncoderPositionTolerance);
}
}

View File

@@ -0,0 +1,86 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANSpeedQuadEncoderModeTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANPercentQuadEncoderModeTest.class
.getName());
/** The stopped value in rev/min */
private static final double kStoppedValue = 0;
/** The running value in rev/min */
private static final double kRunningValue = 200;
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() throws Exception {
getME().getMotor().setSpeedMode(CANJaguar.kQuadEncoder, 360, 0.1f, 0.003f, 0.01f);
getME().getMotor().enableControl();
getME().getMotor().set(0.0f);
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
@Test
public void testDefaultSpeed() {
assertEquals("CAN Jaguar did not start with an initial speed of zero", 0.0f, getME().getMotor()
.getSpeed(), 0.3f);
}
/**
* Test if we can drive the motor forward in Speed mode and get a position
* back
*/
@Test
public void testRotateForwardSpeed() {
double speed = 50.0f;
double initialPosition = getME().getMotor().getPosition();
setCANJaguar(2 * kMotorTime, speed);
assertEquals("The motor did not reach the required speed in speed mode", speed, getME()
.getMotor().getSpeed(), kEncoderSpeedTolerance);
assertThat("The motor did not move forward in speed mode", getME().getMotor().getPosition(),
is(greaterThan(initialPosition)));
}
/**
* Test if we can drive the motor backwards in Speed mode and get a position
* back
*/
@Test
public void testRotateReverseSpeed() {
double speed = -50.0f;
double initialPosition = getME().getMotor().getPosition();
setCANJaguar(2 * kMotorTime, speed);
assertEquals("The motor did not reach the required speed in speed mode", speed, getME()
.getMotor().getSpeed(), kEncoderSpeedTolerance);
assertThat("The motor did not move in reverse in speed mode", getME().getMotor().getPosition(),
is(lessThan(initialPosition)));
}
}

View File

@@ -0,0 +1,26 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import edu.wpi.first.wpilibj.test.AbstractTestSuite;
/**
* @author jonathanleitschuh
*
*/
@RunWith(Suite.class)
@SuiteClasses({CANCurrentQuadEncoderModeTest.class, CANDefaultTest.class,
CANJaguarInversionTest.class, CANPercentQuadEncoderModeTest.class,
CANPositionPotentiometerModeTest.class, CANPositionQuadEncoderModeTest.class,
CANSpeedQuadEncoderModeTest.class, CANVoltageQuadEncoderModeTest.class})
public class CANTestSuite extends AbstractTestSuite {
}

View File

@@ -0,0 +1,219 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.can;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import com.googlecode.junittoolbox.PollingWait;
import com.googlecode.junittoolbox.RunnableAssert;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.Timer;
/**
* @author jonathanleitschuh
*
*/
public class CANVoltageQuadEncoderModeTest extends AbstractCANTest {
private static final Logger logger = Logger.getLogger(CANVoltageQuadEncoderModeTest.class
.getName());
/** The stopped value in volts */
private static final double kStoppedValue = 0;
/** The running value in volts */
private static final double kRunningValue = 4;
private static final double kVoltageTolerance = .25;
private static final PollingWait kWait = new PollingWait().timeoutAfter(
(long) kMotorTimeSettling, TimeUnit.SECONDS).pollEvery(1, TimeUnit.MILLISECONDS);
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#stopMotor()
*/
protected void stopMotor() {
getME().getMotor().set(kStoppedValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorForward()
*/
protected void runMotorForward() {
getME().getMotor().set(kRunningValue);
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.can.AbstractCANTest#runMotorReverse()
*/
protected void runMotorReverse() {
getME().getMotor().set(-kRunningValue);
}
@Override
protected Logger getClassLogger() {
return logger;
}
@Before
public void setUp() throws Exception {
getME().getMotor().setVoltageMode(CANJaguar.kQuadEncoder, 360);
getME().getMotor().set(kStoppedValue);
getME().getMotor().enableControl();
/* The motor might still have momentum from the previous test. */
Timer.delay(kStartupTime);
}
@Test
public void testRotateForwardToVoltage() {
setCANJaguar(kMotorTime, Math.PI);
assertEquals("The output voltage did not match the desired voltage set-point", Math.PI, getME()
.getMotor().getOutputVoltage(), kVoltageTolerance);
}
@Test
public void testRotateReverseToVoltage() {
setCANJaguar(kMotorTime, -Math.PI);
assertEquals("The output voltage did not match the desired voltage set-point", -Math.PI,
getME().getMotor().getOutputVoltage(), kVoltageTolerance);
}
/**
* Sets up the test to have the CANJaguar running at the target voltage
*$
* @param targetValue the target voltage
* @param wait the PollingWait to to use to wait for the setup to complete
* with
*/
private void setupMotorVoltageForTest(final double targetValue, PollingWait wait) {
getME().getMotor().enableControl();
setCANJaguar(1, targetValue);
wait.until(new RunnableAssert(
"[SETUP] Waiting for the output voltage to match the set output value") {
@Override
public void run() throws Exception {
getME().getMotor().set(targetValue);
assertEquals("[TEST SETUP] The output voltage should have matched the set value",
targetValue, getME().getMotor().getOutputVoltage(), 0.5);
assertEquals("[TEST SETUP] The set value did not match the get value", targetValue, getME()
.getMotor().get(), 0.5);
}
});
}
@Test
public void testMaxOutputVoltagePositive() {
// given
double maxVoltage = 3;
setupMotorVoltageForTest(kRunningValue, kWait);
final double fastSpeed = getME().getMotor().getSpeed();
// when
getME().getMotor().configMaxOutputVoltage(maxVoltage);
setCANJaguar(1, kRunningValue);
// Then
kWait.until(new RunnableAssert("Waiting for the speed to reduce using max output voltage") {
@Override
public void run() throws Exception {
runMotorForward();
assertThat("Speed did not reduce when the max output voltage was set", fastSpeed,
is(greaterThan(getME().getMotor().getSpeed())));
}
});
}
@Test
public void testMaxOutputVoltagePositiveSetToZeroStopsMotor() {
// given
final double maxVoltage = 0;
setupMotorVoltageForTest(kRunningValue, kWait);
// when
getME().getMotor().configMaxOutputVoltage(maxVoltage);
setCANJaguar(1, kRunningValue);
// then
kWait.until(new RunnableAssert(
"Waiting for the speed to reduce to zero using max output voltage") {
@Override
public void run() throws Exception {
runMotorForward();
assertEquals("Speed did not go to zero when the max output voltage was set to "
+ maxVoltage, 0, getME().getMotor().getSpeed(), kEncoderSpeedTolerance);
}
});
}
@Test
public void testMaxOutputVoltageNegative() {
// given
double maxVoltage = 3;
setupMotorVoltageForTest(-kRunningValue, kWait);
final double fastSpeed = getME().getMotor().getSpeed();
// when
getME().getMotor().configMaxOutputVoltage(maxVoltage);
setCANJaguar(1, -kRunningValue);
// then
kWait.until(new RunnableAssert("Waiting for the speed to reduce using max output voltage") {
@Override
public void run() throws Exception {
runMotorReverse();
assertThat("Speed did not reduce when the max output voltage was set", fastSpeed,
is(lessThan(getME().getMotor().getSpeed())));
}
});
}
@Test
public void testMaxOutputVoltageNegativeSetToZeroStopsMotor() {
// given
final double maxVoltage = 0;
setupMotorVoltageForTest(-kRunningValue, kWait);
// when
getME().getMotor().configMaxOutputVoltage(maxVoltage);
setCANJaguar(1, -kRunningValue);
// Then
kWait.until(new RunnableAssert(
"Waiting for the speed to reduce to zero using max output voltage") {
@Override
public void run() throws Exception {
runMotorReverse();
assertEquals("Speed did not go to zero when the max output voltage was set to "
+ maxVoltage, 0, getME().getMotor().getSpeed(), kEncoderSpeedTolerance);
}
});
}
}

View File

@@ -0,0 +1,9 @@
/**
* Provides a suite of tests to cover CANJaguar fully in all different control
* modes and with each supported positional input. Different setup parameters
* are provided in each Test class. All test classes that want to take advantage
* of the default test setup frameworks in place should extend
* {@link AbstractCANTest}
*$
*/
package edu.wpi.first.wpilibj.can;

View File

@@ -0,0 +1,59 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Before;
import edu.wpi.first.wpilibj.mocks.MockCommand;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* @author jonathanleitschuh
*
*/
public abstract class AbstractCommandTest extends AbstractComsSetup {
@Before
public void commandSetup() {
Scheduler.getInstance().removeAll();
Scheduler.getInstance().enable();
}
public class ASubsystem extends Subsystem {
Command command;
protected void initDefaultCommand() {
if (command != null) {
setDefaultCommand(command);
}
}
public void init(Command command) {
this.command = command;
}
}
public void assertCommandState(MockCommand command, int initialize, int execute, int isFinished,
int end, int interrupted) {
assertEquals(initialize, command.getInitializeCount());
assertEquals(execute, command.getExecuteCount());
assertEquals(isFinished, command.getIsFinishedCount());
assertEquals(end, command.getEndCount());
assertEquals(interrupted, command.getInterruptedCount());
}
public void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException ex) {
fail("Sleep Interrupted!?!?!?!?");
}
}
}

View File

@@ -0,0 +1,149 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.buttons.InternalButton;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* @author Mitchell
* @author jonathanleitschuh
*
*/
public class ButtonTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(ButtonTest.class.getName());
private InternalButton button1;
private InternalButton button2;
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
button1 = new InternalButton();
button2 = new InternalButton();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Simple Button Test
*/
@Test
public void test() {
MockCommand command1 = new MockCommand();
MockCommand command2 = new MockCommand();
MockCommand command3 = new MockCommand();
MockCommand command4 = new MockCommand();
button1.whenPressed(command1);
button1.whenReleased(command2);
button1.whileHeld(command3);
button2.whileHeld(command4);
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
button1.setPressed(true);
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 1, 1, 1, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 2, 2, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 1, 2, 2, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
button2.setPressed(true);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 1, 3, 3, 0, 0);
assertCommandState(command4, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 1, 4, 4, 0, 0);
assertCommandState(command4, 1, 1, 1, 0, 0);
button1.setPressed(false);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 5, 5, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 6, 6, 0, 0);
assertCommandState(command2, 1, 1, 1, 0, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 3, 3, 0, 0);
button2.setPressed(false);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 7, 7, 0, 0);
assertCommandState(command2, 1, 2, 2, 0, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 3, 3, 0, 1);
command1.cancel();
Scheduler.getInstance().run();
assertCommandState(command1, 1, 7, 7, 0, 1);
assertCommandState(command2, 1, 3, 3, 0, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 3, 3, 0, 1);
command2.setHasFinished(true);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 7, 7, 0, 1);
assertCommandState(command2, 1, 4, 4, 1, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 3, 3, 0, 1);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 7, 7, 0, 1);
assertCommandState(command2, 1, 4, 4, 1, 0);
assertCommandState(command3, 1, 4, 4, 0, 1);
assertCommandState(command4, 1, 3, 3, 0, 1);
}
}

View File

@@ -0,0 +1,106 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* Ported from the old CrioTest Classes
*$
* @author Mitchell
* @author Jonathan Leitschuh
*/
public class CommandParallelGroupTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(CommandParallelGroupTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Simple Parallel Command Group With 2 commands one command terminates first
*/
@Test
public void testParallelCommandGroupWithTwoCommands() {
MockCommand command1 = new MockCommand();
MockCommand command2 = new MockCommand();
CommandGroup commandGroup = new CommandGroup();
commandGroup.addParallel(command1);
commandGroup.addParallel(command2);
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
commandGroup.start();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 0);
assertCommandState(command2, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 2, 2, 0, 0);
assertCommandState(command2, 1, 2, 2, 0, 0);
command1.setHasFinished(true);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 1, 0);
assertCommandState(command2, 1, 3, 3, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 1, 0);
assertCommandState(command2, 1, 4, 4, 0, 0);
command2.setHasFinished(true);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 1, 0);
assertCommandState(command2, 1, 5, 5, 1, 0);
}
public void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException ex) {
fail("Sleep Interrupted!?!?!?!?");
}
}
}

View File

@@ -0,0 +1,105 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* Ported from the old CrioTest Classes
*$
* @author Mitchell
* @author Jonathan Leitschuh
*/
public class CommandScheduleTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(CommandScheduleTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Simple scheduling of a command and making sure the command is run and
* successfully terminates
*/
@Test
public void testRunAndTerminate() {
MockCommand command = new MockCommand();
command.start();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 2, 2, 0, 0);
command.setHasFinished(true);
assertCommandState(command, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 1, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 1, 0);
}
/**
* Simple scheduling of a command and making sure the command is run and
* cancels correctly
*/
@Test
public void testRunAndCancel() {
MockCommand command = new MockCommand();
command.start();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 0, 0);
command.cancel();
assertCommandState(command, 1, 3, 3, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 0, 1);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 0, 1);
}
}

View File

@@ -0,0 +1,142 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* Ported from the old CrioTest Classes
*$
* @author Mitchell
* @author Jonathan Leitschuh
*/
public class CommandSequentialGroupTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(CommandSequentialGroupTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Simple Command Group With 3 commands that all depend on a subsystem. Some
* commands have a timeout
*/
@Test(timeout = 20000)
public void testThreeCommandOnSubSystem() {
logger.fine("Begining Test");
final ASubsystem subsystem = new ASubsystem();
logger.finest("Creating Mock Command1");
MockCommand command1 = new MockCommand() {
{
requires(subsystem);
}
};
logger.finest("Creating Mock Command2");
MockCommand command2 = new MockCommand() {
{
requires(subsystem);
}
};
logger.finest("Creating Mock Command3");
MockCommand command3 = new MockCommand() {
{
requires(subsystem);
}
};
logger.finest("Creating Command Group");
CommandGroup commandGroup = new CommandGroup();
commandGroup.addSequential(command1, 1.0);
commandGroup.addSequential(command2, 2.0);
commandGroup.addSequential(command3);
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
logger.finest("Starting Command group");
commandGroup.start();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
sleep(1000);// command 1 timeout
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 1, 1, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 0);
assertCommandState(command3, 0, 0, 0, 0, 0);
sleep(2000);// command 2 timeout
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 1);
assertCommandState(command3, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 1);
assertCommandState(command3, 1, 2, 2, 0, 0);
command3.setHasFinished(true);
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 1);
assertCommandState(command3, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 1);
assertCommandState(command3, 1, 3, 3, 1, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 1);
assertCommandState(command3, 1, 3, 3, 1, 0);
}
}

View File

@@ -0,0 +1,155 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* Ported from the old CrioTest Classes
*$
* @author Mitchell
* @author Jonathan Leitschuh
*/
public class CommandSupersedeTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(CommandSupersedeTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Testing one command superseding another because of dependencies
*/
@Test
public void testOneCommandSupersedingAnotherBecauseOfDependencies() {
final ASubsystem subsystem = new ASubsystem();
MockCommand command1 = new MockCommand() {
{
requires(subsystem);
}
};
MockCommand command2 = new MockCommand() {
{
requires(subsystem);
}
};
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
command1.start();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 2, 2, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
command2.start();
assertCommandState(command1, 1, 3, 3, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 1);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 1);
assertCommandState(command2, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 1);
assertCommandState(command2, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 1);
assertCommandState(command2, 1, 3, 3, 0, 0);
}
/**
* Testing one command failing superseding another because of dependencies
* because the first command cannot be interrupted"
*/
@Test
public void testCommandFailingSupersedingBecauseFirstCanNotBeInterrupted() {
final ASubsystem subsystem = new ASubsystem();
MockCommand command1 = new MockCommand() {
{
requires(subsystem);
setInterruptible(false);
}
};
MockCommand command2 = new MockCommand() {
{
requires(subsystem);
}
};
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
command1.start();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 0, 0, 0, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 1, 1, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 2, 2, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 3, 3, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
command2.start();
assertCommandState(command1, 1, 3, 3, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command1, 1, 4, 4, 0, 0);
assertCommandState(command2, 0, 0, 0, 0, 0);
}
}

View File

@@ -0,0 +1,25 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import edu.wpi.first.wpilibj.test.AbstractTestSuite;
/**
* @author jonathanleitschuh
*
*/
@RunWith(Suite.class)
@SuiteClasses({ButtonTest.class, CommandParallelGroupTest.class, CommandScheduleTest.class,
CommandSequentialGroupTest.class, CommandSupersedeTest.class, CommandTimeoutTest.class,
DefaultCommandTest.class})
public class CommandTestSuite extends AbstractTestSuite {
}

View File

@@ -0,0 +1,93 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* @author jonathanleitschuh
*
*/
public class CommandTimeoutTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(CommandTimeoutTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Command 2 second Timeout Test
*/
@Test
public void testTwoSecondTimeout() {
final ASubsystem subsystem = new ASubsystem();
MockCommand command = new MockCommand() {
{
requires(subsystem);
setTimeout(2);
}
@Override
public boolean isFinished() {
return super.isFinished() || isTimedOut();
}
};
command.start();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 3, 3, 0, 0);
sleep(2000);
Scheduler.getInstance().run();
assertCommandState(command, 1, 4, 4, 1, 0);
Scheduler.getInstance().run();
assertCommandState(command, 1, 4, 4, 1, 0);
}
}

View File

@@ -0,0 +1,169 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.command;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.wpi.first.wpilibj.mocks.MockCommand;
/**
* @author jonathanleitschuh
*
*/
public class DefaultCommandTest extends AbstractCommandTest {
private static final Logger logger = Logger.getLogger(DefaultCommandTest.class.getName());
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
/**
* Testing of default commands where the interrupting command ends itself
*/
@Test
public void testDefaultCommandWhereTheInteruptingCommandEndsItself() {
final ASubsystem subsystem = new ASubsystem();
MockCommand defaultCommand = new MockCommand() {
{
requires(subsystem);
}
};
MockCommand anotherCommand = new MockCommand() {
{
requires(subsystem);
}
};
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
subsystem.init(defaultCommand);
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
anotherCommand.start();
assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
anotherCommand.setHasFinished(true);
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 2, 4, 4, 0, 1);
assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 2, 5, 5, 0, 1);
assertCommandState(anotherCommand, 1, 3, 3, 1, 0);
}
/**
* Testing of default commands where the interrupting command is canceled
*/
@Test
public void testDefaultCommandsInterruptingCommandCanceled() {
final ASubsystem subsystem = new ASubsystem();
MockCommand defaultCommand = new MockCommand() {
{
requires(subsystem);
}
};
MockCommand anotherCommand = new MockCommand() {
{
requires(subsystem);
}
};
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
subsystem.init(defaultCommand);
subsystem.initDefaultCommand();
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
anotherCommand.start();
assertCommandState(defaultCommand, 1, 2, 2, 0, 0);
assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 0, 0, 0, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 1, 1, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
anotherCommand.cancel();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 0);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 1, 3, 3, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 2, 4, 4, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
Scheduler.getInstance().run();
assertCommandState(defaultCommand, 2, 5, 5, 0, 1);
assertCommandState(anotherCommand, 1, 2, 2, 0, 1);
}
}

View File

@@ -0,0 +1,86 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import edu.wpi.first.wpilibj.AnalogInput;
import edu.wpi.first.wpilibj.AnalogOutput;
/**
* @author jonathanleitschuh
*
*/
public abstract class AnalogCrossConnectFixture implements ITestFixture {
private boolean initialized = false;
private AnalogInput input;
private AnalogOutput output;
abstract protected AnalogInput giveAnalogInput();
abstract protected AnalogOutput giveAnalogOutput();
private void initialize() {
synchronized (this) {
if (!initialized) {
input = giveAnalogInput();
output = giveAnalogOutput();
initialized = true;
}
}
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#setup()
*/
@Override
public boolean setup() {
initialize();
output.setVoltage(0);
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#reset()
*/
@Override
public boolean reset() {
initialize();
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#teardown()
*/
@Override
public boolean teardown() {
input.free();
output.free();
return true;
}
/**
* @return
*/
final public AnalogOutput getOutput() {
initialize();
return output;
}
final public AnalogInput getInput() {
initialize();
return input;
}
}

View File

@@ -0,0 +1,185 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.DigitalOutput;
import edu.wpi.first.wpilibj.Relay;
import edu.wpi.first.wpilibj.Relay.Direction;
import edu.wpi.first.wpilibj.Relay.Value;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.mockhardware.FakePotentiometerSource;
/**
* @author jonathanleitschuh
*
*/
public abstract class CANMotorEncoderFixture extends MotorEncoderFixture<CANJaguar> implements
ITestFixture {
private static final Logger logger = Logger.getLogger(CANMotorEncoderFixture.class.getName());
public static final double RELAY_POWER_UP_TIME = .75;
private FakePotentiometerSource potSource;
private DigitalOutput forwardLimit;
private DigitalOutput reverseLimit;
private Relay powerCycler;
private boolean initialized = false;
protected abstract FakePotentiometerSource giveFakePotentiometerSource();
protected abstract DigitalOutput giveFakeForwardLimit();
protected abstract DigitalOutput giveFakeReverseLimit();
protected abstract Relay givePoweCycleRelay();
public CANMotorEncoderFixture() {}
private void initialize() {
synchronized (this) {
if (!initialized) {
initialized = true;// This ensures it is only initialized once
powerCycler = givePoweCycleRelay();
powerCycler.setDirection(Direction.kForward);
logger.fine("Turning on the power!");
powerCycler.set(Value.kForward);
forwardLimit = giveFakeForwardLimit();
reverseLimit = giveFakeReverseLimit();
forwardLimit.set(false);
reverseLimit.set(false);
potSource = giveFakePotentiometerSource();
Timer.delay(RELAY_POWER_UP_TIME); // Delay so the relay has time to boot
// up
}
}
}
@Override
public boolean setup() {
initialize(); // This initializes the Relay first
return super.setup();
}
@Override
public boolean reset() {
initialize();
potSource.reset();
forwardLimit.set(false);
reverseLimit.set(false);
getMotor().setPercentMode(); // Get the Jaguar into a mode where setting the
// speed means stop
return super.reset();
}
@Override
public boolean teardown() {
boolean wasNull = false;
if (potSource != null) {
potSource.free();
potSource = null;
} else
wasNull = true;
if (forwardLimit != null) {
forwardLimit.set(false);
forwardLimit.free();
forwardLimit = null;
} else
wasNull = true;
if (reverseLimit != null) {
reverseLimit.set(false);
reverseLimit.free();
reverseLimit = null;
} else
wasNull = true;
boolean superTornDown = false;
try {
superTornDown = super.teardown();
} finally {
try {
if (getMotor() != null) {
getMotor().disableControl();
getMotor().free();
} else
wasNull = true;
} finally {
if (powerCycler != null) {
powerCycler.free();
powerCycler = null;
} else
wasNull = true;
}
}
if (wasNull) {
throw new RuntimeException("CANMotorEncoderFixture had a null value at teardown");
}
return superTornDown;
}
public FakePotentiometerSource getFakePot() {
initialize();
return potSource;
}
public DigitalOutput getForwardLimit() {
initialize();
return forwardLimit;
}
public DigitalOutput getReverseLimit() {
initialize();
return reverseLimit;
}
public String printStatus() {
StringBuilder status = new StringBuilder("CAN Motor Encoder Status: ");
if (getMotor() != null) {
status.append("\t" + getMotor().getDescription() + "\n");
status.append("\tFault = " + getMotor().getFaults() + "\n");
status.append("\tValue = " + getMotor().get() + "\n");
status.append("\tOutputVoltage = " + getMotor().getOutputVoltage() + "\n");
status.append("\tPosition = " + getMotor().getPosition() + "\n");
status.append("\tForward Limit Ok = " + getMotor().getForwardLimitOK() + "\n");
status.append("\tReverse Limit Ok = " + getMotor().getReverseLimitOK() + "\n");
} else {
status.append("\t" + "CANJaguar Motor = null" + "\n");
}
if (forwardLimit != null) {
status.append("\tForward Limit Output = " + forwardLimit + "\n");
} else {
status.append("\tForward Limit Output = null" + "\n");
}
if (reverseLimit != null) {
status.append("\tReverse Limit Output = " + reverseLimit + "\n");
} else {
status.append("\tReverse Limit Output = null" + "\n");
}
return status.toString();
}
public void brownOut(double seconds) {
initialize();
powerOff();
Timer.delay(seconds);
powerOn();
}
public void powerOff() {
initialize();
powerCycler.set(Value.kOff);
}
public void powerOn() {
initialize();
powerCycler.set(Value.kForward);
}
}

View File

@@ -0,0 +1,75 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.util.logging.Level;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.DigitalOutput;
public class DIOCrossConnectFixture implements ITestFixture {
private static final Logger logger = Logger.getLogger(DIOCrossConnectFixture.class.getName());
private final DigitalInput input;
private final DigitalOutput output;
private boolean m_allocated;
public DIOCrossConnectFixture(DigitalInput input, DigitalOutput output) {
assert input != null;
assert output != null;
this.input = input;
this.output = output;
m_allocated = false;
}
public DIOCrossConnectFixture(Integer input, Integer output) {
assert input != null;
assert output != null;
assert !input.equals(output);
this.input = new DigitalInput(input);
this.output = new DigitalOutput(output);
m_allocated = true;
}
public DigitalInput getInput() {
return input;
}
public DigitalOutput getOutput() {
return output;
}
@Override
public boolean setup() {
return true;
}
@Override
public boolean reset() {
try {
input.cancelInterrupts();
} catch (IllegalStateException e) {
// This will happen if the interrupt has not been allocated for this test.
}
output.set(false);
return true;
}
@Override
public boolean teardown() {
logger.log(Level.FINE, "Begining teardown");
if (m_allocated) {
input.free();
output.free();
m_allocated = false;
}
return true;
}
}

View File

@@ -0,0 +1,114 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.util.logging.Level;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.Counter;
import edu.wpi.first.wpilibj.mockhardware.FakeCounterSource;
/**
* @author jonathanleitschuh
*
*/
public class FakeCounterFixture implements ITestFixture {
private static final Logger logger = Logger.getLogger(FakeEncoderFixture.class.getName());
private final DIOCrossConnectFixture dio;
private boolean m_allocated;
private final FakeCounterSource source;
private final Counter counter;
/**
* Constructs a FakeCounterFixture.
*$
* @param dio A previously allocated DIOCrossConnectFixture (must be freed
* outside this class)
*/
public FakeCounterFixture(DIOCrossConnectFixture dio) {
this.dio = dio;
m_allocated = false;
source = new FakeCounterSource(dio.getOutput());
counter = new Counter(dio.getInput());
}
/**
* Constructs a FakeCounterFixture using two port numbers
*$
* @param input the input port
* @param output the output port
*/
public FakeCounterFixture(int input, int output) {
this.dio = new DIOCrossConnectFixture(input, output);
m_allocated = true;
source = new FakeCounterSource(dio.getOutput());
counter = new Counter(dio.getInput());
}
/**
* Retrieves the FakeCouterSource for use
*$
* @return the FakeCounterSource
*/
public FakeCounterSource getFakeCounterSource() {
return source;
}
/**
* Gets the Counter for use
*$
* @return the Counter
*/
public Counter getCounter() {
return counter;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#setup()
*/
@Override
public boolean setup() {
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#reset()
*/
@Override
public boolean reset() {
counter.reset();
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#teardown()
*/
@Override
public boolean teardown() {
logger.log(Level.FINE, "Begining teardown");
counter.free();
source.free();
if (m_allocated) { // Only tear down the dio if this class allocated it
dio.teardown();
m_allocated = false;
}
return true;
}
}

View File

@@ -0,0 +1,124 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.util.logging.Level;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.Encoder;
import edu.wpi.first.wpilibj.mockhardware.FakeEncoderSource;
/**
* @author jonathanleitschuh
*
*/
public class FakeEncoderFixture implements ITestFixture {
private static final Logger logger = Logger.getLogger(FakeEncoderFixture.class.getName());
private final DIOCrossConnectFixture m_dio1;
private final DIOCrossConnectFixture m_dio2;
private boolean m_allocated;
private final FakeEncoderSource m_source;
private int m_sourcePort[] = new int[2];
private final Encoder m_encoder;
private int m_encoderPort[] = new int[2];
/**
* Constructs a FakeEncoderFixture from two DIOCrossConnectFixture
*$
* @param dio1
* @param dio2
*/
public FakeEncoderFixture(DIOCrossConnectFixture dio1, DIOCrossConnectFixture dio2) {
assert dio1 != null;
assert dio2 != null;
this.m_dio1 = dio1;
this.m_dio2 = dio2;
m_allocated = false;
m_source = new FakeEncoderSource(dio1.getOutput(), dio2.getOutput());
m_encoder = new Encoder(dio1.getInput(), dio2.getOutput());
}
/**
* Construcst a FakeEncoderFixture from a set of Digital I/O ports
*$
* @param inputA
* @param outputA
* @param inputB
* @param outputB
*/
public FakeEncoderFixture(int inputA, int outputA, int inputB, int outputB) {
assert outputA != outputB;
assert outputA != inputA;
assert outputA != inputB;
assert outputB != inputA;
assert outputB != inputB;
assert inputA != inputB;
this.m_dio1 = new DIOCrossConnectFixture(inputA, outputA);
this.m_dio2 = new DIOCrossConnectFixture(inputB, outputB);
m_allocated = true;
m_sourcePort[0] = outputA;
m_sourcePort[1] = outputB;
m_encoderPort[0] = inputA;
m_encoderPort[1] = inputB;
m_source = new FakeEncoderSource(m_dio1.getOutput(), m_dio2.getOutput());
m_encoder = new Encoder(m_dio1.getInput(), m_dio2.getOutput());
}
public FakeEncoderSource getFakeEncoderSource() {
return m_source;
}
public Encoder getEncoder() {
return m_encoder;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#setup()
*/
@Override
public boolean setup() {
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#reset()
*/
@Override
public boolean reset() {
m_dio1.reset();
m_dio2.reset();
m_encoder.reset();
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#teardown()
*/
@Override
public boolean teardown() {
logger.fine("Begining teardown");
m_source.free();
logger.finer("Source freed " + m_sourcePort[0] + ", " + m_sourcePort[1]);
m_encoder.free();
logger.finer("Encoder freed " + m_encoderPort[0] + ", " + m_encoderPort[1]);
if (m_allocated) {
m_dio1.teardown();
m_dio2.teardown();
}
return true;
}
}

View File

@@ -0,0 +1,53 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Master interface for all test fixtures. This ensures that all test fixtures
* have setup and teardown methods, to ensure that the tests run properly.
*$
* Test fixtures should be modeled around the content of a test, rather than the
* actual physical layout of the testing board. They should obtain references to
* hardware from the {@link TestBench} class, which is a singleton. Testing
* Fixtures are responsible for ensuring that the hardware is in an appropriate
* state for the start of a test, and ensuring that future tests will not be
* affected by the results of a test.
*$
* @author Fredric Silberberg
*/
public interface ITestFixture {
/**
* Performs any required setup for this fixture, ensuring that all fixture
* elements are ready for testing.
*$
* @return True if the fixture is ready for testing
*/
boolean setup();
/**
* Resets the fixture back to test start state. This should be called by the
* test class in the test setup method to ensure that the hardware is in the
* default state. This differs from {@link ITestFixture#setup()} as that is
* called once, before the class is constructed, so it may need to start
* sensors. This method should not have to start anything, just reset sensors
* and ensure that motors are stopped.
*$
* @return True if the fixture is ready for testing
*/
boolean reset();
/**
* Performs any required teardown after use of the fixture, ensuring that
* future tests will not run into conflicts.
*$
* @return True if the teardown succeeded
*/
boolean teardown();
}

View File

@@ -0,0 +1,242 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.lang.reflect.ParameterizedType;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.Counter;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.Encoder;
import edu.wpi.first.wpilibj.PWM;
import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.test.TestBench;
/**
* Represents a physically connected Motor and Encoder to allow for unit tests
* on these difrent pairs<br>
* Designed to allow the user to easily setup and tear down the fixture to allow
* for reuse. This class should be explicitly instantiated in the TestBed class
* to allow any test to access this fixture. This allows tests to be mailable so
* that you can easily reconfigure the physical testbed without breaking the
* tests.
*
* @author Jonathan Leitschuh
*
*/
public abstract class MotorEncoderFixture<T extends SpeedController> implements ITestFixture {
private static final Logger logger = Logger.getLogger(MotorEncoderFixture.class.getName());
private boolean initialized = false;
private boolean tornDown = false;
protected T motor;
private Encoder encoder;
private final Counter counters[] = new Counter[2];
protected DigitalInput aSource; // Stored so it can be freed at tear down
protected DigitalInput bSource;
/**
* Default constructor for a MotorEncoderFixture
*/
public MotorEncoderFixture() {}
abstract public int getPDPChannel();
/**
* Where the implementer of this class should pass the speed controller
* Constructor should only be called from outside this class if the Speed
* controller is not also an implementation of PWM interface
*$
* @return
*/
abstract protected T giveSpeedController();
/**
* Where the implementer of this class should pass one of the digital inputs<br>
* CONSTRUCTOR SHOULD NOT BE CALLED FROM OUTSIDE THIS CLASS!
*$
* @return
*/
abstract protected DigitalInput giveDigitalInputA();
/**
* Where the implementer fo this class should pass the other digital input<br>
* CONSTRUCTOR SHOULD NOT BE CALLED FROM OUTSIDE THIS CLASS!
*$
* @return Input B to be used when this class is instantiated
*/
abstract protected DigitalInput giveDigitalInputB();
final private void initialize() {
synchronized (this) {
if (!initialized) {
initialized = true; // This ensures it is only initialized once
aSource = giveDigitalInputA();
bSource = giveDigitalInputB();
encoder = new Encoder(aSource, bSource);
counters[0] = new Counter(aSource);
counters[1] = new Counter(bSource);
logger.fine("Creating the speed controller!");
motor = giveSpeedController(); // CANJaguar throws an exception if it
// doesn't get the message
}
}
}
@Override
public boolean setup() {
initialize();
return true;
}
/**
* Gets the motor for this Object
*$
* @return the motor this object refers too
*/
public T getMotor() {
initialize();
return motor;
}
/**
* Gets the encoder for this object
*$
* @return the encoder that this object refers too
*/
public Encoder getEncoder() {
initialize();
return encoder;
}
public Counter[] getCounters() {
initialize();
return counters;
}
/**
* Retrieves the name of the motor that this object refers to
*$
* @return The simple name of the motor {@link Class#getSimpleName()}
*/
public String getType() {
initialize();
return motor.getClass().getSimpleName();
}
/**
* Checks to see if the speed of the motor is within some range of a given
* value. This is used instead of equals() because doubles can have
* inaccuracies.
*$
* @param value The value to compare against
* @param accuracy The accuracy range to check against to see if the
* @return true if the range of values between motors speed accuracy contains
* the 'value'.
*/
public boolean isMotorSpeedWithinRange(double value, double accuracy) {
initialize();
return Math.abs((Math.abs(motor.get()) - Math.abs(value))) < Math.abs(accuracy);
}
@Override
public boolean reset() {
initialize();
boolean wasReset = true;
motor.setInverted(false);
motor.set(0);
Timer.delay(TestBench.MOTOR_STOP_TIME); // DEFINED IN THE TestBench
encoder.reset();
for (Counter c : counters) {
c.reset();
}
wasReset = wasReset && motor.get() == 0;
wasReset = wasReset && encoder.get() == 0;
for (Counter c : counters) {
wasReset = wasReset && c.get() == 0;
}
return wasReset;
}
/**
* Safely tears down the MotorEncoder Fixture in a way that makes sure that
* even if an object fails to initialize the reset of the fixture can still be
* torn down and the resources deallocated
*/
@Override
public boolean teardown() {
String type;
if (motor != null) {
type = getType();
} else {
type = "null";
}
if (!tornDown) {
boolean wasNull = false;
if (motor instanceof PWM && motor != null) {
((PWM) motor).free();
motor = null;
} else if (motor == null)
wasNull = true;
if (encoder != null) {
encoder.free();
encoder = null;
} else
wasNull = true;
if (counters[0] != null) {
counters[0].free();
counters[0] = null;
} else
wasNull = true;
if (counters[1] != null) {
counters[1].free();
counters[1] = null;
} else
wasNull = true;
if (aSource != null) {
aSource.free();
aSource = null;
} else
wasNull = true;
if (bSource != null) {
bSource.free();
bSource = null;
} else
wasNull = true;
tornDown = true;
if (wasNull) {
throw new NullPointerException("MotorEncoderFixture had null params at teardown");
}
} else {
throw new RuntimeException(type + " Motor Encoder torn down multiple times");
}
return true;
}
@Override
public String toString() {
StringBuilder string = new StringBuilder("MotorEncoderFixture<");
// Get the generic type as a class
@SuppressWarnings("unchecked")
Class<T> class1 =
(Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
string.append(class1.getSimpleName());
string.append(">");
return string.toString();
}
}

View File

@@ -0,0 +1,101 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.Relay;
import edu.wpi.first.wpilibj.Relay.Direction;
import edu.wpi.first.wpilibj.Relay.Value;
/**
* @author jonathanleitschuh
*
*/
public abstract class RelayCrossConnectFixture implements ITestFixture {
private DigitalInput inputOne;
private DigitalInput inputTwo;
private Relay relay;
private boolean initialized = false;
private boolean freed = false;
protected abstract Relay giveRelay();
protected abstract DigitalInput giveInputOne();
protected abstract DigitalInput giveInputTwo();
private void initialize() {
synchronized (this) {
if (!initialized) {
relay = giveRelay();
inputOne = giveInputOne();
inputTwo = giveInputTwo();
initialized = true;
}
}
}
public Relay getRelay() {
initialize();
return relay;
}
public DigitalInput getInputOne() {
initialize();
return inputOne;
}
public DigitalInput getInputTwo() {
initialize();
return inputTwo;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#setup()
*/
@Override
public boolean setup() {
initialize();
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#reset()
*/
@Override
public boolean reset() {
initialize();
return true;
}
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.fixtures.ITestFixture#teardown()
*/
@Override
public boolean teardown() {
if (!freed) {
relay.free();
inputOne.free();
inputTwo.free();
freed = true;
} else {
throw new RuntimeException("You attempted to free the "
+ RelayCrossConnectFixture.class.getSimpleName() + " multiple times");
}
return true;
}
}

View File

@@ -0,0 +1,57 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
/**
* This is an example of how to use the {@link ITestFixture} interface to create
* test fixtures for a test.
*$
* @author Fredric Silberberg
*$
*/
public class SampleFixture implements ITestFixture {
/**
* {@inheritDoc}
*/
@Override
public boolean setup() {
/*
* If this fixture actually accessed the hardware, here is where it would
* set up the starting state of the test bench. For example, reseting
* encoders, ensuring motors are stopped, reseting any serial communication
* if necessary, etc.
*/
return true;
}
@Override
public boolean reset() {
/*
* This is where the fixture would reset any sensors or motors used by the
* fixture to test default state. This method should not worry about whether
* or not the sensors have been allocated correctly, that is the job of the
* setup function.
*/
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean teardown() {
/*
* This is where the fixture would deallocate and reset back to normal
* conditions any necessary hardware. This includes ensuring motors are
* stopped, stoppable sensors are actually stopped, ensuring serial
* communications are ready for the next test, etc.
*/
return true;
}
}

View File

@@ -0,0 +1,91 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.fixtures;
import java.util.logging.Logger;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.Servo;
import edu.wpi.first.wpilibj.Timer;
/**
* A class to represent the a physical Camera with two servos (tilt and pan)
* designed to test to see if the gyroscope is operating normally.
*
* @author Jonathan Leitschuh
*
*/
public abstract class TiltPanCameraFixture implements ITestFixture {
public static final Logger logger = Logger.getLogger(TiltPanCameraFixture.class.getName());
public static final double RESET_TIME = 2.0;
private Gyro gyro;
private Servo tilt;
private Servo pan;
private boolean initialized = false;
protected abstract Gyro giveGyro();
protected abstract Servo giveTilt();
protected abstract Servo givePan();
/**
* Constructs the TiltPanCamera
*/
public TiltPanCameraFixture() {}
@Override
public boolean setup() {
boolean wasSetup = false;
if (!initialized) {
initialized = true;
tilt = giveTilt();
tilt.set(0);
pan = givePan();
pan.set(0);
Timer.delay(RESET_TIME);
logger.fine("Initializing the gyro");
gyro = giveGyro();
gyro.reset();
wasSetup = true;
}
return wasSetup;
}
@Override
public boolean reset() {
gyro.reset();
return true;
}
public Servo getTilt() {
return tilt;
}
public Servo getPan() {
return pan;
}
public Gyro getGyro() {
return gyro;
}
@Override
public boolean teardown() {
tilt.free();
tilt = null;
pan.free();
pan = null;
gyro.free();
gyro = null;
return true;
}
}

View File

@@ -0,0 +1,137 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.mockhardware;
import edu.wpi.first.wpilibj.DigitalOutput;
import edu.wpi.first.wpilibj.Timer;
/**
* @file FakeCounterSource.java Simulates an encoder for testing purposes
* @author Ryan O'Meara
*/
public class FakeCounterSource {
private Thread m_task;
private int m_count;
private int m_mSec;
private DigitalOutput m_output;
private boolean m_allocated;
/**
* Thread object that allows emulation of an encoder
*/
private class EncoderThread extends Thread {
FakeCounterSource m_encoder;
EncoderThread(FakeCounterSource encode) {
m_encoder = encode;
}
public void run() {
m_encoder.m_output.set(false);
try {
for (int i = 0; i < m_encoder.m_count; i++) {
Thread.sleep(m_encoder.m_mSec);
m_encoder.m_output.set(true);
Thread.sleep(m_encoder.m_mSec);
m_encoder.m_output.set(false);
}
} catch (InterruptedException e) {
}
}
}
/**
* Create a fake encoder on a given port
*$
* @param output the port to output the given signal to
*/
public FakeCounterSource(DigitalOutput output) {
m_output = output;
m_allocated = false;
initEncoder();
}
/**
* Create a fake encoder on a given port
*$
* @param port The port the encoder is supposed to be on
*/
public FakeCounterSource(int port) {
m_output = new DigitalOutput(port);
m_allocated = true;
initEncoder();
}
/**
* Destroy Object with minimum memory leak
*/
public void free() {
m_task = null;
if (m_allocated) {
m_output.free();
m_output = null;
m_allocated = false;
}
}
/**
* Common initailization code
*/
private void initEncoder() {
m_mSec = 1;
m_task = new EncoderThread(this);
m_output.set(false);
}
/**
* Starts the thread execution task
*/
public void start() {
m_task.start();
}
/**
* Waits for the thread to complete
*/
public void complete() {
try {
m_task.join();
} catch (InterruptedException e) {
}
m_task = new EncoderThread(this);
Timer.delay(.01);
}
/**
* Starts and completes a task set - does not return until thred has finished
* its operations
*/
public void execute() {
start();
complete();
}
/**
* Sets the count to run encoder
*$
* @param count The count to emulate to the controller
*/
public void setCount(int count) {
m_count = count;
}
/**
* Specify the rate to send pulses
*$
* @param mSec The rate to send out pulses at
*/
public void setRate(int mSec) {
m_mSec = mSec;
}
}

View File

@@ -0,0 +1,162 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.mockhardware;
import edu.wpi.first.wpilibj.DigitalOutput;
import edu.wpi.first.wpilibj.Timer;
/**
* @file FakeEncoderSource.java Emulates a quadrature encoder
* @author Ryan O'Meara
*/
public class FakeEncoderSource {
private Thread m_task;
private int m_count;
private int m_mSec;
private boolean m_forward;
private DigitalOutput m_outputA, m_outputB;
private final boolean allocatedOutputs;
/**
* Thread object that allows emulation of a quadrature encoder
*/
private class QuadEncoderThread extends Thread {
FakeEncoderSource m_encoder;
QuadEncoderThread(FakeEncoderSource encode) {
m_encoder = encode;
}
public void run() {
DigitalOutput lead, lag;
m_encoder.m_outputA.set(false);
m_encoder.m_outputB.set(false);
if (m_encoder.isForward()) {
lead = m_encoder.m_outputA;
lag = m_encoder.m_outputB;
} else {
lead = m_encoder.m_outputB;
lag = m_encoder.m_outputA;
}
try {
for (int i = 0; i < m_encoder.m_count; i++) {
lead.set(true);
Thread.sleep(m_encoder.m_mSec);
lag.set(true);
Thread.sleep(m_encoder.m_mSec);
lead.set(false);
Thread.sleep(m_encoder.m_mSec);
lag.set(false);
Thread.sleep(m_encoder.m_mSec);
}
} catch (InterruptedException e) {
}
}
}
public FakeEncoderSource(int portA, int portB) {
m_outputA = new DigitalOutput(portA);
m_outputB = new DigitalOutput(portB);
allocatedOutputs = true;
initQuadEncoder();
}
public FakeEncoderSource(DigitalOutput iA, DigitalOutput iB) {
m_outputA = iA;
m_outputB = iB;
allocatedOutputs = false;
initQuadEncoder();
}
public void free() {
m_task = null;
if (allocatedOutputs) {
m_outputA.free();
m_outputB.free();
}
}
/**
* Common initialization code
*/
private final void initQuadEncoder() {
m_mSec = 1;
m_forward = true;
m_task = new QuadEncoderThread(this);
m_outputA.set(false);
m_outputB.set(false);
}
/**
* Starts the thread
*/
public void start() {
m_task.start();
}
/**
* Waits for thread to end
*/
public void complete() {
try {
m_task.join();
} catch (InterruptedException e) {
}
m_task = new QuadEncoderThread(this);
Timer.delay(.01);
}
/**
* Runs and waits for thread to end before returning
*/
public void execute() {
start();
complete();
}
/**
* Rate of pulses to send
*$
* @param mSec Pulse Rate
*/
public void setRate(int mSec) {
m_mSec = mSec;
}
/**
* Set the number of pulses to simulate
*$
* @param count Pulse count
*/
public void setCount(int count) {
m_count = Math.abs(count);
}
/**
* Set which direction the encoder simulates motion in
*$
* @param isForward Whether to simulate forward motion
*/
public void setForward(boolean isForward) {
m_forward = isForward;
}
/**
* Accesses whether the encoder is simulating forward motion
*$
* @return Whether the simulated motion is in the forward direction
*/
public boolean isForward() {
return m_forward;
}
}

View File

@@ -0,0 +1,84 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.mockhardware;
import edu.wpi.first.wpilibj.AnalogOutput;
/**
* @author jonathanleitschuh
*
*/
public class FakePotentiometerSource {
private AnalogOutput output;
private boolean m_init_output;
private double potMaxAngle;
private double potMaxVoltage = 5.0;
private final double defaultPotMaxAngle;
public FakePotentiometerSource(AnalogOutput output, double defaultPotMaxAngle) {
this.defaultPotMaxAngle = defaultPotMaxAngle;
potMaxAngle = defaultPotMaxAngle;
this.output = output;
m_init_output = false;
}
public FakePotentiometerSource(int port, double defaultPotMaxAngle) {
this(new AnalogOutput(port), defaultPotMaxAngle);
m_init_output = true;
}
/**
* Sets the maximum voltage output. If not the default is 5.0V
*$
* @param voltage The voltage that indicates that the pot is at the max value.
*/
public void setMaxVoltage(double voltage) {
potMaxVoltage = voltage;
}
public void setRange(double range) {
potMaxAngle = range;
}
public void reset() {
potMaxAngle = defaultPotMaxAngle;
output.setVoltage(0.0);
}
public void setAngle(double angle) {
output.setVoltage((potMaxVoltage / potMaxAngle) * angle);
}
public void setVoltage(double voltage) {
output.setVoltage(voltage);
}
public double getVoltage() {
return output.getVoltage();
}
/**
* Returns the currently set angle
*$
* @return
*/
public double getAngle() {
double voltage = output.getVoltage();
if (voltage == 0) { // Removes divide by zero error
return 0;
}
return voltage * (potMaxAngle / potMaxVoltage);
}
public void free() {
if (m_init_output) {
output.free();
output = null;
m_init_output = false;
}
}
}

View File

@@ -0,0 +1,112 @@
package edu.wpi.first.wpilibj.mocks;
import edu.wpi.first.wpilibj.command.Command;
/**
* A class to simulate a simple command The command keeps track of how many
* times each method was called
*
* @author mwills
*/
public class MockCommand extends Command {
private int initializeCount = 0;
private int executeCount = 0;
private int isFinishedCount = 0;
private boolean hasFinished = false;
private int endCount = 0;
private int interruptedCount = 0;
protected void initialize() {
++initializeCount;
}
protected void execute() {
++executeCount;
}
protected boolean isFinished() {
++isFinishedCount;
return isHasFinished();
}
protected void end() {
++endCount;
}
protected void interrupted() {
++interruptedCount;
}
/**
* @return how many times the initialize method has been called
*/
public int getInitializeCount() {
return initializeCount;
}
/**
* @return if the initialize method has been called at least once
*/
public boolean hasInitialized() {
return getInitializeCount() > 0;
}
/**
* @return how many time the execute method has been called
*/
public int getExecuteCount() {
return executeCount;
}
/**
* @return how many times the isFinished method has been called
*/
public int getIsFinishedCount() {
return isFinishedCount;
}
/**
* @return what value the isFinished method will return
*/
public boolean isHasFinished() {
return hasFinished;
}
/**
* @param set what value the isFinished method will return
*/
public void setHasFinished(boolean hasFinished) {
this.hasFinished = hasFinished;
}
/**
* @return how many times the end method has been called
*/
public int getEndCount() {
return endCount;
}
/**
* @return if the end method has been called at least once
*/
public boolean hasEnd() {
return getEndCount() > 0;
}
/**
* @return how many times the interrupted method has been called
*/
public int getInterruptedCount() {
return interruptedCount;
}
/**
* @return if the interrupted method has been called at least once
*/
public boolean hasInterrupted() {
return getInterruptedCount() > 0;
}
}

View File

@@ -0,0 +1,117 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.smartdashboard;
import static org.junit.Assert.assertEquals;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import edu.wpi.first.wpilibj.networktables.NetworkTable;
import edu.wpi.first.wpilibj.networktables.NetworkTableKeyNotDefined;
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
/**
* @author jonathanleitschuh
*
*/
public class SmartDashboardTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(SmartDashboardTest.class.getName());
private static final NetworkTable table = NetworkTable.getTable("SmartDashboard");
protected Logger getClassLogger() {
return logger;
}
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {}
@Test(expected = NetworkTableKeyNotDefined.class)
public void testGetBadValue() {
SmartDashboard.getString("_404_STRING_KEY_SHOULD_NOT_BE_FOUND_");
}
@Test
public void testPutString() {
String key = "testPutString";
String value = "thisIsAValue";
SmartDashboard.putString(key, value);
assertEquals(value, SmartDashboard.getString(key));
assertEquals(value, table.getString(key));
}
@Test
public void testPutNumber() {
String key = "testPutNumber";
int value = 2147483647;
SmartDashboard.putNumber(key, value);
assertEquals(value, SmartDashboard.getNumber(key), 0.01);
assertEquals(value, table.getNumber(key), 0.01);
}
@Test
public void testPutBoolean() {
String key = "testPutBoolean";
boolean value = true;
SmartDashboard.putBoolean(key, value);
assertEquals(value, SmartDashboard.getBoolean(key));
assertEquals(value, table.getBoolean(key));
}
@Test
public void testReplaceString() {
String key = "testReplaceString";
String valueOld = "oldValue";
String valueNew = "newValue";
SmartDashboard.putString(key, valueOld);
assertEquals(valueOld, SmartDashboard.getString(key));
assertEquals(valueOld, table.getString(key));
SmartDashboard.putString(key, valueNew);
assertEquals(valueNew, SmartDashboard.getString(key));
assertEquals(valueNew, table.getString(key));
}
@Ignore
@Test(expected = IllegalArgumentException.class)
public void testPutStringNullKey() {
SmartDashboard.putString(null, "This should not work");
}
@Ignore
@Test(expected = IllegalArgumentException.class)
public void testPutStringNullValue() {
SmartDashboard.putString("KEY_SHOULD_NOT_BE_STORED", null);
}
}

View File

@@ -0,0 +1,22 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.smartdashboard;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import edu.wpi.first.wpilibj.test.AbstractTestSuite;
/**
* @author jonathanleitschuh
*
*/
@RunWith(Suite.class)
@SuiteClasses({SmartDashboardTest.class})
public class SmartDashboardTestSuite extends AbstractTestSuite {
}

View File

@@ -0,0 +1,230 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
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.RobotBase;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* This class serves as a superclass for all tests that involve the hardware on
* the roboRIO. It uses an {@link BeforeClass} statement to initialize network
* communications. Any test that needs to use the hardware <b>MUST</b> extend
* 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 */
private static boolean initialized = false;
/**
* This sets up the network communications library to enable the driver
* station. After starting network coms, it will loop until the driver station
* returns that the robot is enabled, to ensure that tests will be able to run
* on the hardware.
*$
*/
static {
if (!initialized) {
// Set some implementations so that the static methods work properly
RobotBase.initializeHardwareConfiguration();
FRCNetworkCommunicationsLibrary.FRCNetworkCommunicationObserveUserProgramStarting();
LiveWindow.setEnabled(false);
TestBench.out().println("Started coms");
// Wait until the robot is enabled before starting the 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++);
}
TestBench.out().println();
// Ready to go!
initialized = true;
TestBench.out().println("Running!");
}
}
protected abstract Logger getClassLogger();
/**
* This causes a stack trace to be printed as the test is running as well as
* at the end
*/
@Rule
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 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(),
"Starting");
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;
}
}

View File

@@ -0,0 +1,280 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.Request;
import org.junit.runners.Suite.SuiteClasses;
import org.junit.runners.model.InitializationError;
/**
* Allows tests suites and tests to be run selectively from the command line
* using a regex text pattern.
*$
* @author jonathanleitschuh
*
*/
public abstract class AbstractTestSuite {
private static final Logger logger = Logger.getLogger(AbstractTestSuite.class.getName());
/**
* Gets all of the classes listed within the SuiteClasses annotation. To use
* it, annotate a class with <code>@RunWith(Suite.class)</code> and
* <code>@SuiteClasses({TestClass1.class, ...})</code>. When you run this
* class, it will run all the tests in all the suite classes. When loading the
* tests using regex the test list will be generated from this annotation.
*$
* @return the list of classes listed in the
* <code>@SuiteClasses({TestClass1.class, ...})</code> annotation.
*/
protected List<Class<?>> getAnnotatedTestClasses() {
SuiteClasses annotation = getClass().getAnnotation(SuiteClasses.class);
List<Class<?>> classes = new Vector<Class<?>>();
if (annotation == null) {
throw new RuntimeException(String.format("class '%s' must have a SuiteClasses annotation",
getClass().getName()));
}
for (Class<?> c : annotation.value()) {
classes.add(c);
}
return classes;
}
/**
*$
* @param check
* @return
*/
private boolean areAnySuperClassesOfTypeAbstractTestSuite(Class<?> check) {
while (check != null) {
if (check.equals(AbstractTestSuite.class)) {
return true;
}
check = check.getSuperclass();
}
return false;
}
/**
* Stores a method name and method class pair. Used when searching for methods
* matching a given regex text.
*$
* @author jonathanleitschuh
*
*/
protected class ClassMethodPair {
public final Class<?> methodClass;
public final String methodName;
public ClassMethodPair(Class<?> klass, Method m) {
this.methodClass = klass;
this.methodName = m.getName();
}
public Request getMethodRunRequest() {
return Request.method(methodClass, methodName);
}
}
/**
* @param regex
* @return
*/
protected List<ClassMethodPair> getMethodMatching(final String regex) {
List<ClassMethodPair> classMethodPairs = new Vector<ClassMethodPair>();
// Get all of the test classes
for (Class<?> c : getAllContainedBaseTests()) {
for (Method m : c.getMethods()) {
// If this is a test method that is not trying to be ignored and it
// matches the regex
if (m.getAnnotation(Test.class) != null && m.getAnnotation(Ignore.class) == null
&& Pattern.matches(regex, m.getName())) {
ClassMethodPair pair = new ClassMethodPair(c, m);
classMethodPairs.add(pair);
}
}
}
return classMethodPairs;
}
/**
* Gets all of the test classes listed in this suite. Does not include any of
* the test suites. All of these classes contain tests.
*$
* @param runningList the running list of classes to prevent recursion.
* @return The list of base test classes.
*/
private List<Class<?>> getAllContainedBaseTests(List<Class<?>> runningList) {
for (Class<?> c : getAnnotatedTestClasses()) {
// Check to see if this is a test class or a suite
if (areAnySuperClassesOfTypeAbstractTestSuite(c)) {
// Create a new instance of this class so that we can retrieve its data
try {
AbstractTestSuite suite = null;
Object o = c.newInstance();
suite = (AbstractTestSuite) c.newInstance();
// Add the tests from this suite that match the regex to the list of
// tests to run
runningList = suite.getAllContainedBaseTests(runningList);
} catch (InstantiationException | IllegalAccessException e) {
// This shouldn't happen unless the constructor is changed in some
// way.
logger.log(Level.SEVERE, "Test suites can not take paramaters in their constructors.", e);
}
} else if (c.getAnnotation(SuiteClasses.class) != null) {
logger.log(Level.SEVERE,
String.format("class '%s' must extend %s to be searchable using regex.", c.getName()),
AbstractTestSuite.class.getName());
} else { // This is a class containing tests
// so add it to the list
runningList.add(c);
}
}
return runningList;
}
/**
* Gets all of the test classes listed in this suite. Does not include any of
* the test suites. All of these classes contain tests.
*$
* @return The list of base test classes.
*/
public List<Class<?>> getAllContainedBaseTests() {
List<Class<?>> runningBaseTests = new Vector<Class<?>>();
return getAllContainedBaseTests(runningBaseTests);
}
/**
* Retrieves all of the classes listed in the
* <code>@SuiteClasses<code> annotation that match the given regex text.
*$
* @param regex the text pattern to retrieve.
* @param runningList the running list of classes to prevent recursion
* @return The list of classes matching the regex pattern
*/
private List<Class<?>> getAllClassMatching(final String regex, final List<Class<?>> runningList) {
for (Class<?> c : getAnnotatedTestClasses()) {
// Compare the regex against the simple name of the class
if (Pattern.matches(regex, c.getName()) && !runningList.contains(c)) {
runningList.add(c);
}
}
return runningList;
}
/**
* Retrieves all of the classes listed in the
* <code>@SuiteClasses<code> annotation that match the given regex text.
*$
* @param regex the text pattern to retrieve.
* @return The list of classes matching the regex pattern
*/
public List<Class<?>> getAllClassMatching(final String regex) {
final List<Class<?>> matchingClasses = new Vector<Class<?>>();
return getAllClassMatching(regex, matchingClasses);
}
/**
* Searches through all of the suites and tests and loads only the test or
* test suites matching the regex text. This method also prevents a single
* test from being loaded multiple times by loading the suite first then
* loading tests from all non loaded suites.
*$
* @param regex the regex text to search for
* @return the list of suite and/or test classes matching the regex.
*/
private List<Class<?>> getSuiteOrTestMatchingRegex(final String regex, List<Class<?>> runningList) {
// Get any test suites matching the regex using the superclass methods
runningList = getAllClassMatching(regex, runningList);
// Then search any test suites not retrieved already for test classes
// matching the regex.
List<Class<?>> unCollectedSuites = getAllClasses();
// If we already have a test suite then we don't want to load the test twice
// so remove the suite from the list
unCollectedSuites.removeAll(runningList);
for (Class<?> c : unCollectedSuites) {
// Prevents recursively adding tests/suites that have already been added
if (!runningList.contains(c)) {
try {
AbstractTestSuite suite = null;
// Check the class to make sure that it is not a test class
if (areAnySuperClassesOfTypeAbstractTestSuite(c)) {
// Create a new instance of this class so that we can retrieve its
// data.
Object o = c.newInstance();
suite = (AbstractTestSuite) c.newInstance();
// Add the tests from this suite that match the regex to the list of
// tests to run
runningList = suite.getSuiteOrTestMatchingRegex(regex, runningList);
}
} catch (InstantiationException | IllegalAccessException e) {
// This shouldn't happen unless the constructor is changed in some
// way.
logger.log(Level.SEVERE, "Test suites can not take paramaters in their constructors.", e);
}
}
}
return runningList;
}
/**
* Searches through all of the suites and tests and loads only the test or
* test suites matching the regex text. This method also prevents a single
* test from being loaded multiple times by loading the suite first then
* loading tests from all non loaded suites.
*$
* @param regex the regex text to search for
* @return the list of suite and/or test classes matching the regex.
*/
protected List<Class<?>> getSuiteOrTestMatchingRegex(final String regex) {
final List<Class<?>> matchingClasses = new Vector<Class<?>>();
return getSuiteOrTestMatchingRegex(regex, matchingClasses);
}
/**
* Retrieves all of the classes listed in the
* <code>@SuiteClasses<code> annotation.
*$
* @return
* @throws InitializationError If the <code>@SuiteClasses<code> annotation is
* missing.
*/
public List<Class<?>> getAllClasses() {
return getAnnotatedTestClasses();
}
/**
* Gets the name of all of the classes listed within the
* <code>@SuiteClasses<code> annotation.
*$
* @return the list of classes.
* @throws InitializationError If the <code>@SuiteClasses<code> annotation is
* missing.
*/
public List<String> getAllClassName() {
List<String> classNames = new Vector<String>();
for (Class<?> c : getAnnotatedTestClasses()) {
classNames.add(c.getName());
}
return classNames;
}
}

View File

@@ -0,0 +1,88 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.io.File;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junit.FormatterElement;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
/**
* Provides an entry point for tests to run with ANT. This allows ant to output
* JUnit XML test results for Jenkins.
*$
* @author jonathanleitschuh
*
*/
public class AntJunitLanucher {
public static void main(String... args) {
if (args.length == 0) {
String path =
String.format("%s/%s", System.getProperty("user.dir"), "/testResults/AntReports");
String pathToReports = path;
Project project = new Project();
try {
// Create the file to store the test output
new File(pathToReports).mkdirs();
JUnitTask task = new JUnitTask();
project.setProperty("java.io.tmpdir", pathToReports);
/* Output to screen */
FormatterElement.TypeAttribute typeScreen = new FormatterElement.TypeAttribute();
typeScreen.setValue("plain");
FormatterElement formatToScreen = new FormatterElement();
formatToScreen.setType(typeScreen);
formatToScreen.setUseFile(false);
formatToScreen.setOutput(System.out);
task.addFormatter(formatToScreen);
// add a build listener to the project
BuildLogger logger = new DefaultLogger();
logger.setOutputPrintStream(System.out);
logger.setErrorPrintStream(System.err);
logger.setMessageOutputLevel(Project.MSG_INFO);
logger.setEmacsMode(true);
project.addBuildListener(logger);
task.setProject(project);
// Set the output to the XML file
FormatterElement.TypeAttribute type = new FormatterElement.TypeAttribute();
type.setValue("xml");
FormatterElement formater = new FormatterElement();
formater.setType(type);
task.addFormatter(formater);
// Create the JUnitTest
JUnitTest test = new JUnitTest(TestSuite.class.getName());
test.setTodir(new File(pathToReports));
task.addTest(test);
TestBench.out().println("Beginning Test Execution With ANT");
task.execute();
} catch (Exception e) {
e.printStackTrace();
}
} else {
TestBench.out().println(
"Run will not output XML for Jenkins because " + "tests are not being run with ANT");
// This should never return as it makes its own call to
// System.exit();
TestSuite.main(args);
}
System.exit(0);
}
}

View File

@@ -0,0 +1,42 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.util.logging.Logger;
import org.junit.Test;
/**
* This class is designated to allow for simple testing of the library without
* the overlying testing framework. This test is NOT run as a normal part of the
* testing process and must be explicitly selected at runtime by using the
* 'quick' argument.
*$
* This test should never be committed with changes to it but can be used during
* development to aid in feature testing.
*$
* @author Jonathan Leitschuh
*/
public class QuickTest extends AbstractComsSetup {
private static final Logger logger = Logger.getLogger(QuickTest.class.getName());
/*
* (non-Javadoc)
*$
* @see edu.wpi.first.wpilibj.test.AbstractComsSetup#getClassLogger()
*/
@Override
protected Logger getClassLogger() {
return logger;
}
@Test
public void test() {
}
}

View File

@@ -0,0 +1,64 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* This JUnit Rule allows you to apply this rule to any test to allow it to run
* multiple times. This is important if you have a test that fails only
* "sometimes" and needs to be rerun to find the issue.
*$
* This code was originally found here: <a href=
* "http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/"
* >Running JUnit Tests Repeatedly Without Loops<a>
*$
* @author Frank Appel
*/
public class RepeatRule implements TestRule {
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.METHOD})
public @interface Repeat {
public abstract int times();
}
private static class RepeatStatement extends Statement {
private final int times;
private final Statement statement;
private RepeatStatement(int times, Statement statement) {
this.times = times;
this.statement = statement;
}
@Override
public void evaluate() throws Throwable {
for (int i = 0; i < times; i++) {
statement.evaluate();
}
}
}
@Override
public Statement apply(Statement statement, Description description) {
Statement result = statement;
Repeat repeat = description.getAnnotation(Repeat.class);
if (repeat != null) {
int times = repeat.times();
result = new RepeatStatement(times, statement);
}
return result;
}
}

View File

@@ -0,0 +1,441 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import edu.wpi.first.wpilibj.AnalogGyro;
import edu.wpi.first.wpilibj.AnalogInput;
import edu.wpi.first.wpilibj.AnalogOutput;
import edu.wpi.first.wpilibj.CANJaguar;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.DigitalOutput;
import edu.wpi.first.wpilibj.Jaguar;
import edu.wpi.first.wpilibj.Relay;
import edu.wpi.first.wpilibj.Servo;
import edu.wpi.first.wpilibj.Talon;
import edu.wpi.first.wpilibj.Victor;
import edu.wpi.first.wpilibj.fixtures.AnalogCrossConnectFixture;
import edu.wpi.first.wpilibj.fixtures.CANMotorEncoderFixture;
import edu.wpi.first.wpilibj.fixtures.DIOCrossConnectFixture;
import edu.wpi.first.wpilibj.fixtures.MotorEncoderFixture;
import edu.wpi.first.wpilibj.fixtures.RelayCrossConnectFixture;
import edu.wpi.first.wpilibj.fixtures.TiltPanCameraFixture;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.mockhardware.FakePotentiometerSource;
/**
* This class provides access to all of the elements on the test bench, for use
* in fixtures. This class is a singleton, you should use {@link #getInstance()}
* to obtain a reference to the {@code TestBench}.
*
* TODO: This needs to be updated to the most recent test bench setup.
*
* @author Fredric Silberberg
*/
public final class TestBench {
/**
* The time that it takes to have a motor go from rotating at full speed to
* completely stopped
*/
public static final double MOTOR_STOP_TIME = 0.25;
public static final int kTalonChannel = 10;
public static final int kVictorChannel = 1;
public static final int kJaguarChannel = 2;
/* TiltPanCamera Channels */
public static final int kGyroChannel = 0;
public static final double kGyroSensitivity = 0.013;
public static final int kTiltServoChannel = 9;
public static final int kPanServoChannel = 8;
/* PowerDistributionPanel channels */
public static final int kJaguarPDPChannel = 6;
public static final int kVictorPDPChannel = 8;
public static final int kTalonPDPChannel = 11;
public static final int kCANJaguarPDPChannel = 5;
/* CAN ASSOICATED CHANNELS */
public static final int kCANRelayPowerCycler = 1;
public static final int kFakeJaguarPotentiometer = 1;
public static final int kFakeJaguarForwardLimit = 20;
public static final int kFakeJaguarReverseLimit = 21;
public static final int kCANJaguarID = 2;
// THESE MUST BE IN INCREMENTING ORDER
public static final int DIOCrossConnectB2 = 9;
public static final int DIOCrossConnectB1 = 8;
public static final int DIOCrossConnectA2 = 7;
public static final int DIOCrossConnectA1 = 6;
/** The Singleton instance of the Test Bench */
private static TestBench instance = null;
/**
* The single constructor for the TestBench. This method is private in order
* to prevent multiple TestBench objects from being allocated
*/
protected TestBench() {}
/**
* Constructs a new set of objects representing a connected set of Talon
* controlled Motors and an encoder
*
* @return a freshly allocated Talon, Encoder pair
*/
public MotorEncoderFixture<Talon> getTalonPair() {
MotorEncoderFixture<Talon> talonPair = new MotorEncoderFixture<Talon>() {
@Override
protected Talon giveSpeedController() {
return new Talon(kTalonChannel);
}
@Override
protected DigitalInput giveDigitalInputA() {
return new DigitalInput(0);
}
@Override
protected DigitalInput giveDigitalInputB() {
return new DigitalInput(1);
}
@Override
public int getPDPChannel() {
return kTalonPDPChannel;
}
};
return talonPair;
}
/**
* Constructs a new set of objects representing a connected set of Victor
* controlled Motors and an encoder
*
* @return a freshly allocated Victor, Encoder pair
*/
public MotorEncoderFixture<Victor> getVictorPair() {
MotorEncoderFixture<Victor> vicPair = new MotorEncoderFixture<Victor>() {
@Override
protected Victor giveSpeedController() {
return new Victor(kVictorChannel);
}
@Override
protected DigitalInput giveDigitalInputA() {
return new DigitalInput(2);
}
@Override
protected DigitalInput giveDigitalInputB() {
return new DigitalInput(3);
}
@Override
public int getPDPChannel() {
return kVictorPDPChannel;
}
};
return vicPair;
}
/**
* Constructs a new set of objects representing a connected set of Jaguar
* controlled Motors and an encoder
*
* @return a freshly allocated Jaguar, Encoder pair
*/
public MotorEncoderFixture<Jaguar> getJaguarPair() {
MotorEncoderFixture<Jaguar> jagPair = new MotorEncoderFixture<Jaguar>() {
@Override
protected Jaguar giveSpeedController() {
return new Jaguar(kJaguarChannel);
}
@Override
protected DigitalInput giveDigitalInputA() {
return new DigitalInput(4);
}
@Override
protected DigitalInput giveDigitalInputB() {
return new DigitalInput(5);
}
@Override
public int getPDPChannel() {
return kJaguarPDPChannel;
}
};
return jagPair;
}
public class BaseCANMotorEncoderFixture extends CANMotorEncoderFixture {
@Override
protected CANJaguar giveSpeedController() {
return new CANJaguar(kCANJaguarID);
}
@Override
protected DigitalInput giveDigitalInputA() {
return new DigitalInput(18);
}
@Override
protected DigitalInput giveDigitalInputB() {
return new DigitalInput(19);
}
@Override
protected FakePotentiometerSource giveFakePotentiometerSource() {
return new FakePotentiometerSource(kFakeJaguarPotentiometer, 360);
}
@Override
protected DigitalOutput giveFakeForwardLimit() {
return new DigitalOutput(kFakeJaguarForwardLimit);
}
@Override
protected DigitalOutput giveFakeReverseLimit() {
return new DigitalOutput(kFakeJaguarReverseLimit);
}
/*
* (non-Javadoc)
*$
* @see
* edu.wpi.first.wpilibj.fixtures.CANMotorEncoderFixture#givePoweCycleRelay
* ()
*/
@Override
protected Relay givePoweCycleRelay() {
return new Relay(kCANRelayPowerCycler);
}
@Override
public int getPDPChannel() {
return kCANJaguarPDPChannel;
}
}
/**
* Constructs a new set of objects representing a connected set of CANJaguar
* controlled Motors and an encoder<br>
* Note: The CANJaguar is not freshly allocated because the CANJaguar lacks a
* free() method
*
* @return an existing CANJaguar and a freshly allocated Encoder
*/
public CANMotorEncoderFixture getCanJaguarPair() {
CANMotorEncoderFixture canPair = new BaseCANMotorEncoderFixture();
return canPair;
}
/**
* Constructs a new set of two Servo's and a Gyroscope.
*
* @return a freshly allocated Servo's and a freshly allocated Gyroscope
*/
public TiltPanCameraFixture getTiltPanCam() {
TiltPanCameraFixture tpcam = new TiltPanCameraFixture() {
@Override
protected Gyro giveGyro() {
AnalogGyro gyro = new AnalogGyro(kGyroChannel);
gyro.setSensitivity(kGyroSensitivity);
return gyro;
}
@Override
protected Servo giveTilt() {
return new Servo(kTiltServoChannel);
}
@Override
protected Servo givePan() {
return new Servo(kPanServoChannel);
}
};
return tpcam;
}
public DIOCrossConnectFixture getDIOCrossConnectFixture(int inputPort, int outputPort) {
DIOCrossConnectFixture dio = new DIOCrossConnectFixture(inputPort, outputPort);
return dio;
}
/**
* Gets two lists of possible DIO pairs for the two pairs
*$
* @return
*/
private List<List<Integer[]>> getDIOCrossConnect() {
List<List<Integer[]>> pairs = new ArrayList<List<Integer[]>>();
List<Integer[]> setA =
Arrays.asList(new Integer[][] {
{new Integer(DIOCrossConnectA1), new Integer(DIOCrossConnectA2)},
{new Integer(DIOCrossConnectA2), new Integer(DIOCrossConnectA1)}});
pairs.add(setA);
List<Integer[]> setB =
Arrays.asList(new Integer[][] {
{new Integer(DIOCrossConnectB1), new Integer(DIOCrossConnectB2)},
{new Integer(DIOCrossConnectB2), new Integer(DIOCrossConnectB1)}});
pairs.add(setB);
// NOTE: IF MORE DIOCROSSCONNECT PAIRS ARE ADDED ADD THEM HERE
return pairs;
}
public static AnalogCrossConnectFixture getAnalogCrossConnectFixture() {
AnalogCrossConnectFixture analogIO = new AnalogCrossConnectFixture() {
@Override
protected AnalogOutput giveAnalogOutput() {
return new AnalogOutput(0);
}
@Override
protected AnalogInput giveAnalogInput() {
return new AnalogInput(2);
}
};
return analogIO;
}
public static RelayCrossConnectFixture getRelayCrossConnectFixture() {
RelayCrossConnectFixture relay = new RelayCrossConnectFixture() {
@Override
protected Relay giveRelay() {
return new Relay(0);
}
@Override
protected DigitalInput giveInputTwo() {
return new DigitalInput(18);
}
@Override
protected DigitalInput giveInputOne() {
return new DigitalInput(19);
}
};
return relay;
}
/**
* Return a single Collection containing all of the DIOCrossConnectFixtures in
* all two pair combinations
*$
* @return
*/
public Collection<Integer[]> getDIOCrossConnectCollection() {
Collection<Integer[]> pairs = new ArrayList<Integer[]>();
for (Collection<Integer[]> collection : getDIOCrossConnect()) {
pairs.addAll(collection);
}
return pairs;
}
/**
* Gets an array of pairs for the encoder to use using two different lists
*$
* @param listA
* @param listB
* @param flip whether this encoder needs to be flipped
* @return A list of different inputs to use for the tests
*/
private Collection<Integer[]> getPairArray(List<Integer[]> listA, List<Integer[]> listB,
boolean flip) {
Collection<Integer[]> encoderPortPairs = new ArrayList<Integer[]>();
for (Integer[] portPairsA : listA) {
ArrayList<Integer[]> construtorInput = new ArrayList<Integer[]>();
Integer inputs[] = new Integer[5];
inputs[0] = portPairsA[0]; // InputA
inputs[1] = portPairsA[1]; // InputB
for (Integer[] portPairsB : listB) {
inputs[2] = portPairsB[0]; // OutputA
inputs[3] = portPairsB[1]; // OutputB
inputs[4] = flip ? 0 : 1; // The flip bit
}
construtorInput.add(inputs);
inputs = inputs.clone();
for (Integer[] portPairsB : listB) {
inputs[2] = portPairsB[1]; // OutputA
inputs[3] = portPairsB[0]; // OutputB
inputs[4] = flip ? 0 : 1; // The flip bit
}
construtorInput.add(inputs);
encoderPortPairs.addAll(construtorInput);
}
return encoderPortPairs;
}
/**
* Constructs the list of inputs to be used for the encoder test
*$
* @return A collection of different input pairs to use for the encoder
*/
public Collection<Integer[]> getEncoderDIOCrossConnectCollection() {
Collection<Integer[]> encoderPortPairs = new ArrayList<Integer[]>();
assert getDIOCrossConnect().size() == 2;
encoderPortPairs.addAll(getPairArray(getDIOCrossConnect().get(0), getDIOCrossConnect().get(1),
false));
encoderPortPairs.addAll(getPairArray(getDIOCrossConnect().get(1), getDIOCrossConnect().get(0),
false));
assert (encoderPortPairs.size() == 8);
return encoderPortPairs;
}
/**
* Gets the singleton of the TestBench. If the TestBench is not already
* allocated in constructs an new instance of it. Otherwise it returns the
* existing instance.
*
* @return The Singleton instance of the TestBench
*/
public static TestBench getInstance() {
if (instance == null) {
instance = new TestBench();
}
return instance;
}
/**
* Provides access to the output stream for the test system. This should be
* used instead of System.out This is gives us a way to implement changes to
* where the output text of this test system is sent.
*$
* @return The test bench global print stream.
*/
public static PrintStream out() {
return System.out;
}
/**
* Provides access to the error stream for the test system. This should be
* used instead of System.err This is gives us a way to implement changes to
* where the output text of this test system is sent.
*$
* @return The test bench global print stream.
*/
public static PrintStream err() {
return System.err;
}
}

View File

@@ -0,0 +1,382 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2014. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import junit.framework.JUnit4TestAdapter;
import junit.runner.Version;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import edu.wpi.first.wpilibj.WpiLibJTestSuite;
import edu.wpi.first.wpilibj.can.CANTestSuite;
import edu.wpi.first.wpilibj.command.CommandTestSuite;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboardTestSuite;
/**
* The WPILibJ Integeration Test Suite collects all of the tests to be run by
* junit. In order for a test to be run, it must be added the list of suite
* classes below. The tests will be run in the order they are listed in the
* suite classes annotation.
*/
@RunWith(Suite.class)
// These are listed on separate lines to prevent merge conflicts
@SuiteClasses({WpiLibJTestSuite.class, CANTestSuite.class, CommandTestSuite.class,
SmartDashboardTestSuite.class})
public class TestSuite extends AbstractTestSuite {
static {
// Sets up the logging output
final InputStream inputStream = TestSuite.class.getResourceAsStream("/logging.properties");
try {
if (inputStream == null)
throw new NullPointerException("./logging.properties was not loaded");
LogManager.getLogManager().readConfiguration(inputStream);
Logger.getAnonymousLogger().info("Loaded");
} catch (final IOException | NullPointerException e) {
Logger.getAnonymousLogger().severe("Could not load default logging.properties file");
Logger.getAnonymousLogger().severe(e.getMessage());
}
TestBench.out().println("Starting Tests");
}
private static final Logger WPILIBJ_ROOT_LOGGER = Logger.getLogger("edu.wpi.first.wpilibj");
private static final Logger WPILIBJ_COMMAND_ROOT_LOGGER = Logger
.getLogger("edu.wpi.first.wpilibj.command");
private static final Class<?> QUICK_TEST = QuickTest.class;
private static final String QUICK_TEST_FLAG = "--quick";
private static final String HELP_FLAG = "--help";
private static final String METHOD_NAME_FILTER = "--methodFilter=";
private static final String METHOD_REPEAT_FILTER = "--repeat=";
private static final String CLASS_NAME_FILTER = "--filter=";
private static TestSuite instance = null;
public static TestSuite getInstance() {
if (instance == null) {
instance = new TestSuite();
}
return instance;
}
/**
* This has to be public so that the JUnit4
*/
public TestSuite() {}
/**
* Displays a help message for the user when they use the --help flag at
* runtime.
*/
protected static void displayHelp() {
StringBuilder helpMessage = new StringBuilder("Test Parameters help: \n");
helpMessage.append("\t" + QUICK_TEST_FLAG
+ " will cause the quick test to be run. Ignores other flags except for "
+ METHOD_REPEAT_FILTER + "\n");
helpMessage.append("\t" + CLASS_NAME_FILTER
+ " will use the supplied regex text to search for suite/test class names "
+ "matching the regex and run them.\n");
helpMessage.append("\t" + METHOD_NAME_FILTER
+ " will use the supplied regex text to search for test methods (excluding methods "
+ "with the @Ignore annotation) and run only those methods. Can be paired with "
+ METHOD_REPEAT_FILTER + " to " + "repeat the selected tests multiple times.\n");
helpMessage.append("\t" + METHOD_REPEAT_FILTER + " will repeat the tests selected with either "
+ QUICK_TEST_FLAG + " or " + CLASS_NAME_FILTER
+ " and run them the given number of times.\n");
helpMessage
.append("[NOTE] All regex uses the syntax defined by java.util.regex.Pattern. This documentation can be found at "
+ "http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html\n");
helpMessage.append("\n");
helpMessage.append("\n");
TestBench.out().println(helpMessage);
}
/**
* Lets the user know that they used the TestSuite improperly and gives
* details about how to use it correctly in the future.
*/
protected static void displayInvalidUsage(String message, String... args) {
StringBuilder invalidMessage = new StringBuilder("Invalid Usage: " + message + "\n");
invalidMessage.append("Params received: ");
for (String a : args) {
invalidMessage.append(a + " ");
}
invalidMessage.append("\n");
invalidMessage
.append("For details on proper usage of the runtime flags please run again with the "
+ HELP_FLAG + " flag.\n\n");
TestBench.out().println(invalidMessage);
}
/**
* Prints the loaded tests before they are run.
*$
* @param classes the classes that were loaded.
*/
protected static void printLoadedTests(final Class<?>... classes) {
StringBuilder loadedTestsMessage = new StringBuilder("The following tests were loaded:\n");
Package p = null;
for (Class<?> c : classes) {
if (c.getPackage().equals(p)) {
p = c.getPackage();
loadedTestsMessage.append(p.getName() + "\n");
}
loadedTestsMessage.append("\t" + c.getSimpleName() + "\n");
}
TestBench.out().println(loadedTestsMessage);
}
/**
* Parses the arguments passed at runtime and runs the appropriate tests based
* upon these arguments
*$
* @param args the args passed into the program at runtime
* @return the restults of the tests that have run. If no tests were run then
* null is returned.
*/
protected static Result parseArgsRunAndGetResult(final String[] args) {
if (args.length == 0) { // If there are no args passed at runtime then just
// run all of the tests.
printLoadedTests(TestSuite.class);
return JUnitCore.runClasses(TestSuite.class);
}
// The method filter was passed
boolean methodFilter = false;
String methodRegex = "";
// The class filter was passed
boolean classFilter = false;
String classRegex = "";
boolean repeatFilter = false;
int repeatCount = 1;
for (String s : args) {
if (Pattern.matches(METHOD_NAME_FILTER + ".*", s)) {
methodFilter = true;
methodRegex = new String(s).replace(METHOD_NAME_FILTER, "");
}
if (Pattern.matches(METHOD_REPEAT_FILTER + ".*", s)) {
repeatFilter = true;
try {
repeatCount = Integer.parseInt(new String(s).replace(METHOD_REPEAT_FILTER, ""));
} catch (NumberFormatException e) {
displayInvalidUsage("The argument passed to the repeat rule was not a valid integer.",
args);
}
}
if (Pattern.matches(CLASS_NAME_FILTER + ".*", s)) {
classFilter = true;
classRegex = new String(s).replace(CLASS_NAME_FILTER, "");
}
}
ArrayList<String> argsParsed = new ArrayList<String>(Arrays.asList(args));
if (argsParsed.contains(HELP_FLAG)) {
// If the user inputs the help flag then return the help message and exit
// without running any tests
displayHelp();
return null;
}
if (argsParsed.contains(QUICK_TEST_FLAG)) {
printLoadedTests(QUICK_TEST);
return JUnitCore.runClasses(QUICK_TEST);
}
/**
* Stores the data from multiple {@link Result}s in one class that can be
* returned to display the results.
*/
class MultipleResult extends Result {
private static final long serialVersionUID = 1L;
private final List<Failure> failures = new Vector<Failure>();
private int runCount = 0;
private int ignoreCount = 0;
private long runTime = 0;
@Override
public int getRunCount() {
return runCount;
}
@Override
public int getFailureCount() {
return failures.size();
}
@Override
public long getRunTime() {
return runTime;
}
@Override
public List<Failure> getFailures() {
return failures;
}
@Override
public int getIgnoreCount() {
return ignoreCount;
}
/**
* Adds the given result's data to this result
*$
* @param r the result to add to this result
*/
void addResult(Result r) {
failures.addAll(r.getFailures());
runCount += r.getRunCount();
ignoreCount += r.getIgnoreCount();
runTime += r.getRunTime();
}
}
// If a specific method has been requested
if (methodFilter) {
List<ClassMethodPair> pairs = (new TestSuite()).getMethodMatching(methodRegex);
if (pairs.size() == 0) {
displayInvalidUsage("None of the arguments passed to the method name filter matched.", args);
return null;
}
// Print out the list of tests before we run them
TestBench.out().println("Running the following tests:");
Class<?> classListing = null;
for (ClassMethodPair p : pairs) {
if (!p.methodClass.equals(classListing)) {
// Only display the class name every time it changes
classListing = p.methodClass;
TestBench.out().println(classListing);
}
TestBench.out().println("\t" + p.methodName);
}
// The test results will be saved here
MultipleResult results = new MultipleResult();
// Runs tests multiple times if the repeat rule is used
for (int i = 0; i < repeatCount; i++) {
// Now run all of the tests
for (ClassMethodPair p : pairs) {
Result result = (new JUnitCore()).run(p.getMethodRunRequest());
// Store the given results in one cohesive result
results.addResult(result);
}
}
return results;
}
// If a specific class has been requested
if (classFilter) {
List<Class<?>> testClasses = (new TestSuite()).getSuiteOrTestMatchingRegex(classRegex);
if (testClasses.size() == 0) {
displayInvalidUsage("None of the arguments passed to the filter matched.", args);
return null;
}
printLoadedTests(testClasses.toArray(new Class[0]));
MultipleResult results = new MultipleResult();
// Runs tests multiple times if the repeat rule is used
for (int i = 0; i < repeatCount; i++) {
Result result = (new JUnitCore()).run(testClasses.toArray(new Class[0]));
// Store the given results in one cohesive result
results.addResult(result);
}
return results;
}
displayInvalidUsage(
"None of the parameters that you passed matched any of the accepted flags.", args);
return null;
}
protected static void displayResults(Result result) {
// Results are collected and displayed here
TestBench.out().println("\n");
if (!result.wasSuccessful()) {
// Prints out a list of stack traces for the failed tests
TestBench.out().println("Failure List: ");
for (Failure f : result.getFailures()) {
TestBench.out().println(f.getDescription());
TestBench.out().println(f.getTrace());
}
TestBench.out().println();
TestBench.out().println("FAILURES!!!");
// Print the test statistics
TestBench.out().println(
"Tests run: " + result.getRunCount() + ", Failures: " + result.getFailureCount()
+ ", Ignored: " + result.getIgnoreCount() + ", In " + result.getRunTime() + "ms");
// Prints out a list of test that failed
TestBench.out().println("Failure List (short):");
String failureClass = result.getFailures().get(0).getDescription().getClassName();
TestBench.out().println(failureClass);
for (Failure f : result.getFailures()) {
if (!failureClass.equals(f.getDescription().getClassName())) {
failureClass = f.getDescription().getClassName();
TestBench.out().println(failureClass);
}
TestBench.err().println("\t" + f.getDescription());
}
} else {
TestBench.out().println("SUCCESS!");
TestBench.out().println(
"Tests run: " + result.getRunCount() + ", Ignored: " + result.getIgnoreCount() + ", In "
+ result.getRunTime() + "ms");
}
TestBench.out().println();
}
/**
* This is used by ant to get the Junit tests. This is required because the
* tests try to load using a JUnit 3 framework. JUnit4 uses annotations to
* load tests. This method allows JUnit3 to load JUnit4 tests.
*/
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(TestSuite.class);
}
/**
* The method called at runtime
*$
* @param args The test suites to run
*/
public static void main(String[] args) {
TestBench.out().println("JUnit version " + Version.id());
// Tests are run here
Result result = parseArgsRunAndGetResult(args);
if (result != null) {
// Results are collected and displayed here
displayResults(result);
System.exit(result.wasSuccessful() ? 0 : 1);
}
System.exit(1);
}
}

View File

@@ -0,0 +1,13 @@
/**
* This is the starting point for the integration testing framework. This
* package should contain classes that are not explicitly for testing the
* library but instead provide the framework that the tests can extend from.
* Every test should extend from
* {@link edu.wpi.first.wpilibj.test.AbstractComsSetup} to ensure that Network
* Communications is properly instantiated before the test is run.
*$
* The {@link edu.wpi.first.wpilibj.test.TestBench} should contain the port
* numbers for all of the hardware and these values should not be explicitly
* defined anywhere else in the testing framework.
*/
package edu.wpi.first.wpilibj.test;