Add some basic tests for base stage implementation
This commit is contained in:
parent
10f73cfb76
commit
8a77c09305
3 changed files with 48 additions and 7 deletions
|
|
@ -42,13 +42,14 @@ class JogCommand:
|
||||||
None for stop motion.
|
None for stop motion.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.displacement = displacement
|
self.displacement = None if displacement is None else tuple(displacement)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""Represent the command as a string."""
|
"""Represent the command as a string."""
|
||||||
|
class_name = type(self).__name__
|
||||||
if self.displacement is None:
|
if self.displacement is None:
|
||||||
return "<JogCommand>STOP"
|
return f"<{class_name}>STOP"
|
||||||
return f"<JogCommand>{self.displacement}"
|
return f"<{class_name}>{self.displacement}"
|
||||||
|
|
||||||
|
|
||||||
class JogQueue(queue.Queue[JogCommand]):
|
class JogQueue(queue.Queue[JogCommand]):
|
||||||
|
|
@ -227,13 +228,13 @@ class BaseStage(lt.Thing):
|
||||||
Make sure to use and update ``self._hardware_position`` not ``self.position``.
|
Make sure to use and update ``self._hardware_position`` not ``self.position``.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"StageThings must define their own move_absolute method"
|
"StageThings must define their own _hardware_move_absolute method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _hardware_start_move_relative(self, displacement: Sequence[int]) -> None:
|
def _hardware_start_move_relative(self, displacement: Sequence[int]) -> None:
|
||||||
"""Start a relative move."""
|
"""Start a relative move."""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"StageThings must define their own hardware_start_move_relative method"
|
"StageThings must define their own _hardware_start_move_relative method"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _hardware_stop(self) -> None:
|
def _hardware_stop(self) -> None:
|
||||||
|
|
@ -250,7 +251,7 @@ class BaseStage(lt.Thing):
|
||||||
def _estimate_move_duration(self, displacement: Sequence[int]) -> float:
|
def _estimate_move_duration(self, displacement: Sequence[int]) -> float:
|
||||||
"""Calculate the expected duration of a move with the given displacement."""
|
"""Calculate the expected duration of a move with the given displacement."""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"StageThings must define their own _estimate_move_duration"
|
"StageThings must define their own _estimate_move_duration method"
|
||||||
)
|
)
|
||||||
|
|
||||||
@lt.action
|
@lt.action
|
||||||
|
|
|
||||||
|
|
@ -1 +1,10 @@
|
||||||
"""Shared utilities for all test suites."""
|
"""Shared utilities for all test suites."""
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
|
|
||||||
|
def get_method_name(method):
|
||||||
|
"""Reliably get a methods name even if wrapped."""
|
||||||
|
while isinstance(method, functools.partial):
|
||||||
|
method = method.func
|
||||||
|
return getattr(method, "__name__", type(method).__name__)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from openflexure_microscope_server.things.stage import (
|
||||||
)
|
)
|
||||||
from openflexure_microscope_server.things.stage.dummy import DummyStage
|
from openflexure_microscope_server.things.stage.dummy import DummyStage
|
||||||
|
|
||||||
|
from ..shared_utils import get_method_name
|
||||||
from ..shared_utils.lt_test_utils import LabThingsTestEnv
|
from ..shared_utils.lt_test_utils import LabThingsTestEnv
|
||||||
|
|
||||||
# Keep the size and number of moves fairly small or the tests can take forever
|
# Keep the size and number of moves fairly small or the tests can take forever
|
||||||
|
|
@ -35,6 +36,26 @@ def dummy_stage():
|
||||||
return create_thing_without_server(DummyStage, step_time=0.000001)
|
return create_thing_without_server(DummyStage, step_time=0.000001)
|
||||||
|
|
||||||
|
|
||||||
|
def test_not_implemented_methods():
|
||||||
|
"""Check all methods a child class should implement raise NotImplemented."""
|
||||||
|
stage = create_thing_without_server(BaseStage)
|
||||||
|
methods_and_args = [
|
||||||
|
(stage.update_position, ()),
|
||||||
|
(stage._hardware_move_relative, ()),
|
||||||
|
(stage._hardware_move_absolute, ()),
|
||||||
|
(stage._hardware_start_move_relative, ((1, 2, 3),)),
|
||||||
|
(stage._hardware_stop, ()),
|
||||||
|
(stage._poll_moving, ()),
|
||||||
|
(stage._estimate_move_duration, ((1, 2, 3),)),
|
||||||
|
(stage.set_zero_position, ()),
|
||||||
|
]
|
||||||
|
for method, args in methods_and_args:
|
||||||
|
method_name = get_method_name(method)
|
||||||
|
msg = f"StageThings must define their own {method_name} method"
|
||||||
|
with pytest.raises(NotImplementedError, match=msg):
|
||||||
|
method(*args)
|
||||||
|
|
||||||
|
|
||||||
def test_override_base_movement():
|
def test_override_base_movement():
|
||||||
"""Child classes of stage should implement functions in the hardware reference frame.
|
"""Child classes of stage should implement functions in the hardware reference frame.
|
||||||
|
|
||||||
|
|
@ -303,6 +324,16 @@ def test_thing_description_equivalence(dummy_stage, mocker):
|
||||||
assert sanga_properties == dummy_properties == base_properties
|
assert sanga_properties == dummy_properties == base_properties
|
||||||
|
|
||||||
|
|
||||||
|
def test_job_repr():
|
||||||
|
"""Test when printing a jog command the result is as expected."""
|
||||||
|
# Jog should represent itself the same whether displacement is set with a list or a
|
||||||
|
# tuple.
|
||||||
|
assert str(JogCommand([1, 2, 3])) == "<JogCommand>(1, 2, 3)"
|
||||||
|
assert str(JogCommand((1, 2, 3))) == "<JogCommand>(1, 2, 3)"
|
||||||
|
# Stop should be very clear.
|
||||||
|
assert str(JogCommand(None)) == "<JogCommand>STOP"
|
||||||
|
|
||||||
|
|
||||||
def test_get_jog_from_queue_most_recent(dummy_stage):
|
def test_get_jog_from_queue_most_recent(dummy_stage):
|
||||||
"""Test that the jog queue gives the most recent Jog Command."""
|
"""Test that the jog queue gives the most recent Jog Command."""
|
||||||
# Try to stack 4 moves in the queue, only 1 should be queued.
|
# Try to stack 4 moves in the queue, only 1 should be queued.
|
||||||
|
|
@ -312,6 +343,6 @@ def test_get_jog_from_queue_most_recent(dummy_stage):
|
||||||
command = dummy_stage._get_from_jog_queue(0.001)
|
command = dummy_stage._get_from_jog_queue(0.001)
|
||||||
assert isinstance(command, JogCommand)
|
assert isinstance(command, JogCommand)
|
||||||
# Should be the last one queued
|
# Should be the last one queued
|
||||||
assert command.displacement == [3, 3, 3]
|
assert command.displacement == (3, 3, 3)
|
||||||
# Nothing else is queued
|
# Nothing else is queued
|
||||||
assert dummy_stage._get_from_jog_queue(0.001) is None
|
assert dummy_stage._get_from_jog_queue(0.001) is None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue