[hal,wpilib] Move Alert to HAL (#8646)

SystemCore implementation is not yet connected to MRCComm.
This commit is contained in:
Peter Johnson
2026-03-03 21:58:47 -07:00
committed by GitHub
parent f4935a2ea9
commit 733cfa4b07
33 changed files with 1719 additions and 1121 deletions

View File

@@ -0,0 +1,158 @@
// 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.
package org.wpilib.simulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.wpilib.driverstation.Alert;
import org.wpilib.driverstation.Alert.Level;
import org.wpilib.hardware.hal.HAL;
class AlertSimTest {
private String m_groupName;
@BeforeEach
void setup(TestInfo info) {
HAL.initialize(500, 0);
m_groupName = "AlertTest_" + info.getDisplayName();
}
@AfterEach
void cleanup() {
AlertSim.resetData();
}
private String[] getActiveAlerts(Level type) {
return Arrays.stream(AlertSim.getAll())
.filter(a -> a.isActive() && a.level == type)
.map(a -> a.text)
.toArray(String[]::new);
}
private boolean isAlertActive(String text, Alert.Level type) {
return Arrays.stream(AlertSim.getAll())
.filter(a -> a.isActive() && a.level == type)
.anyMatch(a -> a.text.equals(text));
}
private void assertState(Alert.Level type, List<String> state) {
assertEquals(state, Arrays.asList(getActiveAlerts(type)));
}
private Alert makeAlert(String text, Alert.Level type) {
return new Alert(m_groupName, text, type);
}
@Test
void testInitialization() {
assertEquals(0, AlertSim.getCount());
assertEquals(0, AlertSim.getAll().length);
}
@Test
void testReset() {
try (var alert = makeAlert("alert", Level.HIGH)) {
alert.set(true);
assertTrue(isAlertActive("alert", Level.HIGH));
}
AlertSim.resetData();
assertFalse(isAlertActive("alert", Level.HIGH));
}
@Test
void setUnsetSingle() {
try (var one = makeAlert("one", Level.LOW)) {
assertFalse(isAlertActive("one", Level.LOW));
one.set(true);
assertTrue(isAlertActive("one", Level.LOW));
one.set(false);
assertFalse(isAlertActive("one", Level.LOW));
}
}
@Test
void setUnsetMultiple() {
try (var one = makeAlert("one", Level.HIGH);
var two = makeAlert("two", Level.LOW)) {
assertFalse(isAlertActive("one", Level.HIGH));
assertFalse(isAlertActive("two", Level.LOW));
one.set(true);
assertTrue(isAlertActive("one", Level.HIGH));
assertFalse(isAlertActive("two", Level.LOW));
one.set(true);
two.set(true);
assertTrue(isAlertActive("one", Level.HIGH));
assertTrue(isAlertActive("two", Level.LOW));
one.set(false);
assertFalse(isAlertActive("one", Level.HIGH));
assertTrue(isAlertActive("two", Level.LOW));
}
}
@Test
void setIsIdempotent() {
try (var a = makeAlert("A", Level.LOW);
var b = makeAlert("B", Level.LOW);
var c = makeAlert("C", Level.LOW)) {
a.set(true);
b.set(true);
c.set(true);
var startState = List.of(getActiveAlerts(Level.LOW));
b.set(true);
assertState(Level.LOW, startState);
a.set(true);
assertState(Level.LOW, startState);
}
}
@Test
void closeUnsetsAlert() {
try (var alert = makeAlert("alert", Level.MEDIUM)) {
alert.set(true);
assertTrue(isAlertActive("alert", Level.MEDIUM));
}
assertFalse(isAlertActive("alert", Level.MEDIUM));
}
@Test
void setTextWhileUnset() {
try (var alert = makeAlert("BEFORE", Level.LOW)) {
assertEquals("BEFORE", alert.getText());
alert.set(true);
assertTrue(isAlertActive("BEFORE", Level.LOW));
alert.set(false);
assertFalse(isAlertActive("BEFORE", Level.LOW));
alert.setText("AFTER");
assertEquals("AFTER", alert.getText());
alert.set(true);
assertFalse(isAlertActive("BEFORE", Level.LOW));
assertTrue(isAlertActive("AFTER", Level.LOW));
}
}
@Test
void setTextWhileSet() {
try (var alert = makeAlert("BEFORE", Level.LOW)) {
assertEquals("BEFORE", alert.getText());
alert.set(true);
assertTrue(isAlertActive("BEFORE", Level.LOW));
alert.setText("AFTER");
assertEquals("AFTER", alert.getText());
assertFalse(isAlertActive("BEFORE", Level.LOW));
assertTrue(isAlertActive("AFTER", Level.LOW));
}
}
}

View File

@@ -1,243 +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.
package org.wpilib.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.parallel.ResourceLock;
import org.wpilib.networktables.NetworkTableInstance;
import org.wpilib.networktables.StringArraySubscriber;
import org.wpilib.simulation.SimHooks;
import org.wpilib.smartdashboard.SmartDashboard;
import org.wpilib.util.Alert.AlertType;
class AlertTest {
private NetworkTableInstance m_inst;
private String m_groupName;
@BeforeEach
void setup(TestInfo info) {
m_groupName = "AlertTest_" + info.getDisplayName();
m_inst = NetworkTableInstance.create();
SmartDashboard.setNetworkTableInstance(m_inst);
}
@AfterEach
void checkClean() {
update();
assertEquals(0, getActiveAlerts(AlertType.kError).length);
assertEquals(0, getActiveAlerts(AlertType.kWarning).length);
assertEquals(0, getActiveAlerts(AlertType.kInfo).length);
m_inst.close();
SmartDashboard.setNetworkTableInstance(NetworkTableInstance.getDefault());
}
private String getSubtableName(Alert.AlertType type) {
switch (type) {
case kError:
return "errors";
case kWarning:
return "warnings";
case kInfo:
return "infos";
default:
return "unknown";
}
}
private StringArraySubscriber getSubscriberForType(Alert.AlertType type) {
return m_inst
.getStringArrayTopic("/SmartDashboard/" + m_groupName + "/" + getSubtableName(type))
.subscribe(new String[] {});
}
private String[] getActiveAlerts(AlertType type) {
update();
try (var sub = getSubscriberForType(type)) {
return sub.get();
}
}
private void update() {
SmartDashboard.updateValues();
}
private boolean isAlertActive(String text, Alert.AlertType type) {
return Arrays.asList(getActiveAlerts(type)).contains(text);
}
private void assertState(Alert.AlertType type, List<String> state) {
assertEquals(state, Arrays.asList(getActiveAlerts(type)));
}
private Alert makeAlert(String text, Alert.AlertType type) {
return new Alert(m_groupName, text, type);
}
@Test
void setUnsetSingle() {
try (var one = makeAlert("one", AlertType.kInfo)) {
assertFalse(isAlertActive("one", AlertType.kInfo));
one.set(true);
assertTrue(isAlertActive("one", AlertType.kInfo));
one.set(false);
assertFalse(isAlertActive("one", AlertType.kInfo));
}
}
@Test
void setUnsetMultiple() {
try (var one = makeAlert("one", AlertType.kError);
var two = makeAlert("two", AlertType.kInfo)) {
assertFalse(isAlertActive("one", AlertType.kError));
assertFalse(isAlertActive("two", AlertType.kInfo));
one.set(true);
assertTrue(isAlertActive("one", AlertType.kError));
assertFalse(isAlertActive("two", AlertType.kInfo));
one.set(true);
two.set(true);
assertTrue(isAlertActive("one", AlertType.kError));
assertTrue(isAlertActive("two", AlertType.kInfo));
one.set(false);
assertFalse(isAlertActive("one", AlertType.kError));
assertTrue(isAlertActive("two", AlertType.kInfo));
}
}
@Test
void setIsIdempotent() {
try (var a = makeAlert("A", AlertType.kInfo);
var b = makeAlert("B", AlertType.kInfo);
var c = makeAlert("C", AlertType.kInfo)) {
a.set(true);
b.set(true);
c.set(true);
var startState = List.of(getActiveAlerts(AlertType.kInfo));
b.set(true);
assertState(AlertType.kInfo, startState);
a.set(true);
assertState(AlertType.kInfo, startState);
}
}
@Test
void closeUnsetsAlert() {
try (var alert = makeAlert("alert", AlertType.kWarning)) {
alert.set(true);
assertTrue(isAlertActive("alert", AlertType.kWarning));
}
assertFalse(isAlertActive("alert", AlertType.kWarning));
}
@Test
void setTextWhileUnset() {
try (var alert = makeAlert("BEFORE", AlertType.kInfo)) {
assertEquals("BEFORE", alert.getText());
alert.set(true);
assertTrue(isAlertActive("BEFORE", AlertType.kInfo));
alert.set(false);
assertFalse(isAlertActive("BEFORE", AlertType.kInfo));
alert.setText("AFTER");
assertEquals("AFTER", alert.getText());
alert.set(true);
assertFalse(isAlertActive("BEFORE", AlertType.kInfo));
assertTrue(isAlertActive("AFTER", AlertType.kInfo));
}
}
@Test
void setTextWhileSet() {
try (var alert = makeAlert("BEFORE", AlertType.kInfo)) {
assertEquals("BEFORE", alert.getText());
alert.set(true);
assertTrue(isAlertActive("BEFORE", AlertType.kInfo));
alert.setText("AFTER");
assertEquals("AFTER", alert.getText());
assertFalse(isAlertActive("BEFORE", AlertType.kInfo));
assertTrue(isAlertActive("AFTER", AlertType.kInfo));
}
}
@ResourceLock("timing")
@Test
void setTextDoesNotAffectFirstOrderSort() {
SimHooks.pauseTiming();
try (var a = makeAlert("A", AlertType.kInfo);
var b = makeAlert("B", AlertType.kInfo);
var c = makeAlert("C", AlertType.kInfo)) {
a.set(true);
SimHooks.stepTiming(1);
b.set(true);
SimHooks.stepTiming(1);
c.set(true);
var expectedEndState = new ArrayList<>(List.of(getActiveAlerts(AlertType.kInfo)));
expectedEndState.replaceAll(s -> "B".equals(s) ? "AFTER" : s);
b.setText("AFTER");
assertState(AlertType.kInfo, expectedEndState);
} finally {
SimHooks.resumeTiming();
}
}
@ResourceLock("timing")
@Test
void sortOrder() {
SimHooks.pauseTiming();
try (var a = makeAlert("A", AlertType.kInfo);
var b = makeAlert("B", AlertType.kInfo);
var c = makeAlert("C", AlertType.kInfo)) {
a.set(true);
assertState(AlertType.kInfo, List.of("A"));
SimHooks.stepTiming(1);
b.set(true);
assertState(AlertType.kInfo, List.of("B", "A"));
SimHooks.stepTiming(1);
c.set(true);
assertState(AlertType.kInfo, List.of("C", "B", "A"));
SimHooks.stepTiming(1);
c.set(false);
assertState(AlertType.kInfo, List.of("B", "A"));
SimHooks.stepTiming(1);
c.set(true);
assertState(AlertType.kInfo, List.of("C", "B", "A"));
SimHooks.stepTiming(1);
a.set(false);
assertState(AlertType.kInfo, List.of("C", "B"));
SimHooks.stepTiming(1);
b.set(false);
assertState(AlertType.kInfo, List.of("C"));
SimHooks.stepTiming(1);
b.set(true);
assertState(AlertType.kInfo, List.of("B", "C"));
SimHooks.stepTiming(1);
a.set(true);
assertState(AlertType.kInfo, List.of("A", "B", "C"));
} finally {
SimHooks.resumeTiming();
}
}
}