""" test_babylin_backend.py — Tests for Step 6: BabyLIN communication backend. All tests run in MOCK MODE since we don't have hardware in CI. The mock mode verifies the state machine and API surface. When real hardware is connected, the same API calls go to the DLL. """ import sys import pytest from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from babylin_backend import BabyLinBackend, BackendState, DeviceInfo @pytest.fixture def backend(): """Create a fresh BabyLinBackend in mock mode.""" b = BabyLinBackend() assert b.is_mock_mode # Should be mock on macOS / CI return b class TestBackendInit: """Test initial state.""" def test_initial_state_idle(self, backend): assert backend.state == BackendState.IDLE def test_is_mock_mode(self, backend): assert backend.is_mock_mode def test_no_device_initially(self, backend): assert backend.device_info is None def test_sdf_not_loaded_initially(self, backend): assert not backend.sdf_loaded class TestDeviceScanning: """Test device discovery in mock mode.""" def test_scan_returns_mock_device(self, backend): devices = backend.scan_devices() assert len(devices) >= 1 assert "Mock" in devices[0].hardware_type def test_scan_returns_device_info(self, backend): devices = backend.scan_devices() assert isinstance(devices[0], DeviceInfo) assert devices[0].port_name != "" class TestConnection: """Test connect/disconnect flow in mock mode.""" def test_connect_success(self, backend): result = backend.connect("MOCK-BABYLIN") assert result is True assert backend.state == BackendState.IDLE assert backend.device_info is not None assert backend.device_info.port_name == "MOCK-BABYLIN" def test_disconnect(self, backend): backend.connect("MOCK-BABYLIN") backend.disconnect() assert backend.device_info is None assert backend.state == BackendState.IDLE class TestSdfLoading: """Test SDF file loading in mock mode.""" def test_load_existing_sdf(self, backend, tmp_path): backend.connect("MOCK-BABYLIN") sdf_file = tmp_path / "test.sdf" sdf_file.write_text("mock sdf content") result = backend.load_sdf(str(sdf_file)) assert result is True assert backend.sdf_loaded def test_load_nonexistent_sdf(self, backend): backend.connect("MOCK-BABYLIN") result = backend.load_sdf("/nonexistent/path.sdf") assert result is False assert not backend.sdf_loaded class TestBusControl: """Test start/stop in mock mode.""" def test_start(self, backend): backend.connect("MOCK-BABYLIN") result = backend.start(schedule_index=0) assert result is True assert backend.state == BackendState.RUNNING def test_stop(self, backend): backend.connect("MOCK-BABYLIN") backend.start() result = backend.stop() assert result is True assert backend.state == BackendState.STOPPED def test_start_with_schedule(self, backend): backend.connect("MOCK-BABYLIN") result = backend.start(schedule_index=2) assert result is True assert backend.state == BackendState.RUNNING class TestSignalAccess: """Test signal read/write in mock mode.""" def test_set_signal_by_name(self, backend): backend.connect("MOCK-BABYLIN") result = backend.set_signal_by_name("MotorSpeed", 128) assert result is True def test_set_signal_by_index(self, backend): backend.connect("MOCK-BABYLIN") result = backend.set_signal_by_index(0, 1) assert result is True def test_get_signal_value(self, backend): backend.connect("MOCK-BABYLIN") value = backend.get_signal_value(0) assert value == 0 # Mock returns 0 class TestFrameCallback: """Test frame callback registration in mock mode.""" def test_register_callback(self, backend): received = [] backend.connect("MOCK-BABYLIN") backend.register_frame_callback(lambda fid, data: received.append((fid, data))) # In mock mode, callback is stored but not called automatically assert backend._frame_callback is not None def test_unregister_callback(self, backend): backend.connect("MOCK-BABYLIN") backend.register_frame_callback(lambda fid, data: None) backend.register_frame_callback(None) assert backend._frame_callback is None class TestRawAccess: """Test raw frame and command sending in mock mode.""" def test_send_raw_master_request(self, backend): backend.connect("MOCK-BABYLIN") result = backend.send_raw_master_request(bytes([0x3C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) assert result is True def test_send_command(self, backend): backend.connect("MOCK-BABYLIN") result = backend.send_command("start;") assert result is True