import importlib.util import unittest from pathlib import Path from unittest.mock import patch MODULE_PATH = Path(__file__).resolve().parents[1] / "core" / "simulated_device.py" SPEC = importlib.util.spec_from_file_location("simulated_device_under_test", MODULE_PATH) SIMULATED = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(SIMULATED) class SimulatedDeviceTests(unittest.TestCase): def test_connect_read_and_write_without_hardware(self): device = SIMULATED.SimulatedDevice() self.assertTrue(device.connect()) self.assertTrue(device.set_motor_position(0)) self.assertIsInstance(device.get_pressure(), float) self.assertIsInstance(device.get_flow(), float) self.assertEqual(len(device.command_log), 1) device.disconnect() self.assertFalse(device.connected) def test_pressure_model_responds_to_valve_position(self): class FakeClock: def __init__(self): self.now = 0.0 def monotonic(self): return self.now def advance(self, duration): self.now += duration clock = FakeClock() with patch.object(SIMULATED.time, "monotonic", clock.monotonic): device = SIMULATED.SimulatedDevice() device.connect() def settled_pressure(position): device.set_motor_position(position) pressure = None for _ in range(1200): clock.advance(0.1) pressure = device.get_pressure() return pressure open_pressure = settled_pressure(0) half_open_pressure = settled_pressure(500) closed_pressure = settled_pressure(1000) self.assertAlmostEqual(open_pressure, 10.0, delta=0.1) self.assertAlmostEqual(half_open_pressure, 205.0, delta=0.1) self.assertAlmostEqual(closed_pressure, 400.0, delta=0.1) self.assertGreater(closed_pressure, half_open_pressure) self.assertGreater(half_open_pressure, open_pressure) self.assertEqual(device.read_current_position(), 1000.0) device.disconnect() if __name__ == "__main__": unittest.main()