openflexure-microscope-server/tests/unit_tests/test_illumination.py
2026-02-12 15:33:58 +00:00

127 lines
4.3 KiB
Python

"""Tests for the Illumination thing."""
from unittest.mock import call, patch
import pytest
from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things.illumination import (
Illumination,
SangaIllumination,
SimulatorIllumination,
)
# Test the BaseClass before testing specific implementation
def test_base_illumination_set_led_not_implemented():
"""Check that calling set_led on the base Illumination raises NotImplementedError."""
ill = create_thing_without_server(Illumination)
with pytest.raises(
NotImplementedError,
match="Turning the LED on and off should be implemented by child classes.",
):
ill.set_led(led_on=True)
def test_flash_calls_set_led_and_raises():
"""Check that calling flash from Baseclass calls flash with right arguments."""
ill = create_thing_without_server(Illumination)
number_of_flashes = 3 # smaller number for test speed
dt = 0 # avoid sleeping
with pytest.raises(NotImplementedError):
ill.flash(number_of_flashes=number_of_flashes, dt=dt)
# Patch set_led to just record calls without raising
with patch.object(ill, "set_led") as mock_set_led:
# Call flash normally
ill.flash(number_of_flashes=number_of_flashes, dt=dt)
# Each flash calls set_led twice: False, True
expected_sequence = [call(False), call(True)] * number_of_flashes
assert mock_set_led.call_args_list == expected_sequence
# Also check total number of calls
assert mock_set_led.call_count == number_of_flashes * 2
def test_negative_flash_calls():
"""Check that calling flash with negative number doesn't call set_led."""
ill = create_thing_without_server(Illumination)
number_of_flashes = -33 # smaller number for test speed
dt = 0 # avoid sleeping
# Patch set_led to just record calls without raising
with patch.object(ill, "set_led") as mock_set_led:
# Call flash normally
ill.flash(number_of_flashes=number_of_flashes, dt=dt)
# Also check total number of calls
assert mock_set_led.call_count == 0
def test_negative_flash_dt():
"""Check that calling flash with negative dt raises ValueError."""
ill = create_thing_without_server(Illumination)
number_of_flashes = 3 # smaller number for test speed
dt = -5 # set a negative delay
# Patch set_led to just record calls without raising
with (
patch.object(ill, "set_led"),
pytest.raises(ValueError, match="sleep length must be non-negative"),
):
ill.flash(number_of_flashes=number_of_flashes, dt=dt)
@pytest.fixture
def sanga_mock_stage():
"""Return a SangaIllumination with a mocked stage."""
return create_thing_without_server(SangaIllumination, mock_all_slots=True)
@pytest.fixture
def sim_mock_cam():
"""Return a SimulatorIllumination with a mocked camera."""
return create_thing_without_server(SimulatorIllumination, mock_all_slots=True)
def test_sanga_flash_calls_led(sanga_mock_stage):
"""Test that flashing calls set_led with correct parameters."""
number_of_flashes = 3
dt = 0.01 # tiny sleep for test speed
sanga_mock_stage.flash(number_of_flashes=number_of_flashes, dt=dt)
# Each flash calls set_led False then True
assert sanga_mock_stage._stage.set_led.call_count == 2 * number_of_flashes
# Check that False and True are alternating when sent to _stage.set_led
calls = sanga_mock_stage._stage.set_led.call_args_list
expected_sequence = [False, True] * number_of_flashes
for led_call, expected in zip(calls, expected_sequence, strict=True):
args, kwargs = led_call
assert args[0] == expected
def test_sim_flash_calls_led(sim_mock_cam):
"""Test that simulator flash calls set_led correctly."""
number_of_flashes = 2
dt = 0.01
sim_mock_cam.flash(number_of_flashes=number_of_flashes, dt=dt)
# Each flash calls set_led False then True
assert sim_mock_cam._cam.set_led.call_count == 2 * number_of_flashes
# Check that False and True are alternating when sent to _cam.set_led
calls = sim_mock_cam._cam.set_led.call_args_list
expected_sequence = [False, True] * number_of_flashes
for led_call, expected in zip(calls, expected_sequence, strict=True):
args, kwargs = led_call
assert args[0] == expected