Coverage for tests/ui/test_nifti_mask_selection_page.py: 99%
107 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 15:51 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-03 15:51 +0000
1import pytest
2import os
3import tempfile
4import shutil
5from unittest.mock import Mock, patch, MagicMock
6from PyQt6.QtCore import QSettings, pyqtSignal, QObject
8from main.ui.nifti_mask_selection_page import MaskNiftiSelectionPage
10@pytest.fixture
11def mask_page(qtbot, mock_context, mock_file_selector_mask):
12 previous_page = Mock()
13 page = MaskNiftiSelectionPage(mock_context, previous_page)
14 qtbot.addWidget(page)
15 return page
17class TestNiftiMaskSelectionPageSetup:
18 """Tests for NiftiMaskSelectionPage initialization"""
20 def test_page_initialization(self, mask_page):
21 """Test correct initialization"""
22 assert mask_page.context is not None
23 assert mask_page.previous_page is not None
24 assert mask_page.selected_file is None
26 def test_title_created(self, mask_page):
27 """Test title creation"""
28 assert mask_page.title is not None
29 assert mask_page.title.text() != ""
31 def test_file_selector_created(self, mask_page):
32 """Test file selector creation"""
33 assert mask_page.file_selector_widget is not None
35 def test_viewer_button_created(self, mask_page):
36 """Test viewer button creation"""
37 assert mask_page.viewer_button is not None
38 assert not mask_page.viewer_button.isEnabled() # Disabled initially
41class TestNiftiMaskSelectionPageExistingMask:
42 """Tests for checking existing masks"""
44 def test_has_existing_manual_mask(self, mask_page, temp_workspace):
45 """Test detection of existing manual mask"""
46 nifti_path = os.path.join(temp_workspace, "sub-01", "anat", "T1w.nii")
48 result = mask_page.has_existing_mask(nifti_path, temp_workspace)
50 assert result == True
52 def test_has_no_existing_mask(self, mask_page, temp_workspace):
53 """Test when mask does not exist"""
54 nifti_path = os.path.join(temp_workspace, "sub-03", "anat", "T1w.nii")
56 result = mask_page.has_existing_mask(nifti_path, temp_workspace)
58 assert result == False
60 def test_has_existing_mask_no_subject_id(self, mask_page, temp_workspace):
61 """Test behavior without subject ID"""
62 nifti_path = os.path.join(temp_workspace, "invalid", "T1w.nii")
64 result = mask_page.has_existing_mask(nifti_path, temp_workspace)
66 assert result == False
68 def test_has_existing_mask_empty_directory(self, mask_page, temp_workspace):
69 """Test behavior with empty directory"""
70 # Create directory but without files
71 empty_dir = os.path.join(temp_workspace, "derivatives", "manual_masks", "sub-04", "anat")
72 os.makedirs(empty_dir)
74 nifti_path = os.path.join(temp_workspace, "sub-04", "anat", "T1w.nii")
76 result = mask_page.has_existing_mask(nifti_path, temp_workspace)
78 assert result == False
81class TestNiftiMaskSelectionPageViewer:
82 """Tests for opening NIfTI viewer"""
84 def test_open_nifti_viewer_calls_context(self, mask_page):
85 """Test that open_nifti_viewer calls the context"""
86 test_file = "/path/to/scan.nii"
87 mask_page.file_selector_widget.get_selected_files = Mock(
88 return_value=[test_file]
89 )
91 mask_page.open_nifti_viewer()
93 mask_page.context["open_nifti_viewer"].assert_called_once_with(test_file)
95 def test_open_nifti_viewer_uses_last_file(self, mask_page):
96 """Test that it uses the last selected file"""
97 files = ["/path/file1.nii", "/path/file2.nii"]
98 mask_page.file_selector_widget.get_selected_files = Mock(
99 return_value=files
100 )
102 mask_page.open_nifti_viewer()
104 # Should use the last file
105 mask_page.context["open_nifti_viewer"].assert_called_once_with(files[-1])
107 def test_open_nifti_viewer_handles_error(self, mask_page):
108 """Test error handling"""
109 mask_page.file_selector_widget.get_selected_files = Mock(
110 side_effect=Exception("Test error")
111 )
113 # Should not raise exception
114 mask_page.open_nifti_viewer()
117class TestNiftiMaskSelectionPageReadiness:
118 """Tests for advancement logic"""
120 def test_not_ready_to_advance(self, mask_page):
121 """Test that advancing is not ready"""
122 assert not mask_page.is_ready_to_advance()
124 def test_ready_to_go_back(self, mask_page):
125 """Test that going back is ready"""
126 assert mask_page.is_ready_to_go_back()
129class TestNiftiMaskSelectionPageNavigation:
130 """Tests for navigation"""
132 def test_back_returns_previous_page(self, mask_page):
133 """Test return to previous page"""
134 result = mask_page.back()
136 assert result == mask_page.previous_page
137 mask_page.previous_page.on_enter.assert_called_once()
139 def test_back_returns_none_without_previous(self, mask_page):
140 """Test return None without previous page"""
141 mask_page.previous_page = None
143 result = mask_page.back()
145 assert result is None
148class TestNiftiMaskSelectionPageReset:
149 """Tests for page reset"""
151 def test_reset_clears_selected_file(self, mask_page):
152 """Test that reset clears the selected file"""
153 mask_page.selected_file = "/path/to/file.nii"
155 mask_page.reset_page()
157 assert mask_page.selected_file is None
159 def test_reset_calls_clear_selected_files(self, mask_page):
160 """Test that reset calls clear_selected_files"""
161 mask_page.reset_page()
163 mask_page.file_selector_widget.clear_selected_files.assert_called_once()
165 def test_reset_disables_viewer_button(self, mask_page):
166 """Test that reset disables the viewer button"""
167 mask_page.viewer_button.setEnabled(True)
169 mask_page.reset_page()
171 assert not mask_page.viewer_button.isEnabled()
174class TestNiftiMaskSelectionPageTranslation:
175 """Tests for translations"""
177 def test_translate_ui_updates_title(self, mask_page):
178 """Test title update"""
179 mask_page._translate_ui()
180 assert mask_page.title.text() != ""
182 def test_translate_ui_updates_button(self, mask_page):
183 """Test button update"""
184 mask_page._translate_ui()
185 assert mask_page.viewer_button.text() != ""
187class TestNiftiMaskSelectionPageOnEnter:
188 """Tests for on_enter"""
190 def test_on_enter_does_nothing(self, mask_page):
191 """Test that on_enter does not cause errors"""
192 # Should execute without errors
193 mask_page.on_enter()
196# Integration tests
197class TestNiftiMaskSelectionPageIntegration:
198 """Integration tests"""
200 def test_full_workflow(self, mask_page, temp_workspace):
201 """Test full workflow"""
202 # Test initial state
203 assert mask_page.selected_file is None
204 assert not mask_page.viewer_button.isEnabled()
206 # Simulate file selection
207 test_file = os.path.join(temp_workspace, "sub-01", "anat", "T1w.nii")
208 mask_page.file_selector_widget.get_selected_files = Mock(
209 return_value=[test_file]
210 )
212 # Open viewer
213 mask_page.open_nifti_viewer()
214 mask_page.context["open_nifti_viewer"].assert_called_once_with(test_file)
216 # Reset
217 mask_page.reset_page()
218 assert mask_page.selected_file is None
220if __name__ == "__main__":
221 pytest.main([__file__, "-v", "--tb=short"])