From 2ccb3aa7aeee3f4e4bd3b9b709feca2663639af9 Mon Sep 17 00:00:00 2001 From: appleb_m Date: Wed, 22 Apr 2026 15:59:55 +0200 Subject: [PATCH] TESTS: added some simple tests to the GUI --- tests/conftest.py | 17 +++++++++ .../common/test_data_collection_parameters.py | 29 +++++++++++++++ tests/unit/common/test_mlbox_model.py | 21 +++++++++++ .../common/test_zoom_model_camera_settings.py | 35 +++++++++++++++++++ tests/unit/daq/test_mlbox_logic.py | 27 ++++++++++++++ tests/unit/gui/test_prediction_subscriber.py | 11 ++++++ 6 files changed, 140 insertions(+) create mode 100644 tests/conftest.py create mode 100644 tests/unit/common/test_data_collection_parameters.py create mode 100644 tests/unit/common/test_mlbox_model.py create mode 100644 tests/unit/common/test_zoom_model_camera_settings.py create mode 100644 tests/unit/daq/test_mlbox_logic.py create mode 100644 tests/unit/gui/test_prediction_subscriber.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..984fabff --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,17 @@ +import pytest + +from aare.common.models import SampleShortInfo, DewarAddress + + +@pytest.fixture +def sample_info(): + return SampleShortInfo( + db_id=1, + puck_name="puck1", + dewar_name="dew1", + sample_name="sample1", + run_number=1, + user="group1", + pin=3, + location=DewarAddress(segment="A", pos=2), + ) diff --git a/tests/unit/common/test_data_collection_parameters.py b/tests/unit/common/test_data_collection_parameters.py new file mode 100644 index 00000000..80cc8f7c --- /dev/null +++ b/tests/unit/common/test_data_collection_parameters.py @@ -0,0 +1,29 @@ +import pytest +from pydantic import ValidationError + +from aare.common.models import DataCollectionParameters + + +def test_directory_defaults_when_missing(): + params = DataCollectionParameters() + assert params.directory == "{date}/{prefix}" + + +def test_directory_spaces_are_replaced(): + params = DataCollectionParameters(directory="my folder/run 1") + assert params.directory == "my_folder/run_1" + + +def test_directory_rejects_invalid_characters(): + with pytest.raises(ValidationError): + DataCollectionParameters(directory="bad|path") + + +def test_exposure_must_be_between_0_and_1(): + with pytest.raises(ValidationError): + DataCollectionParameters(exposure=1.5) + + +def test_cloud_blank_defaults_to_true(): + params = DataCollectionParameters(cloud="") + assert params.cloud is True diff --git a/tests/unit/common/test_mlbox_model.py b/tests/unit/common/test_mlbox_model.py new file mode 100644 index 00000000..03788792 --- /dev/null +++ b/tests/unit/common/test_mlbox_model.py @@ -0,0 +1,21 @@ +from aare.common.models import MLOutputModel, MLBoxType + + +def test_add_box_generates_unique_keys(): + model = MLOutputModel() + key1 = model.add_box(MLBoxType.Crystal, (1, 2, 3, 4), 0.8) + key2 = model.add_box(MLBoxType.Crystal, (5, 6, 7, 8), 0.9) + + assert key1 == "Crystal" + assert key2 == "Crystal_2" + + +def test_get_best_for_class_returns_highest_confidence(): + model = MLOutputModel() + model.add_box(MLBoxType.Pin, (1, 1, 2, 2), 0.3) + model.add_box(MLBoxType.Pin, (3, 3, 4, 4), 0.7) + + best = model.get_best_for_class(MLBoxType.Pin) + + assert best is not None + assert best.conf == 0.7 diff --git a/tests/unit/common/test_zoom_model_camera_settings.py b/tests/unit/common/test_zoom_model_camera_settings.py new file mode 100644 index 00000000..67eba498 --- /dev/null +++ b/tests/unit/common/test_zoom_model_camera_settings.py @@ -0,0 +1,35 @@ +import pytest + +from aare.common.models import ZoomModel, SampleCameraSettings + + +def test_get_camera_settings_exact_match(): + model = ZoomModel( + z={ + 100: SampleCameraSettings(gain=1.0, exposure=0.1), + 200: SampleCameraSettings(gain=2.0, exposure=0.2), + } + ) + + settings = model.get_camera_settings(100) + assert settings.gain == 1.0 + assert settings.exposure == 0.1 + + +def test_get_camera_settings_interpolates(): + model = ZoomModel( + z={ + 100: SampleCameraSettings(gain=0.0, exposure=0.1), + 200: SampleCameraSettings(gain=2.0, exposure=0.3), + } + ) + + settings = model.get_camera_settings(150) + assert settings.gain == 1.0 + assert settings.exposure == 0.2 + + +def test_get_camera_settings_raises_when_empty(): + model = ZoomModel(z={}) + with pytest.raises(ValueError): + model.get_camera_settings(100) diff --git a/tests/unit/daq/test_mlbox_logic.py b/tests/unit/daq/test_mlbox_logic.py new file mode 100644 index 00000000..f0cd0450 --- /dev/null +++ b/tests/unit/daq/test_mlbox_logic.py @@ -0,0 +1,27 @@ +from aare.daq.mlbox import MlBox +from aare.common.models import MLOutputModel, MLBoxType + + +def test_preferred_class_prefers_loop_over_pin_when_margin_not_exceeded(): + boxes = MLOutputModel() + boxes.add_box(MLBoxType.Pin, (0, 0, 10, 10), 0.8) + boxes.add_box(MLBoxType.Loop_face, (1, 1, 9, 9), 0.75) + + best = MlBox.get_preferred_class_box_with_confidence_threshold( + boxes, + loop_preference_margin=0.1, + ) + + assert best is not None + assert best.cls == MLBoxType.Loop_face + +def test_prediction_score_empty(): + assert MlBox._prediction_score(None) == (0, 0.0) + + +def test_prediction_score_uses_count_and_max_confidence(): + model = MLOutputModel() + model.add_box(MLBoxType.Pin, (0, 0, 10, 10), 0.4) + model.add_box(MLBoxType.Crystal, (1, 1, 9, 9), 0.8) + + assert MlBox._prediction_score(model) == (2, 0.8) \ No newline at end of file diff --git a/tests/unit/gui/test_prediction_subscriber.py b/tests/unit/gui/test_prediction_subscriber.py new file mode 100644 index 00000000..39bd879b --- /dev/null +++ b/tests/unit/gui/test_prediction_subscriber.py @@ -0,0 +1,11 @@ +import sys +import pytest +from PySide6.QtWidgets import QApplication + + +@pytest.fixture(scope="session") +def qapp(): + app = QApplication.instance() + if app is None: + app = QApplication(sys.argv) + return app