diff --git a/pyproject.toml b/pyproject.toml index 5b0697d67b..0a6ea57fd3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ flake8-implicit-str-concat.allow-multiline=false [tool.ruff.lint.flake8-tidy-imports.banned-api] "pytest.main".msg = "pytest.main requires special handling that is easy to mess up!" +"unittest".msg = "Use pytest" [tool.pytest.ini_options] addopts = "-n auto --ignore-glob='*.sh'" diff --git a/setup.py b/setup.py index a7729cc6f8..76fa6100c5 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,8 @@ def find_version(*file_paths): "pytest-xdist", "pytest-timeout", "pytest-randomly", + "pytest-subtests", + "pytest-order", "parameterized", "pre-commit", "numpy", diff --git a/tests/safety/common.py b/tests/safety/common.py index 884f21a360..8f872e2498 100644 --- a/tests/safety/common.py +++ b/tests/safety/common.py @@ -1,6 +1,6 @@ +import pytest import os import abc -import unittest import importlib import numpy as np from collections.abc import Callable @@ -46,7 +46,7 @@ def _make_regen_test(brake_func): def _regen_test(self): # only for safety modes with a regen message if self._user_regen_msg(0) is None: - raise unittest.SkipTest("Safety mode implements no _user_regen_msg") + raise pytest.skip("Safety mode implements no _user_regen_msg") getattr(self, brake_func)(self._user_regen_msg, self.safety.get_regen_braking_prev) return _regen_test @@ -56,14 +56,14 @@ def _regen_test(self): return cls -class PandaSafetyTestBase(unittest.TestCase): +class PandaSafetyTestBase: safety: libpanda_py.Panda @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "PandaSafetyTestBase": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _reset_safety_hooks(self): self.safety.set_safety_hooks(self.safety.get_current_safety_mode(), @@ -87,8 +87,8 @@ def _generic_limit_safety_check(self, msg_function: MessageFunction, min_allowed """ # Ensure that we at least test the allowed_value range - self.assertGreater(max_possible_value, max_allowed_value) - self.assertLessEqual(min_possible_value, min_allowed_value) + assert max_possible_value > max_allowed_value + assert min_possible_value <= min_allowed_value for controls_allowed in [False, True]: # enforce we don't skip over 0 or inactive @@ -99,23 +99,23 @@ def _generic_limit_safety_check(self, msg_function: MessageFunction, min_allowed additional_setup(v) should_tx = controls_allowed and min_allowed_value <= v <= max_allowed_value should_tx = (should_tx or v == inactive_value) and msg_allowed - self.assertEqual(self._tx(msg_function(v)), should_tx, (controls_allowed, should_tx, v)) + assert self._tx(msg_function(v)) == should_tx, (controls_allowed, should_tx, v) def _common_measurement_test(self, msg_func: Callable, min_value: float, max_value: float, factor: float, meas_min_func: Callable[[], int], meas_max_func: Callable[[], int]): """Tests accurate measurement parsing, and that the struct is reset on safety mode init""" for val in np.arange(min_value, max_value, 0.5): for i in range(MAX_SAMPLE_VALS): - self.assertTrue(self._rx(msg_func(val + i * 0.1))) + assert self._rx(msg_func(val + i * 0.1)) # assert close by one decimal place - self.assertAlmostEqual(meas_min_func() / factor, val, delta=0.1) - self.assertAlmostEqual(meas_max_func() / factor - 0.5, val, delta=0.1) + assert meas_min_func() / factor == pytest.approx(val, abs=0.1) + assert meas_max_func() / factor - 0.5 == pytest.approx(val, abs=0.1) # ensure sample_t is reset on safety init self._reset_safety_hooks() - self.assertEqual(meas_min_func(), 0) - self.assertEqual(meas_max_func(), 0) + assert meas_min_func() == 0 + assert meas_max_func() == 0 class LongitudinalAccelSafetyTest(PandaSafetyTestBase, abc.ABC): @@ -125,18 +125,18 @@ class LongitudinalAccelSafetyTest(PandaSafetyTestBase, abc.ABC): INACTIVE_ACCEL: float = 0.0 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "LongitudinalAccelSafetyTest": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _accel_msg(self, accel: float): pass def test_accel_limits_correct(self): - self.assertGreater(self.MAX_ACCEL, 0) - self.assertLess(self.MIN_ACCEL, 0) + assert self.MAX_ACCEL > 0 + assert self.MIN_ACCEL < 0 def test_accel_actuation_limits(self, stock_longitudinal=False): limits = ((self.MIN_ACCEL, self.MAX_ACCEL, ALTERNATIVE_EXPERIENCE.DEFAULT), @@ -154,7 +154,7 @@ def test_accel_actuation_limits(self, stock_longitudinal=False): else: should_tx = controls_allowed and min_accel <= accel <= max_accel should_tx = should_tx or accel == self.INACTIVE_ACCEL - self.assertEqual(should_tx, self._tx(self._accel_msg(accel))) + assert should_tx == self._tx(self._accel_msg(accel)) class LongitudinalGasBrakeSafetyTest(PandaSafetyTestBase, abc.ABC): @@ -169,11 +169,11 @@ class LongitudinalGasBrakeSafetyTest(PandaSafetyTestBase, abc.ABC): MAX_POSSIBLE_GAS: int | None = None def test_gas_brake_limits_correct(self): - self.assertIsNotNone(self.MAX_POSSIBLE_BRAKE) - self.assertIsNotNone(self.MAX_POSSIBLE_GAS) + assert self.MAX_POSSIBLE_BRAKE is not None + assert self.MAX_POSSIBLE_GAS is not None - self.assertGreater(self.MAX_BRAKE, self.MIN_BRAKE) - self.assertGreater(self.MAX_GAS, self.MIN_GAS) + assert self.MAX_BRAKE > self.MIN_BRAKE + assert self.MAX_GAS > self.MIN_GAS @abc.abstractmethod def _send_gas_msg(self, gas: int): @@ -201,10 +201,10 @@ class TorqueSteeringSafetyTestBase(PandaSafetyTestBase, abc.ABC): NO_STEER_REQ_BIT = False @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TorqueSteeringSafetyTestBase": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _torque_cmd_msg(self, torque, steer_req=1): @@ -220,48 +220,48 @@ def test_steer_safety_check(self): self.safety.set_controls_allowed(enabled) self._set_prev_torque(t) if abs(t) > self.MAX_TORQUE or (not enabled and abs(t) > 0): - self.assertFalse(self._tx(self._torque_cmd_msg(t))) + assert not self._tx(self._torque_cmd_msg(t)) else: - self.assertTrue(self._tx(self._torque_cmd_msg(t))) + assert self._tx(self._torque_cmd_msg(t)) def test_non_realtime_limit_up(self): self.safety.set_controls_allowed(True) self._set_prev_torque(0) - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP))) + assert self._tx(self._torque_cmd_msg(self.MAX_RATE_UP)) self._set_prev_torque(0) - self.assertTrue(self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP))) + assert self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP)) self._set_prev_torque(0) - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP + 1))) + assert not self._tx(self._torque_cmd_msg(self.MAX_RATE_UP + 1)) self.safety.set_controls_allowed(True) self._set_prev_torque(0) - self.assertFalse(self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP - 1))) + assert not self._tx(self._torque_cmd_msg(-self.MAX_RATE_UP - 1)) def test_steer_req_bit(self): """Asserts all torque safety modes check the steering request bit""" if self.NO_STEER_REQ_BIT: - raise unittest.SkipTest("No steering request bit") + raise pytest.skip("No steering request bit") self.safety.set_controls_allowed(True) self._set_prev_torque(self.MAX_TORQUE) # Send torque successfully, then only drop the request bit and ensure it stays blocked for _ in range(10): - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 1)) - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 0))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 0)) for _ in range(10): - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 1))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE, 1)) class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC): @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "SteerRequestCutSafetyTest": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() # Safety around steering request bit mismatch tolerance MIN_VALID_STEERING_FRAMES: int @@ -286,22 +286,22 @@ def test_steer_req_bit_frames(self): self.safety.set_controls_allowed(True) self._set_prev_torque(self.MAX_TORQUE) for _ in range(min_valid_steer_frames): - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) # should tx if we've sent enough valid frames, and we're not cutting torque for too many frames consecutively should_tx = min_valid_steer_frames >= self.MIN_VALID_STEERING_FRAMES for idx in range(self.MAX_INVALID_STEERING_FRAMES * 2): tx = self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) - self.assertEqual(should_tx and idx < self.MAX_INVALID_STEERING_FRAMES, tx) + assert (should_tx and idx < self.MAX_INVALID_STEERING_FRAMES) == tx # Keep blocking after one steer_req mismatch for _ in range(100): - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) # Make sure we can recover - self.assertTrue(self._tx(self._torque_cmd_msg(0, steer_req=1))) + assert self._tx(self._torque_cmd_msg(0, steer_req=1)) self._set_prev_torque(self.MAX_TORQUE) - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) def test_steer_req_bit_multi_invalid(self): """ @@ -317,18 +317,18 @@ def test_steer_req_bit_multi_invalid(self): self.safety.set_controls_allowed(True) self._set_prev_torque(self.MAX_TORQUE) for _ in range(self.MIN_VALID_STEERING_FRAMES): - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) # Send partial amount of allowed invalid frames for idx in range(max_invalid_steer_frames): should_tx = idx < self.MAX_INVALID_STEERING_FRAMES - self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0))) + assert should_tx == self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) # Send one valid frame, and subsequent invalid should now be blocked self._set_prev_torque(self.MAX_TORQUE) - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) for _ in range(self.MIN_VALID_STEERING_FRAMES + 1): - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) def test_steer_req_bit_realtime(self): """ @@ -344,22 +344,22 @@ def test_steer_req_bit_realtime(self): self.safety.set_controls_allowed(True) self._set_prev_torque(self.MAX_TORQUE) for _ in range(self.MIN_VALID_STEERING_FRAMES): - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) # Normally, sending MIN_VALID_STEERING_FRAMES valid frames should always allow self.safety.set_timer(max(rt_us, 0)) should_tx = rt_us >= self.MIN_VALID_STEERING_RT_INTERVAL for _ in range(self.MAX_INVALID_STEERING_FRAMES): - self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0))) + assert should_tx == self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) # Keep blocking after one steer_req mismatch for _ in range(100): - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=0)) # Make sure we can recover - self.assertTrue(self._tx(self._torque_cmd_msg(0, steer_req=1))) + assert self._tx(self._torque_cmd_msg(0, steer_req=1)) self._set_prev_torque(self.MAX_TORQUE) - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE, steer_req=1)) class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC): @@ -368,10 +368,10 @@ class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC): DRIVER_TORQUE_FACTOR = 0 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "DriverTorqueSteeringSafetyTest": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _torque_driver_msg(self, torque): @@ -395,7 +395,7 @@ def test_against_torque_driver(self): self._reset_torque_driver_measurement(-driver_torque * sign) self._set_prev_torque(self.MAX_TORQUE * sign) should_tx = abs(driver_torque) <= self.DRIVER_TORQUE_ALLOWANCE - self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(self.MAX_TORQUE * sign))) + assert should_tx == self._tx(self._torque_cmd_msg(self.MAX_TORQUE * sign)) # arbitrary high driver torque to ensure max steer torque is allowed max_driver_torque = int(self.MAX_TORQUE / self.DRIVER_TORQUE_FACTOR + self.DRIVER_TORQUE_ALLOWANCE + 1) @@ -408,21 +408,21 @@ def test_against_torque_driver(self): delta = 1 * sign self._set_prev_torque(torque_desired) self._reset_torque_driver_measurement(-driver_torque) - self.assertTrue(self._tx(self._torque_cmd_msg(torque_desired))) + assert self._tx(self._torque_cmd_msg(torque_desired)) self._set_prev_torque(torque_desired + delta) self._reset_torque_driver_measurement(-driver_torque) - self.assertFalse(self._tx(self._torque_cmd_msg(torque_desired + delta))) + assert not self._tx(self._torque_cmd_msg(torque_desired + delta)) # If we're well past the allowance, minimum wind down is MAX_RATE_DOWN self._set_prev_torque(self.MAX_TORQUE * sign) self._reset_torque_driver_measurement(-max_driver_torque * sign) - self.assertTrue(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN) * sign))) + assert self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN) * sign)) self._set_prev_torque(self.MAX_TORQUE * sign) self._reset_torque_driver_measurement(-max_driver_torque * sign) - self.assertTrue(self._tx(self._torque_cmd_msg(0))) + assert self._tx(self._torque_cmd_msg(0)) self._set_prev_torque(self.MAX_TORQUE * sign) self._reset_torque_driver_measurement(-max_driver_torque * sign) - self.assertFalse(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN + 1) * sign))) + assert not self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN + 1) * sign)) def test_realtime_limits(self): self.safety.set_controls_allowed(True) @@ -433,30 +433,30 @@ def test_realtime_limits(self): self._reset_torque_driver_measurement(0) for t in np.arange(0, self.MAX_RT_DELTA, 1): t *= sign - self.assertTrue(self._tx(self._torque_cmd_msg(t))) - self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1)))) + assert self._tx(self._torque_cmd_msg(t)) + assert not self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))) self._set_prev_torque(0) for t in np.arange(0, self.MAX_RT_DELTA, 1): t *= sign - self.assertTrue(self._tx(self._torque_cmd_msg(t))) + assert self._tx(self._torque_cmd_msg(t)) # Increase timer to update rt_torque_last self.safety.set_timer(self.RT_INTERVAL + 1) - self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA - 1)))) - self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1)))) + assert self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA - 1))) + assert self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))) def test_reset_driver_torque_measurements(self): # Tests that the driver torque measurement sample_t is reset on safety mode init for t in np.linspace(-self.MAX_TORQUE, self.MAX_TORQUE, MAX_SAMPLE_VALS): - self.assertTrue(self._rx(self._torque_driver_msg(t))) + assert self._rx(self._torque_driver_msg(t)) - self.assertNotEqual(self.safety.get_torque_driver_min(), 0) - self.assertNotEqual(self.safety.get_torque_driver_max(), 0) + assert self.safety.get_torque_driver_min() != 0 + assert self.safety.get_torque_driver_max() != 0 self._reset_safety_hooks() - self.assertEqual(self.safety.get_torque_driver_min(), 0) - self.assertEqual(self.safety.get_torque_driver_max(), 0) + assert self.safety.get_torque_driver_min() == 0 + assert self.safety.get_torque_driver_max() == 0 class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC): @@ -465,10 +465,10 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC): TORQUE_MEAS_TOLERANCE = 0 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "MotorTorqueSteeringSafetyTest": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _torque_meas_msg(self, torque): @@ -491,7 +491,7 @@ def test_torque_absolute_limits(self): else: send = torque == 0 - self.assertEqual(send, self._tx(self._torque_cmd_msg(torque))) + assert send == self._tx(self._torque_cmd_msg(torque)) def test_non_realtime_limit_down(self): self.safety.set_controls_allowed(True) @@ -501,12 +501,12 @@ def test_non_realtime_limit_down(self): self.safety.set_rt_torque_last(self.MAX_TORQUE) self.safety.set_torque_meas(torque_meas, torque_meas) self.safety.set_desired_torque_last(self.MAX_TORQUE) - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN))) + assert self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN)) self.safety.set_rt_torque_last(self.MAX_TORQUE) self.safety.set_torque_meas(torque_meas, torque_meas) self.safety.set_desired_torque_last(self.MAX_TORQUE) - self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN + 1))) + assert not self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN + 1)) def test_exceed_torque_sensor(self): self.safety.set_controls_allowed(True) @@ -515,9 +515,9 @@ def test_exceed_torque_sensor(self): self._set_prev_torque(0) for t in np.arange(0, self.MAX_TORQUE_ERROR + 2, 2): # step needs to be smaller than MAX_TORQUE_ERROR t *= sign - self.assertTrue(self._tx(self._torque_cmd_msg(t))) + assert self._tx(self._torque_cmd_msg(t)) - self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_TORQUE_ERROR + 2)))) + assert not self._tx(self._torque_cmd_msg(sign * (self.MAX_TORQUE_ERROR + 2))) def test_realtime_limit_up(self): self.safety.set_controls_allowed(True) @@ -528,19 +528,19 @@ def test_realtime_limit_up(self): for t in np.arange(0, self.MAX_RT_DELTA + 1, 1): t *= sign self.safety.set_torque_meas(t, t) - self.assertTrue(self._tx(self._torque_cmd_msg(t))) - self.assertFalse(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1)))) + assert self._tx(self._torque_cmd_msg(t)) + assert not self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))) self._set_prev_torque(0) for t in np.arange(0, self.MAX_RT_DELTA + 1, 1): t *= sign self.safety.set_torque_meas(t, t) - self.assertTrue(self._tx(self._torque_cmd_msg(t))) + assert self._tx(self._torque_cmd_msg(t)) # Increase timer to update rt_torque_last self.safety.set_timer(self.RT_INTERVAL + 1) - self.assertTrue(self._tx(self._torque_cmd_msg(sign * self.MAX_RT_DELTA))) - self.assertTrue(self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1)))) + assert self._tx(self._torque_cmd_msg(sign * self.MAX_RT_DELTA)) + assert self._tx(self._torque_cmd_msg(sign * (self.MAX_RT_DELTA + 1))) def test_torque_measurements(self): trq = 50 @@ -549,32 +549,32 @@ def test_torque_measurements(self): max_range = range(trq, trq + self.TORQUE_MEAS_TOLERANCE + 1) min_range = range(-(trq + self.TORQUE_MEAS_TOLERANCE), -trq + 1) - self.assertTrue(self.safety.get_torque_meas_min() in min_range) - self.assertTrue(self.safety.get_torque_meas_max() in max_range) + assert self.safety.get_torque_meas_min() in min_range + assert self.safety.get_torque_meas_max() in max_range max_range = range(self.TORQUE_MEAS_TOLERANCE + 1) min_range = range(-(trq + self.TORQUE_MEAS_TOLERANCE), -trq + 1) self._rx(self._torque_meas_msg(0)) - self.assertTrue(self.safety.get_torque_meas_min() in min_range) - self.assertTrue(self.safety.get_torque_meas_max() in max_range) + assert self.safety.get_torque_meas_min() in min_range + assert self.safety.get_torque_meas_max() in max_range max_range = range(self.TORQUE_MEAS_TOLERANCE + 1) min_range = range(-self.TORQUE_MEAS_TOLERANCE, 0 + 1) self._rx(self._torque_meas_msg(0)) - self.assertTrue(self.safety.get_torque_meas_min() in min_range) - self.assertTrue(self.safety.get_torque_meas_max() in max_range) + assert self.safety.get_torque_meas_min() in min_range + assert self.safety.get_torque_meas_max() in max_range def test_reset_torque_measurements(self): # Tests that the torque measurement sample_t is reset on safety mode init for t in np.linspace(-self.MAX_TORQUE, self.MAX_TORQUE, MAX_SAMPLE_VALS): - self.assertTrue(self._rx(self._torque_meas_msg(t))) + assert self._rx(self._torque_meas_msg(t)) - self.assertNotEqual(self.safety.get_torque_meas_min(), 0) - self.assertNotEqual(self.safety.get_torque_meas_max(), 0) + assert self.safety.get_torque_meas_min() != 0 + assert self.safety.get_torque_meas_max() != 0 self._reset_safety_hooks() - self.assertEqual(self.safety.get_torque_meas_min(), 0) - self.assertEqual(self.safety.get_torque_meas_max(), 0) + assert self.safety.get_torque_meas_min() == 0 + assert self.safety.get_torque_meas_max() == 0 class AngleSteeringSafetyTest(PandaSafetyTestBase): @@ -585,10 +585,10 @@ class AngleSteeringSafetyTest(PandaSafetyTestBase): ANGLE_RATE_DOWN: list[float] # unwind limit @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "AngleSteeringSafetyTest": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _speed_msg(self, speed): @@ -638,34 +638,34 @@ def test_angle_cmd_when_enabled(self, max_angle=300): # Stay within limits # Up - self.assertTrue(self._tx(self._angle_cmd_msg(a + sign_of(a) * max_delta_up, True))) - self.assertTrue(self.safety.get_controls_allowed()) + assert self._tx(self._angle_cmd_msg(a + sign_of(a) * max_delta_up, True)) + assert self.safety.get_controls_allowed() # Don't change - self.assertTrue(self._tx(self._angle_cmd_msg(a, True))) - self.assertTrue(self.safety.get_controls_allowed()) + assert self._tx(self._angle_cmd_msg(a, True)) + assert self.safety.get_controls_allowed() # Down - self.assertTrue(self._tx(self._angle_cmd_msg(a - sign_of(a) * max_delta_down, True))) - self.assertTrue(self.safety.get_controls_allowed()) + assert self._tx(self._angle_cmd_msg(a - sign_of(a) * max_delta_down, True)) + assert self.safety.get_controls_allowed() # Inject too high rates # Up - self.assertFalse(self._tx(self._angle_cmd_msg(a + sign_of(a) * (max_delta_up + 1.1), True))) + assert not self._tx(self._angle_cmd_msg(a + sign_of(a) * (max_delta_up + 1.1), True)) # Don't change self.safety.set_controls_allowed(1) self._set_prev_desired_angle(a) - self.assertTrue(self.safety.get_controls_allowed()) - self.assertTrue(self._tx(self._angle_cmd_msg(a, True))) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() + assert self._tx(self._angle_cmd_msg(a, True)) + assert self.safety.get_controls_allowed() # Down - self.assertFalse(self._tx(self._angle_cmd_msg(a - sign_of(a) * (max_delta_down + 1.1), True))) + assert not self._tx(self._angle_cmd_msg(a - sign_of(a) * (max_delta_down + 1.1), True)) # Check desired steer should be the same as steer angle when controls are off self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._angle_cmd_msg(a, False))) + assert self._tx(self._angle_cmd_msg(a, False)) def test_angle_cmd_when_disabled(self): # Tests that only angles close to the meas are allowed while @@ -682,7 +682,7 @@ def test_angle_cmd_when_disabled(self): # controls_allowed is checked if actuation bit is 1, else the angle must be close to meas (inactive) should_tx = controls_allowed if steer_control_enabled else angle_cmd == angle_meas - self.assertEqual(should_tx, self._tx(self._angle_cmd_msg(angle_cmd, steer_control_enabled))) + assert should_tx == self._tx(self._angle_cmd_msg(angle_cmd, steer_control_enabled)) class PandaSafetyTest(PandaSafetyTestBase): @@ -695,10 +695,10 @@ class PandaSafetyTest(PandaSafetyTestBase): FWD_BUS_LOOKUP: dict[int, int] = {} @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "PandaSafetyTest" or cls.__name__.endswith('Base'): cls.safety = None - raise unittest.SkipTest + raise pytest.skip() # ***** standard tests for all safety modes ***** @@ -708,7 +708,7 @@ def test_tx_msg_in_scanned_range(self): # make sure SCANNED_ADDRS stays up to date with car port TX_MSGS; new # model ports should expand the range if needed for msg in self.TX_MSGS: - self.assertTrue(msg[0] in self.SCANNED_ADDRS, f"{msg[0]=:#x}") + assert msg[0] in self.SCANNED_ADDRS, f"{msg[0]=:#x}" def test_fwd_hook(self): # some safety modes don't forward anything, while others blacklist msgs @@ -718,22 +718,22 @@ def test_fwd_hook(self): fwd_bus = self.FWD_BUS_LOOKUP.get(bus, -1) if bus in self.FWD_BLACKLISTED_ADDRS and addr in self.FWD_BLACKLISTED_ADDRS[bus]: fwd_bus = -1 - self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(bus, addr), f"{addr=:#x} from {bus=} to {fwd_bus=}") + assert fwd_bus == self.safety.safety_fwd_hook(bus, addr), f"{addr=:#x} from {bus=} to {fwd_bus=}" def test_spam_can_buses(self): for bus in range(4): for addr in self.SCANNED_ADDRS: if [addr, bus] not in self.TX_MSGS: - self.assertFalse(self._tx(make_msg(bus, addr, 8)), f"allowed TX {addr=} {bus=}") + assert not self._tx(make_msg(bus, addr, 8)), f"allowed TX {addr=} {bus=}" def test_default_controls_not_allowed(self): - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_manually_enable_controls_allowed(self): self.safety.set_controls_allowed(1) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() self.safety.set_controls_allowed(0) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_tx_hook_on_wrong_safety_mode(self): files = os.listdir(os.path.dirname(os.path.realpath(__file__))) @@ -795,7 +795,7 @@ def test_tx_hook_on_wrong_safety_mode(self): all_tx.append([[m[0], m[1], attr] for m in tx]) # make sure we got all the msgs - self.assertTrue(len(all_tx) >= len(test_files)-1) + assert len(all_tx) >= len(test_files)-1 for tx_msgs in all_tx: for addr, bus, test_name in tx_msgs: @@ -804,7 +804,7 @@ def test_tx_hook_on_wrong_safety_mode(self): # TODO: this should be blocked if current_test in ["TestNissanSafety", "TestNissanSafetyAltEpsBus", "TestNissanLeafSafety"] and [addr, bus] in self.TX_MSGS: continue - self.assertFalse(self._tx(msg), f"transmit of {addr=:#x} {bus=} from {test_name} during {current_test} was allowed") + assert not self._tx(msg), f"transmit of {addr=:#x} {bus=} from {test_name} during {current_test} was allowed" @add_regen_tests @@ -814,10 +814,10 @@ class PandaCarSafetyTest(PandaSafetyTest): RELAY_MALFUNCTION_ADDRS: dict[int, tuple[int, ...]] | None = None @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "PandaCarSafetyTest" or cls.__name__.endswith('Base'): cls.safety = None - raise unittest.SkipTest + raise pytest.skip() @abc.abstractmethod def _user_brake_msg(self, brake): @@ -848,40 +848,40 @@ def test_relay_malfunction(self): # each car has an addr that is used to detect relay malfunction # if that addr is seen on specified bus, triggers the relay malfunction # protection logic: both tx_hook and fwd_hook are expected to return failure - self.assertFalse(self.safety.get_relay_malfunction()) + assert not self.safety.get_relay_malfunction() for bus in range(3): for addr in self.SCANNED_ADDRS: self.safety.set_relay_malfunction(False) self._rx(make_msg(bus, addr, 8)) should_relay_malfunction = addr in self.RELAY_MALFUNCTION_ADDRS.get(bus, ()) - self.assertEqual(should_relay_malfunction, self.safety.get_relay_malfunction(), (bus, addr)) + assert should_relay_malfunction == self.safety.get_relay_malfunction(), (bus, addr) # test relay malfunction protection logic self.safety.set_relay_malfunction(True) for bus in range(3): for addr in self.SCANNED_ADDRS: - self.assertFalse(self._tx(make_msg(bus, addr, 8))) - self.assertEqual(-1, self.safety.safety_fwd_hook(bus, addr)) + assert not self._tx(make_msg(bus, addr, 8)) + assert -1 == self.safety.safety_fwd_hook(bus, addr) def test_prev_gas(self): - self.assertFalse(self.safety.get_gas_pressed_prev()) + assert not self.safety.get_gas_pressed_prev() for pressed in [self.GAS_PRESSED_THRESHOLD + 1, 0]: self._rx(self._user_gas_msg(pressed)) - self.assertEqual(bool(pressed), self.safety.get_gas_pressed_prev()) + assert bool(pressed) == self.safety.get_gas_pressed_prev() def test_allow_engage_with_gas_pressed(self): self._rx(self._user_gas_msg(1)) self.safety.set_controls_allowed(True) self._rx(self._user_gas_msg(1)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() self._rx(self._user_gas_msg(1)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() def test_disengage_on_gas(self): self._rx(self._user_gas_msg(0)) self.safety.set_controls_allowed(True) self._rx(self._user_gas_msg(self.GAS_PRESSED_THRESHOLD + 1)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_alternative_experience_no_disengage_on_gas(self): self._rx(self._user_gas_msg(0)) @@ -889,41 +889,41 @@ def test_alternative_experience_no_disengage_on_gas(self): self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS) self._rx(self._user_gas_msg(self.GAS_PRESSED_THRESHOLD + 1)) # Test we allow lateral, but not longitudinal - self.assertTrue(self.safety.get_controls_allowed()) - self.assertFalse(self.safety.get_longitudinal_allowed()) + assert self.safety.get_controls_allowed() + assert not self.safety.get_longitudinal_allowed() # Make sure we can re-gain longitudinal actuation self._rx(self._user_gas_msg(0)) - self.assertTrue(self.safety.get_longitudinal_allowed()) + assert self.safety.get_longitudinal_allowed() def test_prev_user_brake(self, _user_brake_msg=None, get_brake_pressed_prev=None): if _user_brake_msg is None: _user_brake_msg = self._user_brake_msg get_brake_pressed_prev = self.safety.get_brake_pressed_prev - self.assertFalse(get_brake_pressed_prev()) + assert not get_brake_pressed_prev() for pressed in [True, False]: self._rx(_user_brake_msg(not pressed)) - self.assertEqual(not pressed, get_brake_pressed_prev()) + assert not pressed == get_brake_pressed_prev() self._rx(_user_brake_msg(pressed)) - self.assertEqual(pressed, get_brake_pressed_prev()) + assert pressed == get_brake_pressed_prev() def test_enable_control_allowed_from_cruise(self): self._rx(self._pcm_status_msg(False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() self._rx(self._pcm_status_msg(True)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() def test_disable_control_allowed_from_cruise(self): self.safety.set_controls_allowed(1) self._rx(self._pcm_status_msg(False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_cruise_engaged_prev(self): for engaged in [True, False]: self._rx(self._pcm_status_msg(engaged)) - self.assertEqual(engaged, self.safety.get_cruise_engaged_prev()) + assert engaged == self.safety.get_cruise_engaged_prev() self._rx(self._pcm_status_msg(not engaged)) - self.assertEqual(not engaged, self.safety.get_cruise_engaged_prev()) + assert not engaged == self.safety.get_cruise_engaged_prev() def test_allow_user_brake_at_zero_speed(self, _user_brake_msg=None, get_brake_pressed_prev=None): if _user_brake_msg is None: @@ -934,15 +934,15 @@ def test_allow_user_brake_at_zero_speed(self, _user_brake_msg=None, get_brake_pr self._rx(_user_brake_msg(1)) self.safety.set_controls_allowed(1) self._rx(_user_brake_msg(1)) - self.assertTrue(self.safety.get_controls_allowed()) - self.assertTrue(self.safety.get_longitudinal_allowed()) + assert self.safety.get_controls_allowed() + assert self.safety.get_longitudinal_allowed() self._rx(_user_brake_msg(0)) - self.assertTrue(self.safety.get_controls_allowed()) - self.assertTrue(self.safety.get_longitudinal_allowed()) + assert self.safety.get_controls_allowed() + assert self.safety.get_longitudinal_allowed() # rising edge of brake should disengage self._rx(_user_brake_msg(1)) - self.assertFalse(self.safety.get_controls_allowed()) - self.assertFalse(self.safety.get_longitudinal_allowed()) + assert not self.safety.get_controls_allowed() + assert not self.safety.get_longitudinal_allowed() self._rx(_user_brake_msg(0)) # reset no brakes def test_not_allow_user_brake_when_moving(self, _user_brake_msg=None, get_brake_pressed_prev=None): @@ -954,32 +954,32 @@ def test_not_allow_user_brake_when_moving(self, _user_brake_msg=None, get_brake_ self.safety.set_controls_allowed(1) self._rx(self._vehicle_moving_msg(self.STANDSTILL_THRESHOLD)) self._rx(_user_brake_msg(1)) - self.assertTrue(self.safety.get_controls_allowed()) - self.assertTrue(self.safety.get_longitudinal_allowed()) + assert self.safety.get_controls_allowed() + assert self.safety.get_longitudinal_allowed() self._rx(self._vehicle_moving_msg(self.STANDSTILL_THRESHOLD + 1)) self._rx(_user_brake_msg(1)) - self.assertFalse(self.safety.get_controls_allowed()) - self.assertFalse(self.safety.get_longitudinal_allowed()) + assert not self.safety.get_controls_allowed() + assert not self.safety.get_longitudinal_allowed() self._rx(self._vehicle_moving_msg(0)) def test_vehicle_moving(self): - self.assertFalse(self.safety.get_vehicle_moving()) + assert not self.safety.get_vehicle_moving() # not moving self._rx(self._vehicle_moving_msg(0)) - self.assertFalse(self.safety.get_vehicle_moving()) + assert not self.safety.get_vehicle_moving() # speed is at threshold self._rx(self._vehicle_moving_msg(self.STANDSTILL_THRESHOLD)) - self.assertFalse(self.safety.get_vehicle_moving()) + assert not self.safety.get_vehicle_moving() # past threshold self._rx(self._vehicle_moving_msg(self.STANDSTILL_THRESHOLD + 1)) - self.assertTrue(self.safety.get_vehicle_moving()) + assert self.safety.get_vehicle_moving() def test_safety_tick(self): self.safety.set_timer(int(2e6)) self.safety.set_controls_allowed(True) self.safety.safety_tick_current_safety_config() - self.assertFalse(self.safety.get_controls_allowed()) - self.assertFalse(self.safety.safety_config_valid()) + assert not self.safety.get_controls_allowed() + assert not self.safety.safety_config_valid() diff --git a/tests/safety/hyundai_common.py b/tests/safety/hyundai_common.py index da18671af5..c2947fb874 100644 --- a/tests/safety/hyundai_common.py +++ b/tests/safety/hyundai_common.py @@ -1,5 +1,4 @@ -import unittest - +import pytest import panda.tests.safety.common as common from panda.tests.libpanda import libpanda_py from panda.tests.safety.common import make_msg @@ -28,16 +27,16 @@ def test_button_sends(self): - CANCEL allowed while cruise is enabled """ self.safety.set_controls_allowed(0) - self.assertFalse(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS))) - self.assertFalse(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS))) + assert not self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)) + assert not self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)) self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS))) - self.assertFalse(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS))) + assert self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)) + assert not self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)) for enabled in (True, False): self._rx(self._pcm_status_msg(enabled)) - self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL, bus=self.BUTTONS_TX_BUS))) + assert enabled == self._tx(self._button_msg(Buttons.CANCEL, bus=self.BUTTONS_TX_BUS)) def test_enable_control_allowed_from_cruise(self): """ @@ -53,11 +52,11 @@ def test_enable_control_allowed_from_cruise(self): self._rx(self._button_msg(Buttons.NONE)) self._rx(self._pcm_status_msg(False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() self._rx(self._button_msg(btn, main_button=main_button)) self._rx(self._pcm_status_msg(True)) controls_allowed = btn in ENABLE_BUTTONS or main_button - self.assertEqual(controls_allowed, self.safety.get_controls_allowed()) + assert controls_allowed == self.safety.get_controls_allowed() def test_sampling_cruise_buttons(self): """ @@ -66,10 +65,10 @@ def test_sampling_cruise_buttons(self): self._rx(self._button_msg(Buttons.SET)) for i in range(2 * PREV_BUTTON_SAMPLES): self._rx(self._pcm_status_msg(False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() self._rx(self._pcm_status_msg(True)) controls_allowed = i < PREV_BUTTON_SAMPLES - self.assertEqual(controls_allowed, self.safety.get_controls_allowed()) + assert controls_allowed == self.safety.get_controls_allowed() self._rx(self._button_msg(Buttons.NONE)) @@ -80,10 +79,10 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest): DISABLED_ECU_ACTUATION_MSG: tuple[int, int] @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "HyundaiLongitudinalBase": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() # override these tests from PandaCarSafetyTest, hyundai longitudinal uses button enable def test_disable_control_allowed_from_cruise(self): @@ -117,7 +116,7 @@ def test_set_resume_buttons(self): self.safety.set_controls_allowed(0) for _ in range(10): self._rx(self._button_msg(btn_prev)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() # should enter controls allowed on falling edge and not transitioning to cancel should_enable = btn_cur != btn_prev and \ @@ -125,12 +124,12 @@ def test_set_resume_buttons(self): btn_prev in (Buttons.RESUME, Buttons.SET) self._rx(self._button_msg(btn_cur)) - self.assertEqual(should_enable, self.safety.get_controls_allowed()) + assert should_enable == self.safety.get_controls_allowed() def test_cancel_button(self): self.safety.set_controls_allowed(1) self._rx(self._button_msg(Buttons.CANCEL)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_tester_present_allowed(self): """ @@ -140,10 +139,10 @@ def test_tester_present_allowed(self): addr, bus = self.DISABLED_ECU_UDS_MSG tester_present = libpanda_py.make_CANPacket(addr, bus, b"\x02\x3E\x80\x00\x00\x00\x00\x00") - self.assertTrue(self._tx(tester_present)) + assert self._tx(tester_present) not_tester_present = libpanda_py.make_CANPacket(addr, bus, b"\x03\xAA\xAA\x00\x00\x00\x00\x00") - self.assertFalse(self._tx(not_tester_present)) + assert not self._tx(not_tester_present) def test_disabled_ecu_alive(self): """ @@ -151,7 +150,6 @@ def test_disabled_ecu_alive(self): """ addr, bus = self.DISABLED_ECU_ACTUATION_MSG - self.assertFalse(self.safety.get_relay_malfunction()) + assert not self.safety.get_relay_malfunction() self._rx(make_msg(bus, addr, 8)) - self.assertTrue(self.safety.get_relay_malfunction()) - + assert self.safety.get_relay_malfunction() diff --git a/tests/safety/mutation.sh b/tests/safety/mutation.sh index e8c242cab3..e1dc953049 100755 --- a/tests/safety/mutation.sh +++ b/tests/safety/mutation.sh @@ -17,5 +17,5 @@ for safety_model in ${SAFETY_MODELS[@]}; do echo "" echo "" echo -e "Testing mutations on : $safety_model" - mull-runner-17 --ld-search-path /lib/x86_64-linux-gnu/ ../libpanda/libpanda.so -test-program=./$safety_model + mull-runner-17 --ld-search-path /lib/x86_64-linux-gnu/ ../libpanda/libpanda.so -test-program=python3 $safety_model done diff --git a/tests/safety/test_body.py b/tests/safety/test_body.py old mode 100755 new mode 100644 index d23c09f98c..fc6c4611f6 --- a/tests/safety/test_body.py +++ b/tests/safety/test_body.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 -import unittest - import panda.tests.safety.common as common from panda import Panda @@ -12,7 +9,7 @@ class TestBody(common.PandaSafetyTest): TX_MSGS = [[0x250, 0], [0x251, 0], [0x350, 0], [0x351, 0], [0x1, 0], [0x1, 1], [0x1, 2], [0x1, 3]] - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("comma_body") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_BODY, 0) @@ -35,36 +32,32 @@ def _max_motor_rpm_cmd_msg(self, max_rpm_l, max_rpm_r): return self.packer.make_can_msg_panda("MAX_MOTOR_RPM_CMD", 0, values) def test_rx_hook(self): - self.assertFalse(self.safety.get_controls_allowed()) - self.assertFalse(self.safety.get_vehicle_moving()) + assert not self.safety.get_controls_allowed() + assert not self.safety.get_vehicle_moving() # controls allowed when we get MOTORS_DATA message - self.assertTrue(self._rx(self._torque_cmd_msg(0, 0))) - self.assertTrue(self.safety.get_vehicle_moving()) # always moving - self.assertFalse(self.safety.get_controls_allowed()) + assert self._rx(self._torque_cmd_msg(0, 0)) + assert self.safety.get_vehicle_moving()# always moving + assert not self.safety.get_controls_allowed() - self.assertTrue(self._rx(self._motors_data_msg(0, 0))) - self.assertTrue(self.safety.get_vehicle_moving()) # always moving - self.assertTrue(self.safety.get_controls_allowed()) + assert self._rx(self._motors_data_msg(0, 0)) + assert self.safety.get_vehicle_moving()# always moving + assert self.safety.get_controls_allowed() def test_tx_hook(self): - self.assertFalse(self._tx(self._torque_cmd_msg(0, 0))) - self.assertFalse(self._tx(self._knee_torque_cmd_msg(0, 0))) + assert not self._tx(self._torque_cmd_msg(0, 0)) + assert not self._tx(self._knee_torque_cmd_msg(0, 0)) self.safety.set_controls_allowed(True) - self.assertTrue(self._tx(self._torque_cmd_msg(0, 0))) - self.assertTrue(self._tx(self._knee_torque_cmd_msg(0, 0))) + assert self._tx(self._torque_cmd_msg(0, 0)) + assert self._tx(self._knee_torque_cmd_msg(0, 0)) def test_can_flasher(self): # CAN flasher always allowed self.safety.set_controls_allowed(False) - self.assertTrue(self._tx(common.make_msg(0, 0x1, 8))) + assert self._tx(common.make_msg(0, 0x1, 8)) # 0xdeadfaceU enters CAN flashing mode for base & knee for addr in (0x250, 0x350): - self.assertTrue(self._tx(common.make_msg(0, addr, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a'))) - self.assertFalse(self._tx(common.make_msg(0, addr, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0'))) # not correct data/len - self.assertFalse(self._tx(common.make_msg(0, addr + 1, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a'))) # wrong address - - -if __name__ == "__main__": - unittest.main() + assert self._tx(common.make_msg(0, addr, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a')) + assert not self._tx(common.make_msg(0, addr, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0'))# not correct data/len + assert not self._tx(common.make_msg(0, addr + 1, dat=b'\xce\xfa\xad\xde\x1e\x0b\xb0\x0a'))# wrong address diff --git a/tests/safety/test_chrysler.py b/tests/safety/test_chrysler.py old mode 100755 new mode 100644 index 5bbb6dd103..407accfd6f --- a/tests/safety/test_chrysler.py +++ b/tests/safety/test_chrysler.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -24,7 +22,7 @@ class TestChryslerSafety(common.PandaCarSafetyTest, common.MotorTorqueSteeringSa DAS_BUS = 0 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("chrysler_pacifica_2017_hybrid_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, 0) @@ -63,14 +61,14 @@ def test_buttons(self): self.safety.set_controls_allowed(controls_allowed) # resume only while controls allowed - self.assertEqual(controls_allowed, self._tx(self._button_msg(resume=True))) + assert controls_allowed == self._tx(self._button_msg(resume=True)) # can always cancel - self.assertTrue(self._tx(self._button_msg(cancel=True))) + assert self._tx(self._button_msg(cancel=True)) # only one button at a time - self.assertFalse(self._tx(self._button_msg(cancel=True, resume=True))) - self.assertFalse(self._tx(self._button_msg(cancel=False, resume=False))) + assert not self._tx(self._button_msg(cancel=True, resume=True)) + assert not self._tx(self._button_msg(cancel=False, resume=False)) class TestChryslerRamDTSafety(TestChryslerSafety): @@ -86,7 +84,7 @@ class TestChryslerRamDTSafety(TestChryslerSafety): LKAS_ACTIVE_VALUE = 2 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("chrysler_ram_dt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, Panda.FLAG_CHRYSLER_RAM_DT) @@ -110,7 +108,7 @@ class TestChryslerRamHDSafety(TestChryslerSafety): LKAS_ACTIVE_VALUE = 2 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("chrysler_ram_hd_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, Panda.FLAG_CHRYSLER_RAM_HD) @@ -119,7 +117,3 @@ def setUp(self): def _speed_msg(self, speed): values = {"Vehicle_Speed": speed} return self.packer.make_can_msg_panda("ESP_8", 0, values) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_defaults.py b/tests/safety/test_defaults.py old mode 100755 new mode 100644 index 81bafeefcd..3ed1d0bb82 --- a/tests/safety/test_defaults.py +++ b/tests/safety/test_defaults.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 -import unittest - import panda.tests.safety.common as common from panda import Panda @@ -12,13 +9,13 @@ def test_rx_hook(self): # default rx hook allows all msgs for bus in range(4): for addr in self.SCANNED_ADDRS: - self.assertTrue(self._rx(common.make_msg(bus, addr, 8)), f"failed RX {addr=}") + assert self._rx(common.make_msg(bus, addr, 8)), f"failed RX {addr=}" class TestNoOutput(TestDefaultRxHookBase): TX_MSGS = [] - def setUp(self): + def setup_method(self): self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_NOOUTPUT, 0) self.safety.init_tests() @@ -27,7 +24,7 @@ def setUp(self): class TestSilent(TestNoOutput): """SILENT uses same hooks as NOOUTPUT""" - def setUp(self): + def setup_method(self): self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_SILENT, 0) self.safety.init_tests() @@ -38,7 +35,7 @@ class TestAllOutput(TestDefaultRxHookBase): TX_MSGS = [[addr, bus] for addr in common.PandaSafetyTest.SCANNED_ADDRS for bus in range(4)] - def setUp(self): + def setup_method(self): self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_ALLOUTPUT, 0) self.safety.init_tests() @@ -48,11 +45,11 @@ def test_spam_can_buses(self): for bus in range(4): for addr in self.SCANNED_ADDRS: should_tx = [addr, bus] in self.TX_MSGS - self.assertEqual(should_tx, self._tx(common.make_msg(bus, addr, 8)), f"allowed TX {addr=} {bus=}") + assert should_tx == self._tx(common.make_msg(bus, addr, 8)), f"allowed TX {addr=} {bus=}" def test_default_controls_not_allowed(self): # controls always allowed - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() def test_tx_hook_on_wrong_safety_mode(self): # No point, since we allow all messages @@ -63,11 +60,7 @@ class TestAllOutputPassthrough(TestAllOutput): FWD_BLACKLISTED_ADDRS = {} FWD_BUS_LOOKUP = {0: 2, 2: 0} - def setUp(self): + def setup_method(self): self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_ALLOUTPUT, 1) self.safety.init_tests() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_elm327.py b/tests/safety/test_elm327.py old mode 100755 new mode 100644 index f133b2ead9..6978d9f355 --- a/tests/safety/test_elm327.py +++ b/tests/safety/test_elm327.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 -import unittest - import panda.tests.safety.common as common from panda import DLC_TO_LEN, Panda @@ -16,7 +13,7 @@ class TestElm327(TestDefaultRxHookBase): *[0x18DB33F1], # 29-bit UDS functional address ] for bus in range(4)] - def setUp(self): + def setup_method(self): self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_ELM327, 0) self.safety.init_tests() @@ -26,23 +23,19 @@ def test_tx_hook(self): for bus in range(4): for addr in self.SCANNED_ADDRS: should_tx = [addr, bus] in self.TX_MSGS - self.assertEqual(should_tx, self._tx(common.make_msg(bus, addr, 8))) + assert should_tx == self._tx(common.make_msg(bus, addr, 8)) # ELM only allows 8 byte UDS/KWP messages under ISO 15765-4 for msg_len in DLC_TO_LEN: should_tx = msg_len == 8 - self.assertEqual(should_tx, self._tx(common.make_msg(0, 0x700, msg_len))) + assert should_tx == self._tx(common.make_msg(0, 0x700, msg_len)) # TODO: perform this check for all addresses # 4 to 15 are reserved ISO-TP frame types (https://en.wikipedia.org/wiki/ISO_15765-2) for byte in range(0xff): should_tx = (byte >> 4) <= 3 - self.assertEqual(should_tx, self._tx(common.make_msg(0, GM_CAMERA_DIAG_ADDR, dat=bytes([byte] * 8)))) + assert should_tx == self._tx(common.make_msg(0, GM_CAMERA_DIAG_ADDR, dat=bytes([byte] * 8))) def test_tx_hook_on_wrong_safety_mode(self): # No point, since we allow many diagnostic addresses pass - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_ford.py b/tests/safety/test_ford.py old mode 100755 new mode 100644 index 710462ae95..bee107c651 --- a/tests/safety/test_ford.py +++ b/tests/safety/test_ford.py @@ -1,7 +1,6 @@ -#!/usr/bin/env python3 +import pytest import numpy as np import random -import unittest import panda.tests.safety.common as common @@ -97,9 +96,9 @@ class TestFordSafetyBase(common.PandaCarSafetyTest): safety: libpanda_py.Panda @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestFordSafetyBase": - raise unittest.SkipTest + raise pytest.skip() def _set_prev_desired_angle(self, t): t = round(t * self.DEG_TO_CAN) @@ -212,14 +211,14 @@ def test_rx_hook(self): elif msg == "yaw": to_push = self._yaw_rate_msg(0, 0, quality_flag=quality_flag) - self.assertEqual(quality_flag, self._rx(to_push)) - self.assertEqual(quality_flag, self.safety.get_controls_allowed()) + assert quality_flag == self._rx(to_push) + assert quality_flag == self.safety.get_controls_allowed() # Mess with checksum to make it fail, checksum is not checked for 2nd speed to_push[0].data[3] = 0 # Speed checksum & half of yaw signal should_rx = msg == "speed_2" and quality_flag - self.assertEqual(should_rx, self._rx(to_push)) - self.assertEqual(should_rx, self.safety.get_controls_allowed()) + assert should_rx == self._rx(to_push) + assert should_rx == self.safety.get_controls_allowed() def test_rx_hook_speed_mismatch(self): # Ford relies on speed for driver curvature limiting, so it checks two sources @@ -232,7 +231,7 @@ def test_rx_hook_speed_mismatch(self): self._rx(self._speed_msg_2(speed_2)) within_delta = abs(speed - speed_2) <= self.MAX_SPEED_DELTA - self.assertEqual(self.safety.get_controls_allowed(), within_delta) + assert self.safety.get_controls_allowed() == within_delta def test_angle_measurements(self): """Tests rx hook correctly parses the curvature measurement from the vehicle speed and yaw rate""" @@ -242,22 +241,35 @@ def test_angle_measurements(self): for c in (curvature, -curvature, 0, 0, 0, 0): self._rx(self._yaw_rate_msg(c, speed)) - self.assertEqual(self.safety.get_angle_meas_min(), round(-curvature * self.DEG_TO_CAN)) - self.assertEqual(self.safety.get_angle_meas_max(), round(curvature * self.DEG_TO_CAN)) + assert self.safety.get_angle_meas_min() == round(-curvature * self.DEG_TO_CAN) + assert self.safety.get_angle_meas_max() == round(curvature * self.DEG_TO_CAN) self._rx(self._yaw_rate_msg(0, speed)) - self.assertEqual(self.safety.get_angle_meas_min(), round(-curvature * self.DEG_TO_CAN)) - self.assertEqual(self.safety.get_angle_meas_max(), 0) + assert self.safety.get_angle_meas_min() == round(-curvature * self.DEG_TO_CAN) + assert self.safety.get_angle_meas_max() == 0 self._rx(self._yaw_rate_msg(0, speed)) - self.assertEqual(self.safety.get_angle_meas_min(), 0) - self.assertEqual(self.safety.get_angle_meas_max(), 0) - - def test_steer_allowed(self): - path_offsets = np.arange(-5.12, 5.11, 1).round() - path_angles = np.arange(-0.5, 0.5235, 0.1).round(1) - curvature_rates = np.arange(-0.001024, 0.00102375, 0.001).round(3) - curvatures = np.arange(-0.02, 0.02094, 0.01).round(2) + assert self.safety.get_angle_meas_min() == 0 + assert self.safety.get_angle_meas_max() == 0 + + + def test_steer_allowed(self, subtests): + def _frange_round(start, stop, step=1., round_ndigits=None): + # manually implement this since combinations of execnet and subtests (pytest-xdist related) cannot serialize np.float + value = start + while value < stop: + if round_ndigits: + multiplier = 10 ** round_ndigits + rounded_value = int(value * multiplier + (0.5 if value >= 0 else -0.5)) / multiplier + yield rounded_value + else: + yield value + value += step + + path_offsets = _frange_round(-5.12, 5.11, 1) + path_angles = _frange_round(-0.5, 0.5235, 0.1, round_ndigits=1) + curvature_rates = _frange_round(-0.001024, 0.00102375, 0.001, round_ndigits=3) + curvatures = _frange_round(-0.02, 0.02094, 0.01, round_ndigits=2) for speed in (self.CURVATURE_ERROR_MIN_SPEED - 1, self.CURVATURE_ERROR_MIN_SPEED + 1): @@ -275,10 +287,10 @@ def test_steer_allowed(self): # when request bit is 0, only allow curvature of 0 since the signal range # is not large enough to enforce it tracking measured should_tx = should_tx and (controls_allowed if steer_control_enabled else curvature == 0) - with self.subTest(controls_allowed=controls_allowed, steer_control_enabled=steer_control_enabled, + with subtests.test(controls_allowed=controls_allowed, steer_control_enabled=steer_control_enabled, path_offset=path_offset, path_angle=path_angle, curvature_rate=curvature_rate, curvature=curvature): - self.assertEqual(should_tx, self._tx(self._lat_ctl_msg(steer_control_enabled, path_offset, path_angle, curvature, curvature_rate))) + assert should_tx == self._tx(self._lat_ctl_msg(steer_control_enabled, path_offset, path_angle, curvature, curvature_rate)) def test_curvature_rate_limit_up(self): """ @@ -305,7 +317,7 @@ def test_curvature_rate_limit_up(self): self._reset_curvature_measurement(sign * (self.MAX_CURVATURE_ERROR + 1e-3), speed) for should_tx, curvature in cases: self._set_prev_desired_angle(sign * small_curvature) - self.assertEqual(should_tx, self._tx(self._lat_ctl_msg(True, 0, 0, sign * (small_curvature + curvature), 0))) + assert should_tx == self._tx(self._lat_ctl_msg(True, 0, 0, sign * (small_curvature + curvature), 0)) def test_curvature_rate_limit_down(self): self.safety.set_controls_allowed(True) @@ -328,31 +340,31 @@ def test_curvature_rate_limit_down(self): self._reset_curvature_measurement(sign * (self.MAX_CURVATURE - self.MAX_CURVATURE_ERROR - 1e-3), speed) for should_tx, curvature in cases: self._set_prev_desired_angle(sign * self.MAX_CURVATURE) - self.assertEqual(should_tx, self._tx(self._lat_ctl_msg(True, 0, 0, sign * curvature, 0))) + assert should_tx == self._tx(self._lat_ctl_msg(True, 0, 0, sign * curvature, 0)) def test_prevent_lkas_action(self): self.safety.set_controls_allowed(1) - self.assertFalse(self._tx(self._lkas_command_msg(1))) + assert not self._tx(self._lkas_command_msg(1)) self.safety.set_controls_allowed(0) - self.assertFalse(self._tx(self._lkas_command_msg(1))) + assert not self._tx(self._lkas_command_msg(1)) def test_acc_buttons(self): for allowed in (0, 1): self.safety.set_controls_allowed(allowed) for enabled in (True, False): self._rx(self._pcm_status_msg(enabled)) - self.assertTrue(self._tx(self._acc_button_msg(Buttons.TJA_TOGGLE, 2))) + assert self._tx(self._acc_button_msg(Buttons.TJA_TOGGLE, 2)) for allowed in (0, 1): self.safety.set_controls_allowed(allowed) for bus in (0, 2): - self.assertEqual(allowed, self._tx(self._acc_button_msg(Buttons.RESUME, bus))) + assert allowed == self._tx(self._acc_button_msg(Buttons.RESUME, bus)) for enabled in (True, False): self._rx(self._pcm_status_msg(enabled)) for bus in (0, 2): - self.assertEqual(enabled, self._tx(self._acc_button_msg(Buttons.CANCEL, bus))) + assert enabled == self._tx(self._acc_button_msg(Buttons.CANCEL, bus)) class TestFordStockSafety(TestFordSafetyBase): @@ -363,7 +375,7 @@ class TestFordStockSafety(TestFordSafetyBase): [MSG_LateralMotionControl, 0], [MSG_IPMA_Data, 0], ] - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("ford_lincoln_base_pt") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_FORD, 0) @@ -378,7 +390,7 @@ class TestFordCANFDStockSafety(TestFordSafetyBase): [MSG_LateralMotionControl2, 0], [MSG_IPMA_Data, 0], ] - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("ford_lincoln_base_pt") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_FORD, Panda.FLAG_FORD_CANFD) @@ -401,9 +413,9 @@ class TestFordLongitudinalSafetyBase(TestFordSafetyBase): INACTIVE_GAS = -5.0 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestFordLongitudinalSafetyBase": - raise unittest.SkipTest + raise pytest.skip() # ACC command def _acc_command_msg(self, gas: float, brake: float, cmbb_deny: bool = False): @@ -421,9 +433,9 @@ def test_stock_aeb(self): self.safety.set_controls_allowed(controls_allowed) for cmbb_deny in (True, False): should_tx = not cmbb_deny - self.assertEqual(should_tx, self._tx(self._acc_command_msg(self.INACTIVE_GAS, self.INACTIVE_ACCEL, cmbb_deny))) + assert should_tx == self._tx(self._acc_command_msg(self.INACTIVE_GAS, self.INACTIVE_ACCEL, cmbb_deny)) should_tx = controls_allowed and not cmbb_deny - self.assertEqual(should_tx, self._tx(self._acc_command_msg(self.MAX_GAS, self.MAX_ACCEL, cmbb_deny))) + assert should_tx == self._tx(self._acc_command_msg(self.MAX_GAS, self.MAX_ACCEL, cmbb_deny)) def test_gas_safety_check(self): for controls_allowed in (True, False): @@ -431,7 +443,7 @@ def test_gas_safety_check(self): for gas in np.concatenate((np.arange(self.MIN_GAS - 2, self.MAX_GAS + 2, 0.05), [self.INACTIVE_GAS])): gas = round(gas, 2) # floats might not hit exact boundary conditions without rounding should_tx = (controls_allowed and self.MIN_GAS <= gas <= self.MAX_GAS) or gas == self.INACTIVE_GAS - self.assertEqual(should_tx, self._tx(self._acc_command_msg(gas, self.INACTIVE_ACCEL))) + assert should_tx == self._tx(self._acc_command_msg(gas, self.INACTIVE_ACCEL)) def test_brake_safety_check(self): for controls_allowed in (True, False): @@ -439,7 +451,7 @@ def test_brake_safety_check(self): for brake in np.arange(self.MIN_ACCEL - 2, self.MAX_ACCEL + 2, 0.05): brake = round(brake, 2) # floats might not hit exact boundary conditions without rounding should_tx = (controls_allowed and self.MIN_ACCEL <= brake <= self.MAX_ACCEL) or brake == self.INACTIVE_ACCEL - self.assertEqual(should_tx, self._tx(self._acc_command_msg(self.INACTIVE_GAS, brake))) + assert should_tx == self._tx(self._acc_command_msg(self.INACTIVE_GAS, brake)) class TestFordLongitudinalSafety(TestFordLongitudinalSafetyBase): @@ -450,7 +462,7 @@ class TestFordLongitudinalSafety(TestFordLongitudinalSafetyBase): [MSG_LateralMotionControl, 0], [MSG_IPMA_Data, 0], ] - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("ford_lincoln_base_pt") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_FORD, Panda.FLAG_FORD_LONG_CONTROL) @@ -465,12 +477,8 @@ class TestFordCANFDLongitudinalSafety(TestFordLongitudinalSafetyBase): [MSG_LateralMotionControl2, 0], [MSG_IPMA_Data, 0], ] - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("ford_lincoln_base_pt") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_FORD, Panda.FLAG_FORD_LONG_CONTROL | Panda.FLAG_FORD_CANFD) self.safety.init_tests() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_gm.py b/tests/safety/test_gm.py old mode 100755 new mode 100644 index c6c5ac6b3a..4b942a1b6c --- a/tests/safety/test_gm.py +++ b/tests/safety/test_gm.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 -import unittest +import pytest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -46,13 +45,13 @@ def test_enable_control_allowed_from_cruise(self): def test_cruise_engaged_prev(self): pass - def test_set_resume_buttons(self): + def test_set_resume_buttons(self, subtests): """ SET and RESUME enter controls allowed on their falling and rising edges, respectively. """ for btn_prev in range(8): for btn_cur in range(8): - with self.subTest(btn_prev=btn_prev, btn_cur=btn_cur): + with subtests.test(btn_prev=btn_prev, btn_cur=btn_cur): self._rx(self._button_msg(btn_prev)) self.safety.set_controls_allowed(0) for _ in range(10): @@ -61,12 +60,12 @@ def test_set_resume_buttons(self): should_enable = btn_cur != Buttons.DECEL_SET and btn_prev == Buttons.DECEL_SET should_enable = should_enable or (btn_cur == Buttons.RES_ACCEL and btn_prev != Buttons.RES_ACCEL) should_enable = should_enable and btn_cur != Buttons.CANCEL - self.assertEqual(should_enable, self.safety.get_controls_allowed()) + assert should_enable == self.safety.get_controls_allowed() def test_cancel_button(self): self.safety.set_controls_allowed(1) self._rx(self._button_msg(Buttons.CANCEL)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() class TestGmSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteeringSafetyTest): @@ -87,13 +86,13 @@ class TestGmSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteeringSaf PCM_CRUISE = True # openpilot is tied to the PCM state if not longitudinal @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestGmSafetyBase": cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("gm_global_a_powertrain_generated") self.packer_chassis = CANPackerPanda("gm_global_a_chassis") self.safety = libpanda_py.libpanda @@ -153,7 +152,7 @@ class TestGmAscmSafety(GmLongitudinalBase, TestGmSafetyBase): MIN_GAS = 1404 # maximum regen INACTIVE_GAS = 1404 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("gm_global_a_powertrain_generated") self.packer_chassis = CANPackerPanda("gm_global_a_chassis") self.safety = libpanda_py.libpanda @@ -166,11 +165,11 @@ class TestGmCameraSafetyBase(TestGmSafetyBase): FWD_BUS_LOOKUP = {0: 2, 2: 0} @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestGmCameraSafetyBase": cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _user_brake_msg(self, brake): values = {"BrakePressed": brake} @@ -183,7 +182,7 @@ class TestGmCameraSafety(TestGmCameraSafetyBase): FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184]} # block LKAS message and PSCMStatus BUTTONS_BUS = 2 # tx only - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("gm_global_a_powertrain_generated") self.packer_chassis = CANPackerPanda("gm_global_a_chassis") self.safety = libpanda_py.libpanda @@ -194,15 +193,15 @@ def test_buttons(self): # Only CANCEL button is allowed while cruise is enabled self.safety.set_controls_allowed(0) for btn in range(8): - self.assertFalse(self._tx(self._button_msg(btn))) + assert not self._tx(self._button_msg(btn)) self.safety.set_controls_allowed(1) for btn in range(8): - self.assertFalse(self._tx(self._button_msg(btn))) + assert not self._tx(self._button_msg(btn)) for enabled in (True, False): self._rx(self._pcm_status_msg(enabled)) - self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL))) + assert enabled == self._tx(self._button_msg(Buttons.CANCEL)) class TestGmCameraLongitudinalSafety(GmLongitudinalBase, TestGmCameraSafetyBase): @@ -215,13 +214,9 @@ class TestGmCameraLongitudinalSafety(GmLongitudinalBase, TestGmCameraSafetyBase) MIN_GAS = 1514 # maximum regen INACTIVE_GAS = 1554 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("gm_global_a_powertrain_generated") self.packer_chassis = CANPackerPanda("gm_global_a_chassis") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_GM, Panda.FLAG_GM_HW_CAM | Panda.FLAG_GM_HW_CAM_LONG) self.safety.init_tests() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_honda.py b/tests/safety/test_honda.py old mode 100755 new mode 100644 index 082199c02b..c002f620ee --- a/tests/safety/test_honda.py +++ b/tests/safety/test_honda.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 -import unittest +import pytest import numpy as np from panda import Panda @@ -48,7 +47,7 @@ def test_buttons_with_main_off(self): self.safety.set_controls_allowed(1) self._rx(self._acc_state_msg(False)) self._rx(self._button_msg(btn, main_on=False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_set_resume_buttons(self): """ @@ -62,7 +61,7 @@ def test_set_resume_buttons(self): self.safety.set_controls_allowed(0) for _ in range(10): self._rx(self._button_msg(btn_prev)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() # should enter controls allowed on falling edge and not transitioning to cancel or main should_enable = (main_on and @@ -71,7 +70,7 @@ def test_set_resume_buttons(self): btn_cur not in (Btn.CANCEL, Btn.MAIN)) self._rx(self._button_msg(btn_cur, main_on=main_on)) - self.assertEqual(should_enable, self.safety.get_controls_allowed(), msg=f"{main_on=} {btn_prev=} {btn_cur=}") + assert should_enable == self.safety.get_controls_allowed(), f"{main_on=} {btn_prev=} {btn_cur=}" def test_main_cancel_buttons(self): """ @@ -80,14 +79,14 @@ def test_main_cancel_buttons(self): for btn in (Btn.MAIN, Btn.CANCEL): self.safety.set_controls_allowed(1) self._rx(self._button_msg(btn, main_on=True)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_disengage_on_main(self): self.safety.set_controls_allowed(1) self._rx(self._acc_state_msg(True)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() self._rx(self._acc_state_msg(False)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_rx_hook(self): @@ -101,14 +100,14 @@ def test_rx_hook(self): to_push = self._user_gas_msg(0) if msg == "speed": to_push = self._speed_msg(0) - self.assertTrue(self._rx(to_push)) + assert self._rx(to_push) if msg != "btn": to_push[0].data[4] = 0 # invalidate checksum to_push[0].data[5] = 0 to_push[0].data[6] = 0 to_push[0].data[7] = 0 - self.assertFalse(self._rx(to_push)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self._rx(to_push) + assert not self.safety.get_controls_allowed() # counter # reset wrong_counters to zero by sending valid messages @@ -122,10 +121,10 @@ def test_rx_hook(self): self._rx(self._speed_msg(0)) self._rx(self._user_gas_msg(0)) else: - self.assertFalse(self._rx(self._button_msg(Btn.SET))) - self.assertFalse(self._rx(self._speed_msg(0))) - self.assertFalse(self._rx(self._user_gas_msg(0))) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self._rx(self._button_msg(Btn.SET)) + assert not self._rx(self._speed_msg(0)) + assert not self._rx(self._user_gas_msg(0)) + assert not self.safety.get_controls_allowed() # restore counters for future tests with a couple of good messages for _ in range(2): @@ -134,7 +133,7 @@ def test_rx_hook(self): self._rx(self._speed_msg(0)) self._rx(self._user_gas_msg(0)) self._rx(self._button_msg(Btn.SET, main_on=True)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() class HondaPcmEnableBase(common.PandaCarSafetyTest): @@ -160,9 +159,9 @@ def test_buttons(self): self._rx(self._button_msg(Btn.NONE, main_on=main_on)) if btn == Btn.CANCEL: - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() else: - self.assertEqual(controls_allowed, self.safety.get_controls_allowed()) + assert controls_allowed == self.safety.get_controls_allowed() class HondaBase(common.PandaCarSafetyTest): @@ -182,11 +181,11 @@ class HondaBase(common.PandaCarSafetyTest): cnt_acc_state = 0 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__.endswith("Base"): cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _powertrain_data_msg(self, cruise_on=None, brake_pressed=None, gas_pressed=None): # preserve the state @@ -243,12 +242,12 @@ def _send_brake_msg(self, brake): def test_disengage_on_brake(self): self.safety.set_controls_allowed(1) self._rx(self._user_brake_msg(1)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() def test_steer_safety_check(self): self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._send_steer_msg(0x0000))) - self.assertFalse(self._tx(self._send_steer_msg(0x1000))) + assert self._tx(self._send_steer_msg(0x0000)) + assert not self._tx(self._send_steer_msg(0x1000)) # ********************* Honda Nidec ********************** @@ -264,7 +263,7 @@ class TestHondaNidecSafetyBase(HondaBase): MAX_GAS = 198 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("honda_civic_touring_2016_can_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HONDA_NIDEC, 0) @@ -288,7 +287,7 @@ def test_acc_hud_safety_check(self): for pcm_gas in range(255): for pcm_speed in range(100): send = (controls_allowed and pcm_gas <= self.MAX_GAS) or (pcm_gas == 0 and pcm_speed == 0) - self.assertEqual(send, self._tx(self._send_acc_hud_msg(pcm_gas, pcm_speed))) + assert send == self._tx(self._send_acc_hud_msg(pcm_gas, pcm_speed)) def test_fwd_hook(self): # normal operation, not forwarding AEB @@ -303,27 +302,27 @@ def test_fwd_hook(self): def test_honda_fwd_brake_latching(self): # Shouldn't fwd stock Honda requesting brake without AEB - self.assertTrue(self._rx(self._rx_brake_msg(self.MAX_BRAKE, aeb_req=0))) - self.assertFalse(self.safety.get_honda_fwd_brake()) + assert self._rx(self._rx_brake_msg(self.MAX_BRAKE, aeb_req=0)) + assert not self.safety.get_honda_fwd_brake() # Now allow controls and request some brake openpilot_brake = round(self.MAX_BRAKE / 2.0) self.safety.set_controls_allowed(True) - self.assertTrue(self._tx(self._send_brake_msg(openpilot_brake))) + assert self._tx(self._send_brake_msg(openpilot_brake)) # Still shouldn't fwd stock Honda brake until it's more than openpilot's for stock_honda_brake in range(self.MAX_BRAKE + 1): - self.assertTrue(self._rx(self._rx_brake_msg(stock_honda_brake, aeb_req=1))) + assert self._rx(self._rx_brake_msg(stock_honda_brake, aeb_req=1)) should_fwd_brake = stock_honda_brake >= openpilot_brake - self.assertEqual(should_fwd_brake, self.safety.get_honda_fwd_brake()) + assert should_fwd_brake == self.safety.get_honda_fwd_brake() # Shouldn't stop fwding until AEB event is over for stock_honda_brake in range(self.MAX_BRAKE + 1)[::-1]: - self.assertTrue(self._rx(self._rx_brake_msg(stock_honda_brake, aeb_req=1))) - self.assertTrue(self.safety.get_honda_fwd_brake()) + assert self._rx(self._rx_brake_msg(stock_honda_brake, aeb_req=1)) + assert self.safety.get_honda_fwd_brake() - self.assertTrue(self._rx(self._rx_brake_msg(0, aeb_req=0))) - self.assertFalse(self.safety.get_honda_fwd_brake()) + assert self._rx(self._rx_brake_msg(0, aeb_req=0)) + assert not self.safety.get_honda_fwd_brake() def test_brake_safety_check(self): for fwd_brake in [False, True]: @@ -337,7 +336,7 @@ def test_brake_safety_check(self): send = self.MAX_BRAKE >= brake >= 0 else: send = brake == 0 - self.assertEqual(send, self._tx(self._send_brake_msg(brake))) + assert send == self._tx(self._send_brake_msg(brake)) class TestHondaNidecPcmSafety(HondaPcmEnableBase, TestHondaNidecSafetyBase): @@ -354,7 +353,7 @@ class TestHondaNidecPcmAltSafety(TestHondaNidecPcmSafety): """ Covers the Honda Nidec safety mode with alt SCM messages """ - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("acura_ilx_2016_can_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HONDA_NIDEC, Panda.FLAG_HONDA_NIDEC_ALT) @@ -383,7 +382,7 @@ class TestHondaBoschSafetyBase(HondaBase): TX_MSGS = [[0xE4, 0], [0xE5, 0], [0x296, 1], [0x33D, 0], [0x33DA, 0], [0x33DB, 0]] FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D, 0x33DA, 0x33DB]} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("honda_accord_2018_can_generated") self.safety = libpanda_py.libpanda @@ -399,29 +398,29 @@ def test_alt_disengage_on_brake(self): self.safety.set_honda_alt_brake_msg(1) self.safety.set_controls_allowed(1) self._rx(self._alt_brake_msg(1)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self.safety.get_controls_allowed() self.safety.set_honda_alt_brake_msg(0) self.safety.set_controls_allowed(1) self._rx(self._alt_brake_msg(1)) - self.assertTrue(self.safety.get_controls_allowed()) + assert self.safety.get_controls_allowed() def test_spam_cancel_safety_check(self): self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._button_msg(Btn.CANCEL, bus=self.BUTTONS_BUS))) - self.assertFalse(self._tx(self._button_msg(Btn.RESUME, bus=self.BUTTONS_BUS))) - self.assertFalse(self._tx(self._button_msg(Btn.SET, bus=self.BUTTONS_BUS))) + assert self._tx(self._button_msg(Btn.CANCEL, bus=self.BUTTONS_BUS)) + assert not self._tx(self._button_msg(Btn.RESUME, bus=self.BUTTONS_BUS)) + assert not self._tx(self._button_msg(Btn.SET, bus=self.BUTTONS_BUS)) # do not block resume if we are engaged already self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._button_msg(Btn.RESUME, bus=self.BUTTONS_BUS))) + assert self._tx(self._button_msg(Btn.RESUME, bus=self.BUTTONS_BUS)) class TestHondaBoschAltBrakeSafetyBase(TestHondaBoschSafetyBase): """ Base Bosch safety test class with an alternate brake message """ - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, Panda.FLAG_HONDA_ALT_BRAKE) self.safety.init_tests() @@ -432,18 +431,18 @@ def test_alt_brake_rx_hook(self): self.safety.set_honda_alt_brake_msg(1) self.safety.set_controls_allowed(1) to_push = self._alt_brake_msg(0) - self.assertTrue(self._rx(to_push)) + assert self._rx(to_push) to_push[0].data[2] = to_push[0].data[2] & 0xF0 # invalidate checksum - self.assertFalse(self._rx(to_push)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self._rx(to_push) + assert not self.safety.get_controls_allowed() class TestHondaBoschSafety(HondaPcmEnableBase, TestHondaBoschSafetyBase): """ Covers the Honda Bosch safety mode with stock longitudinal """ - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, 0) self.safety.init_tests() @@ -469,8 +468,8 @@ class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase): # 0x1DF is to test that radar is disabled RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x194), 1: (0x1DF,)} # STEERING_CONTROL, ACC_CONTROL - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, Panda.FLAG_HONDA_BOSCH_LONG) self.safety.init_tests() @@ -488,10 +487,10 @@ def test_spam_cancel_safety_check(self): def test_diagnostics(self): tester_present = libpanda_py.make_CANPacket(0x18DAB0F1, self.PT_BUS, b"\x02\x3E\x80\x00\x00\x00\x00\x00") - self.assertTrue(self._tx(tester_present)) + assert self._tx(tester_present) not_tester_present = libpanda_py.make_CANPacket(0x18DAB0F1, self.PT_BUS, b"\x03\xAA\xAA\x00\x00\x00\x00\x00") - self.assertFalse(self._tx(not_tester_present)) + assert not self._tx(not_tester_present) def test_gas_safety_check(self): for controls_allowed in [True, False]: @@ -499,7 +498,7 @@ def test_gas_safety_check(self): accel = 0 if gas < 0 else gas / 1000 self.safety.set_controls_allowed(controls_allowed) send = (controls_allowed and 0 <= gas <= self.MAX_GAS) or gas == self.NO_GAS - self.assertEqual(send, self._tx(self._send_gas_brake_msg(gas, accel)), (controls_allowed, gas, accel)) + assert send == self._tx(self._send_gas_brake_msg(gas, accel)), (controls_allowed, gas, accel) def test_brake_safety_check(self): for controls_allowed in [True, False]: @@ -507,7 +506,7 @@ def test_brake_safety_check(self): accel = round(accel, 2) # floats might not hit exact boundary conditions without rounding self.safety.set_controls_allowed(controls_allowed) send = self.MIN_ACCEL <= accel <= self.MAX_ACCEL if controls_allowed else accel == 0 - self.assertEqual(send, self._tx(self._send_gas_brake_msg(self.NO_GAS, accel)), (controls_allowed, accel)) + assert send == self._tx(self._send_gas_brake_msg(self.NO_GAS, accel)), (controls_allowed, accel) class TestHondaBoschRadarlessSafetyBase(TestHondaBoschSafetyBase): @@ -519,7 +518,7 @@ class TestHondaBoschRadarlessSafetyBase(TestHondaBoschSafetyBase): TX_MSGS = [[0xE4, 0], [0x296, 2], [0x33D, 0]] FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D, 0x33DA, 0x33DB]} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("honda_civic_ex_2022_can_generated") self.safety = libpanda_py.libpanda @@ -529,8 +528,8 @@ class TestHondaBoschRadarlessSafety(HondaPcmEnableBase, TestHondaBoschRadarlessS Covers the Honda Bosch Radarless safety mode with stock longitudinal """ - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, Panda.FLAG_HONDA_RADARLESS) self.safety.init_tests() @@ -540,8 +539,8 @@ class TestHondaBoschRadarlessAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschRa Covers the Honda Bosch Radarless safety mode with stock longitudinal and an alternate brake message """ - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, Panda.FLAG_HONDA_RADARLESS | Panda.FLAG_HONDA_ALT_BRAKE) self.safety.init_tests() @@ -554,8 +553,8 @@ class TestHondaBoschRadarlessLongSafety(common.LongitudinalAccelSafetyTest, Hond TX_MSGS = [[0xE4, 0], [0x33D, 0], [0x1C8, 0], [0x30C, 0]] FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D, 0x33DA, 0x33DB, 0x1C8, 0x30C]} - def setUp(self): - super().setUp() + def setup_method(self): + super().setup_method() self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, Panda.FLAG_HONDA_RADARLESS | Panda.FLAG_HONDA_BOSCH_LONG) self.safety.init_tests() @@ -568,7 +567,3 @@ def _accel_msg(self, accel): # Longitudinal doesn't need to send buttons def test_spam_cancel_safety_check(self): pass - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_hyundai.py b/tests/safety/test_hyundai.py old mode 100755 new mode 100644 index 1bff99fa75..53e078114f --- a/tests/safety/test_hyundai.py +++ b/tests/safety/test_hyundai.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 import random -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -69,7 +67,7 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri cnt_cruise = 0 cnt_button = 0 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, 0) @@ -118,7 +116,7 @@ class TestHyundaiSafetyAltLimits(TestHyundaiSafety): MAX_RATE_DOWN = 3 MAX_TORQUE = 270 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_ALT_LIMITS) @@ -129,7 +127,7 @@ class TestHyundaiSafetyCameraSCC(TestHyundaiSafety): BUTTONS_TX_BUS = 2 # tx on 2, rx on 0 SCC_BUS = 2 # rx on 2 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_CAMERA_SCC) @@ -137,7 +135,7 @@ def setUp(self): class TestHyundaiLegacySafety(TestHyundaiSafety): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 0) @@ -145,7 +143,7 @@ def setUp(self): class TestHyundaiLegacySafetyEV(TestHyundaiSafety): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 1) @@ -157,7 +155,7 @@ def _user_gas_msg(self, gas): class TestHyundaiLegacySafetyHEV(TestHyundaiSafety): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 2) @@ -175,7 +173,7 @@ class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety): DISABLED_ECU_UDS_MSG = (0x7D0, 0) DISABLED_ECU_ACTUATION_MSG = (0x421, 0) - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_kia_generic") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_LONG) @@ -201,16 +199,12 @@ def _fca11_msg(self, idx=0, vsm_aeb_req=False, fca_aeb_req=False, aeb_decel=0): return self.packer.make_can_msg_panda("FCA11", 0, values) def test_no_aeb_fca11(self): - self.assertTrue(self._tx(self._fca11_msg())) - self.assertFalse(self._tx(self._fca11_msg(vsm_aeb_req=True))) - self.assertFalse(self._tx(self._fca11_msg(fca_aeb_req=True))) - self.assertFalse(self._tx(self._fca11_msg(aeb_decel=1.0))) + assert self._tx(self._fca11_msg()) + assert not self._tx(self._fca11_msg(vsm_aeb_req=True)) + assert not self._tx(self._fca11_msg(fca_aeb_req=True)) + assert not self._tx(self._fca11_msg(aeb_decel=1.0)) def test_no_aeb_scc12(self): - self.assertTrue(self._tx(self._accel_msg(0))) - self.assertFalse(self._tx(self._accel_msg(0, aeb_req=True))) - self.assertFalse(self._tx(self._accel_msg(0, aeb_decel=1.0))) - - -if __name__ == "__main__": - unittest.main() + assert self._tx(self._accel_msg(0)) + assert not self._tx(self._accel_msg(0, aeb_req=True)) + assert not self._tx(self._accel_msg(0, aeb_decel=1.0)) diff --git a/tests/safety/test_hyundai_canfd.py b/tests/safety/test_hyundai_canfd.py old mode 100755 new mode 100644 index 7f280b6319..67fd645514 --- a/tests/safety/test_hyundai_canfd.py +++ b/tests/safety/test_hyundai_canfd.py @@ -1,6 +1,5 @@ -#!/usr/bin/env python3 +import pytest from parameterized import parameterized_class -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -38,12 +37,12 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaCarSafetyTest, common. BUTTONS_TX_BUS = 1 @classmethod - def setUpClass(cls): - super().setUpClass() + def setup_class(cls): + super().setup_class() if cls.__name__ == "TestHyundaiCanfdBase": cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _torque_driver_msg(self, torque): values = {"STEERING_COL_TORQUE": torque} @@ -91,14 +90,14 @@ class TestHyundaiCanfdHDA1Base(TestHyundaiCanfdBase): SAFETY_PARAM: int @classmethod - def setUpClass(cls): - super().setUpClass() + def setup_class(cls): + super().setup_class() if cls.__name__ in ("TestHyundaiCanfdHDA1", "TestHyundaiCanfdHDA1AltButtons"): cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, self.SAFETY_PARAM) @@ -133,7 +132,7 @@ class TestHyundaiCanfdHDA1AltButtons(TestHyundaiCanfdHDA1Base): SAFETY_PARAM: int - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS | self.SAFETY_PARAM) @@ -153,7 +152,7 @@ def test_button_sends(self): for enabled in (True, False): for btn in range(8): self.safety.set_controls_allowed(enabled) - self.assertFalse(self._tx(self._button_msg(btn))) + assert not self._tx(self._button_msg(btn)) class TestHyundaiCanfdHDA2EV(TestHyundaiCanfdBase): @@ -168,7 +167,7 @@ class TestHyundaiCanfdHDA2EV(TestHyundaiCanfdBase): STEER_MSG = "LKAS" GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL") - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_HDA2 | Panda.FLAG_HYUNDAI_EV_GAS) @@ -188,7 +187,7 @@ class TestHyundaiCanfdHDA2EVAltSteering(TestHyundaiCanfdBase): STEER_MSG = "LKAS_ALT" GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL") - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_HDA2 | Panda.FLAG_HYUNDAI_EV_GAS | @@ -210,7 +209,7 @@ class TestHyundaiCanfdHDA2LongEV(HyundaiLongitudinalBase, TestHyundaiCanfdHDA2EV GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL") STEER_BUS = 1 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_HDA2 | Panda.FLAG_HYUNDAI_LONG | Panda.FLAG_HYUNDAI_EV_GAS) @@ -245,12 +244,12 @@ class TestHyundaiCanfdHDA1Long(HyundaiLongitudinalBase, TestHyundaiCanfdHDA1Base SCC_BUS = 2 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestHyundaiCanfdHDA1Long": cls.safety = None - raise unittest.SkipTest + raise pytest.skip() - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("hyundai_canfd") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CAMERA_SCC | self.SAFETY_PARAM) @@ -266,7 +265,3 @@ def _accel_msg(self, accel, aeb_req=False, aeb_decel=0): # no knockout def test_tester_present_allowed(self): pass - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_mazda.py b/tests/safety/test_mazda.py old mode 100755 new mode 100644 index 9d2fb89885..46dfbdf5bc --- a/tests/safety/test_mazda.py +++ b/tests/safety/test_mazda.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -27,7 +25,7 @@ class TestMazdaSafety(common.PandaCarSafetyTest, common.DriverTorqueSteeringSafe # Mazda actually does not set any bit when requesting torque NO_STEER_REQ_BIT = True - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("mazda_2017") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_MAZDA, 0) @@ -73,14 +71,10 @@ def _button_msg(self, resume=False, cancel=False): def test_buttons(self): # only cancel allows while controls not allowed self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._button_msg(cancel=True))) - self.assertFalse(self._tx(self._button_msg(resume=True))) + assert self._tx(self._button_msg(cancel=True)) + assert not self._tx(self._button_msg(resume=True)) # do not block resume if we are engaged already self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._button_msg(cancel=True))) - self.assertTrue(self._tx(self._button_msg(resume=True))) - - -if __name__ == "__main__": - unittest.main() + assert self._tx(self._button_msg(cancel=True)) + assert self._tx(self._button_msg(resume=True)) diff --git a/tests/safety/test_nissan.py b/tests/safety/test_nissan.py old mode 100755 new mode 100644 index 4c83ca329e..b7441b2e88 --- a/tests/safety/test_nissan.py +++ b/tests/safety/test_nissan.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -25,7 +23,7 @@ class TestNissanSafety(common.PandaCarSafetyTest, common.AngleSteeringSafetyTest ANGLE_RATE_UP = [5., .8, .15] # windup limit ANGLE_RATE_DOWN = [5., 3.5, .4] # unwind limit - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("nissan_x_trail_2017_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_NISSAN, 0) @@ -76,7 +74,7 @@ def test_acc_buttons(self): self.safety.set_controls_allowed(controls_allowed) args = {} if btn is None else {btn: 1} tx = self._tx(self._acc_button_cmd(**args)) - self.assertEqual(tx, should_tx) + assert tx == should_tx class TestNissanSafetyAltEpsBus(TestNissanSafety): @@ -85,7 +83,7 @@ class TestNissanSafetyAltEpsBus(TestNissanSafety): EPS_BUS = 1 CRUISE_BUS = 1 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("nissan_x_trail_2017_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_NISSAN, Panda.FLAG_NISSAN_ALT_EPS_BUS) @@ -94,7 +92,7 @@ def setUp(self): class TestNissanLeafSafety(TestNissanSafety): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("nissan_leaf_2018_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_NISSAN, 0) @@ -111,7 +109,3 @@ def _user_gas_msg(self, gas): # TODO: leaf should use its own safety param def test_acc_buttons(self): pass - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_subaru.py b/tests/safety/test_subaru.py old mode 100755 new mode 100644 index 7d07f79aaf..ef33175d6e --- a/tests/safety/test_subaru.py +++ b/tests/safety/test_subaru.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 import enum -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -72,7 +70,7 @@ class TestSubaruSafetyBase(common.PandaCarSafetyTest): INACTIVE_GAS = 1818 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("subaru_global_2017_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_SUBARU, self.FLAGS) @@ -208,21 +206,17 @@ def test_es_uds_message(self): button_did = 0x1130 # Tester present is allowed for gen2 long to keep eyesight disabled - self.assertTrue(self._tx(self._es_uds_msg(tester_present))) + assert self._tx(self._es_uds_msg(tester_present)) # Non-Tester present is not allowed - self.assertFalse(self._tx(self._es_uds_msg(not_tester_present))) + assert not self._tx(self._es_uds_msg(not_tester_present)) # Only button_did is allowed to be read via UDS for did in range(0xFFFF): should_tx = (did == button_did) - self.assertEqual(self._tx(self._es_uds_msg(self._rdbi_msg(did))), should_tx) + assert self._tx(self._es_uds_msg(self._rdbi_msg(did))) == should_tx # any other msg is not allowed for sid in range(0xFF): msg = b'\x03' + sid.to_bytes(1) + b'\x00' * 6 - self.assertFalse(self._tx(self._es_uds_msg(msg))) - - -if __name__ == "__main__": - unittest.main() + assert not self._tx(self._es_uds_msg(msg)) diff --git a/tests/safety/test_subaru_preglobal.py b/tests/safety/test_subaru_preglobal.py old mode 100755 new mode 100644 index 06c4cdefc8..c03364b6ad --- a/tests/safety/test_subaru_preglobal.py +++ b/tests/safety/test_subaru_preglobal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -import unittest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -25,7 +23,7 @@ class TestSubaruPreglobalSafety(common.PandaCarSafetyTest, common.DriverTorqueSt DRIVER_TORQUE_ALLOWANCE = 75 DRIVER_TORQUE_FACTOR = 10 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda(self.DBC) self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_SUBARU_PREGLOBAL, self.FLAGS) @@ -64,7 +62,3 @@ def _pcm_status_msg(self, enable): class TestSubaruPreglobalReversedDriverTorqueSafety(TestSubaruPreglobalSafety): FLAGS = Panda.FLAG_SUBARU_PREGLOBAL_REVERSED_DRIVER_TORQUE DBC = "subaru_outback_2019_generated" - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_tesla.py b/tests/safety/test_tesla.py old mode 100755 new mode 100644 index 9461ff68f9..a33f6c9734 --- a/tests/safety/test_tesla.py +++ b/tests/safety/test_tesla.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 -import unittest +import pytest import numpy as np from panda import Panda import panda.tests.safety.common as common @@ -25,9 +24,9 @@ class TestTeslaSafety(common.PandaCarSafetyTest): GAS_PRESSED_THRESHOLD = 3 FWD_BUS_LOOKUP = {0: 2, 2: 0} - def setUp(self): + def setup_method(self): self.packer = None - raise unittest.SkipTest + raise pytest.skip() def _speed_msg(self, speed): values = {"DI_vehicleSpeed": speed / 0.447} @@ -74,7 +73,7 @@ class TestTeslaSteeringSafety(TestTeslaSafety, common.AngleSteeringSafetyTest): ANGLE_RATE_UP = [10., 1.6, .3] # windup limit ANGLE_RATE_DOWN = [10., 7.0, .8] # unwind limit - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("tesla_can") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TESLA, 0) @@ -105,11 +104,11 @@ def test_acc_buttons(self): for controls_allowed in (True, False): self.safety.set_controls_allowed(controls_allowed) tx = self._tx(self._control_lever_cmd(btn)) - self.assertEqual(tx, should_tx) + assert tx == should_tx class TestTeslaRavenSteeringSafety(TestTeslaSteeringSafety): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("tesla_can") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TESLA, Panda.FLAG_TESLA_RAVEN) @@ -120,12 +119,12 @@ def _angle_meas_msg(self, angle: float): return self.packer.make_can_msg_panda("EPAS3P_sysStatus", 2, values) class TestTeslaLongitudinalSafety(TestTeslaSafety): - def setUp(self): - raise unittest.SkipTest + def setup_method(self): + raise pytest.skip() def test_no_aeb(self): for aeb_event in range(4): - self.assertEqual(self._tx(self._long_control_msg(10, aeb_event=aeb_event)), aeb_event == 0) + assert self._tx(self._long_control_msg(10, aeb_event=aeb_event)) == (aeb_event == 0) def test_stock_aeb_passthrough(self): no_aeb_msg = self._long_control_msg(10, aeb_event=0) @@ -133,14 +132,14 @@ def test_stock_aeb_passthrough(self): aeb_msg_cam = self._long_control_msg(10, aeb_event=1, bus=2) # stock system sends no AEB -> no forwarding, and OP is allowed to TX - self.assertEqual(1, self._rx(no_aeb_msg_cam)) - self.assertEqual(-1, self.safety.safety_fwd_hook(2, no_aeb_msg_cam.addr)) - self.assertEqual(True, self._tx(no_aeb_msg)) + assert 1 == self._rx(no_aeb_msg_cam) + assert -1 == self.safety.safety_fwd_hook(2, no_aeb_msg_cam.addr) + assert True is self._tx(no_aeb_msg) # stock system sends AEB -> forwarding, and OP is not allowed to TX - self.assertEqual(1, self._rx(aeb_msg_cam)) - self.assertEqual(0, self.safety.safety_fwd_hook(2, aeb_msg_cam.addr)) - self.assertEqual(False, self._tx(no_aeb_msg)) + assert 1 == self._rx(aeb_msg_cam) + assert 0 == self.safety.safety_fwd_hook(2, aeb_msg_cam.addr) + assert not self._tx(no_aeb_msg) def test_acc_accel_limits(self): for controls_allowed in [True, False]: @@ -154,7 +153,7 @@ def test_acc_accel_limits(self): send = (MIN_ACCEL <= min_accel <= MAX_ACCEL) and (MIN_ACCEL <= max_accel <= MAX_ACCEL) else: send = np.all(np.isclose([min_accel, max_accel], 0, atol=0.0001)) - self.assertEqual(send, self._tx(self._long_control_msg(10, acc_val=4, accel_limits=[min_accel, max_accel]))) + assert send == self._tx(self._long_control_msg(10, acc_val=4, accel_limits=[min_accel, max_accel])) class TestTeslaChassisLongitudinalSafety(TestTeslaLongitudinalSafety): @@ -162,7 +161,7 @@ class TestTeslaChassisLongitudinalSafety(TestTeslaLongitudinalSafety): RELAY_MALFUNCTION_ADDRS = {0: (0x488,)} FWD_BLACKLISTED_ADDRS = {2: [0x2B9, 0x488]} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("tesla_can") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TESLA, Panda.FLAG_TESLA_LONG_CONTROL) @@ -174,12 +173,8 @@ class TestTeslaPTLongitudinalSafety(TestTeslaLongitudinalSafety): RELAY_MALFUNCTION_ADDRS = {0: (0x2BF,)} FWD_BLACKLISTED_ADDRS = {2: [0x2BF]} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("tesla_powertrain") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TESLA, Panda.FLAG_TESLA_LONG_CONTROL | Panda.FLAG_TESLA_POWERTRAIN) self.safety.init_tests() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_toyota.py b/tests/safety/test_toyota.py old mode 100755 new mode 100644 index 80bf9ce9a1..b762050c23 --- a/tests/safety/test_toyota.py +++ b/tests/safety/test_toyota.py @@ -1,7 +1,6 @@ -#!/usr/bin/env python3 +import pytest import numpy as np import random -import unittest import itertools from panda import Panda @@ -29,11 +28,11 @@ class TestToyotaSafetyBase(common.PandaCarSafetyTest, common.LongitudinalAccelSa safety: libpanda_py.Panda @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__.endswith("Base"): cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _torque_meas_msg(self, torque: int, driver_torque: int | None = None): values = {"STEER_TORQUE_EPS": (torque / self.EPS_SCALE) * 100.} @@ -85,7 +84,7 @@ def test_diagnostics(self, stock_longitudinal: bool = False): (False, b"\x0F\x03\xAA\xAA\x00\x00\x00\x00"), # non-tester present (True, b"\x0F\x02\x3E\x00\x00\x00\x00\x00")): tester_present = libpanda_py.make_CANPacket(0x750, 0, msg) - self.assertEqual(should_tx and not stock_longitudinal, self._tx(tester_present)) + assert (should_tx and not stock_longitudinal) == self._tx(tester_present) def test_block_aeb(self, stock_longitudinal: bool = False): for controls_allowed in (True, False): @@ -96,7 +95,7 @@ def test_block_aeb(self, stock_longitudinal: bool = False): if not bad: dat = [0]*6 + dat[-1:] msg = libpanda_py.make_CANPacket(0x283, 0, bytes(dat)) - self.assertEqual(not bad and not stock_longitudinal, self._tx(msg)) + assert (not bad and not stock_longitudinal) == self._tx(msg) # Only allow LTA msgs with no actuation def test_lta_steer_cmd(self): @@ -107,7 +106,7 @@ def test_lta_steer_cmd(self): self.safety.set_controls_allowed(engaged) should_tx = not req and not req2 and angle == 0 and torque_wind_down == 0 - self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle, torque_wind_down))) + assert should_tx == self._tx(self._lta_msg(req, req2, angle, torque_wind_down)) def test_rx_hook(self): # checksum checks @@ -117,13 +116,13 @@ def test_rx_hook(self): to_push = self._torque_meas_msg(0) if msg == "pcm": to_push = self._pcm_status_msg(True) - self.assertTrue(self._rx(to_push)) + assert self._rx(to_push) to_push[0].data[4] = 0 to_push[0].data[5] = 0 to_push[0].data[6] = 0 to_push[0].data[7] = 0 - self.assertFalse(self._rx(to_push)) - self.assertFalse(self.safety.get_controls_allowed()) + assert not self._rx(to_push) + assert not self.safety.get_controls_allowed() class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest): @@ -141,7 +140,7 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf MAX_INVALID_STEERING_FRAMES = 1 MIN_VALID_STEERING_RT_INTERVAL = 170000 # a ~10% buffer, can send steer up to 110Hz - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("toyota_nodsu_pt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE) @@ -161,7 +160,7 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest MAX_MEAS_TORQUE = 1500 # max allowed measured EPS torque before wind down MAX_LTA_DRIVER_TORQUE = 150 # max allowed driver torque before wind down - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("toyota_nodsu_pt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_LTA) @@ -179,7 +178,7 @@ def test_lka_steer_cmd(self): self.safety.set_desired_torque_last(torque) should_tx = not steer_req and torque == 0 - self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(torque, steer_req))) + assert should_tx == self._tx(self._torque_cmd_msg(torque, steer_req)) def test_lta_steer_cmd(self): """ @@ -198,13 +197,13 @@ def test_lta_steer_cmd(self): self._reset_angle_measurement(angle) self._set_prev_desired_angle(angle) - self.assertTrue(self._tx(self._lta_msg(0, 0, angle, 0))) + assert self._tx(self._lta_msg(0, 0, angle, 0)) if controls_allowed: # Test the two steer request bits and TORQUE_WIND_DOWN torque wind down signal for req, req2, torque_wind_down in itertools.product([0, 1], [0, 1], [0, 50, 100]): mismatch = not (req or req2) and torque_wind_down != 0 should_tx = req == req2 and (torque_wind_down in (0, 100)) and not mismatch - self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle, torque_wind_down))) + assert should_tx == self._tx(self._lta_msg(req, req2, angle, torque_wind_down)) # Test max EPS torque and driver override thresholds cases = itertools.product( @@ -219,14 +218,14 @@ def test_lta_steer_cmd(self): # Toyota adds 1 to EPS torque since it is rounded after EPS factor should_tx = (eps_torque - 1) <= self.MAX_MEAS_TORQUE and driver_torque <= self.MAX_LTA_DRIVER_TORQUE - self.assertEqual(should_tx, self._tx(self._lta_msg(1, 1, angle, 100))) - self.assertTrue(self._tx(self._lta_msg(1, 1, angle, 0))) # should tx if we wind down torque + assert should_tx == self._tx(self._lta_msg(1, 1, angle, 100)) + assert self._tx(self._lta_msg(1, 1, angle, 0))# should tx if we wind down torque else: # Controls not allowed for req, req2, torque_wind_down in itertools.product([0, 1], [0, 1], [0, 50, 100]): should_tx = not (req or req2) and torque_wind_down == 0 - self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle, torque_wind_down))) + assert should_tx == self._tx(self._lta_msg(req, req2, angle, torque_wind_down)) def test_steering_angle_measurements(self, max_angle=None): # Measurement test tests max angle + 0.5 which will fail @@ -244,26 +243,26 @@ def test_angle_measurements(self): for angle in np.arange(0, self.MAX_LTA_ANGLE * 2, 1): # If init flag is set, do not rx or parse any angle measurements for a in (angle, -angle, 0, 0, 0, 0): - self.assertEqual(not steer_angle_initializing, - self._rx(self._angle_meas_msg(a, steer_angle_initializing))) + assert not steer_angle_initializing == \ + self._rx(self._angle_meas_msg(a, steer_angle_initializing)) final_angle = (0 if steer_angle_initializing else round(min(angle, self.MAX_LTA_ANGLE) * self.DEG_TO_CAN)) - self.assertEqual(self.safety.get_angle_meas_min(), -final_angle) - self.assertEqual(self.safety.get_angle_meas_max(), final_angle) + assert self.safety.get_angle_meas_min() == -final_angle + assert self.safety.get_angle_meas_max() == final_angle self._rx(self._angle_meas_msg(0)) - self.assertEqual(self.safety.get_angle_meas_min(), -final_angle) - self.assertEqual(self.safety.get_angle_meas_max(), 0) + assert self.safety.get_angle_meas_min() == -final_angle + assert self.safety.get_angle_meas_max() == 0 self._rx(self._angle_meas_msg(0)) - self.assertEqual(self.safety.get_angle_meas_min(), 0) - self.assertEqual(self.safety.get_angle_meas_max(), 0) + assert self.safety.get_angle_meas_min() == 0 + assert self.safety.get_angle_meas_max() == 0 class TestToyotaAltBrakeSafety(TestToyotaSafetyTorque): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("toyota_new_mc_pt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_ALT_BRAKE) @@ -301,14 +300,14 @@ def test_acc_cancel(self): for controls_allowed in [True, False]: self.safety.set_controls_allowed(controls_allowed) for accel in np.arange(self.MIN_ACCEL - 1, self.MAX_ACCEL + 1, 0.1): - self.assertFalse(self._tx(self._accel_msg(accel))) + assert not self._tx(self._accel_msg(accel)) should_tx = np.isclose(accel, 0, atol=0.0001) - self.assertEqual(should_tx, self._tx(self._accel_msg(accel, cancel_req=1))) + assert should_tx == self._tx(self._accel_msg(accel, cancel_req=1)) class TestToyotaStockLongitudinalTorque(TestToyotaStockLongitudinalBase, TestToyotaSafetyTorque): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("toyota_nodsu_pt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL) @@ -317,12 +316,8 @@ def setUp(self): class TestToyotaStockLongitudinalAngle(TestToyotaStockLongitudinalBase, TestToyotaSafetyAngle): - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("toyota_nodsu_pt_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL | Panda.FLAG_TOYOTA_LTA) self.safety.init_tests() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_volkswagen_mqb.py b/tests/safety/test_volkswagen_mqb.py old mode 100755 new mode 100644 index 276ee6c27d..024300a023 --- a/tests/safety/test_volkswagen_mqb.py +++ b/tests/safety/test_volkswagen_mqb.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 -import unittest +import pytest import numpy as np from panda import Panda from panda.tests.libpanda import libpanda_py @@ -36,11 +35,11 @@ class TestVolkswagenMqbSafety(common.PandaCarSafetyTest, common.DriverTorqueStee DRIVER_TORQUE_FACTOR = 3 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestVolkswagenMqbSafety": cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() # Wheel speeds _esp_19_msg def _speed_msg(self, speed): @@ -108,11 +107,11 @@ def test_redundant_brake_signals(self): for brake_pressed, motor_14_signal, esp_05_signal in test_combinations: self._rx(self._motor_14_msg(False)) self._rx(self._esp_05_msg(False)) - self.assertFalse(self.safety.get_brake_pressed_prev()) + assert not self.safety.get_brake_pressed_prev() self._rx(self._motor_14_msg(motor_14_signal)) self._rx(self._esp_05_msg(esp_05_signal)) - self.assertEqual(brake_pressed, self.safety.get_brake_pressed_prev(), - f"expected {brake_pressed=} with {motor_14_signal=} and {esp_05_signal=}") + assert brake_pressed == self.safety.get_brake_pressed_prev(), \ + f"expected {brake_pressed=} with {motor_14_signal=} and {esp_05_signal=}" def test_torque_measurements(self): # TODO: make this test work with all cars @@ -123,16 +122,16 @@ def test_torque_measurements(self): self._rx(self._torque_driver_msg(0)) self._rx(self._torque_driver_msg(0)) - self.assertEqual(-50, self.safety.get_torque_driver_min()) - self.assertEqual(50, self.safety.get_torque_driver_max()) + assert -50 == self.safety.get_torque_driver_min() + assert 50 == self.safety.get_torque_driver_max() self._rx(self._torque_driver_msg(0)) - self.assertEqual(0, self.safety.get_torque_driver_max()) - self.assertEqual(-50, self.safety.get_torque_driver_min()) + assert 0 == self.safety.get_torque_driver_max() + assert -50 == self.safety.get_torque_driver_min() self._rx(self._torque_driver_msg(0)) - self.assertEqual(0, self.safety.get_torque_driver_max()) - self.assertEqual(0, self.safety.get_torque_driver_min()) + assert 0 == self.safety.get_torque_driver_max() + assert 0 == self.safety.get_torque_driver_min() class TestVolkswagenMqbStockSafety(TestVolkswagenMqbSafety): @@ -140,7 +139,7 @@ class TestVolkswagenMqbStockSafety(TestVolkswagenMqbSafety): FWD_BLACKLISTED_ADDRS = {0: [MSG_LH_EPS_03], 2: [MSG_HCA_01, MSG_LDW_02]} FWD_BUS_LOOKUP = {0: 2, 2: 0} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("vw_mqb_2010") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_VOLKSWAGEN_MQB, 0) @@ -148,12 +147,12 @@ def setUp(self): def test_spam_cancel_safety_check(self): self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._gra_acc_01_msg(cancel=1))) - self.assertFalse(self._tx(self._gra_acc_01_msg(resume=1))) - self.assertFalse(self._tx(self._gra_acc_01_msg(_set=1))) + assert self._tx(self._gra_acc_01_msg(cancel=1)) + assert not self._tx(self._gra_acc_01_msg(resume=1)) + assert not self._tx(self._gra_acc_01_msg(_set=1)) # do not block resume if we are engaged already self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._gra_acc_01_msg(resume=1))) + assert self._tx(self._gra_acc_01_msg(resume=1)) class TestVolkswagenMqbLongSafety(TestVolkswagenMqbSafety): @@ -162,7 +161,7 @@ class TestVolkswagenMqbLongSafety(TestVolkswagenMqbSafety): FWD_BUS_LOOKUP = {0: 2, 2: 0} INACTIVE_ACCEL = 3.01 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("vw_mqb_2010") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_VOLKSWAGEN_MQB, Panda.FLAG_VOLKSWAGEN_LONG_CONTROL) @@ -184,26 +183,26 @@ def test_set_and_resume_buttons(self): self.safety.set_controls_allowed(0) self._rx(self._tsk_status_msg(False, main_switch=False)) self._rx(self._gra_acc_01_msg(_set=(button == "set"), resume=(button == "resume"), bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off") + assert not self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off" self._rx(self._tsk_status_msg(False, main_switch=True)) self._rx(self._gra_acc_01_msg(_set=(button == "set"), resume=(button == "resume"), bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge") + assert not self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge" self._rx(self._gra_acc_01_msg(bus=0)) - self.assertTrue(self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge") + assert self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge" def test_cancel_button(self): # Disable on rising edge of cancel button self._rx(self._tsk_status_msg(False, main_switch=True)) self.safety.set_controls_allowed(1) self._rx(self._gra_acc_01_msg(cancel=True, bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel") + assert not self.safety.get_controls_allowed(), "controls allowed after cancel" def test_main_switch(self): # Disable as soon as main switch turns off self._rx(self._tsk_status_msg(False, main_switch=True)) self.safety.set_controls_allowed(1) self._rx(self._tsk_status_msg(False, main_switch=False)) - self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after ACC main switch off") + assert not self.safety.get_controls_allowed(), "controls allowed after ACC main switch off" def test_accel_safety_check(self): for controls_allowed in [True, False]: @@ -214,12 +213,8 @@ def test_accel_safety_check(self): send = (controls_allowed and MIN_ACCEL <= accel <= MAX_ACCEL) or is_inactive_accel self.safety.set_controls_allowed(controls_allowed) # primary accel request used by ECU - self.assertEqual(send, self._tx(self._acc_06_msg(accel)), (controls_allowed, accel)) + assert send == self._tx(self._acc_06_msg(accel)), (controls_allowed, accel) # additional accel request used by ABS/ESP - self.assertEqual(send, self._tx(self._acc_07_msg(accel)), (controls_allowed, accel)) + assert send == self._tx(self._acc_07_msg(accel)), (controls_allowed, accel) # ensure the optional secondary accel field remains inactive for now - self.assertEqual(is_inactive_accel, self._tx(self._acc_07_msg(accel, secondary_accel=accel)), (controls_allowed, accel)) - - -if __name__ == "__main__": - unittest.main() + assert is_inactive_accel == self._tx(self._acc_07_msg(accel, secondary_accel=accel)), (controls_allowed, accel) diff --git a/tests/safety/test_volkswagen_pq.py b/tests/safety/test_volkswagen_pq.py old mode 100755 new mode 100644 index f2bc317868..2bdf1d153d --- a/tests/safety/test_volkswagen_pq.py +++ b/tests/safety/test_volkswagen_pq.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 -import unittest +import pytest from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common @@ -33,11 +32,11 @@ class TestVolkswagenPqSafety(common.PandaCarSafetyTest, common.DriverTorqueSteer DRIVER_TORQUE_FACTOR = 3 @classmethod - def setUpClass(cls): + def setup_class(cls): if cls.__name__ == "TestVolkswagenPqSafety": cls.packer = None cls.safety = None - raise unittest.SkipTest + raise pytest.skip() def _set_prev_torque(self, t): self.safety.set_desired_torque_last(t) @@ -104,16 +103,16 @@ def test_torque_measurements(self): self._rx(self._torque_driver_msg(0)) self._rx(self._torque_driver_msg(0)) - self.assertEqual(-50, self.safety.get_torque_driver_min()) - self.assertEqual(50, self.safety.get_torque_driver_max()) + assert -50 == self.safety.get_torque_driver_min() + assert 50 == self.safety.get_torque_driver_max() self._rx(self._torque_driver_msg(0)) - self.assertEqual(0, self.safety.get_torque_driver_max()) - self.assertEqual(-50, self.safety.get_torque_driver_min()) + assert 0 == self.safety.get_torque_driver_max() + assert -50 == self.safety.get_torque_driver_min() self._rx(self._torque_driver_msg(0)) - self.assertEqual(0, self.safety.get_torque_driver_max()) - self.assertEqual(0, self.safety.get_torque_driver_min()) + assert 0 == self.safety.get_torque_driver_max() + assert 0 == self.safety.get_torque_driver_min() class TestVolkswagenPqStockSafety(TestVolkswagenPqSafety): @@ -122,7 +121,7 @@ class TestVolkswagenPqStockSafety(TestVolkswagenPqSafety): FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1]} FWD_BUS_LOOKUP = {0: 2, 2: 0} - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("vw_golf_mk4") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_VOLKSWAGEN_PQ, 0) @@ -130,12 +129,12 @@ def setUp(self): def test_spam_cancel_safety_check(self): self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._button_msg(cancel=True))) - self.assertFalse(self._tx(self._button_msg(resume=True))) - self.assertFalse(self._tx(self._button_msg(_set=True))) + assert self._tx(self._button_msg(cancel=True)) + assert not self._tx(self._button_msg(resume=True)) + assert not self._tx(self._button_msg(_set=True)) # do not block resume if we are engaged already self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._button_msg(resume=True))) + assert self._tx(self._button_msg(resume=True)) class TestVolkswagenPqLongSafety(TestVolkswagenPqSafety, common.LongitudinalAccelSafetyTest): @@ -144,7 +143,7 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafety, common.LongitudinalAcce FWD_BUS_LOOKUP = {0: 2, 2: 0} INACTIVE_ACCEL = 3.01 - def setUp(self): + def setup_method(self): self.packer = CANPackerPanda("vw_golf_mk4") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_VOLKSWAGEN_PQ, Panda.FLAG_VOLKSWAGEN_LONG_CONTROL) @@ -167,33 +166,29 @@ def test_set_and_resume_buttons(self): self._rx(self._motor_5_msg(main_switch=False)) self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=0)) self._rx(self._button_msg(bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off") + assert not self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off" self._rx(self._motor_5_msg(main_switch=True)) self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge") + assert not self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge" self._rx(self._button_msg(bus=0)) - self.assertTrue(self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge") + assert self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge" def test_cancel_button(self): # Disable on rising edge of cancel button self._rx(self._motor_5_msg(main_switch=True)) self.safety.set_controls_allowed(1) self._rx(self._button_msg(cancel=True, bus=0)) - self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel") + assert not self.safety.get_controls_allowed(), "controls allowed after cancel" def test_main_switch(self): # Disable as soon as main switch turns off self._rx(self._motor_5_msg(main_switch=True)) self.safety.set_controls_allowed(1) self._rx(self._motor_5_msg(main_switch=False)) - self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after ACC main switch off") + assert not self.safety.get_controls_allowed(), "controls allowed after ACC main switch off" def test_torque_cmd_enable_variants(self): # The EPS rack accepts either 5 or 7 for an enabled status, with different low speed tuning behavior self.safety.set_controls_allowed(1) for enabled_status in (5, 7): - self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP, steer_req=1, hca_status=enabled_status)), - f"torque cmd rejected with {enabled_status=}") - -if __name__ == "__main__": - unittest.main() + assert self._tx(self._torque_cmd_msg(self.MAX_RATE_UP, steer_req=1, hca_status=enabled_status)), f"torque cmd rejected with {enabled_status=}" diff --git a/tests/usbprotocol/test.sh b/tests/usbprotocol/test.sh index b4c32166b9..ea182ca2f0 100755 --- a/tests/usbprotocol/test.sh +++ b/tests/usbprotocol/test.sh @@ -4,5 +4,5 @@ set -e # Loops over all HW_TYPEs, see board/boards/board_declarations.h for hw_type in {0..7}; do echo "Testing HW_TYPE: $hw_type" - HW_TYPE=$hw_type python3 -m unittest discover . + HW_TYPE=$hw_type pytest . done diff --git a/tests/usbprotocol/test_comms.py b/tests/usbprotocol/test_comms.py old mode 100755 new mode 100644 index e649bdaeab..9089337b02 --- a/tests/usbprotocol/test_comms.py +++ b/tests/usbprotocol/test_comms.py @@ -1,6 +1,5 @@ -#!/usr/bin/env python3 +import pytest import random -import unittest from panda import Panda, DLC_TO_LEN, USBPACKET_MAX_SIZE, pack_can_buffer, unpack_can_buffer from panda.tests.libpanda import libpanda_py @@ -28,8 +27,8 @@ def random_can_messages(n, bus=None): return msgs -class TestPandaComms(unittest.TestCase): - def setUp(self): +class TestPandaComms: + def setup_method(self): lpp.comms_can_reset() def test_tx_queues(self): @@ -44,6 +43,7 @@ def test_tx_queues(self): assert unpackage_can_msg(can_pkt_rx) == message + @pytest.mark.order(1) def test_comms_reset_rx(self): # store some test messages in the queue test_msg = (0x100, b"test", 0) @@ -75,6 +75,8 @@ def test_comms_reset_rx(self): assert m == test_msg, "message buffer should contain valid test messages" def test_comms_reset_tx(self): + lpp.set_safety_hooks(Panda.SAFETY_ALLOUTPUT, 0) + # store some test messages in the queue test_msg = (0x100, b"test", 0) packed = pack_can_buffer([test_msg for _ in range(100)]) @@ -100,11 +102,11 @@ def test_comms_reset_tx(self): assert m == test_msg, "message buffer should contain valid test messages" - def test_can_send_usb(self): + def test_can_send_usb(self, subtests): lpp.set_safety_hooks(Panda.SAFETY_ALLOUTPUT, 0) for bus in range(3): - with self.subTest(bus=bus): + with subtests.test(bus=bus): for _ in range(100): msgs = random_can_messages(200, bus=bus) packed = pack_can_buffer(msgs) @@ -121,9 +123,10 @@ def test_can_send_usb(self): while lpp.can_pop(TX_QUEUES[bus], pkt): queue_msgs.append(unpackage_can_msg(pkt)) - self.assertEqual(len(queue_msgs), len(msgs)) - self.assertEqual(queue_msgs, msgs) + assert len(queue_msgs) == len(msgs) + assert queue_msgs == msgs + @pytest.mark.order(2) def test_can_receive_usb(self): msgs = random_can_messages(50000) packets = [libpanda_py.make_CANPacket(m[0], m[2], m[1]) for m in msgs] @@ -152,9 +155,5 @@ def test_can_receive_usb(self): unpacked_msgs, overflow_buf = unpack_can_buffer(overflow_buf + buf) rx_msgs.extend(unpacked_msgs) - self.assertEqual(len(rx_msgs), len(msgs)) - self.assertEqual(rx_msgs, msgs) - - -if __name__ == "__main__": - unittest.main() + assert len(rx_msgs) == len(msgs) + assert rx_msgs == msgs diff --git a/tests/usbprotocol/test_pandalib.py b/tests/usbprotocol/test_pandalib.py old mode 100755 new mode 100644 index ef725948c7..7c31e26206 --- a/tests/usbprotocol/test_pandalib.py +++ b/tests/usbprotocol/test_pandalib.py @@ -1,10 +1,8 @@ -#!/usr/bin/env python3 import random -import unittest from panda import pack_can_buffer, unpack_can_buffer, DLC_TO_LEN -class PandaTestPackUnpack(unittest.TestCase): +class TestPandaPackUnpack: def test_panda_lib_pack_unpack(self): overflow_buf = b'' @@ -20,7 +18,4 @@ def test_panda_lib_pack_unpack(self): msgs, overflow_buf = unpack_can_buffer(overflow_buf + dat) unpacked.extend(msgs) - self.assertEqual(unpacked, to_pack) - -if __name__ == "__main__": - unittest.main() + assert unpacked == to_pack