[wpilibc] Clean up integration tests (#3400)

The command and shuffleboard integration tests were removed because
their unit tests counterparts already provide adequate coverage. Java
already removed these.
This commit is contained in:
Tyler Veness
2021-05-31 10:21:34 -07:00
committed by GitHub
parent 4f7a4464df
commit 93523d572e
38 changed files with 662 additions and 2232 deletions

View File

@@ -12,41 +12,23 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kDelayTime = 10_ms;
/**
* A fixture with an analog input and an analog output wired together
*/
class AnalogLoopTest : public testing::Test {
protected:
AnalogInput* m_input;
AnalogOutput* m_output;
void SetUp() override {
m_input = new AnalogInput(TestBench::kFakeAnalogOutputChannel);
m_output = new AnalogOutput(TestBench::kAnalogOutputChannel);
}
void TearDown() override {
delete m_input;
delete m_output;
}
};
/**
* Test analog inputs and outputs by setting one and making sure the other
* matches.
*/
TEST_F(AnalogLoopTest, AnalogInputWorks) {
TEST(AnalogLoopTest, AnalogInputWorks) {
frc::AnalogInput input{TestBench::kFakeAnalogOutputChannel};
frc::AnalogOutput output{TestBench::kAnalogOutputChannel};
// Set the output voltage and check if the input measures the same voltage
for (int32_t i = 0; i < 50; i++) {
m_output->SetVoltage(i / 10.0);
output.SetVoltage(i / 10.0);
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_NEAR(m_output->GetVoltage(), m_input->GetVoltage(), 0.01);
EXPECT_NEAR(output.GetVoltage(), input.GetVoltage(), 0.01);
}
}
@@ -54,26 +36,29 @@ TEST_F(AnalogLoopTest, AnalogInputWorks) {
* Test if we can use an analog trigger to check if the output is within a
* range correctly.
*/
TEST_F(AnalogLoopTest, AnalogTriggerWorks) {
AnalogTrigger trigger(m_input);
TEST(AnalogLoopTest, AnalogTriggerWorks) {
frc::AnalogInput input{TestBench::kFakeAnalogOutputChannel};
frc::AnalogOutput output{TestBench::kAnalogOutputChannel};
frc::AnalogTrigger trigger{&input};
trigger.SetLimitsVoltage(2.0, 3.0);
m_output->SetVoltage(1.0);
Wait(kDelayTime);
output.SetVoltage(1.0);
frc::Wait(kDelayTime);
EXPECT_FALSE(trigger.GetInWindow())
<< "Analog trigger is in the window (2V, 3V)";
EXPECT_FALSE(trigger.GetTriggerState()) << "Analog trigger is on";
m_output->SetVoltage(2.5);
Wait(kDelayTime);
output.SetVoltage(2.5);
frc::Wait(kDelayTime);
EXPECT_TRUE(trigger.GetInWindow())
<< "Analog trigger is not in the window (2V, 3V)";
EXPECT_FALSE(trigger.GetTriggerState()) << "Analog trigger is on";
m_output->SetVoltage(4.0);
Wait(kDelayTime);
output.SetVoltage(4.0);
frc::Wait(kDelayTime);
EXPECT_FALSE(trigger.GetInWindow())
<< "Analog trigger is in the window (2V, 3V)";
@@ -84,18 +69,21 @@ TEST_F(AnalogLoopTest, AnalogTriggerWorks) {
* Test if we can count the right number of ticks from an analog trigger with
* a counter.
*/
TEST_F(AnalogLoopTest, AnalogTriggerCounterWorks) {
AnalogTrigger trigger(m_input);
TEST(AnalogLoopTest, AnalogTriggerCounterWorks) {
frc::AnalogInput input{TestBench::kFakeAnalogOutputChannel};
frc::AnalogOutput output{TestBench::kAnalogOutputChannel};
frc::AnalogTrigger trigger{&input};
trigger.SetLimitsVoltage(2.0, 3.0);
Counter counter(trigger);
frc::Counter counter{trigger};
// Turn the analog output low and high 50 times
for (int32_t i = 0; i < 50; i++) {
m_output->SetVoltage(1.0);
Wait(kDelayTime);
m_output->SetVoltage(4.0);
Wait(kDelayTime);
output.SetVoltage(1.0);
frc::Wait(kDelayTime);
output.SetVoltage(4.0);
frc::Wait(kDelayTime);
}
// The counter should be 50
@@ -107,24 +95,27 @@ static void InterruptHandler(uint32_t interruptAssertedMask, void* param) {
*reinterpret_cast<int32_t*>(param) = 12345;
}
TEST_F(AnalogLoopTest, AsynchronusInterruptWorks) {
TEST(AnalogLoopTest, AsynchronusInterruptWorks) {
frc::AnalogInput input{TestBench::kFakeAnalogOutputChannel};
frc::AnalogOutput output{TestBench::kAnalogOutputChannel};
int32_t param = 0;
AnalogTrigger trigger(m_input);
frc::AnalogTrigger trigger{&input};
trigger.SetLimitsVoltage(2.0, 3.0);
// Given an interrupt handler that sets an int32_t to 12345
std::shared_ptr<AnalogTriggerOutput> triggerOutput =
trigger.CreateOutput(AnalogTriggerType::kState);
std::shared_ptr<frc::AnalogTriggerOutput> triggerOutput =
trigger.CreateOutput(frc::AnalogTriggerType::kState);
triggerOutput->RequestInterrupts(InterruptHandler, &param);
triggerOutput->EnableInterrupts();
// If the analog output moves from below to above the window
m_output->SetVoltage(0.0);
Wait(kDelayTime);
m_output->SetVoltage(5.0);
output.SetVoltage(0.0);
frc::Wait(kDelayTime);
output.SetVoltage(5.0);
triggerOutput->CancelInterrupts();
// Then the int32_t should be 12345
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_EQ(12345, param) << "The interrupt did not run.";
}

View File

@@ -10,38 +10,25 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr double kScale = 270.0;
static constexpr double kAngle = 180.0;
static const double kScale = 270.0;
static const double kAngle = 180.0;
TEST(AnalogPotentiometerTest, TestInitialSettings) {
frc::AnalogOutput m_fakePot{TestBench::kAnalogOutputChannel};
frc::AnalogPotentiometer m_pot{TestBench::kFakeAnalogOutputChannel, kScale};
class AnalogPotentiometerTest : public testing::Test {
protected:
AnalogOutput* m_fakePot;
AnalogPotentiometer* m_pot;
void SetUp() override {
m_fakePot = new AnalogOutput(TestBench::kAnalogOutputChannel);
m_pot =
new AnalogPotentiometer(TestBench::kFakeAnalogOutputChannel, kScale);
}
void TearDown() override {
delete m_fakePot;
delete m_pot;
}
};
TEST_F(AnalogPotentiometerTest, TestInitialSettings) {
m_fakePot->SetVoltage(0.0);
Wait(0.1_s);
EXPECT_NEAR(0.0, m_pot->Get(), 5.0)
m_fakePot.SetVoltage(0.0);
frc::Wait(100_ms);
EXPECT_NEAR(0.0, m_pot.Get(), 5.0)
<< "The potentiometer did not initialize to 0.";
}
TEST_F(AnalogPotentiometerTest, TestRangeValues) {
m_fakePot->SetVoltage(kAngle / kScale * RobotController::GetVoltage5V());
Wait(0.1_s);
EXPECT_NEAR(kAngle, m_pot->Get(), 2.0)
TEST(AnalogPotentiometerTest, TestRangeValues) {
frc::AnalogOutput m_fakePot{TestBench::kAnalogOutputChannel};
frc::AnalogPotentiometer m_pot{TestBench::kFakeAnalogOutputChannel, kScale};
m_fakePot.SetVoltage(kAngle / kScale * frc::RobotController::GetVoltage5V());
frc::Wait(100_ms);
EXPECT_NEAR(kAngle, m_pot.Get(), 2.0)
<< "The potentiometer did not measure the correct angle.";
}

View File

@@ -7,19 +7,18 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr double kAccelerationTolerance = 0.1;
/**
* 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(BuiltInAccelerometerTest, Accelerometer) {
BuiltInAccelerometer accelerometer;
frc::BuiltInAccelerometer accelerometer;
/* The testbench sometimes shakes a little from a previous test. Give it
some time. */
Wait(1_s);
// The testbench sometimes shakes a little from a previous test. Give it some
// time.
frc::Wait(1_s);
ASSERT_NEAR(0.0, accelerometer.GetX(), kAccelerationTolerance);
ASSERT_NEAR(1.0, accelerometer.GetY(), kAccelerationTolerance);

View File

@@ -13,46 +13,26 @@
#include "frc/motorcontrol/Victor.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kMotorDelay = 2.5_s;
static constexpr auto kMaxPeriod = 2_s;
class CounterTest : public testing::Test {
protected:
Counter* m_talonCounter;
Counter* m_victorCounter;
Counter* m_jaguarCounter;
Talon* m_talon;
Victor* m_victor;
Jaguar* m_jaguar;
void SetUp() override {
m_talonCounter = new Counter(TestBench::kTalonEncoderChannelA);
m_victorCounter = new Counter(TestBench::kVictorEncoderChannelA);
m_jaguarCounter = new Counter(TestBench::kJaguarEncoderChannelA);
m_victor = new Victor(TestBench::kVictorChannel);
m_talon = new Talon(TestBench::kTalonChannel);
m_jaguar = new Jaguar(TestBench::kJaguarChannel);
}
void TearDown() override {
delete m_talonCounter;
delete m_victorCounter;
delete m_jaguarCounter;
delete m_victor;
delete m_talon;
delete m_jaguar;
}
frc::Counter m_talonCounter{TestBench::kTalonEncoderChannelA};
frc::Counter m_victorCounter{TestBench::kVictorEncoderChannelA};
frc::Counter m_jaguarCounter{TestBench::kJaguarEncoderChannelA};
frc::Talon m_talon{TestBench::kVictorChannel};
frc::Victor m_victor{TestBench::kTalonChannel};
frc::Jaguar m_jaguar{TestBench::kJaguarChannel};
void Reset() {
m_talonCounter->Reset();
m_victorCounter->Reset();
m_jaguarCounter->Reset();
m_talon->Set(0.0);
m_victor->Set(0.0);
m_jaguar->Set(0.0);
m_talonCounter.Reset();
m_victorCounter.Reset();
m_jaguarCounter.Reset();
m_talon.Set(0.0);
m_victor.Set(0.0);
m_jaguar.Set(0.0);
}
};
@@ -64,17 +44,17 @@ TEST_F(CounterTest, CountTalon) {
Reset();
/* Run the motor forward and determine if the counter is counting. */
m_talon->Set(1.0);
Wait(0.5_s);
m_talon.Set(1.0);
frc::Wait(0.5_s);
EXPECT_NE(0.0, m_talonCounter->Get()) << "The counter did not count (talon)";
EXPECT_NE(0.0, m_talonCounter.Get()) << "The counter did not count (talon)";
/* Set the motor to 0 and determine if the counter resets to 0. */
m_talon->Set(0.0);
Wait(0.5_s);
m_talonCounter->Reset();
m_talon.Set(0.0);
frc::Wait(0.5_s);
m_talonCounter.Reset();
EXPECT_FLOAT_EQ(0.0, m_talonCounter->Get())
EXPECT_FLOAT_EQ(0.0, m_talonCounter.Get())
<< "The counter did not restart to 0 (talon)";
}
@@ -82,18 +62,17 @@ TEST_F(CounterTest, CountVictor) {
Reset();
/* Run the motor forward and determine if the counter is counting. */
m_victor->Set(1.0);
Wait(0.5_s);
m_victor.Set(1.0);
frc::Wait(0.5_s);
EXPECT_NE(0.0, m_victorCounter->Get())
<< "The counter did not count (victor)";
EXPECT_NE(0.0, m_victorCounter.Get()) << "The counter did not count (victor)";
/* Set the motor to 0 and determine if the counter resets to 0. */
m_victor->Set(0.0);
Wait(0.5_s);
m_victorCounter->Reset();
m_victor.Set(0.0);
frc::Wait(0.5_s);
m_victorCounter.Reset();
EXPECT_FLOAT_EQ(0.0, m_victorCounter->Get())
EXPECT_FLOAT_EQ(0.0, m_victorCounter.Get())
<< "The counter did not restart to 0 (jaguar)";
}
@@ -101,18 +80,17 @@ TEST_F(CounterTest, CountJaguar) {
Reset();
/* Run the motor forward and determine if the counter is counting. */
m_jaguar->Set(1.0);
Wait(0.5_s);
m_jaguar.Set(1.0);
frc::Wait(0.5_s);
EXPECT_NE(0.0, m_jaguarCounter->Get())
<< "The counter did not count (jaguar)";
EXPECT_NE(0.0, m_jaguarCounter.Get()) << "The counter did not count (jaguar)";
/* Set the motor to 0 and determine if the counter resets to 0. */
m_jaguar->Set(0.0);
Wait(0.5_s);
m_jaguarCounter->Reset();
m_jaguar.Set(0.0);
frc::Wait(0.5_s);
m_jaguarCounter.Reset();
EXPECT_FLOAT_EQ(0.0, m_jaguarCounter->Get())
EXPECT_FLOAT_EQ(0.0, m_jaguarCounter.Get())
<< "The counter did not restart to 0 (jaguar)";
}
@@ -124,17 +102,17 @@ TEST_F(CounterTest, TalonGetStopped) {
Reset();
/* Set the Max Period of the counter and run the motor */
m_talonCounter->SetMaxPeriod(kMaxPeriod);
m_talon->Set(1.0);
Wait(0.5_s);
m_talonCounter.SetMaxPeriod(kMaxPeriod);
m_talon.Set(1.0);
frc::Wait(0.5_s);
EXPECT_FALSE(m_talonCounter->GetStopped()) << "The counter did not count.";
EXPECT_FALSE(m_talonCounter.GetStopped()) << "The counter did not count.";
/* Stop the motor and wait until the Max Period is exceeded */
m_talon->Set(0.0);
Wait(kMotorDelay);
m_talon.Set(0.0);
frc::Wait(kMotorDelay);
EXPECT_TRUE(m_talonCounter->GetStopped())
EXPECT_TRUE(m_talonCounter.GetStopped())
<< "The counter did not stop counting.";
}
@@ -142,17 +120,17 @@ TEST_F(CounterTest, VictorGetStopped) {
Reset();
/* Set the Max Period of the counter and run the motor */
m_victorCounter->SetMaxPeriod(kMaxPeriod);
m_victor->Set(1.0);
Wait(0.5_s);
m_victorCounter.SetMaxPeriod(kMaxPeriod);
m_victor.Set(1.0);
frc::Wait(0.5_s);
EXPECT_FALSE(m_victorCounter->GetStopped()) << "The counter did not count.";
EXPECT_FALSE(m_victorCounter.GetStopped()) << "The counter did not count.";
/* Stop the motor and wait until the Max Period is exceeded */
m_victor->Set(0.0);
Wait(kMotorDelay);
m_victor.Set(0.0);
frc::Wait(kMotorDelay);
EXPECT_TRUE(m_victorCounter->GetStopped())
EXPECT_TRUE(m_victorCounter.GetStopped())
<< "The counter did not stop counting.";
}
@@ -160,16 +138,16 @@ TEST_F(CounterTest, JaguarGetStopped) {
Reset();
/* Set the Max Period of the counter and run the motor */
m_jaguarCounter->SetMaxPeriod(kMaxPeriod);
m_jaguar->Set(1.0);
Wait(0.5_s);
m_jaguarCounter.SetMaxPeriod(kMaxPeriod);
m_jaguar.Set(1.0);
frc::Wait(0.5_s);
EXPECT_FALSE(m_jaguarCounter->GetStopped()) << "The counter did not count.";
EXPECT_FALSE(m_jaguarCounter.GetStopped()) << "The counter did not count.";
/* Stop the motor and wait until the Max Period is exceeded */
m_jaguar->Set(0.0);
Wait(kMotorDelay);
m_jaguar.Set(0.0);
frc::Wait(kMotorDelay);
EXPECT_TRUE(m_jaguarCounter->GetStopped())
EXPECT_TRUE(m_jaguarCounter.GetStopped())
<< "The counter did not stop counting.";
}

View File

@@ -18,8 +18,6 @@
#define EXPECT_NEAR_UNITS(val1, val2, eps) \
EXPECT_LE(units::math::abs(val1 - val2), eps)
using namespace frc;
static constexpr auto kCounterTime = 1_ms;
static constexpr auto kDelayTime = 100_ms;
@@ -33,20 +31,10 @@ static constexpr auto kSynchronousInterruptTimeTolerance = 10_ms;
*/
class DIOLoopTest : public testing::Test {
protected:
DigitalInput* m_input;
DigitalOutput* m_output;
frc::DigitalInput m_input{TestBench::kLoop1InputChannel};
frc::DigitalOutput m_output{TestBench::kLoop1OutputChannel};
void SetUp() override {
m_input = new DigitalInput(TestBench::kLoop1InputChannel);
m_output = new DigitalOutput(TestBench::kLoop1OutputChannel);
}
void TearDown() override {
delete m_input;
delete m_output;
}
void Reset() { m_output->Set(false); }
void Reset() { m_output.Set(false); }
};
/**
@@ -56,15 +44,15 @@ class DIOLoopTest : public testing::Test {
TEST_F(DIOLoopTest, Loop) {
Reset();
m_output->Set(false);
Wait(kDelayTime);
EXPECT_FALSE(m_input->Get()) << "The digital output was turned off, but "
<< "the digital input is on.";
m_output.Set(false);
frc::Wait(kDelayTime);
EXPECT_FALSE(m_input.Get()) << "The digital output was turned off, but "
<< "the digital input is on.";
m_output->Set(true);
Wait(kDelayTime);
EXPECT_TRUE(m_input->Get()) << "The digital output was turned on, but "
<< "the digital input is off.";
m_output.Set(true);
frc::Wait(kDelayTime);
EXPECT_TRUE(m_input.Get()) << "The digital output was turned on, but "
<< "the digital input is off.";
}
/**
* Tests to see if the DIO PWM functionality works.
@@ -72,43 +60,43 @@ TEST_F(DIOLoopTest, Loop) {
TEST_F(DIOLoopTest, DIOPWM) {
Reset();
m_output->Set(false);
Wait(kDelayTime);
EXPECT_FALSE(m_input->Get()) << "The digital output was turned off, but "
<< "the digital input is on.";
m_output.Set(false);
frc::Wait(kDelayTime);
EXPECT_FALSE(m_input.Get()) << "The digital output was turned off, but "
<< "the digital input is on.";
// Set frequency to 2.0 Hz
m_output->SetPWMRate(2.0);
m_output.SetPWMRate(2.0);
// Enable PWM, but leave it off
m_output->EnablePWM(0.0);
Wait(0.5_s);
m_output->UpdateDutyCycle(0.5);
m_input->RequestInterrupts();
m_input->SetUpSourceEdge(false, true);
InterruptableSensorBase::WaitResult result =
m_input->WaitForInterrupt(3_s, true);
m_output.EnablePWM(0.0);
frc::Wait(0.5_s);
m_output.UpdateDutyCycle(0.5);
m_input.RequestInterrupts();
m_input.SetUpSourceEdge(false, true);
frc::InterruptableSensorBase::WaitResult result =
m_input.WaitForInterrupt(3_s, true);
Wait(0.5_s);
bool firstCycle = m_input->Get();
Wait(0.5_s);
bool secondCycle = m_input->Get();
Wait(0.5_s);
bool thirdCycle = m_input->Get();
Wait(0.5_s);
bool forthCycle = m_input->Get();
Wait(0.5_s);
bool fifthCycle = m_input->Get();
Wait(0.5_s);
bool sixthCycle = m_input->Get();
Wait(0.5_s);
bool seventhCycle = m_input->Get();
m_output->DisablePWM();
Wait(0.5_s);
bool firstAfterStop = m_input->Get();
Wait(0.5_s);
bool secondAfterStop = m_input->Get();
frc::Wait(0.5_s);
bool firstCycle = m_input.Get();
frc::Wait(0.5_s);
bool secondCycle = m_input.Get();
frc::Wait(0.5_s);
bool thirdCycle = m_input.Get();
frc::Wait(0.5_s);
bool forthCycle = m_input.Get();
frc::Wait(0.5_s);
bool fifthCycle = m_input.Get();
frc::Wait(0.5_s);
bool sixthCycle = m_input.Get();
frc::Wait(0.5_s);
bool seventhCycle = m_input.Get();
m_output.DisablePWM();
frc::Wait(0.5_s);
bool firstAfterStop = m_input.Get();
frc::Wait(0.5_s);
bool secondAfterStop = m_input.Get();
EXPECT_EQ(InterruptableSensorBase::WaitResult::kFallingEdge, result)
EXPECT_EQ(frc::InterruptableSensorBase::WaitResult::kFallingEdge, result)
<< "WaitForInterrupt was not falling.";
EXPECT_FALSE(firstCycle) << "Input not low after first delay";
@@ -129,16 +117,16 @@ TEST_F(DIOLoopTest, DIOPWM) {
TEST_F(DIOLoopTest, FakeCounter) {
Reset();
Counter counter(m_input);
frc::Counter counter{&m_input};
EXPECT_EQ(0, counter.Get()) << "Counter did not initialize to 0.";
/* Count 100 ticks. The counter value should be 100 after this loop. */
for (int32_t i = 0; i < 100; i++) {
m_output->Set(true);
Wait(kCounterTime);
m_output->Set(false);
Wait(kCounterTime);
for (int32_t i = 0; i < 100; ++i) {
m_output.Set(true);
frc::Wait(kCounterTime);
m_output.Set(false);
frc::Wait(kCounterTime);
}
EXPECT_EQ(100, counter.Get()) << "Counter did not count up to 100.";
@@ -152,40 +140,40 @@ TEST_F(DIOLoopTest, AsynchronousInterruptWorks) {
int32_t param = 0;
// Given an interrupt handler that sets an int32_t to 12345
m_input->RequestInterrupts(InterruptHandler, &param);
m_input->EnableInterrupts();
m_input.RequestInterrupts(InterruptHandler, &param);
m_input.EnableInterrupts();
// If the voltage rises
m_output->Set(false);
m_output->Set(true);
m_input->CancelInterrupts();
m_output.Set(false);
m_output.Set(true);
m_input.CancelInterrupts();
// Then the int32_t should be 12345
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_EQ(12345, param) << "The interrupt did not run.";
}
static void* InterruptTriggerer(void* data) {
DigitalOutput* output = static_cast<DigitalOutput*>(data);
output->Set(false);
Wait(kSynchronousInterruptTime);
output->Set(true);
auto& output = *static_cast<frc::DigitalOutput*>(data);
output.Set(false);
frc::Wait(kSynchronousInterruptTime);
output.Set(true);
return nullptr;
}
TEST_F(DIOLoopTest, SynchronousInterruptWorks) {
// Given a synchronous interrupt
m_input->RequestInterrupts();
m_input.RequestInterrupts();
// If we have another thread trigger the interrupt in a few seconds
pthread_t interruptTriggererLoop;
pthread_create(&interruptTriggererLoop, nullptr, InterruptTriggerer,
m_output);
&m_output);
// Then this thread should pause and resume after that number of seconds
Timer timer;
frc::Timer timer;
timer.Start();
m_input->WaitForInterrupt(kSynchronousInterruptTime + 1_s);
m_input.WaitForInterrupt(kSynchronousInterruptTime + 1_s);
EXPECT_NEAR_UNITS(kSynchronousInterruptTime, timer.Get(),
kSynchronousInterruptTimeTolerance);
}

View File

@@ -9,8 +9,6 @@
#include "frc/Encoder.h"
#include "gtest/gtest.h"
using namespace frc;
/**
* Tests that configuring inputs to be filtered succeeds.
*
@@ -19,27 +17,27 @@ using namespace frc;
* make sure that the acutal configuration matches.
*/
TEST(DigitalGlitchFilterTest, BasicTest) {
DigitalInput input1(1);
DigitalInput input2(2);
DigitalInput input3(3);
DigitalInput input4(4);
Encoder encoder5(5, 6);
Counter counter7(7);
frc::DigitalInput input1{1};
frc::DigitalInput input2{2};
frc::DigitalInput input3{3};
frc::DigitalInput input4{4};
frc::Encoder encoder5{5, 6};
frc::Counter counter7{7};
// Check that we can make a single filter and set the period.
DigitalGlitchFilter filter1;
frc::DigitalGlitchFilter filter1;
filter1.Add(&input1);
filter1.SetPeriodNanoSeconds(4200);
// Check that we can make a second filter with 2 inputs.
DigitalGlitchFilter filter2;
frc::DigitalGlitchFilter filter2;
filter2.Add(&input2);
filter2.Add(&input3);
filter2.SetPeriodNanoSeconds(97100);
// Check that we can make a third filter with an input, an encoder, and a
// counter.
DigitalGlitchFilter filter3;
frc::DigitalGlitchFilter filter3;
filter3.Add(&input4);
filter3.Add(&encoder5);
filter3.Add(&counter7);

View File

@@ -14,20 +14,18 @@
#define EXPECT_NEAR_UNITS(val1, val2, eps) \
EXPECT_LE(units::math::abs(val1 - val2), eps)
using namespace frc;
/**
* Test if the WaitForData function works
*/
TEST(DriverStationTest, WaitForData) {
units::microsecond_t initialTime(RobotController::GetFPGATime());
units::microsecond_t initialTime(frc::RobotController::GetFPGATime());
// 20ms waiting intervals * 50 = 1s
for (int i = 0; i < 50; i++) {
DriverStation::GetInstance().WaitForData();
frc::DriverStation::GetInstance().WaitForData();
}
units::microsecond_t finalTime(RobotController::GetFPGATime());
units::microsecond_t finalTime(frc::RobotController::GetFPGATime());
EXPECT_NEAR_UNITS(1_s, finalTime - initialTime, 200_ms);
}

View File

@@ -13,41 +13,24 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kDelayTime = 1_ms;
class FakeEncoderTest : public testing::Test {
protected:
DigitalOutput* m_outputA;
DigitalOutput* m_outputB;
AnalogOutput* m_indexOutput;
frc::DigitalOutput m_outputA{TestBench::kLoop2OutputChannel};
frc::DigitalOutput m_outputB{TestBench::kLoop1OutputChannel};
frc::AnalogOutput m_indexOutput{TestBench::kAnalogOutputChannel};
Encoder* m_encoder;
AnalogTrigger* m_indexAnalogTrigger;
std::shared_ptr<AnalogTriggerOutput> m_indexAnalogTriggerOutput;
frc::Encoder m_encoder{TestBench::kLoop1InputChannel,
TestBench::kLoop2InputChannel};
frc::AnalogTrigger m_indexAnalogTrigger{TestBench::kFakeAnalogOutputChannel};
std::shared_ptr<frc::AnalogTriggerOutput> m_indexAnalogTriggerOutput =
m_indexAnalogTrigger.CreateOutput(frc::AnalogTriggerType::kState);
void SetUp() override {
m_outputA = new DigitalOutput(TestBench::kLoop2OutputChannel);
m_outputB = new DigitalOutput(TestBench::kLoop1OutputChannel);
m_indexOutput = new AnalogOutput(TestBench::kAnalogOutputChannel);
m_outputA->Set(false);
m_outputB->Set(false);
m_encoder = new Encoder(TestBench::kLoop1InputChannel,
TestBench::kLoop2InputChannel);
m_indexAnalogTrigger =
new AnalogTrigger(TestBench::kFakeAnalogOutputChannel);
m_indexAnalogTrigger->SetLimitsVoltage(2.0, 3.0);
m_indexAnalogTriggerOutput =
m_indexAnalogTrigger->CreateOutput(AnalogTriggerType::kState);
}
void TearDown() override {
delete m_outputA;
delete m_outputB;
delete m_indexOutput;
delete m_encoder;
delete m_indexAnalogTrigger;
FakeEncoderTest() {
m_outputA.Set(false);
m_outputB.Set(false);
m_indexAnalogTrigger.SetLimitsVoltage(2.0, 3.0);
}
/**
@@ -56,25 +39,25 @@ class FakeEncoderTest : public testing::Test {
*/
void Simulate100QuadratureTicks() {
for (int32_t i = 0; i < 100; i++) {
m_outputA->Set(true);
Wait(kDelayTime);
m_outputB->Set(true);
Wait(kDelayTime);
m_outputA->Set(false);
Wait(kDelayTime);
m_outputB->Set(false);
Wait(kDelayTime);
m_outputA.Set(true);
frc::Wait(kDelayTime);
m_outputB.Set(true);
frc::Wait(kDelayTime);
m_outputA.Set(false);
frc::Wait(kDelayTime);
m_outputB.Set(false);
frc::Wait(kDelayTime);
}
}
void SetIndexHigh() {
m_indexOutput->SetVoltage(5.0);
Wait(kDelayTime);
m_indexOutput.SetVoltage(5.0);
frc::Wait(kDelayTime);
}
void SetIndexLow() {
m_indexOutput->SetVoltage(0.0);
Wait(kDelayTime);
m_indexOutput.SetVoltage(0.0);
frc::Wait(kDelayTime);
}
};
@@ -82,79 +65,79 @@ class FakeEncoderTest : public testing::Test {
* Test the encoder by reseting it to 0 and reading the value.
*/
TEST_F(FakeEncoderTest, TestDefaultState) {
EXPECT_FLOAT_EQ(0.0, m_encoder->Get()) << "The encoder did not start at 0.";
EXPECT_DOUBLE_EQ(0.0, m_encoder.Get()) << "The encoder did not start at 0.";
}
/**
* Test the encoder by setting the digital outputs and reading the value.
*/
TEST_F(FakeEncoderTest, TestCountUp) {
m_encoder->Reset();
m_encoder.Reset();
Simulate100QuadratureTicks();
EXPECT_FLOAT_EQ(100.0, m_encoder->Get()) << "Encoder did not count to 100.";
EXPECT_DOUBLE_EQ(100.0, m_encoder.Get()) << "Encoder did not count to 100.";
}
/**
* Test that the encoder can stay reset while the index source is high
*/
TEST_F(FakeEncoderTest, TestResetWhileHigh) {
m_encoder->SetIndexSource(*m_indexAnalogTriggerOutput,
Encoder::IndexingType::kResetWhileHigh);
m_encoder.SetIndexSource(*m_indexAnalogTriggerOutput,
frc::Encoder::IndexingType::kResetWhileHigh);
SetIndexLow();
Simulate100QuadratureTicks();
SetIndexHigh();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
Simulate100QuadratureTicks();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
}
/**
* Test that the encoder can reset when the index source goes from low to high
*/
TEST_F(FakeEncoderTest, TestResetOnRisingEdge) {
m_encoder->SetIndexSource(*m_indexAnalogTriggerOutput,
Encoder::IndexingType::kResetOnRisingEdge);
m_encoder.SetIndexSource(*m_indexAnalogTriggerOutput,
frc::Encoder::IndexingType::kResetOnRisingEdge);
SetIndexLow();
Simulate100QuadratureTicks();
SetIndexHigh();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
Simulate100QuadratureTicks();
EXPECT_EQ(100, m_encoder->Get());
EXPECT_EQ(100, m_encoder.Get());
}
/**
* Test that the encoder can stay reset while the index source is low
*/
TEST_F(FakeEncoderTest, TestResetWhileLow) {
m_encoder->SetIndexSource(*m_indexAnalogTriggerOutput,
Encoder::IndexingType::kResetWhileLow);
m_encoder.SetIndexSource(*m_indexAnalogTriggerOutput,
frc::Encoder::IndexingType::kResetWhileLow);
SetIndexHigh();
Simulate100QuadratureTicks();
SetIndexLow();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
Simulate100QuadratureTicks();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
}
/**
* Test that the encoder can reset when the index source goes from high to low
*/
TEST_F(FakeEncoderTest, TestResetOnFallingEdge) {
m_encoder->SetIndexSource(*m_indexAnalogTriggerOutput,
Encoder::IndexingType::kResetOnFallingEdge);
m_encoder.SetIndexSource(*m_indexAnalogTriggerOutput,
frc::Encoder::IndexingType::kResetOnFallingEdge);
SetIndexHigh();
Simulate100QuadratureTicks();
SetIndexLow();
EXPECT_EQ(0, m_encoder->Get());
EXPECT_EQ(0, m_encoder.Get());
Simulate100QuadratureTicks();
EXPECT_EQ(100, m_encoder->Get());
EXPECT_EQ(100, m_encoder.Get());
}

View File

@@ -5,7 +5,6 @@
#include "gtest/gtest.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -17,8 +17,6 @@
#include "frc/motorcontrol/Victor.h"
#include "gtest/gtest.h"
using namespace frc;
enum MotorEncoderTestType { TEST_VICTOR, TEST_JAGUAR, TEST_TALON };
std::ostream& operator<<(std::ostream& os, MotorEncoderTestType const& type) {
@@ -45,38 +43,38 @@ static constexpr auto kMotorTime = 0.5_s;
*/
class MotorEncoderTest : public testing::TestWithParam<MotorEncoderTestType> {
protected:
MotorController* m_motorController;
Encoder* m_encoder;
LinearFilter<double>* m_filter;
frc::MotorController* m_motorController;
frc::Encoder* m_encoder;
frc::LinearFilter<double>* m_filter;
void SetUp() override {
MotorEncoderTest() {
switch (GetParam()) {
case TEST_VICTOR:
m_motorController = new Victor(TestBench::kVictorChannel);
m_encoder = new Encoder(TestBench::kVictorEncoderChannelA,
TestBench::kVictorEncoderChannelB);
m_motorController = new frc::Victor(TestBench::kVictorChannel);
m_encoder = new frc::Encoder(TestBench::kVictorEncoderChannelA,
TestBench::kVictorEncoderChannelB);
break;
case TEST_JAGUAR:
m_motorController = new Jaguar(TestBench::kJaguarChannel);
m_encoder = new Encoder(TestBench::kJaguarEncoderChannelA,
TestBench::kJaguarEncoderChannelB);
m_motorController = new frc::Jaguar(TestBench::kJaguarChannel);
m_encoder = new frc::Encoder(TestBench::kJaguarEncoderChannelA,
TestBench::kJaguarEncoderChannelB);
break;
case TEST_TALON:
m_motorController = new Talon(TestBench::kTalonChannel);
m_encoder = new Encoder(TestBench::kTalonEncoderChannelA,
TestBench::kTalonEncoderChannelB);
m_motorController = new frc::Talon(TestBench::kTalonChannel);
m_encoder = new frc::Encoder(TestBench::kTalonEncoderChannelA,
TestBench::kTalonEncoderChannelB);
break;
}
m_filter =
new LinearFilter<double>(LinearFilter<double>::MovingAverage(50));
m_filter = new frc::LinearFilter<double>(
frc::LinearFilter<double>::MovingAverage(50));
}
void TearDown() override {
delete m_motorController;
delete m_encoder;
~MotorEncoderTest() {
delete m_filter;
delete m_encoder;
delete m_motorController;
}
void Reset() {
@@ -94,7 +92,7 @@ TEST_P(MotorEncoderTest, Increment) {
/* Drive the motor controller briefly to move the encoder */
m_motorController->Set(0.2f);
Wait(kMotorTime);
frc::Wait(kMotorTime);
m_motorController->Set(0.0);
/* The encoder should be positive now */
@@ -110,7 +108,7 @@ TEST_P(MotorEncoderTest, Decrement) {
/* Drive the motor controller briefly to move the encoder */
m_motorController->Set(-0.2);
Wait(kMotorTime);
frc::Wait(kMotorTime);
m_motorController->Set(0.0);
/* The encoder should be positive now */
@@ -125,12 +123,12 @@ TEST_P(MotorEncoderTest, ClampSpeed) {
Reset();
m_motorController->Set(2.0);
Wait(kMotorTime);
frc::Wait(kMotorTime);
EXPECT_FLOAT_EQ(1.0, m_motorController->Get());
m_motorController->Set(-2.0);
Wait(kMotorTime);
frc::Wait(kMotorTime);
EXPECT_FLOAT_EQ(-1.0, m_motorController->Get());
}
@@ -152,7 +150,7 @@ TEST_P(MotorEncoderTest, PositionPIDController) {
m_motorController->Set(std::clamp(speed, -0.2, 0.2));
}};
pidRunner.StartPeriodic(pidController.GetPeriod());
Wait(10_s);
frc::Wait(10_s);
pidRunner.Stop();
RecordProperty("PIDError", pidController.GetPositionError());
@@ -179,7 +177,7 @@ TEST_P(MotorEncoderTest, VelocityPIDController) {
m_motorController->Set(std::clamp(speed, -0.3, 0.3));
}};
pidRunner.StartPeriodic(pidController.GetPeriod());
Wait(10_s);
frc::Wait(10_s);
pidRunner.Stop();
RecordProperty("PIDError", pidController.GetPositionError());

View File

@@ -12,8 +12,6 @@
#include "frc/motorcontrol/Victor.h"
#include "gtest/gtest.h"
using namespace frc;
enum MotorInvertingTestType { TEST_VICTOR, TEST_JAGUAR, TEST_TALON };
static constexpr double kMotorSpeed = 0.15;
@@ -37,34 +35,34 @@ std::ostream& operator<<(std::ostream& os, MotorInvertingTestType const& type) {
class MotorInvertingTest
: public testing::TestWithParam<MotorInvertingTestType> {
protected:
MotorController* m_motorController;
Encoder* m_encoder;
frc::MotorController* m_motorController;
frc::Encoder* m_encoder;
void SetUp() override {
MotorInvertingTest() {
switch (GetParam()) {
case TEST_VICTOR:
m_motorController = new Victor(TestBench::kVictorChannel);
m_encoder = new Encoder(TestBench::kVictorEncoderChannelA,
TestBench::kVictorEncoderChannelB);
m_motorController = new frc::Victor(TestBench::kVictorChannel);
m_encoder = new frc::Encoder(TestBench::kVictorEncoderChannelA,
TestBench::kVictorEncoderChannelB);
break;
case TEST_JAGUAR:
m_motorController = new Jaguar(TestBench::kJaguarChannel);
m_encoder = new Encoder(TestBench::kJaguarEncoderChannelA,
TestBench::kJaguarEncoderChannelB);
m_motorController = new frc::Jaguar(TestBench::kJaguarChannel);
m_encoder = new frc::Encoder(TestBench::kJaguarEncoderChannelA,
TestBench::kJaguarEncoderChannelB);
break;
case TEST_TALON:
m_motorController = new Talon(TestBench::kTalonChannel);
m_encoder = new Encoder(TestBench::kTalonEncoderChannelA,
TestBench::kTalonEncoderChannelB);
m_motorController = new frc::Talon(TestBench::kTalonChannel);
m_encoder = new frc::Encoder(TestBench::kTalonEncoderChannelA,
TestBench::kTalonEncoderChannelB);
break;
}
}
void TearDown() override {
delete m_motorController;
~MotorInvertingTest() {
delete m_encoder;
delete m_motorController;
}
void Reset() {
@@ -79,13 +77,13 @@ TEST_P(MotorInvertingTest, InvertingPositive) {
m_motorController->Set(kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
bool initDirection = m_encoder->GetDirection();
m_motorController->SetInverted(true);
m_motorController->Set(kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_TRUE(m_encoder->GetDirection() != initDirection)
<< "Inverting with Positive value does not change direction";
@@ -99,13 +97,13 @@ TEST_P(MotorInvertingTest, InvertingNegative) {
m_motorController->SetInverted(false);
m_motorController->Set(-kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
bool initDirection = m_encoder->GetDirection();
m_motorController->SetInverted(true);
m_motorController->Set(-kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_TRUE(m_encoder->GetDirection() != initDirection)
<< "Inverting with Negative value does not change direction";
@@ -119,13 +117,13 @@ TEST_P(MotorInvertingTest, InvertingSwitchingPosToNeg) {
m_motorController->SetInverted(false);
m_motorController->Set(kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
bool initDirection = m_encoder->GetDirection();
m_motorController->SetInverted(true);
m_motorController->Set(-kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_TRUE(m_encoder->GetDirection() == initDirection)
<< "Inverting with Switching value does change direction";
@@ -139,13 +137,13 @@ TEST_P(MotorInvertingTest, InvertingSwitchingNegToPos) {
m_motorController->SetInverted(false);
m_motorController->Set(-kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
bool initDirection = m_encoder->GetDirection();
m_motorController->SetInverted(true);
m_motorController->Set(kMotorSpeed);
Wait(kDelayTime);
frc::Wait(kDelayTime);
EXPECT_TRUE(m_encoder->GetDirection() == initDirection)
<< "Inverting with Switching value does change direction";

View File

@@ -4,14 +4,12 @@
#include "frc/Notifier.h" // NOLINT(build/include_order)
#include <wpi/raw_ostream.h>
#include <fmt/core.h>
#include "TestBench.h"
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
unsigned notifierCounter;
void notifierHandler(void*) {
@@ -22,21 +20,20 @@ void notifierHandler(void*) {
* Test if the Wait function works
*/
TEST(NotifierTest, DISABLED_TestTimerNotifications) {
wpi::outs() << "NotifierTest...\n";
fmt::print("NotifierTest...\n");
notifierCounter = 0;
wpi::outs() << "notifier(notifierHandler, nullptr)...\n";
Notifier notifier(notifierHandler, nullptr);
wpi::outs() << "Start Periodic...\n";
fmt::print("notifier(notifierHandler, nullptr)...\n");
frc::Notifier notifier(notifierHandler, nullptr);
fmt::print("Start Periodic...\n");
notifier.StartPeriodic(1_s);
wpi::outs() << "Wait...\n";
Wait(10.5_s);
wpi::outs() << "...Wait\n";
fmt::print("Wait...\n");
frc::Wait(10.5_s);
fmt::print("...Wait\n");
EXPECT_EQ(10u, notifierCounter)
<< "Received " << notifierCounter << " notifications in 10.5 seconds";
wpi::outs() << "Received " << notifierCounter
<< " notifications in 10.5 seconds";
fmt::print("Received {} notifications in 10.5 seconds", notifierCounter);
wpi::outs() << "...NotifierTest\n";
fmt::print("...NotifierTest\n");
}

View File

@@ -12,8 +12,6 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
/* The PCM switches the compressor up to a couple seconds after the pressure
switch changes. */
static constexpr auto kCompressorDelayTime = 3_s;
@@ -28,34 +26,17 @@ static const double kCompressorOffVoltage = 1.68;
class PCMTest : public testing::Test {
protected:
Compressor* m_compressor;
frc::Compressor m_compressor;
DigitalOutput* m_fakePressureSwitch;
AnalogInput* m_fakeCompressor;
DoubleSolenoid* m_doubleSolenoid;
DigitalInput *m_fakeSolenoid1, *m_fakeSolenoid2;
void SetUp() override {
m_compressor = new Compressor();
m_fakePressureSwitch =
new DigitalOutput(TestBench::kFakePressureSwitchChannel);
m_fakeCompressor = new AnalogInput(TestBench::kFakeCompressorChannel);
m_fakeSolenoid1 = new DigitalInput(TestBench::kFakeSolenoid1Channel);
m_fakeSolenoid2 = new DigitalInput(TestBench::kFakeSolenoid2Channel);
}
void TearDown() override {
delete m_compressor;
delete m_fakePressureSwitch;
delete m_fakeCompressor;
delete m_fakeSolenoid1;
delete m_fakeSolenoid2;
}
frc::DigitalOutput m_fakePressureSwitch{
TestBench::kFakePressureSwitchChannel};
frc::AnalogInput m_fakeCompressor{TestBench::kFakeCompressorChannel};
frc::DigitalInput m_fakeSolenoid1{TestBench::kFakeSolenoid1Channel};
frc::DigitalInput m_fakeSolenoid2{TestBench::kFakeSolenoid2Channel};
void Reset() {
m_compressor->Stop();
m_fakePressureSwitch->Set(false);
m_compressor.Stop();
m_fakePressureSwitch.Set(false);
}
};
@@ -65,18 +46,18 @@ class PCMTest : public testing::Test {
TEST_F(PCMTest, PressureSwitch) {
Reset();
m_compressor->SetClosedLoopControl(true);
m_compressor.SetClosedLoopControl(true);
// Turn on the compressor
m_fakePressureSwitch->Set(true);
Wait(kCompressorDelayTime);
EXPECT_NEAR(kCompressorOnVoltage, m_fakeCompressor->GetVoltage(), 0.5)
m_fakePressureSwitch.Set(true);
frc::Wait(kCompressorDelayTime);
EXPECT_NEAR(kCompressorOnVoltage, m_fakeCompressor.GetVoltage(), 0.5)
<< "Compressor did not turn on when the pressure switch turned on.";
// Turn off the compressor
m_fakePressureSwitch->Set(false);
Wait(kCompressorDelayTime);
EXPECT_NEAR(kCompressorOffVoltage, m_fakeCompressor->GetVoltage(), 0.5)
m_fakePressureSwitch.Set(false);
frc::Wait(kCompressorDelayTime);
EXPECT_NEAR(kCompressorOffVoltage, m_fakeCompressor.GetVoltage(), 0.5)
<< "Compressor did not turn off when the pressure switch turned off.";
}
@@ -85,42 +66,42 @@ TEST_F(PCMTest, PressureSwitch) {
*/
TEST_F(PCMTest, Solenoid) {
Reset();
Solenoid solenoid1(TestBench::kSolenoidChannel1);
Solenoid solenoid2(TestBench::kSolenoidChannel2);
frc::Solenoid solenoid1{TestBench::kSolenoidChannel1};
frc::Solenoid solenoid2{TestBench::kSolenoidChannel2};
// Turn both solenoids off
solenoid1.Set(false);
solenoid2.Set(false);
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
// Turn one solenoid on and one off
solenoid1.Set(true);
solenoid2.Set(false);
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
// Turn one solenoid on and one off
solenoid1.Set(false);
solenoid2.Set(true);
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
// Turn both on
solenoid1.Set(true);
solenoid2.Set(true);
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
}
@@ -130,42 +111,42 @@ TEST_F(PCMTest, Solenoid) {
* with the DoubleSolenoid class.
*/
TEST_F(PCMTest, DoubleSolenoid) {
DoubleSolenoid solenoid(TestBench::kSolenoidChannel1,
TestBench::kSolenoidChannel2);
frc::DoubleSolenoid solenoid{TestBench::kSolenoidChannel1,
TestBench::kSolenoidChannel2};
solenoid.Set(DoubleSolenoid::kOff);
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid.Get() == DoubleSolenoid::kOff)
solenoid.Set(frc::DoubleSolenoid::kOff);
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid.Get() == frc::DoubleSolenoid::kOff)
<< "Solenoid does not read off";
solenoid.Set(DoubleSolenoid::kForward);
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid.Get() == DoubleSolenoid::kForward)
solenoid.Set(frc::DoubleSolenoid::kForward);
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid.Get() == frc::DoubleSolenoid::kForward)
<< "Solenoid does not read forward";
solenoid.Set(DoubleSolenoid::kReverse);
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
EXPECT_TRUE(solenoid.Get() == DoubleSolenoid::kReverse)
solenoid.Set(frc::DoubleSolenoid::kReverse);
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_TRUE(solenoid.Get() == frc::DoubleSolenoid::kReverse)
<< "Solenoid does not read reverse";
}
TEST_F(PCMTest, OneShot) {
Reset();
Solenoid solenoid1(TestBench::kSolenoidChannel1);
Solenoid solenoid2(TestBench::kSolenoidChannel2);
frc::Solenoid solenoid1{TestBench::kSolenoidChannel1};
frc::Solenoid solenoid2{TestBench::kSolenoidChannel2};
// Turn both solenoids off
solenoid1.Set(false);
solenoid2.Set(false);
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
@@ -173,14 +154,14 @@ TEST_F(PCMTest, OneShot) {
solenoid1.SetPulseDuration(2 * kSolenoidDelayTime);
solenoid2.Set(false);
solenoid1.StartPulse();
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
@@ -188,14 +169,14 @@ TEST_F(PCMTest, OneShot) {
solenoid1.Set(false);
solenoid2.SetPulseDuration(2 * kSolenoidDelayTime);
solenoid2.StartPulse();
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
@@ -204,14 +185,14 @@ TEST_F(PCMTest, OneShot) {
solenoid2.SetPulseDuration(2 * kSolenoidDelayTime);
solenoid1.StartPulse();
solenoid2.StartPulse();
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
@@ -220,19 +201,19 @@ TEST_F(PCMTest, OneShot) {
solenoid2.SetPulseDuration(2.5 * kSolenoidDelayTime);
solenoid1.StartPulse();
solenoid2.StartPulse();
Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_FALSE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn on";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_TRUE(solenoid1.Get()) << "Solenoid #1 did not read on";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn on";
frc::Wait(kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_FALSE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn on";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_TRUE(solenoid2.Get()) << "Solenoid #2 did not read on";
Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1->Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2->Get()) << "Solenoid #2 did not turn off";
frc::Wait(2 * kSolenoidDelayTime);
EXPECT_TRUE(m_fakeSolenoid1.Get()) << "Solenoid #1 did not turn off";
EXPECT_TRUE(m_fakeSolenoid2.Get()) << "Solenoid #2 did not turn off";
EXPECT_FALSE(solenoid1.Get()) << "Solenoid #1 did not read off";
EXPECT_FALSE(solenoid2.Get()) << "Solenoid #2 did not read off";
}

View File

@@ -9,35 +9,15 @@
#include "TestBench.h"
#include "frc/Timer.h"
#include "frc/motorcontrol/Jaguar.h"
#include "frc/motorcontrol/Talon.h"
#include "frc/motorcontrol/Victor.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kMotorTime = 0.25_s;
class PowerDistributionPanelTest : public testing::Test {
protected:
PowerDistributionPanel* m_pdp;
Talon* m_talon;
Victor* m_victor;
Jaguar* m_jaguar;
void SetUp() override {
m_pdp = new PowerDistributionPanel();
m_talon = new Talon(TestBench::kTalonChannel);
m_victor = new Victor(TestBench::kVictorChannel);
m_jaguar = new Jaguar(TestBench::kJaguarChannel);
}
void TearDown() override {
delete m_pdp;
delete m_talon;
delete m_victor;
delete m_jaguar;
}
frc::PowerDistributionPanel m_pdp;
frc::Talon m_talon{TestBench::kTalonChannel};
};
TEST_F(PowerDistributionPanelTest, CheckRepeatedCalls) {
@@ -45,28 +25,28 @@ TEST_F(PowerDistributionPanelTest, CheckRepeatedCalls) {
// 1 second
for (int i = 0; i < 50; i++) {
for (int j = 0; j < numChannels; j++) {
m_pdp->GetCurrent(j);
m_pdp.GetCurrent(j);
}
m_pdp->GetVoltage();
m_pdp.GetVoltage();
}
Wait(20_ms);
frc::Wait(20_ms);
}
/**
* Test if the current changes when the motor is driven using a talon
*/
TEST_F(PowerDistributionPanelTest, CheckCurrentTalon) {
Wait(kMotorTime);
frc::Wait(kMotorTime);
/* The Current should be 0 */
EXPECT_FLOAT_EQ(0, m_pdp->GetCurrent(TestBench::kTalonPDPChannel))
EXPECT_FLOAT_EQ(0, m_pdp.GetCurrent(TestBench::kTalonPDPChannel))
<< "The Talon current was non-zero";
/* Set the motor to full forward */
m_talon->Set(1.0);
Wait(kMotorTime);
m_talon.Set(1.0);
frc::Wait(kMotorTime);
/* The current should now be positive */
ASSERT_GT(m_pdp->GetCurrent(TestBench::kTalonPDPChannel), 0)
ASSERT_GT(m_pdp.GetCurrent(TestBench::kTalonPDPChannel), 0)
<< "The Talon current was not positive";
}

View File

@@ -14,8 +14,6 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static const char* kFileName = "networktables.ini";
static constexpr auto kSaveTime = 1.2_s;
@@ -26,6 +24,7 @@ static constexpr auto kSaveTime = 1.2_s;
TEST(PreferencesTest, ReadPreferencesFromFile) {
auto inst = nt::NetworkTableInstance::GetDefault();
inst.StopServer();
std::remove(kFileName);
std::ofstream preferencesFile(kFileName);
preferencesFile << "[NetworkTables Storage 3.0]" << std::endl;
@@ -43,16 +42,17 @@ TEST(PreferencesTest, ReadPreferencesFromFile) {
<< "double \"/Preferences/testFileGetLong\"=1000000000000000000"
<< std::endl;
preferencesFile.close();
inst.StartServer();
Preferences* preferences = Preferences::GetInstance();
auto& preferences = *frc::Preferences::GetInstance();
EXPECT_EQ("Hello, preferences file",
preferences->GetString("testFileGetString"));
EXPECT_EQ(1, preferences->GetInt("testFileGetInt"));
EXPECT_FLOAT_EQ(0.5, preferences->GetDouble("testFileGetDouble"));
EXPECT_FLOAT_EQ(0.25f, preferences->GetFloat("testFileGetFloat"));
EXPECT_TRUE(preferences->GetBoolean("testFileGetBoolean"));
EXPECT_EQ(1000000000000000000ll, preferences->GetLong("testFileGetLong"));
preferences.GetString("testFileGetString"));
EXPECT_EQ(1, preferences.GetInt("testFileGetInt"));
EXPECT_FLOAT_EQ(0.5, preferences.GetDouble("testFileGetDouble"));
EXPECT_FLOAT_EQ(0.25f, preferences.GetFloat("testFileGetFloat"));
EXPECT_TRUE(preferences.GetBoolean("testFileGetBoolean"));
EXPECT_EQ(1000000000000000000ll, preferences.GetLong("testFileGetLong"));
}
/**
@@ -62,24 +62,24 @@ TEST(PreferencesTest, ReadPreferencesFromFile) {
TEST(PreferencesTest, WritePreferencesToFile) {
auto inst = nt::NetworkTableInstance::GetDefault();
inst.StartServer();
Preferences* preferences = Preferences::GetInstance();
preferences->Remove("testFileGetString");
preferences->Remove("testFileGetInt");
preferences->Remove("testFileGetDouble");
preferences->Remove("testFileGetFloat");
preferences->Remove("testFileGetBoolean");
preferences->Remove("testFileGetLong");
auto& preferences = *frc::Preferences::GetInstance();
preferences.Remove("testFileGetString");
preferences.Remove("testFileGetInt");
preferences.Remove("testFileGetDouble");
preferences.Remove("testFileGetFloat");
preferences.Remove("testFileGetBoolean");
preferences.Remove("testFileGetLong");
Wait(kSaveTime);
frc::Wait(kSaveTime);
preferences->SetString("testFileSetString", "Hello, preferences file");
preferences->SetInt("testFileSetInt", 1);
preferences->SetDouble("testFileSetDouble", 0.5);
preferences->SetFloat("testFileSetFloat", 0.25f);
preferences->SetBoolean("testFileSetBoolean", true);
preferences->SetLong("testFileSetLong", 1000000000000000000ll);
preferences.SetString("testFileSetString", "Hello, preferences file");
preferences.SetInt("testFileSetInt", 1);
preferences.SetDouble("testFileSetDouble", 0.5);
preferences.SetFloat("testFileSetFloat", 0.25f);
preferences.SetBoolean("testFileSetBoolean", true);
preferences.SetLong("testFileSetLong", 1000000000000000000ll);
Wait(kSaveTime);
frc::Wait(kSaveTime);
static char const* kExpectedFileContents[] = {
"[NetworkTables Storage 3.0]",

View File

@@ -11,82 +11,62 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kDelayTime = 10_ms;
class RelayTest : public testing::Test {
protected:
Relay* m_relay;
DigitalInput* m_forward;
DigitalInput* m_reverse;
TEST(RelayTest, BothDirections) {
frc::Relay relay{TestBench::kRelayChannel};
frc::DigitalInput forward{TestBench::kFakeRelayForward};
frc::DigitalInput reverse{TestBench::kFakeRelayReverse};
void SetUp() override {
m_relay = new Relay(TestBench::kRelayChannel);
m_forward = new DigitalInput(TestBench::kFakeRelayForward);
m_reverse = new DigitalInput(TestBench::kFakeRelayReverse);
}
// Set the relay to forward
relay.Set(frc::Relay::kForward);
frc::Wait(kDelayTime);
EXPECT_TRUE(forward.Get()) << "Relay did not set forward";
EXPECT_FALSE(reverse.Get()) << "Relay did not set forward";
EXPECT_EQ(relay.Get(), frc::Relay::kForward);
void TearDown() override {
delete m_relay;
delete m_forward;
delete m_reverse;
}
// Set the relay to reverse
relay.Set(frc::Relay::kReverse);
frc::Wait(kDelayTime);
EXPECT_TRUE(reverse.Get()) << "Relay did not set reverse";
EXPECT_FALSE(forward.Get()) << "Relay did not set reverse";
EXPECT_EQ(relay.Get(), frc::Relay::kReverse);
void Reset() { m_relay->Set(Relay::kOff); }
};
// Set the relay to off
relay.Set(frc::Relay::kOff);
frc::Wait(kDelayTime);
EXPECT_FALSE(forward.Get()) << "Relay did not set off";
EXPECT_FALSE(reverse.Get()) << "Relay did not set off";
EXPECT_EQ(relay.Get(), frc::Relay::kOff);
/**
* Test the relay by setting it forward, reverse, off, and on.
*/
TEST_F(RelayTest, Relay) {
Reset();
// set the relay to forward
m_relay->Set(Relay::kForward);
Wait(kDelayTime);
EXPECT_TRUE(m_forward->Get()) << "Relay did not set forward";
EXPECT_FALSE(m_reverse->Get()) << "Relay did not set forward";
EXPECT_EQ(m_relay->Get(), Relay::kForward);
// set the relay to reverse
m_relay->Set(Relay::kReverse);
Wait(kDelayTime);
EXPECT_TRUE(m_reverse->Get()) << "Relay did not set reverse";
EXPECT_FALSE(m_forward->Get()) << "Relay did not set reverse";
EXPECT_EQ(m_relay->Get(), Relay::kReverse);
// set the relay to off
m_relay->Set(Relay::kOff);
Wait(kDelayTime);
EXPECT_FALSE(m_forward->Get()) << "Relay did not set off";
EXPECT_FALSE(m_reverse->Get()) << "Relay did not set off";
EXPECT_EQ(m_relay->Get(), Relay::kOff);
// set the relay to on
m_relay->Set(Relay::kOn);
Wait(kDelayTime);
EXPECT_TRUE(m_forward->Get()) << "Relay did not set on";
EXPECT_TRUE(m_reverse->Get()) << "Relay did not set on";
EXPECT_EQ(m_relay->Get(), Relay::kOn);
// test forward direction
delete m_relay;
m_relay = new Relay(TestBench::kRelayChannel, Relay::kForwardOnly);
m_relay->Set(Relay::kOn);
Wait(kDelayTime);
EXPECT_TRUE(m_forward->Get()) << "Relay did not set forward";
EXPECT_FALSE(m_reverse->Get()) << "Relay did not set forward";
EXPECT_EQ(m_relay->Get(), Relay::kOn);
// test reverse direction
delete m_relay;
m_relay = new Relay(TestBench::kRelayChannel, Relay::kReverseOnly);
m_relay->Set(Relay::kOn);
Wait(kDelayTime);
EXPECT_FALSE(m_forward->Get()) << "Relay did not set reverse";
EXPECT_TRUE(m_reverse->Get()) << "Relay did not set reverse";
EXPECT_EQ(m_relay->Get(), Relay::kOn);
// Set the relay to on
relay.Set(frc::Relay::kOn);
frc::Wait(kDelayTime);
EXPECT_TRUE(forward.Get()) << "Relay did not set on";
EXPECT_TRUE(reverse.Get()) << "Relay did not set on";
EXPECT_EQ(relay.Get(), frc::Relay::kOn);
}
TEST(RelayTest, ForwardOnly) {
frc::Relay relay{TestBench::kRelayChannel, frc::Relay::kForwardOnly};
frc::DigitalInput forward{TestBench::kFakeRelayForward};
frc::DigitalInput reverse{TestBench::kFakeRelayReverse};
relay.Set(frc::Relay::kOn);
frc::Wait(kDelayTime);
EXPECT_TRUE(forward.Get()) << "Relay did not set forward";
EXPECT_FALSE(reverse.Get()) << "Relay did not set forward";
EXPECT_EQ(relay.Get(), frc::Relay::kOn);
}
TEST(RelayTest, ReverseOnly) {
frc::Relay relay{TestBench::kRelayChannel, frc::Relay::kReverseOnly};
frc::DigitalInput forward{TestBench::kFakeRelayForward};
frc::DigitalInput reverse{TestBench::kFakeRelayReverse};
relay.Set(frc::Relay::kOn);
frc::Wait(kDelayTime);
EXPECT_FALSE(forward.Get()) << "Relay did not set reverse";
EXPECT_TRUE(reverse.Get()) << "Relay did not set reverse";
EXPECT_EQ(relay.Get(), frc::Relay::kOn);
}

View File

@@ -3,63 +3,63 @@
// the WPILib BSD license file in the root directory of this project.
#include <cstdlib>
#include <thread>
#include <fmt/core.h>
#include <hal/HAL.h>
#include <wpi/raw_ostream.h>
#include "frc/DriverStation.h"
#include "frc/Timer.h"
#include "frc/livewindow/LiveWindow.h"
#include "gtest/gtest.h"
#include "mockds/MockDS.h"
using namespace frc;
using namespace std::chrono_literals;
class TestEnvironment : public testing::Environment {
bool m_alreadySetUp = false;
MockDS m_mockDS;
public:
void SetUp() override {
/* Only set up once. This allows gtest_repeat to be used to
automatically repeat tests. */
TestEnvironment() {
// Only set up once. This allows gtest_repeat to be used to automatically
// repeat tests.
if (m_alreadySetUp) {
return;
}
m_alreadySetUp = true;
if (!HAL_Initialize(500, 0)) {
wpi::errs() << "FATAL ERROR: HAL could not be initialized\n";
fmt::print(stderr, "FATAL ERROR: HAL could not be initialized\n");
std::exit(-1);
}
m_mockDS.start();
m_mockDS.Start();
/* 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. */
// 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.
HAL_ObserveUserProgramStarting();
LiveWindow::GetInstance()->SetEnabled(false);
frc::LiveWindow::GetInstance()->SetEnabled(false);
wpi::outs() << "Started coms\n";
fmt::print("Started coms\n");
int enableCounter = 0;
while (!DriverStation::GetInstance().IsEnabled()) {
while (!frc::DriverStation::GetInstance().IsEnabled()) {
if (enableCounter > 50) {
// Robot did not enable properly after 5 seconds.
// Force exit
wpi::errs() << " Failed to enable. Aborting\n";
fmt::print(stderr, " Failed to enable. Aborting\n");
std::terminate();
}
Wait(0.1_s);
std::this_thread::sleep_for(100ms);
wpi::outs() << "Waiting for enable: " << enableCounter++ << "\n";
fmt::print("Waiting for enable: {}\n", enableCounter++);
}
}
void TearDown() override { m_mockDS.stop(); }
~TestEnvironment() { m_mockDS.Stop(); }
};
testing::Environment* const environment =

View File

@@ -13,137 +13,79 @@
#include "frc/Timer.h"
#include "gtest/gtest.h"
using namespace frc;
static constexpr auto kServoResetTime = 2_s;
static constexpr double kTestAngle = 90.0;
static constexpr double kTiltSetpoint0 = 0.22;
static constexpr double kTiltSetpoint45 = 0.45;
static constexpr double kTiltSetpoint90 = 0.68;
static constexpr auto kTiltTime = 1_s;
static constexpr double kAccelerometerTolerance = 0.2;
static constexpr double kSensitivity = 0.013;
/**
* A fixture for the camera with two servos and a gyro
*/
class TiltPanCameraTest : public testing::Test {
protected:
static AnalogGyro* m_gyro;
Servo *m_tilt, *m_pan;
Accelerometer* m_spiAccel;
frc::Servo m_tilt{TestBench::kCameraTiltChannel};
frc::Servo m_pan{TestBench::kCameraPanChannel};
frc::ADXL345_SPI m_spiAccel{frc::SPI::kOnboardCS1};
static void SetUpTestCase() {
// The gyro object blocks for 5 seconds in the constructor, so only
// construct it once for the whole test case
m_gyro = new AnalogGyro(TestBench::kCameraGyroChannel);
m_gyro->SetSensitivity(kSensitivity);
TiltPanCameraTest() {
m_tilt.Set(kTiltSetpoint45);
m_pan.SetAngle(0.0);
// Wait for servos to reset
frc::Wait(2_s);
}
static void TearDownTestCase() { delete m_gyro; }
/**
* Test if the servo turns 90 degrees and the gyroscope measures this angle
* 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.
*/
void GyroTests(frc::AnalogGyro& gyro) {
gyro.SetSensitivity(0.013);
void SetUp() override {
m_tilt = new Servo(TestBench::kCameraTiltChannel);
m_pan = new Servo(TestBench::kCameraPanChannel);
m_spiAccel = new ADXL345_SPI(SPI::kOnboardCS1);
gyro.Reset();
m_tilt->Set(kTiltSetpoint45);
m_pan->SetAngle(0.0);
// Accumulator needs a small amount of time to reset before being tested
frc::Wait(1_ms);
Wait(kServoResetTime);
// Verify the gyro angle defaults to 0 immediately after being reset
EXPECT_NEAR(0.0, gyro.GetAngle(), 1.0);
m_gyro->Reset();
}
// Make sure that the gyro doesn't get jerked when the servo goes to zero.
m_pan.SetAngle(0.0);
frc::Wait(0.5_s);
gyro.Reset();
void DefaultGyroAngle();
void GyroAngle();
void GyroCalibratedParameters();
for (int32_t i = 0; i < 600; i++) {
m_pan.Set(i / 1000.0);
frc::Wait(1_ms);
}
void TearDown() override {
delete m_tilt;
delete m_pan;
delete m_spiAccel;
double gyroAngle = gyro.GetAngle();
EXPECT_NEAR(gyroAngle, 90.0, 10.0)
<< "Gyro measured " << gyroAngle
<< " degrees, servo should have turned 90 degrees";
}
};
AnalogGyro* TiltPanCameraTest::m_gyro = nullptr;
TEST_F(TiltPanCameraTest, Gyro) {
int cCenter;
double cOffset;
/**
* Test if the gyro angle defaults to 0 immediately after being reset.
*/
void TiltPanCameraTest::DefaultGyroAngle() {
EXPECT_NEAR(0.0, m_gyro->GetAngle(), 1.0);
}
{
frc::AnalogGyro gyro{TestBench::kCameraGyroChannel};
GyroTests(gyro);
/**
* Test if the servo turns 90 degrees and the gyroscope measures this angle
* 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.
*/
void TiltPanCameraTest::GyroAngle() {
// Make sure that the gyro doesn't get jerked when the servo goes to zero.
m_pan->SetAngle(0.0);
Wait(0.5_s);
m_gyro->Reset();
for (int32_t i = 0; i < 600; i++) {
m_pan->Set(i / 1000.0);
Wait(1_ms);
// Gets calibrated parameters from previously calibrated gyro, allocates a
// new gyro with the given parameters for center and offset, and re-runs
// tests on the new gyro.
cCenter = gyro.GetCenter();
cOffset = gyro.GetOffset();
}
double gyroAngle = m_gyro->GetAngle();
EXPECT_NEAR(gyroAngle, kTestAngle, 10.0)
<< "Gyro measured " << gyroAngle << " degrees, servo should have turned "
<< kTestAngle << " degrees";
}
/**
* Gets calibrated parameters from previously calibrated gyro, allocates a new
* gyro with the given parameters for center and offset, and re-runs tests on
* the new gyro.
*/
void TiltPanCameraTest::GyroCalibratedParameters() {
uint32_t cCenter = m_gyro->GetCenter();
double cOffset = m_gyro->GetOffset();
delete m_gyro;
m_gyro = new AnalogGyro(TestBench::kCameraGyroChannel, cCenter, cOffset);
m_gyro->SetSensitivity(kSensitivity);
// Default gyro angle test
// Accumulator needs a small amount of time to reset before being tested
m_gyro->Reset();
Wait(1_ms);
EXPECT_NEAR(0.0, m_gyro->GetAngle(), 1.0);
// Gyro angle test
// Make sure that the gyro doesn't get jerked when the servo goes to zero.
m_pan->SetAngle(0.0);
Wait(0.5_s);
m_gyro->Reset();
for (int32_t i = 0; i < 600; i++) {
m_pan->Set(i / 1000.0);
Wait(1_ms);
}
double gyroAngle = m_gyro->GetAngle();
EXPECT_NEAR(gyroAngle, kTestAngle, 10.0)
<< "Gyro measured " << gyroAngle << " degrees, servo should have turned "
<< kTestAngle << " degrees";
}
/**
* Run all gyro tests in one function to make sure they are run in order.
*/
TEST_F(TiltPanCameraTest, TestAllGyroTests) {
DefaultGyroAngle();
GyroAngle();
GyroCalibratedParameters();
frc::AnalogGyro gyro{TestBench::kCameraGyroChannel, cCenter, cOffset};
GyroTests(gyro);
}
/**
@@ -151,21 +93,24 @@ TEST_F(TiltPanCameraTest, TestAllGyroTests) {
* camera rotates
*/
TEST_F(TiltPanCameraTest, SPIAccelerometer) {
m_tilt->Set(kTiltSetpoint0);
Wait(kTiltTime);
EXPECT_NEAR(-1.0, m_spiAccel->GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel->GetY(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel->GetZ(), kAccelerometerTolerance);
static constexpr auto kTiltTime = 1_s;
static constexpr double kAccelerometerTolerance = 0.2;
m_tilt->Set(kTiltSetpoint45);
Wait(kTiltTime);
EXPECT_NEAR(-std::sqrt(0.5), m_spiAccel->GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel->GetY(), kAccelerometerTolerance);
EXPECT_NEAR(std::sqrt(0.5), m_spiAccel->GetZ(), kAccelerometerTolerance);
m_tilt.Set(kTiltSetpoint0);
frc::Wait(kTiltTime);
EXPECT_NEAR(-1.0, m_spiAccel.GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel.GetY(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel.GetZ(), kAccelerometerTolerance);
m_tilt->Set(kTiltSetpoint90);
Wait(kTiltTime);
EXPECT_NEAR(0.0, m_spiAccel->GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel->GetY(), kAccelerometerTolerance);
EXPECT_NEAR(1.0, m_spiAccel->GetZ(), kAccelerometerTolerance);
m_tilt.Set(kTiltSetpoint45);
frc::Wait(kTiltTime);
EXPECT_NEAR(-std::sqrt(0.5), m_spiAccel.GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel.GetY(), kAccelerometerTolerance);
EXPECT_NEAR(std::sqrt(0.5), m_spiAccel.GetZ(), kAccelerometerTolerance);
m_tilt.Set(kTiltSetpoint90);
frc::Wait(kTiltTime);
EXPECT_NEAR(0.0, m_spiAccel.GetX(), kAccelerometerTolerance);
EXPECT_NEAR(0.0, m_spiAccel.GetY(), kAccelerometerTolerance);
EXPECT_NEAR(1.0, m_spiAccel.GetZ(), kAccelerometerTolerance);
}

View File

@@ -1,437 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "command/MockCommand.h"
#include "frc/DriverStation.h"
#include "frc/RobotState.h"
#include "frc/Timer.h"
#include "frc/commands/CommandGroup.h"
#include "frc/commands/Scheduler.h"
#include "frc/commands/Subsystem.h"
#include "gtest/gtest.h"
using namespace frc;
class CommandTest : public testing::Test {
protected:
void SetUp() override { Scheduler::GetInstance()->SetEnabled(true); }
/**
* Tears Down the Scheduler at the end of each test.
* Must be called at the end of each test inside each test in order to prevent
* them being deallocated
* when they leave the scope of the test (causing a segfault).
* This can not be done within the virtual void Teardown() method because it
* is called outside of the
* scope of the test.
*/
void TeardownScheduler() { Scheduler::GetInstance()->ResetAll(); }
void AssertCommandState(MockCommand* command, int32_t initialize,
int32_t execute, int32_t isFinished, int32_t end,
int32_t interrupted) {
EXPECT_EQ(initialize, command->GetInitializeCount());
EXPECT_EQ(execute, command->GetExecuteCount());
EXPECT_EQ(isFinished, command->GetIsFinishedCount());
EXPECT_EQ(end, command->GetEndCount());
EXPECT_EQ(interrupted, command->GetInterruptedCount());
}
};
class ASubsystem : public Subsystem {
private:
Command* m_command = nullptr;
public:
explicit ASubsystem(const std::string& name) : Subsystem(name) {}
void InitDefaultCommand() override {
if (m_command != nullptr) {
SetDefaultCommand(m_command);
}
}
void Init(Command* command) { m_command = command; }
};
// CommandParallelGroupTest ported from CommandParallelGroupTest.java
TEST_F(CommandTest, ParallelCommands) {
auto command1 = new MockCommand;
auto command2 = new MockCommand;
CommandGroup 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);
TeardownScheduler();
}
// END CommandParallelGroupTest
// CommandScheduleTest ported from CommandScheduleTest.java
TEST_F(CommandTest, RunAndTerminate) {
MockCommand command;
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);
TeardownScheduler();
}
TEST_F(CommandTest, RunAndCancel) {
MockCommand command;
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);
TeardownScheduler();
}
// END CommandScheduleTest
// CommandSequentialGroupTest ported from CommandSequentialGroupTest.java
TEST_F(CommandTest, ThreeCommandOnSubSystem) {
ASubsystem subsystem("Three Command Test Subsystem");
auto command1 = new MockCommand;
command1->Requires(&subsystem);
auto command2 = new MockCommand;
command2->Requires(&subsystem);
auto command3 = new MockCommand;
command3->Requires(&subsystem);
CommandGroup commandGroup;
commandGroup.AddSequential(command1, 1_s);
commandGroup.AddSequential(command2, 2_s);
commandGroup.AddSequential(command3);
AssertCommandState(command1, 0, 0, 0, 0, 0);
AssertCommandState(command2, 0, 0, 0, 0, 0);
AssertCommandState(command3, 0, 0, 0, 0, 0);
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);
Wait(1_s);
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);
Wait(2_s);
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);
TeardownScheduler();
}
// END CommandSequentialGroupTest
// CommandSequentialGroupTest ported from CommandSequentialGroupTest.java
TEST_F(CommandTest, OneCommandSupersedingAnotherBecauseOfDependencies) {
ASubsystem subsystem("Command Superseding Test Subsystem");
MockCommand command1;
command1.Requires(&subsystem);
MockCommand command2;
command2.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);
TeardownScheduler();
}
TEST_F(CommandTest,
OneCommandFailingSupersedingBecauseFirstCanNotBeInterrupted) {
ASubsystem subsystem("Command Superseding Test Subsystem");
MockCommand command1;
command1.Requires(&subsystem);
command1.SetInterruptible(false);
MockCommand command2;
command2.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);
TeardownScheduler();
}
// END CommandSequentialGroupTest
class ModifiedMockCommand : public MockCommand {
public:
ModifiedMockCommand() : MockCommand() { SetTimeout(2_s); }
bool IsFinished() override {
return MockCommand::IsFinished() || IsTimedOut();
}
};
TEST_F(CommandTest, TwoSecondTimeout) {
ASubsystem subsystem("Two Second Timeout Test Subsystem");
ModifiedMockCommand command;
command.Requires(&subsystem);
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);
Wait(2_s);
Scheduler::GetInstance()->Run();
AssertCommandState(&command, 1, 4, 4, 1, 0);
Scheduler::GetInstance()->Run();
AssertCommandState(&command, 1, 4, 4, 1, 0);
TeardownScheduler();
}
TEST_F(CommandTest, DefaultCommandWhereTheInteruptingCommandEndsItself) {
ASubsystem subsystem("Default Command Test Subsystem");
auto defaultCommand = new MockCommand;
defaultCommand->Requires(&subsystem);
MockCommand anotherCommand;
anotherCommand.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);
TeardownScheduler();
}
TEST_F(CommandTest, DefaultCommandsInterruptingCommandCanceled) {
ASubsystem subsystem("Default Command Test Subsystem");
auto defaultCommand = new MockCommand;
defaultCommand->Requires(&subsystem);
MockCommand anotherCommand;
anotherCommand.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.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);
TeardownScheduler();
}

View File

@@ -1,432 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "command/MockCommand.h"
#include "command/MockConditionalCommand.h"
#include "frc/DriverStation.h"
#include "frc/RobotState.h"
#include "frc/commands/ConditionalCommand.h"
#include "frc/commands/Scheduler.h"
#include "frc/commands/Subsystem.h"
#include "gtest/gtest.h"
using namespace frc;
class ConditionalCommandTest : public testing::Test {
public:
MockConditionalCommand* m_command;
MockCommand* m_onTrue;
MockCommand* m_onFalse;
MockConditionalCommand* m_commandNull;
Subsystem* m_subsystem;
protected:
void SetUp() override {
Scheduler::GetInstance()->SetEnabled(true);
m_subsystem = new Subsystem("MockSubsystem");
m_onTrue = new MockCommand(m_subsystem);
m_onFalse = new MockCommand(m_subsystem);
m_command = new MockConditionalCommand(m_onTrue, m_onFalse);
m_commandNull = new MockConditionalCommand(m_onTrue, nullptr);
}
void TearDown() override { delete m_command; }
/**
* Tears Down the Scheduler at the end of each test.
*
* Must be called at the end of each test inside each test in order to prevent
* them being deallocated when they leave the scope of the test (causing a
* segfault). This cannot be done within the virtual void Teardown() method
* because it is called outside of the scope of the test.
*/
void TeardownScheduler() { Scheduler::GetInstance()->ResetAll(); }
void AssertCommandState(MockCommand& command, int32_t initialize,
int32_t execute, int32_t isFinished, int32_t end,
int32_t interrupted) {
EXPECT_EQ(initialize, command.GetInitializeCount());
EXPECT_EQ(execute, command.GetExecuteCount());
EXPECT_EQ(isFinished, command.GetIsFinishedCount());
EXPECT_EQ(end, command.GetEndCount());
EXPECT_EQ(interrupted, command.GetInterruptedCount());
}
void AssertConditionalCommandState(MockConditionalCommand& command,
int32_t initialize, int32_t execute,
int32_t isFinished, int32_t end,
int32_t interrupted) {
EXPECT_EQ(initialize, command.GetInitializeCount());
EXPECT_EQ(execute, command.GetExecuteCount());
EXPECT_EQ(isFinished, command.GetIsFinishedCount());
EXPECT_EQ(end, command.GetEndCount());
EXPECT_EQ(interrupted, command.GetInterruptedCount());
}
};
TEST_F(ConditionalCommandTest, OnTrueTest) {
m_command->SetCondition(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_onTrue->SetHasFinished(true);
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
EXPECT_TRUE(m_onTrue->GetInitializeCount() > 0)
<< "Did not initialize the true command\n";
EXPECT_TRUE(m_onFalse->GetInitializeCount() == 0)
<< "Initialized the false command\n";
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, OnFalseTest) {
m_command->SetCondition(false);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onFalse, 1, 1, 1, 0, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onFalse, 1, 2, 2, 0, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_onFalse->SetHasFinished(true);
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onFalse, 1, 3, 3, 1, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onFalse, 1, 3, 3, 1, 0);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
EXPECT_TRUE(m_onFalse->GetInitializeCount() > 0)
<< "Did not initialize the false command";
EXPECT_TRUE(m_onTrue->GetInitializeCount() == 0)
<< "Initialized the true command";
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, CancelSubCommandTest) {
m_command->SetCondition(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_onTrue->Cancel();
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 1);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 1);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, CancelCondCommandTest) {
m_command->SetCondition(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_command->Cancel();
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 1);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 1);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 1);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 1);
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, OnTrueTwiceTest) {
m_command->SetCondition(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_onTrue->SetHasFinished(true);
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
m_onTrue->ResetCounters();
m_command->ResetCounters();
Scheduler::GetInstance()->AddCommand(m_command);
SCOPED_TRACE("11");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("12");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("13");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("14");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("15");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("16");
m_onTrue->SetHasFinished(true);
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
SCOPED_TRACE("17");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 1, 0);
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, OnTrueInstantTest) {
m_command->SetCondition(true);
m_onTrue->SetHasFinished(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 1, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 1, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 1, 0);
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, CancelRequiresTest) {
m_command->SetCondition(true);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_command);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 1, 1, 0, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 1, 1, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 2, 2, 0, 0);
SCOPED_TRACE("5");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 2, 2, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 3, 3, 0, 0);
SCOPED_TRACE("6");
m_onFalse->Start();
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 0, 0);
AssertCommandState(*m_onFalse, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 0, 1);
SCOPED_TRACE("7");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 1, 3, 3, 0, 1);
AssertCommandState(*m_onFalse, 1, 1, 1, 0, 0);
AssertConditionalCommandState(*m_command, 1, 4, 4, 0, 1);
TeardownScheduler();
}
TEST_F(ConditionalCommandTest, OnFalseNullTest) {
m_command->SetCondition(false);
SCOPED_TRACE("1");
Scheduler::GetInstance()->AddCommand(m_commandNull);
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_commandNull, 0, 0, 0, 0, 0);
SCOPED_TRACE("2");
Scheduler::GetInstance()->Run(); // init command and select m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_commandNull, 0, 0, 0, 0, 0);
SCOPED_TRACE("3");
Scheduler::GetInstance()->Run(); // init m_onTrue
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_commandNull, 1, 1, 1, 1, 0);
SCOPED_TRACE("4");
Scheduler::GetInstance()->Run();
AssertCommandState(*m_onTrue, 0, 0, 0, 0, 0);
AssertConditionalCommandState(*m_commandNull, 1, 1, 1, 1, 0);
TeardownScheduler();
}

View File

@@ -1,62 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "command/MockCommand.h"
using namespace frc;
MockCommand::MockCommand(Subsystem* subsys) : MockCommand() {
Requires(subsys);
}
MockCommand::MockCommand() {
m_initializeCount = 0;
m_executeCount = 0;
m_isFinishedCount = 0;
m_hasFinished = false;
m_endCount = 0;
m_interruptedCount = 0;
}
bool MockCommand::HasInitialized() {
return GetInitializeCount() > 0;
}
bool MockCommand::HasEnd() {
return GetEndCount() > 0;
}
bool MockCommand::HasInterrupted() {
return GetInterruptedCount() > 0;
}
void MockCommand::Initialize() {
++m_initializeCount;
}
void MockCommand::Execute() {
++m_executeCount;
}
bool MockCommand::IsFinished() {
++m_isFinishedCount;
return IsHasFinished();
}
void MockCommand::End() {
++m_endCount;
}
void MockCommand::Interrupted() {
++m_interruptedCount;
}
void MockCommand::ResetCounters() {
m_initializeCount = 0;
m_executeCount = 0;
m_isFinishedCount = 0;
m_hasFinished = false;
m_endCount = 0;
m_interruptedCount = 0;
}

View File

@@ -1,66 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "command/MockConditionalCommand.h"
using namespace frc;
MockConditionalCommand::MockConditionalCommand(MockCommand* onTrue,
MockCommand* onFalse)
: ConditionalCommand(onTrue, onFalse) {
m_initializeCount = 0;
m_executeCount = 0;
m_isFinishedCount = 0;
m_endCount = 0;
m_interruptedCount = 0;
}
void MockConditionalCommand::SetCondition(bool condition) {
m_condition = condition;
}
bool MockConditionalCommand::Condition() {
return m_condition;
}
bool MockConditionalCommand::HasInitialized() {
return GetInitializeCount() > 0;
}
bool MockConditionalCommand::HasEnd() {
return GetEndCount() > 0;
}
bool MockConditionalCommand::HasInterrupted() {
return GetInterruptedCount() > 0;
}
void MockConditionalCommand::Initialize() {
++m_initializeCount;
}
void MockConditionalCommand::Execute() {
++m_executeCount;
}
bool MockConditionalCommand::IsFinished() {
++m_isFinishedCount;
return ConditionalCommand::IsFinished();
}
void MockConditionalCommand::End() {
++m_endCount;
}
void MockConditionalCommand::Interrupted() {
++m_interruptedCount;
}
void MockConditionalCommand::ResetCounters() {
m_initializeCount = 0;
m_executeCount = 0;
m_isFinishedCount = 0;
m_endCount = 0;
m_interruptedCount = 0;
}

View File

@@ -6,35 +6,32 @@
#include <stdint.h>
#include <string_view>
#include <fmt/core.h>
#include <hal/cpp/fpga_clock.h>
#include <wpi/Logger.h>
#include <wpi/SmallString.h>
#include <wpi/SmallVector.h>
#include <wpi/UDPClient.h>
#include <wpi/raw_ostream.h>
static void LoggerFunc(unsigned int level, const char* file, unsigned int line,
const char* msg) {
wpi::SmallString<128> buf;
wpi::raw_svector_ostream oss(buf);
if (level == 20) {
oss << "DS: " << msg << '\n';
wpi::errs() << oss.str();
fmt::print(stderr, "DS: {}\n", msg);
return;
}
wpi::StringRef levelmsg;
std::string_view levelmsg;
if (level >= 50) {
levelmsg = "CRITICAL: ";
levelmsg = "CRITICAL";
} else if (level >= 40) {
levelmsg = "ERROR: ";
levelmsg = "ERROR";
} else if (level >= 30) {
levelmsg = "WARNING: ";
levelmsg = "WARNING";
} else {
return;
}
oss << "DS: " << levelmsg << msg << " (" << file << ':' << line << ")\n";
wpi::errs() << oss.str();
fmt::print(stderr, "DS: {}: {} ({}:{})\n", levelmsg, msg, file, line);
}
static void generateEnabledDsPacket(wpi::SmallVectorImpl<uint8_t>& data,
@@ -48,9 +45,7 @@ static void generateEnabledDsPacket(wpi::SmallVectorImpl<uint8_t>& data,
data.push_back(0x00); // red 1 station
}
using namespace frc;
void MockDS::start() {
void MockDS::Start() {
if (m_active) {
return;
}
@@ -83,7 +78,7 @@ void MockDS::start() {
});
}
void MockDS::stop() {
void MockDS::Stop() {
m_active = false;
if (m_thread.joinable()) {
m_thread.join();

View File

@@ -7,19 +7,17 @@
#include <atomic>
#include <thread>
namespace frc {
class MockDS {
public:
MockDS() = default;
~MockDS() { stop(); }
~MockDS() { Stop(); }
MockDS(const MockDS& other) = delete;
MockDS& operator=(const MockDS& other) = delete;
void start();
void stop();
void Start();
void Stop();
private:
std::thread m_thread;
std::atomic_bool m_active{false};
};
} // namespace frc

View File

@@ -1,17 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "shuffleboard/MockActuatorSendable.h"
#include "frc/smartdashboard/SendableRegistry.h"
using namespace frc;
MockActuatorSendable::MockActuatorSendable(wpi::StringRef name) {
SendableRegistry::GetInstance().Add(this, name);
}
void MockActuatorSendable::InitSendable(SendableBuilder& builder) {
builder.SetActuator(true);
}

View File

@@ -1,102 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/shuffleboard/ShuffleboardInstance.h" // NOLINT(build/include_order)
#include <memory>
#include <string>
#include <networktables/NetworkTableEntry.h>
#include <networktables/NetworkTableInstance.h>
#include "frc/shuffleboard/ShuffleboardInstance.h"
#include "gtest/gtest.h"
#include "shuffleboard/MockActuatorSendable.h"
using namespace frc;
class ShuffleboardInstanceTest : public testing::Test {
void SetUp() override {
m_ntInstance = nt::NetworkTableInstance::Create();
m_shuffleboardInstance =
std::make_unique<detail::ShuffleboardInstance>(m_ntInstance);
}
protected:
nt::NetworkTableInstance m_ntInstance;
std::unique_ptr<detail::ShuffleboardInstance> m_shuffleboardInstance;
};
TEST_F(ShuffleboardInstanceTest, PathFluent) {
auto entry = m_shuffleboardInstance->GetTab("Tab Title")
.GetLayout("List", "List Layout")
.Add("Data", "string")
.WithWidget("Text View")
.GetEntry();
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
EXPECT_EQ("/Shuffleboard/Tab Title/List/Data", entry.GetName())
<< "Entry path generated incorrectly";
}
TEST_F(ShuffleboardInstanceTest, NestedLayoutsFluent) {
auto entry = m_shuffleboardInstance->GetTab("Tab")
.GetLayout("First", "List")
.GetLayout("Second", "List")
.GetLayout("Third", "List")
.GetLayout("Fourth", "List")
.Add("Value", "string")
.GetEntry();
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
EXPECT_EQ("/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
entry.GetName())
<< "Entry path generated incorrectly";
}
TEST_F(ShuffleboardInstanceTest, NestedLayoutsOop) {
ShuffleboardTab& tab = m_shuffleboardInstance->GetTab("Tab");
ShuffleboardLayout& first = tab.GetLayout("First", "List");
ShuffleboardLayout& second = first.GetLayout("Second", "List");
ShuffleboardLayout& third = second.GetLayout("Third", "List");
ShuffleboardLayout& fourth = third.GetLayout("Fourth", "List");
SimpleWidget& widget = fourth.Add("Value", "string");
auto entry = widget.GetEntry();
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
EXPECT_EQ("/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
entry.GetName())
<< "Entry path generated incorrectly";
}
TEST_F(ShuffleboardInstanceTest, LayoutTypeIsSet) {
std::string layoutType = "Type";
m_shuffleboardInstance->GetTab("Tab").GetLayout("Title", layoutType);
m_shuffleboardInstance->Update();
nt::NetworkTableEntry entry = m_ntInstance.GetEntry(
"/Shuffleboard/.metadata/Tab/Title/PreferredComponent");
EXPECT_EQ(layoutType, entry.GetString("Not Set")) << "Layout type not set";
}
TEST_F(ShuffleboardInstanceTest, NestedActuatorWidgetsAreDisabled) {
MockActuatorSendable sendable("Actuator");
m_shuffleboardInstance->GetTab("Tab")
.GetLayout("Title", "Layout")
.Add(sendable);
auto controllableEntry =
m_ntInstance.GetEntry("/Shuffleboard/Tab/Title/Actuator/.controllable");
m_shuffleboardInstance->Update();
// Note: we use the unsafe `GetBoolean()` method because if the value is NOT
// a boolean, or if it is not present, then something has clearly gone very,
// very wrong
bool controllable = controllableEntry.GetValue()->GetBoolean();
// Sanity check
EXPECT_TRUE(controllable)
<< "The nested actuator widget should be enabled by default";
m_shuffleboardInstance->DisableActuatorWidgets();
controllable = controllableEntry.GetValue()->GetBoolean();
EXPECT_FALSE(controllable)
<< "The nested actuator widget should have been disabled";
}

View File

@@ -1,112 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <array>
#include <memory>
#include <string>
#include <networktables/NetworkTableEntry.h>
#include <networktables/NetworkTableInstance.h>
#include "frc/commands/InstantCommand.h"
#include "frc/shuffleboard/ShuffleboardInstance.h"
#include "frc/shuffleboard/ShuffleboardTab.h"
#include "frc/smartdashboard/Sendable.h"
#include "gtest/gtest.h"
using namespace frc;
class ShuffleboardTabTest : public testing::Test {
void SetUp() override {
m_ntInstance = nt::NetworkTableInstance::Create();
m_instance = std::make_unique<detail::ShuffleboardInstance>(m_ntInstance);
m_tab = &(m_instance->GetTab("Tab"));
}
protected:
nt::NetworkTableInstance m_ntInstance;
ShuffleboardTab* m_tab;
std::unique_ptr<detail::ShuffleboardInstance> m_instance;
};
TEST_F(ShuffleboardTabTest, AddDouble) {
auto entry = m_tab->Add("Double", 1.0).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/Double", entry.GetName());
EXPECT_FLOAT_EQ(1.0, entry.GetValue()->GetDouble());
}
TEST_F(ShuffleboardTabTest, AddInteger) {
auto entry = m_tab->Add("Int", 1).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/Int", entry.GetName());
EXPECT_FLOAT_EQ(1.0, entry.GetValue()->GetDouble());
}
TEST_F(ShuffleboardTabTest, AddBoolean) {
auto entry = m_tab->Add("Bool", false).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/Bool", entry.GetName());
EXPECT_FALSE(entry.GetValue()->GetBoolean());
}
TEST_F(ShuffleboardTabTest, AddString) {
auto entry = m_tab->Add("String", "foobar").GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/String", entry.GetName());
EXPECT_EQ("foobar", entry.GetValue()->GetString());
}
TEST_F(ShuffleboardTabTest, AddNamedSendableWithProperties) {
InstantCommand sendable("Command");
std::string widgetType = "Command Widget";
wpi::StringMap<std::shared_ptr<nt::Value>> map;
map.try_emplace("foo", nt::Value::MakeDouble(1234));
map.try_emplace("bar", nt::Value::MakeString("baz"));
m_tab->Add(sendable).WithWidget(widgetType).WithProperties(map);
m_instance->Update();
std::string meta = "/Shuffleboard/.metadata/Tab/Command";
EXPECT_EQ(1234, m_ntInstance.GetEntry(meta + "/Properties/foo").GetDouble(-1))
<< "Property 'foo' not set correctly";
EXPECT_EQ("baz",
m_ntInstance.GetEntry(meta + "/Properties/bar").GetString(""))
<< "Property 'bar' not set correctly";
EXPECT_EQ(widgetType,
m_ntInstance.GetEntry(meta + "/PreferredComponent").GetString(""))
<< "Preferred component not set correctly";
}
TEST_F(ShuffleboardTabTest, AddNumberArray) {
std::array<double, 3> expect = {{1.0, 2.0, 3.0}};
auto entry = m_tab->Add("DoubleArray", expect).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/DoubleArray", entry.GetName());
auto actual = entry.GetValue()->GetDoubleArray();
EXPECT_EQ(expect.size(), actual.size());
for (size_t i = 0; i < expect.size(); i++) {
EXPECT_FLOAT_EQ(expect[i], actual[i]);
}
}
TEST_F(ShuffleboardTabTest, AddBooleanArray) {
std::array<bool, 2> expect = {{true, false}};
auto entry = m_tab->Add("BoolArray", expect).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/BoolArray", entry.GetName());
auto actual = entry.GetValue()->GetBooleanArray();
EXPECT_EQ(expect.size(), actual.size());
for (size_t i = 0; i < expect.size(); i++) {
EXPECT_EQ(expect[i], actual[i]);
}
}
TEST_F(ShuffleboardTabTest, AddStringArray) {
std::array<std::string, 2> expect = {{"foo", "bar"}};
auto entry = m_tab->Add("StringArray", expect).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/StringArray", entry.GetName());
auto actual = entry.GetValue()->GetStringArray();
EXPECT_EQ(expect.size(), actual.size());
for (size_t i = 0; i < expect.size(); i++) {
EXPECT_EQ(expect[i], actual[i]);
}
}

View File

@@ -1,17 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/shuffleboard/Shuffleboard.h"
#include "frc/shuffleboard/ShuffleboardTab.h"
#include "gtest/gtest.h"
using namespace frc;
class ShuffleboardTest : public testing::Test {};
TEST_F(ShuffleboardTest, TabObjectsCached) {
ShuffleboardTab& tab1 = Shuffleboard::GetTab("testTabObjectsCached");
ShuffleboardTab& tab2 = Shuffleboard::GetTab("testTabObjectsCached");
EXPECT_EQ(&tab1, &tab2) << "Tab objects were not cached";
}