import pytest from ecu_framework.lin.base import LinFrame from ecu_framework.lin.babylin import BabyLinInterface # Inject the pure-Python mock wrapper to run SDK adapter tests without hardware from vendor import mock_babylin_wrapper as mock_bl class _MockBytesOnly: """Shim exposing BLC_sendRawMasterRequest(bytes) only, to test bytes signature. We wrap the existing mock but override BLC_sendRawMasterRequest to accept only the bytes payload form. The response still uses the deterministic pattern implied by the payload length (zeros are fine; we assert by length here). """ @staticmethod def create_BabyLIN(): base = mock_bl.create_BabyLIN() def bytes_only(channel, frame_id, payload): # Delegate to the base mock's bytes variant by ensuring we pass bytes if not isinstance(payload, (bytes, bytearray)): raise TypeError("expected bytes payload") return base.BLC_sendRawMasterRequest(channel, frame_id, bytes(payload)) # Monkey-patch the method to raise TypeError when a length is provided def patched_raw_req(*args): # Expected signature: (channel, frame_id, payload_bytes) if len(args) != 3 or not isinstance(args[2], (bytes, bytearray)): raise TypeError("bytes signature only") return bytes_only(*args) base.BLC_sendRawMasterRequest = patched_raw_req return base @pytest.mark.babylin @pytest.mark.smoke @pytest.mark.req_001 def test_babylin_sdk_adapter_with_mock_wrapper(rp): """ Title: SDK Adapter - Send/Receive with Mock Wrapper Description: Validate that the BabyLIN SDK-based adapter can send and receive using a mocked wrapper exposing BLC_* APIs. The mock implements loopback by echoing transmitted frames into the receive queue. Requirements: REQ-001 Test Steps: 1. Construct BabyLinInterface with injected mock wrapper 2. Connect (discovers port, opens, loads SDF, starts schedule) 3. Send a frame via BLC_mon_set_xmit 4. Receive the same frame via BLC_getNextFrameTimeout 5. Disconnect Expected Result: - Received frame matches sent frame (ID and payload) """ # Step 1-2: Create adapter with wrapper injection and connect lin = BabyLinInterface(sdf_path="./vendor/Example.sdf", schedule_nr=0, wrapper_module=mock_bl) rp("wrapper", "mock_bl") lin.connect() try: # Step 3: Transmit a known payload on a chosen ID tx = LinFrame(id=0x12, data=bytes([0xAA, 0x55, 0x01])) lin.send(tx) # Step 4: Receive from the mock's RX queue (loopback) rx = lin.receive(timeout=0.1) rp("tx_id", f"0x{tx.id:02X}") rp("tx_data", list(tx.data)) rp("rx_present", rx is not None) # Step 5: Validate ID and payload integrity assert rx is not None, "Expected a frame from mock loopback" assert rx.id == tx.id assert rx.data == tx.data finally: # Always disconnect to leave the mock in a clean state lin.disconnect() @pytest.mark.babylin @pytest.mark.smoke @pytest.mark.req_001 @pytest.mark.parametrize("wrapper,expect_pattern", [ (mock_bl, True), # length signature available: expect deterministic pattern (_MockBytesOnly, False), # bytes-only signature: expect zeros of requested length ]) def test_babylin_master_request_with_mock_wrapper(wrapper, expect_pattern, rp): """ Title: SDK Adapter - Master Request using Mock Wrapper Description: Verify that request() prefers the SDK's BLC_sendRawMasterRequest when available. The mock wrapper enqueues a deterministic response where data[i] = (id + i) & 0xFF, allowing predictable assertions. Requirements: REQ-001 Test Steps: 1. Construct BabyLinInterface with injected mock wrapper 2. Connect (mock open/initialize) 3. Issue a master request for a specific ID and length 4. Receive the response frame 5. Validate ID and deterministic payload pattern Expected Result: - Response frame ID matches request ID - Response data length matches requested length - Response data follows deterministic pattern """ # Step 1-2: Initialize mock-backed adapter lin = BabyLinInterface(wrapper_module=wrapper) rp("wrapper", getattr(wrapper, "__name__", str(wrapper))) lin.connect() try: # Step 3: Request 4 bytes for ID 0x22 req_id = 0x22 length = 4 rp("req_id", f"0x{req_id:02X}") rp("req_len", length) rx = lin.request(id=req_id, length=length, timeout=0.1) # Step 4-5: Validate response assert rx is not None, "Expected a response from mock master request" assert rx.id == req_id if expect_pattern: # length-signature mock returns deterministic pattern expected = bytes(((req_id + i) & 0xFF) for i in range(length)) rp("expected_data", list(expected)) rp("rx_data", list(rx.data)) assert rx.data == expected else: # bytes-only mock returns exactly the bytes we sent (zeros of requested length) expected = bytes([0] * length) rp("expected_data", list(expected)) rp("rx_data", list(rx.data)) assert rx.data == expected finally: lin.disconnect()