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

1import pytest 

2import os 

3import tempfile 

4import shutil 

5from unittest.mock import Mock, patch, MagicMock 

6from PyQt6.QtCore import QSettings, pyqtSignal, QObject 

7 

8from main.ui.nifti_mask_selection_page import MaskNiftiSelectionPage 

9 

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 

16 

17class TestNiftiMaskSelectionPageSetup: 

18 """Tests for NiftiMaskSelectionPage initialization""" 

19 

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 

25 

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() != "" 

30 

31 def test_file_selector_created(self, mask_page): 

32 """Test file selector creation""" 

33 assert mask_page.file_selector_widget is not None 

34 

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 

39 

40 

41class TestNiftiMaskSelectionPageExistingMask: 

42 """Tests for checking existing masks""" 

43 

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") 

47 

48 result = mask_page.has_existing_mask(nifti_path, temp_workspace) 

49 

50 assert result == True 

51 

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") 

55 

56 result = mask_page.has_existing_mask(nifti_path, temp_workspace) 

57 

58 assert result == False 

59 

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") 

63 

64 result = mask_page.has_existing_mask(nifti_path, temp_workspace) 

65 

66 assert result == False 

67 

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) 

73 

74 nifti_path = os.path.join(temp_workspace, "sub-04", "anat", "T1w.nii") 

75 

76 result = mask_page.has_existing_mask(nifti_path, temp_workspace) 

77 

78 assert result == False 

79 

80 

81class TestNiftiMaskSelectionPageViewer: 

82 """Tests for opening NIfTI viewer""" 

83 

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 ) 

90 

91 mask_page.open_nifti_viewer() 

92 

93 mask_page.context["open_nifti_viewer"].assert_called_once_with(test_file) 

94 

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 ) 

101 

102 mask_page.open_nifti_viewer() 

103 

104 # Should use the last file 

105 mask_page.context["open_nifti_viewer"].assert_called_once_with(files[-1]) 

106 

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 ) 

112 

113 # Should not raise exception 

114 mask_page.open_nifti_viewer() 

115 

116 

117class TestNiftiMaskSelectionPageReadiness: 

118 """Tests for advancement logic""" 

119 

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() 

123 

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() 

127 

128 

129class TestNiftiMaskSelectionPageNavigation: 

130 """Tests for navigation""" 

131 

132 def test_back_returns_previous_page(self, mask_page): 

133 """Test return to previous page""" 

134 result = mask_page.back() 

135 

136 assert result == mask_page.previous_page 

137 mask_page.previous_page.on_enter.assert_called_once() 

138 

139 def test_back_returns_none_without_previous(self, mask_page): 

140 """Test return None without previous page""" 

141 mask_page.previous_page = None 

142 

143 result = mask_page.back() 

144 

145 assert result is None 

146 

147 

148class TestNiftiMaskSelectionPageReset: 

149 """Tests for page reset""" 

150 

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" 

154 

155 mask_page.reset_page() 

156 

157 assert mask_page.selected_file is None 

158 

159 def test_reset_calls_clear_selected_files(self, mask_page): 

160 """Test that reset calls clear_selected_files""" 

161 mask_page.reset_page() 

162 

163 mask_page.file_selector_widget.clear_selected_files.assert_called_once() 

164 

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) 

168 

169 mask_page.reset_page() 

170 

171 assert not mask_page.viewer_button.isEnabled() 

172 

173 

174class TestNiftiMaskSelectionPageTranslation: 

175 """Tests for translations""" 

176 

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() != "" 

181 

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() != "" 

186 

187class TestNiftiMaskSelectionPageOnEnter: 

188 """Tests for on_enter""" 

189 

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() 

194 

195 

196# Integration tests 

197class TestNiftiMaskSelectionPageIntegration: 

198 """Integration tests""" 

199 

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() 

205 

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 ) 

211 

212 # Open viewer 

213 mask_page.open_nifti_viewer() 

214 mask_page.context["open_nifti_viewer"].assert_called_once_with(test_file) 

215 

216 # Reset 

217 mask_page.reset_page() 

218 assert mask_page.selected_file is None 

219 

220if __name__ == "__main__": 

221 pytest.main([__file__, "-v", "--tb=short"])