mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
feat(widgets): added device box with spinner
This commit is contained in:
@ -49,11 +49,19 @@ class FakePositioner(FakeDevice):
|
||||
self.read_value = read_value
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def precision(self):
|
||||
return 3
|
||||
|
||||
def set_read_value(self, value):
|
||||
self.read_value = value
|
||||
|
||||
def read(self):
|
||||
return {self.name: {"value": self.read_value}}
|
||||
return {
|
||||
self.name: {"value": self.read_value},
|
||||
f"{self.name}_setpoint": {"value": self.read_value},
|
||||
f"{self.name}_motor_is_moving": {"value": 0},
|
||||
}
|
||||
|
||||
def set_limits(self, limits):
|
||||
self.limits = limits
|
||||
|
BIN
tests/unit_tests/references/SpinnerWidget_darwin.png
Normal file
BIN
tests/unit_tests/references/SpinnerWidget_darwin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
tests/unit_tests/references/SpinnerWidget_linux.png
Normal file
BIN
tests/unit_tests/references/SpinnerWidget_linux.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
tests/unit_tests/references/SpinnerWidget_started_darwin.png
Normal file
BIN
tests/unit_tests/references/SpinnerWidget_started_darwin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
tests/unit_tests/references/SpinnerWidget_started_linux.png
Normal file
BIN
tests/unit_tests/references/SpinnerWidget_started_linux.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
98
tests/unit_tests/test_device_box.py
Normal file
98
tests/unit_tests/test_device_box.py
Normal file
@ -0,0 +1,98 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.messages import ScanQueueMessage
|
||||
from qtpy.QtGui import QValidator
|
||||
|
||||
from bec_widgets.widgets.device_box.device_box import DeviceBox
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_box(qtbot, mocked_client):
|
||||
with mock.patch("bec_widgets.widgets.device_box.device_box.uuid.uuid4") as mock_uuid:
|
||||
mock_uuid.return_value = "fake_uuid"
|
||||
db = DeviceBox(device="samx", client=mocked_client)
|
||||
qtbot.addWidget(db)
|
||||
yield db
|
||||
|
||||
|
||||
def test_device_box(device_box):
|
||||
assert device_box.device == "samx"
|
||||
data = device_box.dev["samx"].read()
|
||||
|
||||
setpoint_text = device_box.ui.setpoint.text()
|
||||
# check that the setpoint is taken correctly after init
|
||||
assert float(setpoint_text) == data["samx_setpoint"]["value"]
|
||||
|
||||
# check that the precision is taken correctly after init
|
||||
precision = device_box.dev["samx"].precision
|
||||
assert setpoint_text == f"{data['samx_setpoint']['value']:.{precision}f}"
|
||||
|
||||
# check that the step size is set according to the device precision
|
||||
assert device_box.ui.step_size.value() == 10**-precision * 10
|
||||
|
||||
|
||||
def test_device_box_update_limits(device_box):
|
||||
device_box._limits = None
|
||||
device_box.update_limits([0, 10])
|
||||
assert device_box._limits == [0, 10]
|
||||
assert device_box.setpoint_validator.bottom() == 0
|
||||
assert device_box.setpoint_validator.top() == 10
|
||||
assert device_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Intermediate,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
device_box.update_limits(None)
|
||||
assert device_box._limits is None
|
||||
assert device_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Acceptable,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
def test_device_box_on_stop(device_box):
|
||||
with mock.patch.object(device_box.client.connector, "send") as mock_send:
|
||||
device_box.on_stop()
|
||||
params = {"device": "samx", "rpc_id": "fake_uuid", "func": "stop", "args": [], "kwargs": {}}
|
||||
msg = ScanQueueMessage(
|
||||
scan_type="device_rpc",
|
||||
parameter=params,
|
||||
queue="emergency",
|
||||
metadata={"RID": "fake_uuid", "response": False},
|
||||
)
|
||||
mock_send.assert_called_once_with(MessageEndpoints.scan_queue_request(), msg)
|
||||
|
||||
|
||||
def test_device_box_setpoint_change(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.setpoint.setText("100")
|
||||
device_box.on_setpoint_change()
|
||||
mock_move.assert_called_once_with(100, relative=False)
|
||||
|
||||
|
||||
def test_device_box_on_tweak_right(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.step_size.setValue(0.1)
|
||||
device_box.on_tweak_right()
|
||||
mock_move.assert_called_once_with(0.1, relative=True)
|
||||
|
||||
|
||||
def test_device_box_on_tweak_left(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.step_size.setValue(0.1)
|
||||
device_box.on_tweak_left()
|
||||
mock_move.assert_called_once_with(-0.1, relative=True)
|
||||
|
||||
|
||||
def test_device_box_setpoint_out_of_range(device_box):
|
||||
device_box.update_limits([0, 10])
|
||||
device_box.ui.setpoint.setText("100")
|
||||
device_box.on_setpoint_change()
|
||||
assert device_box.ui.setpoint.text() == "100"
|
||||
assert device_box.ui.setpoint.hasAcceptableInput() == False
|
92
tests/unit_tests/test_spinner.py
Normal file
92
tests/unit_tests/test_spinner.py
Normal file
@ -0,0 +1,92 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
import qdarktheme
|
||||
from PIL import Image, ImageChops
|
||||
from qtpy.QtGui import QPixmap
|
||||
|
||||
from bec_widgets.widgets.spinner.spinner import SpinnerWidget
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def spinner_widget(qtbot):
|
||||
qdarktheme.setup_theme("light")
|
||||
spinner = SpinnerWidget()
|
||||
qtbot.addWidget(spinner)
|
||||
qtbot.waitExposed(spinner)
|
||||
yield spinner
|
||||
|
||||
|
||||
def save_pixmap(widget, filename):
|
||||
pixmap = QPixmap(widget.size())
|
||||
widget.render(pixmap)
|
||||
pixmap.save(str(filename))
|
||||
return pixmap
|
||||
|
||||
|
||||
def compare_images(image1_path: str, reference_image_path: str):
|
||||
image1 = Image.open(image1_path)
|
||||
image2 = Image.open(reference_image_path)
|
||||
if image1.size != image2.size:
|
||||
raise ValueError("Image size has changed")
|
||||
diff = ImageChops.difference(image1, image2)
|
||||
if diff.getbbox():
|
||||
# copy image1 to the reference directory to upload as artifact
|
||||
output_dir = os.path.join(os.path.dirname(__file__), "reference_failures")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
image_name = os.path.join(output_dir, os.path.basename(image1_path))
|
||||
image1.save(image_name)
|
||||
print(f"Image saved to {image_name}")
|
||||
|
||||
raise ValueError("Images are different")
|
||||
|
||||
|
||||
def test_spinner_widget_paint_event(spinner_widget, qtbot):
|
||||
spinner_widget.paintEvent(None)
|
||||
|
||||
|
||||
def snap_and_compare(widget, tmpdir, suffix=""):
|
||||
os_suffix = sys.platform
|
||||
|
||||
name = (
|
||||
f"{widget.__class__.__name__}_{suffix}_{os_suffix}.png"
|
||||
if suffix
|
||||
else f"{widget.__class__.__name__}_{os_suffix}.png"
|
||||
)
|
||||
|
||||
# Save the widget to a pixmap
|
||||
test_image_path = str(tmpdir / name)
|
||||
pixmap = QPixmap(widget.size())
|
||||
widget.render(pixmap)
|
||||
pixmap.save(test_image_path)
|
||||
|
||||
try:
|
||||
references_path = os.path.join(os.path.dirname(__file__), "references")
|
||||
reference_image_path = os.path.join(references_path, name)
|
||||
|
||||
if not os.path.exists(reference_image_path):
|
||||
raise ValueError(f"Reference image not found: {reference_image_path}")
|
||||
|
||||
compare_images(test_image_path, reference_image_path)
|
||||
|
||||
except ValueError:
|
||||
image = Image.open(test_image_path)
|
||||
output_dir = os.path.join(os.path.dirname(__file__), "reference_failures")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
image_name = os.path.join(output_dir, name)
|
||||
image.save(image_name)
|
||||
print(f"Image saved to {image_name}")
|
||||
raise
|
||||
|
||||
|
||||
def test_spinner_widget_rendered(spinner_widget, qtbot, tmpdir):
|
||||
spinner_widget.update()
|
||||
qtbot.wait(200)
|
||||
snap_and_compare(spinner_widget, tmpdir, suffix="")
|
||||
|
||||
spinner_widget._started = True
|
||||
spinner_widget.update()
|
||||
qtbot.wait(200)
|
||||
|
||||
snap_and_compare(spinner_widget, tmpdir, suffix="started")
|
Reference in New Issue
Block a user