diff --git a/tests/unit_tests/test_illumination.py b/tests/unit_tests/test_illumination.py index 1c675c0a..a7e02ee1 100644 --- a/tests/unit_tests/test_illumination.py +++ b/tests/unit_tests/test_illumination.py @@ -1,5 +1,7 @@ """Tests for the Illumination thing.""" +from unittest.mock import call, patch + import pytest from labthings_fastapi.testing import create_thing_without_server @@ -10,12 +12,71 @@ from openflexure_microscope_server.things.illumination import ( SimulatorIllumination, ) +# Test the BaseClass before testing specific implementation -def test_base_illumination_flash_not_implemented(): - """Check that calling flash on the base Illumination raises NotImplementedError.""" + +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="Flashing the LED can only be done"): - ill.flash(number_of_flashes=1, dt=0.01) + 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 @@ -43,8 +104,8 @@ def test_sanga_flash_calls_led(sanga_mock_stage): # 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 call, expected in zip(calls, expected_sequence, strict=True): - args, kwargs = call + for led_call, expected in zip(calls, expected_sequence, strict=True): + args, kwargs = led_call assert args[0] == expected @@ -61,6 +122,6 @@ def test_sim_flash_calls_led(sim_mock_cam): # 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 call, expected in zip(calls, expected_sequence, strict=True): - args, kwargs = call + for led_call, expected in zip(calls, expected_sequence, strict=True): + args, kwargs = led_call assert args[0] == expected