Skip to content

Commit

Permalink
Expand tests for loader widget
Browse files Browse the repository at this point in the history
  • Loading branch information
niksirbi committed Sep 13, 2024
1 parent b7753a3 commit 800a157
Showing 1 changed file with 99 additions and 6 deletions.
105 changes: 99 additions & 6 deletions tests/test_integration/test_napari_plugin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import pytest
from qtpy.QtWidgets import QPushButton, QWidget
from napari.settings import get_settings
from qtpy.QtWidgets import QComboBox, QLineEdit, QPushButton, QSpinBox, QWidget

from movement.napari._loader_widget import PosesLoader
from movement.napari._loader_widget import SUPPORTED_POSES_FILES, PosesLoader
from movement.napari._meta_widget import MovementMetaWidget


# -------------------- widget fixtures ---------------------------------------#
@pytest.fixture
def meta_widget(make_napari_viewer_proxy) -> MovementMetaWidget:
"""Fixture to expose the MovementMetaWidget for testing.
Expand All @@ -22,7 +24,8 @@ def loader_widget(meta_widget) -> QWidget:
return loader


def test_meta_widget(meta_widget):
# -------------------- tests for widget instantiation ------------------------#
def test_meta_widget_instantiation(meta_widget):
"""Test that the meta widget is properly instantiated."""
assert meta_widget is not None
assert len(meta_widget.collapsible_widgets) == 1
Expand All @@ -32,19 +35,67 @@ def test_meta_widget(meta_widget):
assert first_widget.isExpanded()


def test_loader_widget(loader_widget):
def test_loader_widget_instantiation(loader_widget):
"""Test that the loader widget is properly instantiated."""
assert loader_widget is not None
assert loader_widget.layout().rowCount() == 4

# Make sure the all rows except last start with lowercase text
# which ends with a semicolon
for i in range(loader_widget.layout().rowCount() - 1):
label = loader_widget.layout().itemAt(i, 0).widget()
assert label.text().islower()
assert label.text().endswith(":")

# Make sure that the source software combo box is populated
source_software_combo = loader_widget.findChildren(QComboBox)[0]
assert source_software_combo.count() == len(SUPPORTED_POSES_FILES)

# Test that the default fps is 30
fps_spinbox = loader_widget.findChildren(QSpinBox)[0]
assert fps_spinbox.value() == 30

# Make sure that the line edit for file path is empty
file_path_edit = loader_widget.findChildren(QLineEdit)[-1]
assert file_path_edit.text() == ""

# Make sure that the first button is a "Browse" button
browse_button = loader_widget.findChildren(QPushButton)[0]
assert browse_button.text() == "Browse"

# Make sure that the last row is a "Load" button
load_button = loader_widget.findChildren(QPushButton)[-1]
assert load_button.text() == "Load"

# Make sure that layer tooltips are enabled
assert get_settings().appearance.layer_tooltip_visibility is True

def test_load_button_calls_on_load_clicked(make_napari_viewer_proxy, mocker):
"""Test that clicking the 'Load' call the right function.

# -------------------- tests for callbacks -----------------------------------#
def test_browse_button_calls_on_browse_clicked(
make_napari_viewer_proxy, mocker
):
"""Test that clicking the 'Browse' button calls the right function.
Here we have to create a new Loader widget after mocking the method.
We cannot reuse the existing widget fixture because then it would be too
late to mock (the widget has already "decided" which method to call).
"""
mock_method = mocker.patch(
"movement.napari._loader_widget.PosesLoader._on_browse_clicked"
)
loader = PosesLoader(make_napari_viewer_proxy)
browse_button = loader.findChildren(QPushButton)[0]
browse_button.click()
mock_method.assert_called_once()


def test_load_button_calls_on_load_clicked(make_napari_viewer_proxy, mocker):
"""Test that clicking the 'Load' button calls the right function.
Here we also have to create a new Loader widget after mocking the method,
as in the previous test.
"""
mock_method = mocker.patch(
"movement.napari._loader_widget.PosesLoader._on_load_clicked"
)
Expand All @@ -59,3 +110,45 @@ def test_on_load_clicked_without_file_path(loader_widget, capsys):
loader_widget._on_load_clicked()
captured = capsys.readouterr()
assert "No file path specified." in captured.out


def test_on_load_clicked_with_valid_file_path(loader_widget, caplog):
"""Test clicking 'Load' with a valid file path.
This test checks that the `_on_load_clicked` method causes the following:
- creates the `data`, `props`, and `file_name` attributes
- emits a series of expected log messages
- adds a Points layer to the viewer (with the correct name)
- sets the playback fps to the correct value
"""
# Set the file path to a valid file
file_path = pytest.DATA_PATHS.get("DLC_single-wasp.predictions.h5")
loader_widget.file_path_edit.setText(file_path.as_posix())

# Set the fps to 60
loader_widget.fps_spinbox.setValue(60)

# Call the _on_load_clicked method (pretend the user clicked "Load")
loader_widget._on_load_clicked()

# Check that class attributes have been created
assert loader_widget.file_name == file_path.name
assert loader_widget.data is not None
assert loader_widget.props is not None

# Check that the expected log messages were emitted
expected_log_messages = [
"Converted poses dataset to a napari Tracks array.",
"Tracks array shape: ",
"Added poses dataset as a napari Points layer.",
"Set napari playback speed to ",
]
for msg in expected_log_messages:
assert any(msg in record.getMessage() for record in caplog.records)

# Check that a Points layer was added to the viewer
points_layer = loader_widget.viewer.layers[0]
assert points_layer.name == f"poses: {file_path.name}"

# Check that the playback fps was set correctly
assert get_settings().application.playback_fps == 60

0 comments on commit 800a157

Please sign in to comment.