Skip to content

Commit 28f5be2

Browse files
committed
feat(tests): Add full test coverage for netCDF loader
1 parent f6b6893 commit 28f5be2

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

movement/napari/loader_widgets.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,10 @@ def _on_load_clicked(self):
199199
return
200200

201201
# Format data for napari layers
202-
self._format_data_for_layers()
202+
success = self._format_data_for_layers()
203+
if not success:
204+
return # Stop execution if formatting/validation failed
205+
203206
logger.info("Converted dataset to a napari Tracks array.")
204207
logger.debug(f"Tracks array shape: {self.data.shape}")
205208
if self.data_bboxes is not None:
@@ -229,7 +232,7 @@ def _format_data_for_layers(self):
229232
ds = xr.open_dataset(self.file_path)
230233
except Exception as e:
231234
show_error(f"Error opening netCDF file: {e}")
232-
return
235+
return False
233236

234237
# Get the dataset type from its attributes
235238
ds_type = ds.attrs.get("ds_type", None)
@@ -247,13 +250,13 @@ def _format_data_for_layers(self):
247250
f"The netCDF file does not appear to be a valid "
248251
f"movement {ds_type} dataset: {e}"
249252
)
250-
return
253+
return False
251254
else:
252255
show_error(
253256
f"The netCDF file has an unknown 'ds_type' attribute:"
254257
f"{ds_type}."
255258
)
256-
return
259+
return False
257260
else:
258261
# Original Logic continue
259262
loader = (
@@ -270,6 +273,7 @@ def _format_data_for_layers(self):
270273

271274
# Find rows that do not contain NaN values
272275
self.data_not_nan = ~np.any(np.isnan(self.data), axis=1)
276+
return True
273277

274278
def _set_common_color_property(self):
275279
"""Set the color property for the Points and Tracks layers.

tests/fixtures/files.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import h5py
1111
import pytest
12+
import xarray as xr
1213
from sleap_io.io.slp import read_labels, write_labels
1314
from sleap_io.model.labels import LabeledFrame, Labels
1415

@@ -499,3 +500,28 @@ def via_track_ids_not_unique_per_frame():
499500
'"{""name"":""rect"",""x"":2567.627,""y"":466.888,""width"":40,""height"":37}",'
500501
'"{""track"":""71""}"' # same track ID as the previous row
501502
)
503+
504+
505+
@pytest.fixture(scope="session")
506+
def invalid_netcdf_file_missing_confidence(tmp_path_factory):
507+
"""Create an invalid 'poses' netCDF file missing the
508+
'confidence' variable.
509+
"""
510+
from pytest import DATA_PATHS
511+
512+
# 1. Get path to a VALID file (the 'poses' one)
513+
valid_file = DATA_PATHS.get("MOVE_two-mice_octagon.analysis.nc")
514+
515+
# 2. Load it
516+
ds = xr.open_dataset(valid_file)
517+
518+
# 3. Break it (our validator requires 'confidence' for 'poses')
519+
del ds["confidence"]
520+
521+
# 4. Save to a temp file
522+
temp_dir = tmp_path_factory.mktemp("invalid_netcdf")
523+
invalid_path = temp_dir / "invalid_file_missing_confidence.nc"
524+
ds.to_netcdf(invalid_path)
525+
526+
# 5. Yield the path to the test
527+
yield str(invalid_path)

tests/test_unit/test_napari_plugin/test_data_loader_widget.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,36 @@ def test_on_load_clicked_with_valid_file_path(
398398
assert expected_log_messages <= log_messages
399399

400400

401+
def test_on_load_clicked_with_invalid_netcdf(
402+
make_napari_viewer_proxy,
403+
mocker,
404+
invalid_netcdf_file_missing_confidence, # Our new fixture
405+
):
406+
"""Test that show_error is called when loading an invalid netCDF file."""
407+
data_loader_widget = DataLoader(make_napari_viewer_proxy())
408+
409+
# 1. Mock the show_error function so we can check if it's called
410+
mock_show_error = mocker.patch("movement.napari.loader_widgets.show_error")
411+
412+
# 2. Set up the widget to load the broken file
413+
data_loader_widget.file_path_edit.setText(
414+
invalid_netcdf_file_missing_confidence
415+
)
416+
data_loader_widget.source_software_combo.setCurrentText(
417+
"movement (netCDF)"
418+
)
419+
420+
# 3. Click "Load"
421+
data_loader_widget._on_load_clicked()
422+
423+
# 4. Assert that show_error was called
424+
mock_show_error.assert_called_once()
425+
426+
# 5. Assert the error message is correct
427+
call_args = mock_show_error.call_args[0][0] # Get the first argument
428+
assert "does not appear to be a valid movement poses dataset" in call_args
429+
430+
401431
# ------------------- tests for dimension slider ----------------------------#
402432
# These tests check that the frame slider is set to the expected range
403433
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)