mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
[robotpy] Mirror most other subprojects (#8208)
GitOrigin-RevId: ac60fd3cf4a24023184376687da28373d14b781a This mirrors the robotpy files for the following projects: - apriltag - datalog - hal - ntcore - romiVendordep - wpilibc - wpimath - xrpVendordep This excludes cscore and the halsim wrappers for at this time. NOTE: This does not hook these projects up to the build system, just simply mirrors the files. The building will take place in a follow up PR to make it easier to review the changes necessary to build.
This commit is contained in:
31
wpilibc/src/test/python/conftest.py
Normal file
31
wpilibc/src/test/python/conftest.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
import ntcore
|
||||
import wpilib
|
||||
from wpilib.simulation._simulation import _resetWpilibSimulationData
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cfg_logging(caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def wpilib_state():
|
||||
try:
|
||||
yield None
|
||||
finally:
|
||||
_resetWpilibSimulationData()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nt(cfg_logging, wpilib_state):
|
||||
instance = ntcore.NetworkTableInstance.getDefault()
|
||||
instance.startLocal()
|
||||
|
||||
try:
|
||||
yield instance
|
||||
finally:
|
||||
instance.stopLocal()
|
||||
instance._reset()
|
||||
223
wpilibc/src/test/python/test_alert.py
Normal file
223
wpilibc/src/test/python/test_alert.py
Normal file
@@ -0,0 +1,223 @@
|
||||
import typing as T
|
||||
|
||||
import pytest
|
||||
|
||||
from ntcore import NetworkTableInstance
|
||||
from wpilib import Alert, SmartDashboard
|
||||
from wpilib.simulation import pauseTiming, resumeTiming, stepTiming
|
||||
|
||||
AlertType = Alert.AlertType
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def group_name(nt, request):
|
||||
|
||||
group_name = f"AlertTest_{request.node.name}"
|
||||
yield group_name
|
||||
|
||||
SmartDashboard.updateValues()
|
||||
assert len(get_active_alerts(nt, group_name, AlertType.kError)) == 0
|
||||
assert len(get_active_alerts(nt, group_name, AlertType.kWarning)) == 0
|
||||
assert len(get_active_alerts(nt, group_name, AlertType.kInfo)) == 0
|
||||
|
||||
|
||||
def get_subscriber_for_type(
|
||||
nt: NetworkTableInstance, group_name: str, alert_type: AlertType
|
||||
):
|
||||
subtable_name = {
|
||||
AlertType.kError: "errors",
|
||||
AlertType.kWarning: "warnings",
|
||||
AlertType.kInfo: "infos",
|
||||
}.get(alert_type, "unknown")
|
||||
topic = f"/SmartDashboard/{group_name}/{subtable_name}"
|
||||
return nt.getStringArrayTopic(topic).subscribe([])
|
||||
|
||||
|
||||
def get_active_alerts(
|
||||
nt: NetworkTableInstance, group_name: str, alert_type: AlertType
|
||||
) -> T.List[str]:
|
||||
SmartDashboard.updateValues()
|
||||
with get_subscriber_for_type(nt, group_name, alert_type) as sub:
|
||||
return sub.get()
|
||||
|
||||
|
||||
def is_alert_active(
|
||||
nt: NetworkTableInstance, group_name: str, text: str, alert_type: AlertType
|
||||
):
|
||||
active_alerts = get_active_alerts(nt, group_name, alert_type)
|
||||
return text in active_alerts
|
||||
|
||||
|
||||
def assert_state(
|
||||
nt: NetworkTableInstance,
|
||||
group_name: str,
|
||||
alert_type: AlertType,
|
||||
expected_state: T.List[str],
|
||||
):
|
||||
assert expected_state == get_active_alerts(nt, group_name, alert_type)
|
||||
|
||||
|
||||
def test_set_unset_single(nt, group_name):
|
||||
with Alert(group_name, "one", AlertType.kError) as one:
|
||||
|
||||
assert not is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
assert not is_alert_active(nt, group_name, "two", AlertType.kInfo)
|
||||
|
||||
one.set(True)
|
||||
assert is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
|
||||
one.set(True)
|
||||
assert is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
|
||||
one.set(False)
|
||||
assert not is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
|
||||
|
||||
def test_set_unset_multiple(nt, group_name):
|
||||
with (
|
||||
Alert(group_name, "one", AlertType.kError) as one,
|
||||
Alert(group_name, "two", AlertType.kInfo) as two,
|
||||
):
|
||||
|
||||
assert not is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
assert not is_alert_active(nt, group_name, "two", AlertType.kInfo)
|
||||
|
||||
one.set(True)
|
||||
assert is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
assert not is_alert_active(nt, group_name, "two", AlertType.kInfo)
|
||||
|
||||
one.set(True)
|
||||
two.set(True)
|
||||
assert is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
assert is_alert_active(nt, group_name, "two", AlertType.kInfo)
|
||||
|
||||
one.set(False)
|
||||
assert not is_alert_active(nt, group_name, "one", AlertType.kError)
|
||||
assert is_alert_active(nt, group_name, "two", AlertType.kInfo)
|
||||
|
||||
|
||||
def test_set_is_idempotent(nt, group_name):
|
||||
group_name = group_name
|
||||
with (
|
||||
Alert(group_name, "A", AlertType.kInfo) as a,
|
||||
Alert(group_name, "B", AlertType.kInfo) as b,
|
||||
Alert(group_name, "C", AlertType.kInfo) as c,
|
||||
):
|
||||
|
||||
a.set(True)
|
||||
b.set(True)
|
||||
c.set(True)
|
||||
|
||||
start_state = get_active_alerts(nt, group_name, AlertType.kInfo)
|
||||
assert set(start_state) == {"A", "B", "C"}
|
||||
|
||||
b.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, start_state)
|
||||
|
||||
a.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, start_state)
|
||||
|
||||
|
||||
def test_close_unsets_alert(nt, group_name):
|
||||
group_name = group_name
|
||||
with Alert(group_name, "alert", AlertType.kWarning) as alert:
|
||||
alert.set(True)
|
||||
assert is_alert_active(nt, group_name, "alert", AlertType.kWarning)
|
||||
assert not is_alert_active(nt, group_name, "alert", AlertType.kWarning)
|
||||
|
||||
|
||||
def test_set_text_while_unset(nt, group_name):
|
||||
group_name = group_name
|
||||
with Alert(group_name, "BEFORE", AlertType.kInfo) as alert:
|
||||
assert alert.getText() == "BEFORE"
|
||||
alert.set(True)
|
||||
assert is_alert_active(nt, group_name, "BEFORE", AlertType.kInfo)
|
||||
alert.set(False)
|
||||
assert not is_alert_active(nt, group_name, "BEFORE", AlertType.kInfo)
|
||||
alert.setText("AFTER")
|
||||
assert alert.getText() == "AFTER"
|
||||
alert.set(True)
|
||||
assert not is_alert_active(nt, group_name, "BEFORE", AlertType.kInfo)
|
||||
assert is_alert_active(nt, group_name, "AFTER", AlertType.kInfo)
|
||||
|
||||
|
||||
def test_set_text_while_set(nt, group_name):
|
||||
with Alert(group_name, "BEFORE", AlertType.kInfo) as alert:
|
||||
assert alert.getText() == "BEFORE"
|
||||
alert.set(True)
|
||||
assert is_alert_active(nt, group_name, "BEFORE", AlertType.kInfo)
|
||||
alert.setText("AFTER")
|
||||
assert alert.getText() == "AFTER"
|
||||
assert not is_alert_active(nt, group_name, "BEFORE", AlertType.kInfo)
|
||||
assert is_alert_active(nt, group_name, "AFTER", AlertType.kInfo)
|
||||
|
||||
|
||||
def test_set_text_does_not_affect_sort(nt, group_name):
|
||||
pauseTiming()
|
||||
try:
|
||||
with (
|
||||
Alert(group_name, "A", AlertType.kInfo) as a,
|
||||
Alert(group_name, "B", AlertType.kInfo) as b,
|
||||
Alert(group_name, "C", AlertType.kInfo) as c,
|
||||
):
|
||||
|
||||
a.set(True)
|
||||
stepTiming(1)
|
||||
b.set(True)
|
||||
stepTiming(1)
|
||||
c.set(True)
|
||||
|
||||
expected_state = get_active_alerts(nt, group_name, AlertType.kInfo)
|
||||
expected_state[expected_state.index("B")] = "AFTER"
|
||||
|
||||
b.setText("AFTER")
|
||||
assert_state(nt, group_name, AlertType.kInfo, expected_state)
|
||||
finally:
|
||||
resumeTiming()
|
||||
|
||||
|
||||
def test_sort_order(nt, group_name):
|
||||
pauseTiming()
|
||||
try:
|
||||
with (
|
||||
Alert(group_name, "A", AlertType.kInfo) as a,
|
||||
Alert(group_name, "B", AlertType.kInfo) as b,
|
||||
Alert(group_name, "C", AlertType.kInfo) as c,
|
||||
):
|
||||
|
||||
a.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["A"])
|
||||
|
||||
stepTiming(1)
|
||||
b.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["B", "A"])
|
||||
|
||||
stepTiming(1)
|
||||
c.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["C", "B", "A"])
|
||||
|
||||
stepTiming(1)
|
||||
c.set(False)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["B", "A"])
|
||||
|
||||
stepTiming(1)
|
||||
c.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["C", "B", "A"])
|
||||
|
||||
stepTiming(1)
|
||||
a.set(False)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["C", "B"])
|
||||
|
||||
stepTiming(1)
|
||||
b.set(False)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["C"])
|
||||
|
||||
stepTiming(1)
|
||||
b.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["B", "C"])
|
||||
|
||||
stepTiming(1)
|
||||
a.set(True)
|
||||
assert_state(nt, group_name, AlertType.kInfo, ["A", "B", "C"])
|
||||
finally:
|
||||
resumeTiming()
|
||||
13
wpilibc/src/test/python/test_datalogmanager.py
Normal file
13
wpilibc/src/test/python/test_datalogmanager.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import pathlib
|
||||
import wpilib
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "darwin", reason="DataLogManager crashes on exit")
|
||||
def test_get_log(tmp_path: pathlib.Path):
|
||||
log_dir = tmp_path / "wpilogs"
|
||||
log_dir.mkdir()
|
||||
wpilib.DataLogManager.start(str(log_dir))
|
||||
log = wpilib.DataLogManager.getLog()
|
||||
assert log is not None
|
||||
144
wpilibc/src/test/python/test_joystick.py
Normal file
144
wpilibc/src/test/python/test_joystick.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import math
|
||||
|
||||
from wpilib import Joystick
|
||||
from wpilib.simulation import JoystickSim
|
||||
|
||||
|
||||
def test_getX() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setX(0.25)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getX(), 0.25)
|
||||
|
||||
joysim.setX(0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getX(), 0.0)
|
||||
|
||||
|
||||
def test_getY() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setY(0.25)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getY(), 0.25)
|
||||
|
||||
joysim.setY(0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getY(), 0.0)
|
||||
|
||||
|
||||
def test_getZ() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setZ(0.25)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getZ(), 0.25)
|
||||
|
||||
joysim.setZ(0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getZ(), 0.0)
|
||||
|
||||
|
||||
def test_getTwist() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setTwist(0.25)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getTwist(), 0.25)
|
||||
|
||||
joysim.setTwist(0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getTwist(), 0.0)
|
||||
|
||||
|
||||
def test_getThrottle() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setThrottle(0.25)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getThrottle(), 0.25)
|
||||
|
||||
joysim.setThrottle(0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getThrottle(), 0.0)
|
||||
|
||||
|
||||
def test_getTrigger() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setTrigger(True)
|
||||
joysim.notifyNewData()
|
||||
assert joy.getTrigger()
|
||||
|
||||
joysim.setTrigger(False)
|
||||
joysim.notifyNewData()
|
||||
assert not joy.getTrigger()
|
||||
|
||||
|
||||
def test_getTop() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
joysim.setTop(True)
|
||||
joysim.notifyNewData()
|
||||
assert joy.getTop()
|
||||
|
||||
joysim.setTop(False)
|
||||
joysim.notifyNewData()
|
||||
assert not joy.getTop()
|
||||
|
||||
|
||||
def test_getMagnitude() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
# X Only
|
||||
joysim.setX(0.5)
|
||||
joysim.setY(0.0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getMagnitude(), 0.5)
|
||||
|
||||
# Y Only
|
||||
joysim.setX(0.0)
|
||||
joysim.setY(-0.5)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getMagnitude(), 0.5)
|
||||
|
||||
# Both
|
||||
joysim.setX(0.5)
|
||||
joysim.setY(-0.5)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getMagnitude(), 0.70710678118)
|
||||
|
||||
|
||||
def test_getDirection() -> None:
|
||||
joy = Joystick(1)
|
||||
joysim = JoystickSim(joy)
|
||||
|
||||
# X Only
|
||||
joysim.setX(0.5)
|
||||
joysim.setY(0.0)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getDirectionDegrees(), 90)
|
||||
assert math.isclose(joy.getDirectionRadians(), math.radians(90))
|
||||
|
||||
# Y Only
|
||||
joysim.setX(0.0)
|
||||
joysim.setY(-0.5)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getDirectionDegrees(), 0)
|
||||
assert math.isclose(joy.getDirectionRadians(), math.radians(0))
|
||||
|
||||
# Both
|
||||
joysim.setX(0.5)
|
||||
joysim.setY(-0.5)
|
||||
joysim.notifyNewData()
|
||||
assert math.isclose(joy.getDirectionDegrees(), 45)
|
||||
assert math.isclose(joy.getDirectionRadians(), math.radians(45))
|
||||
11
wpilibc/src/test/python/test_mechanism2d.py
Normal file
11
wpilibc/src/test/python/test_mechanism2d.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from wpilib import Mechanism2d
|
||||
|
||||
|
||||
def test_create_mechanism():
|
||||
m = Mechanism2d(100, 100)
|
||||
r1 = m.getRoot("r1", 10, 10)
|
||||
l1 = r1.appendLigament("l1", 4, 3)
|
||||
l2 = l1.appendLigament("l2", 4, 3)
|
||||
assert l2 is not None
|
||||
|
||||
# TODO... check that they do something?
|
||||
62
wpilibc/src/test/python/test_notifier.py
Normal file
62
wpilibc/src/test/python/test_notifier.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# 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.
|
||||
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
|
||||
from wpilib import Notifier
|
||||
from wpilib.simulation import pauseTiming, restartTiming, resumeTiming, stepTiming
|
||||
|
||||
# These tests fail because of race conditions in simulation
|
||||
if False:
|
||||
|
||||
class AtomicInteger:
|
||||
def __init__(self) -> None:
|
||||
self.lock = threading.Lock()
|
||||
self.val = 0
|
||||
|
||||
def get(self) -> int:
|
||||
with self.lock:
|
||||
return self.val
|
||||
|
||||
def getAndIncrement(self) -> int:
|
||||
with self.lock:
|
||||
val = self.val
|
||||
self.val += 1
|
||||
return val
|
||||
|
||||
@pytest.fixture
|
||||
def counter():
|
||||
return AtomicInteger()
|
||||
|
||||
@pytest.fixture
|
||||
def notifier(counter):
|
||||
pauseTiming()
|
||||
restartTiming()
|
||||
n = Notifier(counter.getAndIncrement)
|
||||
yield n
|
||||
del n
|
||||
resumeTiming()
|
||||
|
||||
@pytest.mark.xfail(strict=False)
|
||||
def test_testStartPeriodicAndStop(counter: AtomicInteger, notifier: Notifier):
|
||||
notifier.startPeriodic(1.0)
|
||||
|
||||
stepTiming(10)
|
||||
|
||||
notifier.stop()
|
||||
assert counter.get() == 10
|
||||
|
||||
stepTiming(3)
|
||||
|
||||
assert counter.get() == 10
|
||||
|
||||
@pytest.mark.xfail(strict=False)
|
||||
def test_testStartSingle(counter, notifier):
|
||||
notifier.startSingle(1.0)
|
||||
|
||||
stepTiming(10)
|
||||
|
||||
assert counter.get() == 1
|
||||
55
wpilibc/src/test/python/test_sendable_chooser.py
Normal file
55
wpilibc/src/test/python/test_sendable_chooser.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import pytest
|
||||
|
||||
from ntcore import NetworkTableInstance
|
||||
from wpilib import SendableChooser, SmartDashboard
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def chooser() -> SendableChooser:
|
||||
chooser = SendableChooser()
|
||||
for i in range(1, 4):
|
||||
chooser.addOption(str(i), i)
|
||||
return chooser
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [0, 1, 2, 3])
|
||||
def test_returns_selected(
|
||||
nt: NetworkTableInstance, chooser: SendableChooser, value: int
|
||||
):
|
||||
chooser.setDefaultOption("0", 0)
|
||||
|
||||
with nt.getStringTopic(
|
||||
"/SmartDashboard/ReturnsSelectedChooser/selected"
|
||||
).publish() as pub:
|
||||
SmartDashboard.putData("ReturnsSelectedChooser", chooser)
|
||||
SmartDashboard.updateValues()
|
||||
print("set", value)
|
||||
pub.set(str(value))
|
||||
SmartDashboard.updateValues()
|
||||
print("get", chooser.getSelected())
|
||||
assert value == chooser.getSelected()
|
||||
|
||||
|
||||
def test_default_is_returned_on_no_select(chooser: SendableChooser):
|
||||
chooser.setDefaultOption("4", 4)
|
||||
assert 4 == chooser.getSelected()
|
||||
|
||||
|
||||
def test_default_constructable_is_returned_on_no_select_and_no_default(
|
||||
chooser: SendableChooser,
|
||||
):
|
||||
assert chooser.getSelected() is None
|
||||
|
||||
|
||||
def test_change_listener(nt: NetworkTableInstance, chooser: SendableChooser):
|
||||
current_val = [0]
|
||||
|
||||
def on_change(val):
|
||||
current_val[0] = val
|
||||
|
||||
chooser.onChange(on_change)
|
||||
SmartDashboard.putData("ChangeListenerChooser", chooser)
|
||||
SmartDashboard.updateValues()
|
||||
SmartDashboard.putString("ChangeListenerChooser/selected", "3")
|
||||
SmartDashboard.updateValues()
|
||||
assert 3 == current_val[0]
|
||||
43
wpilibc/src/test/python/test_wpilib.py
Normal file
43
wpilibc/src/test/python/test_wpilib.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import pytest
|
||||
import re
|
||||
import weakref
|
||||
|
||||
import wpilib
|
||||
|
||||
|
||||
def test_sendable_chooser():
|
||||
chooser = wpilib.SendableChooser()
|
||||
assert chooser.getSelected() is None
|
||||
|
||||
chooser.setDefaultOption("option", True)
|
||||
assert chooser.getSelected() is True
|
||||
|
||||
|
||||
def test_smart_dashboard_putdata():
|
||||
t = wpilib.Talon(4)
|
||||
ref = weakref.ref(t)
|
||||
wpilib.SmartDashboard.putData("talon", t)
|
||||
del t
|
||||
assert bool(ref) is True
|
||||
assert wpilib.SmartDashboard.getData("talon") is ref()
|
||||
|
||||
|
||||
def test_motorcontrollergroup():
|
||||
t1 = wpilib.Talon(7)
|
||||
t2 = wpilib.Talon(8)
|
||||
g = wpilib.MotorControllerGroup(t1, t2)
|
||||
|
||||
g.set(1)
|
||||
assert t1.get() == pytest.approx(1)
|
||||
assert t2.get() == pytest.approx(1)
|
||||
|
||||
g.set(-1)
|
||||
assert t1.get() == pytest.approx(-1)
|
||||
assert t2.get() == pytest.approx(-1)
|
||||
|
||||
|
||||
def test_motorcontrollergroup_error():
|
||||
with pytest.raises(
|
||||
TypeError, match=re.escape("Argument 1 must be a MotorController (got '1')")
|
||||
):
|
||||
wpilib.MotorControllerGroup(1)
|
||||
5
wpilibc/src/test/python/test_wpilib_drive.py
Normal file
5
wpilibc/src/test/python/test_wpilib_drive.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import wpilib.drive
|
||||
|
||||
|
||||
def test_wpilib_drive():
|
||||
pass
|
||||
5
wpilibc/src/test/python/test_wpilib_interfaces.py
Normal file
5
wpilibc/src/test/python/test_wpilib_interfaces.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import wpilib.interfaces
|
||||
|
||||
|
||||
def test_wpilib_interfaces():
|
||||
pass
|
||||
5
wpilibc/src/test/python/test_wpilib_simulation.py
Normal file
5
wpilibc/src/test/python/test_wpilib_simulation.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import wpilib.simulation
|
||||
|
||||
|
||||
def test_wpilib_simulation():
|
||||
pass
|
||||
Reference in New Issue
Block a user