from unittest.mock import MagicMock, patch import numpy as np import pytest from bookmark.camera import CameraSource def test_open_raises_when_capture_not_opened(): with patch("bookmark.camera.cv2.VideoCapture") as mock_video_capture: mock_instance = MagicMock() mock_instance.isOpened.return_value = False mock_video_capture.return_value = mock_instance source = CameraSource(device_index=0) with pytest.raises(RuntimeError, match="Could not open camera"): source.open() # Verify that release() was called on the failed capture mock_instance.release.assert_called_once() def test_read_frame_returns_frame_from_capture(): with patch("bookmark.camera.cv2.VideoCapture") as mock_video_capture: mock_instance = MagicMock() mock_instance.isOpened.return_value = True fake_frame = np.zeros((10, 10, 3), dtype=np.uint8) mock_instance.read.return_value = (True, fake_frame) mock_video_capture.return_value = mock_instance source = CameraSource(device_index=0) source.open() frame = source.read_frame() assert frame.shape == (10, 10, 3) def test_read_frame_raises_when_capture_fails(): with patch("bookmark.camera.cv2.VideoCapture") as mock_video_capture: mock_instance = MagicMock() mock_instance.isOpened.return_value = True mock_instance.read.return_value = (False, None) mock_video_capture.return_value = mock_instance source = CameraSource(device_index=0) source.open() with pytest.raises(RuntimeError, match="Failed to read frame"): source.read_frame() def test_read_frame_raises_if_not_opened(): source = CameraSource(device_index=0) with pytest.raises(RuntimeError, match="not opened"): source.read_frame() def test_open_twice_releases_first_capture(): with patch("bookmark.camera.cv2.VideoCapture") as mock_video_capture: # Setup two distinct mock instances first_mock = MagicMock() first_mock.isOpened.return_value = True second_mock = MagicMock() second_mock.isOpened.return_value = True mock_video_capture.side_effect = [first_mock, second_mock] source = CameraSource(device_index=0) # First open source.open() assert source._capture is first_mock # Second open should release the first capture source.open() assert source._capture is second_mock # Verify the first mock's release() was called before the second was assigned first_mock.release.assert_called_once()