mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[copybara] Resync robotpy (#8585)
Project import generated by Copybara.
GitOrigin-RevId: fd000778e9b78c72cc7ca7b2ebe476129b78c6e0
This commit is contained in:
476
wpilibc/src/test/python/test_boolean_event.py
Normal file
476
wpilibc/src/test/python/test_boolean_event.py
Normal file
@@ -0,0 +1,476 @@
|
||||
from wpilib import BooleanEvent, EventLoop
|
||||
|
||||
|
||||
def test_binary_compositions():
|
||||
loop = EventLoop()
|
||||
and_counter = {"value": 0}
|
||||
or_counter = {"value": 0}
|
||||
|
||||
def inc_and():
|
||||
and_counter["value"] += 1
|
||||
|
||||
def inc_or():
|
||||
or_counter["value"] += 1
|
||||
|
||||
assert and_counter["value"] == 0
|
||||
assert or_counter["value"] == 0
|
||||
|
||||
BooleanEvent(loop, lambda: True).and_(lambda: False).ifHigh(inc_and)
|
||||
BooleanEvent(loop, lambda: True).or_(lambda: False).ifHigh(inc_or)
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert and_counter["value"] == 0
|
||||
assert or_counter["value"] == 1
|
||||
|
||||
|
||||
def test_binary_compositions_with_edge_decorators():
|
||||
loop = EventLoop()
|
||||
bool1 = {"value": False}
|
||||
bool2 = {"value": False}
|
||||
bool3 = {"value": False}
|
||||
bool4 = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
event1 = BooleanEvent(loop, lambda: bool1["value"]).rising()
|
||||
event2 = BooleanEvent(loop, lambda: bool2["value"]).rising()
|
||||
event3 = BooleanEvent(loop, lambda: bool3["value"]).rising()
|
||||
event4 = BooleanEvent(loop, lambda: bool4["value"]).rising()
|
||||
event1.and_(event2).ifHigh(inc)
|
||||
event3.or_(event4).ifHigh(inc)
|
||||
assert counter["value"] == 0
|
||||
|
||||
bool1["value"] = True
|
||||
bool2["value"] = True
|
||||
bool3["value"] = True
|
||||
bool4["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
bool1["value"] = False
|
||||
bool2["value"] = False
|
||||
bool3["value"] = False
|
||||
bool4["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
bool1["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
bool2["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
bool1["value"] = False
|
||||
bool2["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
bool1["value"] = True
|
||||
bool2["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 3
|
||||
|
||||
bool3["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 4
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 4
|
||||
|
||||
bool4["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 5
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 5
|
||||
|
||||
|
||||
def test_binary_composition_loop_semantics():
|
||||
loop1 = EventLoop()
|
||||
loop2 = EventLoop()
|
||||
bool1 = {"value": True}
|
||||
bool2 = {"value": True}
|
||||
counter1 = {"value": 0}
|
||||
counter2 = {"value": 0}
|
||||
|
||||
def inc1():
|
||||
counter1["value"] += 1
|
||||
|
||||
def inc2():
|
||||
counter2["value"] += 1
|
||||
|
||||
BooleanEvent(loop1, lambda: bool1["value"]).and_(
|
||||
BooleanEvent(loop2, lambda: bool2["value"])
|
||||
).ifHigh(inc1)
|
||||
|
||||
BooleanEvent(loop2, lambda: bool2["value"]).and_(
|
||||
BooleanEvent(loop1, lambda: bool1["value"])
|
||||
).ifHigh(inc2)
|
||||
|
||||
assert counter1["value"] == 0
|
||||
assert counter2["value"] == 0
|
||||
|
||||
loop1.poll()
|
||||
|
||||
assert counter1["value"] == 1
|
||||
assert counter2["value"] == 0
|
||||
|
||||
loop2.poll()
|
||||
|
||||
assert counter1["value"] == 1
|
||||
assert counter2["value"] == 1
|
||||
|
||||
bool2["value"] = False
|
||||
loop1.poll()
|
||||
|
||||
assert counter1["value"] == 2
|
||||
assert counter2["value"] == 1
|
||||
|
||||
loop2.poll()
|
||||
|
||||
assert counter1["value"] == 2
|
||||
assert counter2["value"] == 1
|
||||
|
||||
loop1.poll()
|
||||
|
||||
assert counter1["value"] == 2
|
||||
assert counter2["value"] == 1
|
||||
|
||||
bool2["value"] = True
|
||||
loop2.poll()
|
||||
|
||||
assert counter1["value"] == 2
|
||||
assert counter2["value"] == 2
|
||||
|
||||
loop1.poll()
|
||||
|
||||
assert counter1["value"] == 3
|
||||
assert counter2["value"] == 2
|
||||
|
||||
bool1["value"] = False
|
||||
loop2.poll()
|
||||
|
||||
assert counter1["value"] == 3
|
||||
assert counter2["value"] == 3
|
||||
|
||||
loop1.poll()
|
||||
|
||||
assert counter1["value"] == 3
|
||||
assert counter2["value"] == 3
|
||||
|
||||
loop2.poll()
|
||||
|
||||
assert counter1["value"] == 3
|
||||
assert counter2["value"] == 3
|
||||
|
||||
|
||||
def test_poll_ordering():
|
||||
loop = EventLoop()
|
||||
bool1 = {"value": True}
|
||||
bool2 = {"value": True}
|
||||
enable_assert = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def action1():
|
||||
if enable_assert["value"]:
|
||||
counter["value"] += 1
|
||||
assert counter["value"] % 3 == 1
|
||||
return bool1["value"]
|
||||
|
||||
def action2():
|
||||
if enable_assert["value"]:
|
||||
counter["value"] += 1
|
||||
assert counter["value"] % 3 == 2
|
||||
return bool2["value"]
|
||||
|
||||
def action3():
|
||||
if enable_assert["value"]:
|
||||
counter["value"] += 1
|
||||
assert counter["value"] % 3 == 0
|
||||
|
||||
BooleanEvent(loop, action1).and_(BooleanEvent(loop, action2)).ifHigh(action3)
|
||||
enable_assert["value"] = True
|
||||
loop.poll()
|
||||
loop.poll()
|
||||
loop.poll()
|
||||
loop.poll()
|
||||
|
||||
|
||||
def test_edge_decorators():
|
||||
loop = EventLoop()
|
||||
flag = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
def dec():
|
||||
counter["value"] -= 1
|
||||
|
||||
BooleanEvent(loop, lambda: flag["value"]).falling().ifHigh(dec)
|
||||
BooleanEvent(loop, lambda: flag["value"]).rising().ifHigh(inc)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 1
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 1
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
|
||||
def test_edge_reuse():
|
||||
loop = EventLoop()
|
||||
flag = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
event = BooleanEvent(loop, lambda: flag["value"]).rising()
|
||||
event.ifHigh(inc)
|
||||
event.ifHigh(inc)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 4
|
||||
|
||||
|
||||
def test_edge_reconstruct():
|
||||
loop = EventLoop()
|
||||
flag = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
event = BooleanEvent(loop, lambda: flag["value"])
|
||||
event.rising().ifHigh(inc)
|
||||
event.rising().ifHigh(inc)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 4
|
||||
|
||||
|
||||
def test_mid_loop_boolean_change():
|
||||
loop = EventLoop()
|
||||
flag = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
event = BooleanEvent(loop, lambda: flag["value"]).rising()
|
||||
|
||||
def first_action():
|
||||
flag["value"] = False
|
||||
counter["value"] += 1
|
||||
|
||||
event.ifHigh(first_action)
|
||||
event.ifHigh(inc)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 4
|
||||
|
||||
|
||||
def test_mid_loop_boolean_change_with_composed_events():
|
||||
loop = EventLoop()
|
||||
bool1 = {"value": False}
|
||||
bool2 = {"value": False}
|
||||
bool3 = {"value": False}
|
||||
bool4 = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
event1 = BooleanEvent(loop, lambda: bool1["value"])
|
||||
event2 = BooleanEvent(loop, lambda: bool2["value"])
|
||||
event3 = BooleanEvent(loop, lambda: bool3["value"])
|
||||
event4 = BooleanEvent(loop, lambda: bool4["value"])
|
||||
|
||||
def action1():
|
||||
bool2["value"] = False
|
||||
bool3["value"] = False
|
||||
counter["value"] += 1
|
||||
|
||||
event1.ifHigh(action1)
|
||||
|
||||
def action2():
|
||||
bool1["value"] = False
|
||||
counter["value"] += 1
|
||||
|
||||
event3.or_(event4).ifHigh(action2)
|
||||
|
||||
def action3():
|
||||
bool4["value"] = False
|
||||
counter["value"] += 1
|
||||
|
||||
event1.and_(event2).ifHigh(action3)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
bool1["value"] = True
|
||||
bool2["value"] = True
|
||||
bool3["value"] = True
|
||||
bool4["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 3
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 3
|
||||
|
||||
bool1["value"] = True
|
||||
bool2["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 5
|
||||
|
||||
bool1["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 5
|
||||
|
||||
bool1["value"] = True
|
||||
bool3["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 7
|
||||
|
||||
bool1["value"] = False
|
||||
bool4["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 8
|
||||
|
||||
|
||||
def test_negation():
|
||||
loop = EventLoop()
|
||||
flag = {"value": False}
|
||||
counter = {"value": 0}
|
||||
|
||||
def inc():
|
||||
counter["value"] += 1
|
||||
|
||||
BooleanEvent(loop, lambda: flag["value"]).negate().ifHigh(inc)
|
||||
|
||||
assert counter["value"] == 0
|
||||
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 1
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 1
|
||||
|
||||
flag["value"] = False
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
|
||||
flag["value"] = True
|
||||
loop.poll()
|
||||
|
||||
assert counter["value"] == 2
|
||||
@@ -135,6 +135,7 @@ def test_remove_op_mode():
|
||||
assert options[0].name == "OneArgOpMode"
|
||||
|
||||
|
||||
# @pytest.mark.xfail(reason="wpilib bug")
|
||||
def test_none_periodic():
|
||||
class MyMockRobot(MockRobot):
|
||||
def __init__(self):
|
||||
|
||||
@@ -5,8 +5,7 @@ import pytest
|
||||
|
||||
|
||||
def _make_robot_module(pytester):
|
||||
pytester.makepyfile(
|
||||
robot_module="""
|
||||
pytester.makepyfile(robot_module="""
|
||||
import wpilib
|
||||
|
||||
|
||||
@@ -51,13 +50,11 @@ class IterativeStateRobot(wpilib.TimedRobot):
|
||||
def teleopPeriodic(self):
|
||||
self.did_teleop_periodic = True
|
||||
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
def _configure_robot_testing_plugin(pytester, robot_class="DummyRobot"):
|
||||
pytester.makeconftest(
|
||||
f"""
|
||||
pytester.makeconftest(f"""
|
||||
import pathlib
|
||||
|
||||
from wpilib.testing.pytest_plugin import RobotTestingPlugin
|
||||
@@ -68,13 +65,11 @@ from robot_module import {robot_class}
|
||||
def pytest_configure(config):
|
||||
robot_file = pathlib.Path(__file__).resolve()
|
||||
config.pluginmanager.register(RobotTestingPlugin({robot_class}, robot_file, False))
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
def _configure_isolated_plugin(pytester, parallelism=1, robot_class="DummyRobot"):
|
||||
pytester.makeconftest(
|
||||
f"""
|
||||
pytester.makeconftest(f"""
|
||||
import pathlib
|
||||
|
||||
from wpilib.testing.pytest_isolated_tests_plugin import IsolatedTestsPlugin
|
||||
@@ -88,19 +83,16 @@ def pytest_configure(config):
|
||||
config.pluginmanager.register(
|
||||
IsolatedTestsPlugin({robot_class}, robot_file, False, False, {parallelism})
|
||||
)
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
def test_robot_testing_plugin_success(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_robot_testing_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_success="""
|
||||
pytester.makepyfile(test_success="""
|
||||
def test_robot_fixture(robot):
|
||||
assert robot.did_init
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest("-vv")
|
||||
|
||||
@@ -110,13 +102,11 @@ def test_robot_fixture(robot):
|
||||
def test_robot_testing_plugin_failure_shows_output(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_robot_testing_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_failure="""
|
||||
pytester.makepyfile(test_failure="""
|
||||
def test_robot_failure(robot):
|
||||
print("checked failure output")
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest("-vv")
|
||||
|
||||
@@ -132,8 +122,7 @@ def test_robot_failure(robot):
|
||||
def test_isolated_plugin_process_and_output(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_isolated_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_isolated="""
|
||||
pytester.makepyfile(test_isolated="""
|
||||
import os
|
||||
|
||||
|
||||
@@ -155,8 +144,7 @@ def test_robot_pid_two(robot):
|
||||
def test_robot_failure_output(robot):
|
||||
print("isolated failure output")
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest_subprocess("-vv")
|
||||
|
||||
@@ -181,8 +169,7 @@ def test_robot_failure_output(robot):
|
||||
def test_isolated_plugin_no_duplicate_verbose_output(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_isolated_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_isolated="""
|
||||
pytester.makepyfile(test_isolated="""
|
||||
def test_non_robot():
|
||||
assert True
|
||||
|
||||
@@ -193,8 +180,7 @@ def test_robot_one(robot):
|
||||
|
||||
def test_robot_two(robot):
|
||||
assert robot is not None
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest_subprocess("-v")
|
||||
|
||||
@@ -216,16 +202,14 @@ def test_robot_two(robot):
|
||||
def test_isolated_plugin_reports_signal_exit(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_isolated_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_isolated="""
|
||||
pytester.makepyfile(test_isolated="""
|
||||
import os
|
||||
import signal
|
||||
|
||||
|
||||
def test_robot_signal_exit(robot):
|
||||
os.kill(os.getpid(), signal.SIGTERM)
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest_subprocess("-vv")
|
||||
|
||||
@@ -241,8 +225,7 @@ def test_robot_signal_exit(robot):
|
||||
def test_isolated_plugin_shows_file_in_non_verbose_output(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_isolated_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_isolated="""
|
||||
pytester.makepyfile(test_isolated="""
|
||||
def test_non_robot():
|
||||
assert True
|
||||
|
||||
@@ -253,8 +236,7 @@ def test_robot_one(robot):
|
||||
|
||||
def test_robot_two(robot):
|
||||
assert robot is not None
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest_subprocess()
|
||||
|
||||
@@ -267,16 +249,14 @@ def test_robot_two(robot):
|
||||
def test_isolated_plugin_maxfail_stops_early(pytester):
|
||||
_make_robot_module(pytester)
|
||||
_configure_isolated_plugin(pytester)
|
||||
pytester.makepyfile(
|
||||
test_isolated="""
|
||||
pytester.makepyfile(test_isolated="""
|
||||
def test_robot_first(robot):
|
||||
assert False
|
||||
|
||||
|
||||
def test_robot_second(robot):
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
result = pytester.runpytest_subprocess("-v", "-x")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user