mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
[hal,wpilib] Move Alert to HAL (#8646)
SystemCore implementation is not yet connected to MRCComm.
This commit is contained in:
@@ -1,250 +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 "wpi/util/Alert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "wpi/nt/NetworkTableInstance.hpp"
|
||||
#include "wpi/nt/StringArrayTopic.hpp"
|
||||
#include "wpi/simulation/SimHooks.hpp"
|
||||
#include "wpi/smartdashboard/SmartDashboard.hpp"
|
||||
|
||||
using namespace wpi;
|
||||
using enum Alert::AlertType;
|
||||
class AlertsTest : public ::testing::Test {
|
||||
public:
|
||||
~AlertsTest() override {
|
||||
// test all destructors
|
||||
Update();
|
||||
EXPECT_EQ(GetSubscriberForType(kError).Get().size(), 0ul);
|
||||
EXPECT_EQ(GetSubscriberForType(kWarning).Get().size(), 0ul);
|
||||
EXPECT_EQ(GetSubscriberForType(kInfo).Get().size(), 0ul);
|
||||
}
|
||||
|
||||
std::string GetGroupName() {
|
||||
const ::testing::TestInfo* testInfo =
|
||||
::testing::UnitTest::GetInstance()->current_test_info();
|
||||
return fmt::format("{}_{}", testInfo->test_suite_name(), testInfo->name());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Alert MakeAlert(Args&&... args) {
|
||||
return Alert(GetGroupName(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetActiveAlerts(Alert::AlertType type) {
|
||||
Update();
|
||||
return GetSubscriberForType(type).Get();
|
||||
}
|
||||
|
||||
bool IsAlertActive(std::string_view text, Alert::AlertType type) {
|
||||
auto activeAlerts = GetActiveAlerts(type);
|
||||
return std::find(activeAlerts.begin(), activeAlerts.end(), text) !=
|
||||
activeAlerts.end();
|
||||
}
|
||||
|
||||
void Update() { wpi::SmartDashboard::UpdateValues(); }
|
||||
|
||||
private:
|
||||
std::string GetSubtableName(Alert::AlertType type) {
|
||||
switch (type) {
|
||||
case kError:
|
||||
return "errors";
|
||||
case kWarning:
|
||||
return "warnings";
|
||||
case kInfo:
|
||||
return "infos";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const wpi::nt::StringArraySubscriber GetSubscriberForType(
|
||||
Alert::AlertType type) {
|
||||
return wpi::nt::NetworkTableInstance::GetDefault()
|
||||
.GetStringArrayTopic(fmt::format("/SmartDashboard/{}/{}",
|
||||
GetGroupName(), GetSubtableName(type)))
|
||||
.Subscribe({});
|
||||
}
|
||||
};
|
||||
|
||||
#define EXPECT_STATE(type, ...) \
|
||||
EXPECT_EQ(GetActiveAlerts(type), (std::vector<std::string>{__VA_ARGS__}))
|
||||
|
||||
TEST_F(AlertsTest, SetUnsetSingle) {
|
||||
auto one = MakeAlert("one", kInfo);
|
||||
EXPECT_FALSE(IsAlertActive("one", kInfo));
|
||||
one.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", kInfo));
|
||||
one.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("one", kInfo));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SetUnsetMultiple) {
|
||||
auto one = MakeAlert("one", kError);
|
||||
auto two = MakeAlert("two", kInfo);
|
||||
EXPECT_FALSE(IsAlertActive("one", kError));
|
||||
EXPECT_FALSE(IsAlertActive("two", kInfo));
|
||||
one.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", kError));
|
||||
EXPECT_FALSE(IsAlertActive("two", kInfo));
|
||||
one.Set(true);
|
||||
two.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", kError));
|
||||
EXPECT_TRUE(IsAlertActive("two", kInfo));
|
||||
one.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("one", kError));
|
||||
EXPECT_TRUE(IsAlertActive("two", kInfo));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SetIsIdempotent) {
|
||||
auto a = MakeAlert("A", kInfo);
|
||||
auto b = MakeAlert("B", kInfo);
|
||||
auto c = MakeAlert("C", kInfo);
|
||||
a.Set(true);
|
||||
|
||||
b.Set(true);
|
||||
c.Set(true);
|
||||
|
||||
const auto startState = GetActiveAlerts(kInfo);
|
||||
|
||||
b.Set(true);
|
||||
EXPECT_STATE(kInfo, startState);
|
||||
|
||||
a.Set(true);
|
||||
EXPECT_STATE(kInfo, startState);
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, DestructorUnsetsAlert) {
|
||||
{
|
||||
auto alert = MakeAlert("alert", kWarning);
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("alert", kWarning));
|
||||
}
|
||||
EXPECT_FALSE(IsAlertActive("alert", kWarning));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SetTextWhileUnset) {
|
||||
auto alert = MakeAlert("BEFORE", kInfo);
|
||||
EXPECT_EQ("BEFORE", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("BEFORE", kInfo));
|
||||
alert.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", kInfo));
|
||||
alert.SetText("AFTER");
|
||||
EXPECT_EQ("AFTER", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", kInfo));
|
||||
EXPECT_TRUE(IsAlertActive("AFTER", kInfo));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SetTextWhileSet) {
|
||||
auto alert = MakeAlert("BEFORE", kInfo);
|
||||
EXPECT_EQ("BEFORE", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("BEFORE", kInfo));
|
||||
alert.SetText("AFTER");
|
||||
EXPECT_EQ("AFTER", alert.GetText());
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", kInfo));
|
||||
EXPECT_TRUE(IsAlertActive("AFTER", kInfo));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SetTextDoesNotAffectFirstOrderSort) {
|
||||
wpi::sim::PauseTiming();
|
||||
|
||||
auto a = MakeAlert("A", kError);
|
||||
auto b = MakeAlert("B", kError);
|
||||
auto c = MakeAlert("C", kError);
|
||||
|
||||
a.Set(true);
|
||||
wpi::sim::StepTiming(1_s);
|
||||
b.Set(true);
|
||||
wpi::sim::StepTiming(1_s);
|
||||
c.Set(true);
|
||||
|
||||
auto expectedEndState = GetActiveAlerts(kError);
|
||||
std::replace(expectedEndState.begin(), expectedEndState.end(),
|
||||
std::string("B"), std::string("AFTER"));
|
||||
b.SetText("AFTER");
|
||||
|
||||
EXPECT_STATE(kError, expectedEndState);
|
||||
wpi::sim::ResumeTiming();
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, MoveAssign) {
|
||||
auto outer = MakeAlert("outer", kInfo);
|
||||
outer.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("outer", kInfo));
|
||||
|
||||
{
|
||||
auto inner = MakeAlert("inner", kWarning);
|
||||
inner.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("inner", kWarning));
|
||||
outer = std::move(inner);
|
||||
// Assignment target should be unset and invalidated as part of move, before
|
||||
// destruction
|
||||
EXPECT_FALSE(IsAlertActive("outer", kInfo));
|
||||
}
|
||||
EXPECT_TRUE(IsAlertActive("inner", kWarning));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, MoveConstruct) {
|
||||
auto a = MakeAlert("A", kInfo);
|
||||
a.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("A", kInfo));
|
||||
Alert b{std::move(a)};
|
||||
EXPECT_TRUE(IsAlertActive("A", kInfo));
|
||||
b.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("A", kInfo));
|
||||
b.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("A", kInfo));
|
||||
}
|
||||
|
||||
TEST_F(AlertsTest, SortOrder) {
|
||||
wpi::sim::PauseTiming();
|
||||
auto a = MakeAlert("A", kInfo);
|
||||
auto b = MakeAlert("B", kInfo);
|
||||
auto c = MakeAlert("C", kInfo);
|
||||
a.Set(true);
|
||||
EXPECT_STATE(kInfo, "A");
|
||||
wpi::sim::StepTiming(1_s);
|
||||
b.Set(true);
|
||||
EXPECT_STATE(kInfo, "B", "A");
|
||||
wpi::sim::StepTiming(1_s);
|
||||
c.Set(true);
|
||||
EXPECT_STATE(kInfo, "C", "B", "A");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
c.Set(false);
|
||||
EXPECT_STATE(kInfo, "B", "A");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
c.Set(true);
|
||||
EXPECT_STATE(kInfo, "C", "B", "A");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
a.Set(false);
|
||||
EXPECT_STATE(kInfo, "C", "B");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
b.Set(false);
|
||||
EXPECT_STATE(kInfo, "C");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
b.Set(true);
|
||||
EXPECT_STATE(kInfo, "B", "C");
|
||||
|
||||
wpi::sim::StepTiming(1_s);
|
||||
a.Set(true);
|
||||
EXPECT_STATE(kInfo, "A", "B", "C");
|
||||
|
||||
wpi::sim::ResumeTiming();
|
||||
}
|
||||
153
wpilibc/src/test/native/cpp/simulation/AlertSimTest.cpp
Normal file
153
wpilibc/src/test/native/cpp/simulation/AlertSimTest.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
// 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 "wpi/simulation/AlertSim.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "wpi/driverstation/Alert.hpp"
|
||||
#include "wpi/hal/HALBase.h"
|
||||
|
||||
namespace wpi::sim {
|
||||
|
||||
class AlertSimTest : public ::testing::Test {
|
||||
public:
|
||||
AlertSimTest() { HAL_Initialize(500, 0); }
|
||||
|
||||
~AlertSimTest() override { AlertSim::ResetData(); }
|
||||
|
||||
std::string GetGroupName() {
|
||||
const ::testing::TestInfo* testInfo =
|
||||
::testing::UnitTest::GetInstance()->current_test_info();
|
||||
return fmt::format("{}_{}", testInfo->test_suite_name(), testInfo->name());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Alert MakeAlert(Args&&... args) {
|
||||
return Alert(GetGroupName(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetActiveAlerts(Alert::Level type) {
|
||||
auto alerts = AlertSim::GetAll();
|
||||
std::vector<std::string> activeAlerts;
|
||||
for (const auto& alert : alerts) {
|
||||
if (alert.isActive() && alert.level == type) {
|
||||
activeAlerts.emplace_back(std::move(alert.text));
|
||||
}
|
||||
}
|
||||
return activeAlerts;
|
||||
}
|
||||
|
||||
bool IsAlertActive(std::string_view text, Alert::Level type) {
|
||||
auto alerts = AlertSim::GetAll();
|
||||
return std::any_of(alerts.begin(), alerts.end(),
|
||||
[text, type](const AlertSim::AlertInfo& alert) {
|
||||
return alert.isActive() && alert.level == type &&
|
||||
alert.text == text;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#define EXPECT_STATE(type, ...) \
|
||||
EXPECT_EQ(GetActiveAlerts(type), (std::vector<std::string>{__VA_ARGS__}))
|
||||
|
||||
TEST_F(AlertSimTest, NoAlertsInitially) {
|
||||
EXPECT_EQ(AlertSim::GetCount(), 0);
|
||||
EXPECT_TRUE(AlertSim::GetAll().empty());
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, NoAlertsAfterReset) {
|
||||
auto alert = MakeAlert("alert", Alert::Level::HIGH);
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("alert", Alert::Level::HIGH));
|
||||
AlertSim::ResetData();
|
||||
EXPECT_EQ(AlertSim::GetCount(), 0);
|
||||
EXPECT_TRUE(AlertSim::GetAll().empty());
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, SetUnsetSingle) {
|
||||
auto one = MakeAlert("one", Alert::Level::LOW);
|
||||
EXPECT_FALSE(IsAlertActive("one", Alert::Level::LOW));
|
||||
one.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", Alert::Level::LOW));
|
||||
one.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("one", Alert::Level::LOW));
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, SetUnsetMultiple) {
|
||||
auto one = MakeAlert("one", Alert::Level::HIGH);
|
||||
auto two = MakeAlert("two", Alert::Level::LOW);
|
||||
EXPECT_FALSE(IsAlertActive("one", Alert::Level::HIGH));
|
||||
EXPECT_FALSE(IsAlertActive("two", Alert::Level::LOW));
|
||||
one.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", Alert::Level::HIGH));
|
||||
EXPECT_FALSE(IsAlertActive("two", Alert::Level::LOW));
|
||||
one.Set(true);
|
||||
two.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("one", Alert::Level::HIGH));
|
||||
EXPECT_TRUE(IsAlertActive("two", Alert::Level::LOW));
|
||||
one.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("one", Alert::Level::HIGH));
|
||||
EXPECT_TRUE(IsAlertActive("two", Alert::Level::LOW));
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, SetIsIdempotent) {
|
||||
auto a = MakeAlert("A", Alert::Level::LOW);
|
||||
auto b = MakeAlert("B", Alert::Level::LOW);
|
||||
auto c = MakeAlert("C", Alert::Level::LOW);
|
||||
a.Set(true);
|
||||
|
||||
b.Set(true);
|
||||
c.Set(true);
|
||||
|
||||
const auto startState = GetActiveAlerts(Alert::Level::LOW);
|
||||
|
||||
b.Set(true);
|
||||
EXPECT_STATE(Alert::Level::LOW, startState);
|
||||
|
||||
a.Set(true);
|
||||
EXPECT_STATE(Alert::Level::LOW, startState);
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, DestructorUnsetsAlert) {
|
||||
{
|
||||
auto alert = MakeAlert("alert", Alert::Level::MEDIUM);
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("alert", Alert::Level::MEDIUM));
|
||||
}
|
||||
EXPECT_FALSE(IsAlertActive("alert", Alert::Level::MEDIUM));
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, SetTextWhileUnset) {
|
||||
auto alert = MakeAlert("BEFORE", Alert::Level::LOW);
|
||||
EXPECT_EQ("BEFORE", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("BEFORE", Alert::Level::LOW));
|
||||
alert.Set(false);
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", Alert::Level::LOW));
|
||||
alert.SetText("AFTER");
|
||||
EXPECT_EQ("AFTER", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", Alert::Level::LOW));
|
||||
EXPECT_TRUE(IsAlertActive("AFTER", Alert::Level::LOW));
|
||||
}
|
||||
|
||||
TEST_F(AlertSimTest, SetTextWhileSet) {
|
||||
auto alert = MakeAlert("BEFORE", Alert::Level::LOW);
|
||||
EXPECT_EQ("BEFORE", alert.GetText());
|
||||
alert.Set(true);
|
||||
EXPECT_TRUE(IsAlertActive("BEFORE", Alert::Level::LOW));
|
||||
alert.SetText("AFTER");
|
||||
EXPECT_EQ("AFTER", alert.GetText());
|
||||
EXPECT_FALSE(IsAlertActive("BEFORE", Alert::Level::LOW));
|
||||
EXPECT_TRUE(IsAlertActive("AFTER", Alert::Level::LOW));
|
||||
}
|
||||
|
||||
} // namespace wpi::sim
|
||||
Reference in New Issue
Block a user