2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2023-07-18 21:18:32 -07:00
|
|
|
#include <functional>
|
2019-08-25 23:55:59 -04:00
|
|
|
#include <memory>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2020-06-27 22:11:24 -07:00
|
|
|
#include <frc/simulation/DriverStationSim.h>
|
2023-08-28 15:13:34 -07:00
|
|
|
#include <gtest/gtest.h>
|
2019-08-25 23:55:59 -04:00
|
|
|
|
2022-08-30 07:53:47 +03:00
|
|
|
#include "frc2/command/CommandHelper.h"
|
2019-08-25 23:55:59 -04:00
|
|
|
#include "frc2/command/CommandScheduler.h"
|
2023-07-14 01:12:01 -04:00
|
|
|
#include "frc2/command/Subsystem.h"
|
2019-08-25 23:55:59 -04:00
|
|
|
#include "gmock/gmock.h"
|
|
|
|
|
#include "make_vector.h"
|
|
|
|
|
|
|
|
|
|
namespace frc2 {
|
2022-06-16 09:32:16 +03:00
|
|
|
|
2023-07-14 01:12:01 -04:00
|
|
|
class TestSubsystem : public Subsystem {
|
2023-06-20 23:29:59 -04:00
|
|
|
public:
|
|
|
|
|
explicit TestSubsystem(std::function<void()> periodic = [] {})
|
|
|
|
|
: m_periodic{periodic} {}
|
|
|
|
|
void Periodic() override { m_periodic(); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::function<void()> m_periodic;
|
|
|
|
|
};
|
2023-01-08 17:44:53 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NOTE: Moving mock objects causes EXPECT_CALL to not work correctly!
|
|
|
|
|
*/
|
2023-07-14 01:12:01 -04:00
|
|
|
class MockCommand : public CommandHelper<Command, MockCommand> {
|
2023-01-08 17:44:53 +02:00
|
|
|
public:
|
|
|
|
|
MOCK_CONST_METHOD0(GetRequirements, wpi::SmallSet<Subsystem*, 4>());
|
|
|
|
|
MOCK_METHOD0(IsFinished, bool());
|
|
|
|
|
MOCK_CONST_METHOD0(RunsWhenDisabled, bool());
|
|
|
|
|
MOCK_METHOD0(Initialize, void());
|
|
|
|
|
MOCK_METHOD0(Execute, void());
|
|
|
|
|
MOCK_METHOD1(End, void(bool interrupted));
|
|
|
|
|
|
|
|
|
|
MockCommand() {
|
|
|
|
|
m_requirements = {};
|
|
|
|
|
EXPECT_CALL(*this, GetRequirements())
|
|
|
|
|
.WillRepeatedly(::testing::Return(m_requirements));
|
|
|
|
|
EXPECT_CALL(*this, IsFinished()).WillRepeatedly(::testing::Return(false));
|
|
|
|
|
EXPECT_CALL(*this, RunsWhenDisabled())
|
|
|
|
|
.WillRepeatedly(::testing::Return(true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MockCommand(std::initializer_list<Subsystem*> requirements,
|
|
|
|
|
bool finished = false, bool runWhenDisabled = true) {
|
|
|
|
|
m_requirements.insert(requirements.begin(), requirements.end());
|
|
|
|
|
EXPECT_CALL(*this, GetRequirements())
|
|
|
|
|
.WillRepeatedly(::testing::Return(m_requirements));
|
|
|
|
|
EXPECT_CALL(*this, IsFinished())
|
|
|
|
|
.WillRepeatedly(::testing::Return(finished));
|
|
|
|
|
EXPECT_CALL(*this, RunsWhenDisabled())
|
|
|
|
|
.WillRepeatedly(::testing::Return(runWhenDisabled));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MockCommand(MockCommand&& other) {
|
|
|
|
|
EXPECT_CALL(*this, IsFinished())
|
|
|
|
|
.WillRepeatedly(::testing::Return(other.IsFinished()));
|
|
|
|
|
EXPECT_CALL(*this, RunsWhenDisabled())
|
|
|
|
|
.WillRepeatedly(::testing::Return(other.RunsWhenDisabled()));
|
|
|
|
|
std::swap(m_requirements, other.m_requirements);
|
|
|
|
|
EXPECT_CALL(*this, GetRequirements())
|
|
|
|
|
.WillRepeatedly(::testing::Return(m_requirements));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MockCommand(const MockCommand& other) : CommandHelper{other} {}
|
|
|
|
|
|
|
|
|
|
void SetFinished(bool finished) {
|
|
|
|
|
EXPECT_CALL(*this, IsFinished())
|
|
|
|
|
.WillRepeatedly(::testing::Return(finished));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~MockCommand() { // NOLINT
|
|
|
|
|
auto& scheduler = CommandScheduler::GetInstance();
|
|
|
|
|
scheduler.Cancel(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
wpi::SmallSet<Subsystem*, 4> m_requirements;
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
class CommandTestBase : public ::testing::Test {
|
|
|
|
|
public:
|
|
|
|
|
CommandTestBase();
|
|
|
|
|
|
2023-06-19 22:56:56 -07:00
|
|
|
~CommandTestBase() override;
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
protected:
|
|
|
|
|
CommandScheduler GetScheduler();
|
|
|
|
|
|
|
|
|
|
void SetDSEnabled(bool enabled);
|
|
|
|
|
};
|
2022-06-16 09:32:16 +03:00
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
class CommandTestBaseWithParam : public ::testing::TestWithParam<T> {
|
|
|
|
|
public:
|
|
|
|
|
CommandTestBaseWithParam() {
|
|
|
|
|
auto& scheduler = CommandScheduler::GetInstance();
|
|
|
|
|
scheduler.CancelAll();
|
|
|
|
|
scheduler.Enable();
|
|
|
|
|
scheduler.GetActiveButtonLoop()->Clear();
|
2023-07-14 01:12:01 -04:00
|
|
|
scheduler.UnregisterAllSubsystems();
|
2022-06-16 09:32:16 +03:00
|
|
|
|
2023-06-19 22:56:56 -07:00
|
|
|
SetDSEnabled(true);
|
|
|
|
|
}
|
2022-06-16 09:32:16 +03:00
|
|
|
|
2023-06-19 22:56:56 -07:00
|
|
|
~CommandTestBaseWithParam() override {
|
2022-06-16 09:32:16 +03:00
|
|
|
CommandScheduler::GetInstance().GetActiveButtonLoop()->Clear();
|
2023-07-14 01:12:01 -04:00
|
|
|
CommandScheduler::GetInstance().UnregisterAllSubsystems();
|
2022-06-16 09:32:16 +03:00
|
|
|
}
|
|
|
|
|
|
2023-06-19 22:56:56 -07:00
|
|
|
protected:
|
|
|
|
|
CommandScheduler GetScheduler() { return CommandScheduler(); }
|
|
|
|
|
|
2022-06-16 09:32:16 +03:00
|
|
|
void SetDSEnabled(bool enabled) {
|
2023-06-19 22:56:56 -07:00
|
|
|
frc::sim::DriverStationSim::SetDsAttached(true);
|
2022-06-16 09:32:16 +03:00
|
|
|
frc::sim::DriverStationSim::SetEnabled(enabled);
|
2023-06-19 22:56:56 -07:00
|
|
|
frc::sim::DriverStationSim::NotifyNewData();
|
2022-06-16 09:32:16 +03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
} // namespace frc2
|