mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[copybara] Sync with mostrobotpy (#8820)
GitOrigin-RevId: f03f29e57af22a74b680873090028b9c9f5c8063
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
build-backend = "hatchling.build"
|
||||
requires = [
|
||||
"semiwrap~=0.3.0",
|
||||
"hatch-meson~=0.1.0",
|
||||
"hatch-meson~=0.1.2",
|
||||
"hatch-robotpy~=0.2.1",
|
||||
"hatchling",
|
||||
"robotpy-native-wpilib==0.0.0",
|
||||
|
||||
@@ -90,7 +90,11 @@ class RobotTest:
|
||||
pyproject_path = project_path / "pyproject.toml"
|
||||
if pyproject_path.exists():
|
||||
with open(pyproject_path, "rb") as fp:
|
||||
d = tomllib.load(fp)
|
||||
try:
|
||||
d = tomllib.load(fp)
|
||||
except tomllib.TOMLDecodeError as e:
|
||||
print(f"ERROR: {pyproject_path}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
v = d["tool"]["robotpy"]["testing"]["isolated"]
|
||||
@@ -98,9 +102,12 @@ class RobotTest:
|
||||
pass
|
||||
else:
|
||||
if not isinstance(v, bool):
|
||||
raise ValueError(
|
||||
f"tool.robotpy.testing.isolated must be a boolean value (got {v})"
|
||||
print(
|
||||
f"ERROR: {pyproject_path}: tool.robotpy.testing.isolated "
|
||||
f"must be a boolean value (got {v!r})",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
isolated = v
|
||||
|
||||
@@ -162,7 +169,10 @@ class RobotTest:
|
||||
break
|
||||
else:
|
||||
if not builtin:
|
||||
print("ERROR: Cannot run robot tests, as test directory was not found!")
|
||||
print(
|
||||
"ERROR: Cannot run robot tests, as test directory was not found!",
|
||||
file=sys.stderr,
|
||||
)
|
||||
retv = self._no_tests(main_file, project_path)
|
||||
return 1
|
||||
|
||||
@@ -194,8 +204,11 @@ class RobotTest:
|
||||
|
||||
# requires pytest 2.8.x
|
||||
if retv == 5:
|
||||
print()
|
||||
print("ERROR: a tests directory was found, but no tests were defined")
|
||||
print(file=sys.stderr)
|
||||
print(
|
||||
"ERROR: a tests directory was found, but no tests were defined",
|
||||
file=sys.stderr,
|
||||
)
|
||||
retv = self._no_tests(main_file, project_path, retv)
|
||||
|
||||
return retv
|
||||
|
||||
@@ -18,11 +18,7 @@ def group_name(request):
|
||||
|
||||
|
||||
def get_active_alerts(level: Alert.Level) -> T.List[str]:
|
||||
return [
|
||||
a.text
|
||||
for a in AlertSim.getAll()
|
||||
if a.level == level and a.isActive()
|
||||
]
|
||||
return [a.text for a in AlertSim.getAll() if a.level == level and a.isActive()]
|
||||
|
||||
|
||||
def is_alert_active(text: str, level: Alert.Level):
|
||||
@@ -144,6 +140,7 @@ def test_set_text_while_set(group_name):
|
||||
assert not is_alert_active("BEFORE", Alert.Level.LOW)
|
||||
assert is_alert_active("AFTER", Alert.Level.LOW)
|
||||
|
||||
|
||||
def test_get_active(group_name):
|
||||
with (
|
||||
Alert(group_name, "A", Alert.Level.HIGH) as a,
|
||||
@@ -154,10 +151,10 @@ def test_get_active(group_name):
|
||||
a.set(True)
|
||||
b.set(True)
|
||||
c.set(False)
|
||||
|
||||
|
||||
active = AlertSim.getActive()
|
||||
allAlerts = AlertSim.getAll()
|
||||
|
||||
|
||||
assert len(active) == 2
|
||||
assert len(allAlerts) == 3
|
||||
|
||||
@@ -169,4 +166,4 @@ def test_get_active(group_name):
|
||||
allAlerts = AlertSim.getAll()
|
||||
assert len(active) == 1
|
||||
assert len(allAlerts) == 3
|
||||
assert active[0].text == "B"
|
||||
assert active[0].text == "B"
|
||||
|
||||
@@ -41,6 +41,7 @@ class MockRobot(OpModeRobot):
|
||||
super().__init__()
|
||||
self.driver_station_connected_count = 0
|
||||
self.none_periodic_count = 0
|
||||
self.periodic_count = 0
|
||||
|
||||
def driverStationConnected(self):
|
||||
self.driver_station_connected_count += 1
|
||||
@@ -48,6 +49,9 @@ class MockRobot(OpModeRobot):
|
||||
def nonePeriodic(self):
|
||||
self.none_periodic_count += 1
|
||||
|
||||
def robotPeriodic(self):
|
||||
self.periodic_count += 1
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def sim_timing_setup():
|
||||
@@ -135,8 +139,8 @@ def test_remove_op_mode():
|
||||
assert options[0].name == "OneArgOpMode"
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="wpilib bug")
|
||||
def test_none_periodic():
|
||||
@pytest.fixture
|
||||
def periodic_robot_test_fixture():
|
||||
class MyMockRobot(MockRobot):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -146,14 +150,40 @@ def test_none_periodic():
|
||||
robot = MyMockRobot()
|
||||
|
||||
robot_thread = threading.Thread(target=robot.startCompetition)
|
||||
robot_thread.daemon = True # Make thread daemon so it doesn't block test exit
|
||||
robot_thread.start()
|
||||
|
||||
yield robot
|
||||
|
||||
robot.endCompetition()
|
||||
robot_thread.join()
|
||||
|
||||
|
||||
# @pytest.mark.xfail(reason="wpilib bug")
|
||||
def test_none_periodic(periodic_robot_test_fixture):
|
||||
robot = periodic_robot_test_fixture
|
||||
|
||||
wsim.waitForProgramStart()
|
||||
|
||||
# Time step to get periodic calls on 20 ms robot loop
|
||||
wsim.stepTiming(0.110)
|
||||
|
||||
assert robot.none_periodic_count == 2
|
||||
assert robot.none_periodic_count == 5
|
||||
|
||||
robot.endCompetition()
|
||||
robot_thread.join(timeout=1.0) # Add timeout to prevent hanging
|
||||
|
||||
def test_robot_periodic(periodic_robot_test_fixture):
|
||||
kPeriod = 0.020 # 20 ms
|
||||
|
||||
robot = periodic_robot_test_fixture
|
||||
|
||||
wsim.waitForProgramStart()
|
||||
|
||||
# RobotPeriodic should be called regardless of state
|
||||
assert robot.periodic_count == 0
|
||||
|
||||
# Time step to get periodic calls on 20 ms robot loop
|
||||
wsim.stepTiming(kPeriod)
|
||||
assert robot.periodic_count == 1
|
||||
|
||||
# Additional time steps should continue calling RobotPeriodic
|
||||
wsim.stepTiming(kPeriod)
|
||||
assert robot.periodic_count == 2
|
||||
|
||||
Reference in New Issue
Block a user