"""TDD for PiCameraSource (CSI camera via picamera2) — no hardware/picamera2 needed, by injecting a fake Picamera2 object. Locks the SourcePort contract: read() -> (ok, frame).""" import numpy as np from edge.adapters.picamera_source import PiCameraSource class _FakePicam2: def __init__(self, frames): self.frames = list(frames) self.i = 0 self.started = False def capture_array(self): frame = self.frames[self.i % len(self.frames)] self.i += 1 return frame def test_read_returns_ok_and_frame(): frame = np.full((480, 640, 3), 128, np.uint8) src = PiCameraSource(picam2=_FakePicam2([frame])) ok, f = src.read() assert ok is True assert f.shape == (480, 640, 3) def test_read_none_frame_returns_false(): class _Empty: def capture_array(self): return None src = PiCameraSource(picam2=_Empty()) ok, f = src.read() assert ok is False assert f is None