mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
251 lines
6.6 KiB
C++
251 lines
6.6 KiB
C++
// 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 <algorithm>
|
|
#include <chrono>
|
|
#include <map>
|
|
#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"
|
|
#include "wpi/util/Alert.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();
|
|
}
|