|
| 1 | +# Copyright (C) 2012-2025 C-PAC Developers |
| 2 | + |
| 3 | +# This file is part of C-PAC. |
| 4 | + |
| 5 | +# C-PAC is free software: you can redistribute it and/or modify it under |
| 6 | +# the terms of the GNU Lesser General Public License as published by the |
| 7 | +# Free Software Foundation, either version 3 of the License, or (at your |
| 8 | +# option) any later version. |
| 9 | + |
| 10 | +# C-PAC is distributed in the hope that it will be useful, but WITHOUT |
| 11 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 12 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| 13 | +# License for more details. |
| 14 | + |
| 15 | +# You should have received a copy of the GNU Lesser General Public |
| 16 | +# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>. |
| 17 | +"""Tests for anatomical preprocessing.""" |
| 18 | + |
1 | 19 | import os |
2 | | -from unittest.mock import Mock, patch |
3 | 20 |
|
4 | | -from nose.tools import * |
5 | 21 | import numpy as np |
| 22 | +import pytest |
6 | 23 | import nibabel as nib |
7 | 24 |
|
8 | | -from .. import anat_preproc |
9 | | -from ..anat_preproc import brain_mask_freesurfer |
| 25 | +from CPAC.anat_preproc import anat_preproc |
| 26 | +from CPAC.anat_preproc.anat_preproc import brain_mask_freesurfer |
| 27 | +from CPAC.pipeline import nipype_pipeline_engine as pe |
| 28 | +from CPAC.pipeline.engine import ResourcePool |
| 29 | +from CPAC.utils.configuration import Preconfiguration |
| 30 | +from CPAC.utils.test_init import create_dummy_node |
10 | 31 |
|
| 32 | +CFG = Preconfiguration("ccs-options") |
11 | 33 |
|
12 | | -class TestAnatPreproc: |
13 | | - def __init__(self): |
| 34 | + |
| 35 | +@pytest.mark.skip(reason="This test needs refactoring.") |
| 36 | +class TestAnatPreproc: # noqa |
| 37 | + def setup_method(self) -> None: |
14 | 38 | """ |
15 | 39 | Initialize and run the the anat_preproc workflow. |
16 | 40 |
|
17 | 41 | Populate the node-name : node_output dictionary using the workflow object. |
18 | 42 | This dictionary serves the outputs of each of the nodes in the workflow to all the tests that need them. |
19 | | -
|
20 | | - Parameters |
21 | | - ---------- |
22 | | - self |
23 | | -
|
24 | | - Returns |
25 | | - ------- |
26 | | - None |
27 | | -
|
28 | | -
|
29 | 43 | """ |
30 | 44 | self.preproc = anat_preproc.create_anat_preproc() |
31 | 45 | self.input_anat = os.path.abspath("$FSLDIR/data/standard/MNI152_T1_2mm.nii.gz") |
@@ -273,67 +287,51 @@ def test_anat_brain(self): |
273 | 287 | assert correlation[0, 1] >= 0.97 |
274 | 288 |
|
275 | 289 |
|
276 | | -@patch("CPAC.anat_preproc.anat_preproc.freesurfer_fsl_brain_connector") |
277 | | -def test_brain_mask_freesurfer_fsl_loose(mock_connector): |
278 | | - """Test that brain_mask_freesurfer_fsl_loose correctly renames output key.""" |
279 | | - mock_wf = Mock() |
280 | | - mock_cfg = Mock() |
281 | | - mock_strat_pool = Mock() |
282 | | - pipe_num = 1 |
283 | | - |
284 | | - mock_outputs = { |
285 | | - "space-T1w_desc-loose_brain_mask": "brain_mask_data", |
286 | | - "other_output": "other_data", |
287 | | - } |
288 | | - |
289 | | - mock_connector.return_value = (mock_wf, mock_outputs) |
290 | | - |
291 | | - result_wf, result_outputs = brain_mask_freesurfer( |
292 | | - mock_wf, mock_cfg, mock_strat_pool, pipe_num |
293 | | - ) |
294 | | - |
295 | | - mock_connector.assert_called_once_with( |
296 | | - mock_wf, mock_cfg, mock_strat_pool, pipe_num, None |
297 | | - ) |
298 | | - |
299 | | - # Assert workflow returned unchanged |
300 | | - assert result_wf == mock_wf |
301 | | - |
302 | | - # Assert output key was renamed correctly |
303 | | - assert "space-T1w_desc-brain_mask" in result_outputs |
304 | | - assert "space-T1w_desc-loose_brain_mask" not in result_outputs |
305 | | - assert result_outputs["space-T1w_desc-brain_mask"] == "brain_mask_data" |
306 | | - assert result_outputs["other_output"] == "other_data" |
307 | | - |
| 290 | +@pytest.mark.parametrize("opt", ["FreeSurfer-BET-Loose", "FreeSurfer-BET-Tight"]) |
| 291 | +@pytest.mark.parametrize("t1w", ["desc-restore_T1w", "desc-preproc_T1w"]) |
| 292 | +def test_brain_mask_freesurfer_fsl_real(opt: str, t1w: str): |
| 293 | + """Test that brain_mask_freesurfer_fsl correctly generates output key using real code.""" |
| 294 | + # Create minimal mocks for required workflow/config/strat_pool, but do not patch freesurfer_fsl_brain_connector |
| 295 | + |
| 296 | + CFG["subject_id"] = opt |
| 297 | + |
| 298 | + wf = pe.Workflow(name=opt) |
| 299 | + pre_resources = [ |
| 300 | + t1w, |
| 301 | + "space-T1w_desc-brain_mask", |
| 302 | + "pipeline-fs_T1", |
| 303 | + "pipeline-fs_wmparc", |
| 304 | + "pipeline-fs_raw-average", |
| 305 | + "pipeline-fs_brainmask", |
| 306 | + "freesurfer-subject-dir", |
| 307 | + "T1w-brain-template-mask-ccs", |
| 308 | + "T1w-ACPC-template", |
| 309 | + ] |
| 310 | + before_this_test = create_dummy_node("created_before_this_test", pre_resources) |
| 311 | + rpool = ResourcePool(name=f"{opt}_{opt}", cfg=CFG) |
| 312 | + for resource in pre_resources: |
| 313 | + rpool.set_data( |
| 314 | + resource, before_this_test, resource, {}, "", before_this_test.name |
| 315 | + ) |
| 316 | + rpool.gather_pipes(wf, CFG) |
| 317 | + strat_pool = next(iter(rpool.get_strats(pre_resources).values())) |
308 | 318 |
|
309 | | -@patch("CPAC.anat_preproc.anat_preproc.freesurfer_fsl_brain_connector") |
310 | | -def test_brain_mask_freesurfer_fsl_tight(mock_connector): |
311 | | - """Test that brain_mask_freesurfer_fsl_tight correctly renames output key.""" |
312 | | - mock_wf = Mock() |
313 | | - mock_cfg = Mock() |
314 | | - mock_strat_pool = Mock() |
315 | 319 | pipe_num = 1 |
316 | 320 |
|
317 | | - mock_outputs = { |
318 | | - "space-T1w_desc-tight_brain_mask": "brain_mask_data", |
319 | | - "other_output": "other_data", |
320 | | - } |
321 | | - |
322 | | - mock_connector.return_value = (mock_wf, mock_outputs) |
323 | | - |
324 | 321 | result_wf, result_outputs = brain_mask_freesurfer( |
325 | | - mock_wf, mock_cfg, mock_strat_pool, pipe_num |
326 | | - ) |
327 | | - |
328 | | - mock_connector.assert_called_once_with( |
329 | | - mock_wf, mock_cfg, mock_strat_pool, pipe_num, None |
| 322 | + wf, CFG, strat_pool, pipe_num, opt |
330 | 323 | ) |
331 | 324 |
|
332 | | - # Assert workflow returned unchanged |
333 | | - assert result_wf == mock_wf |
334 | | - |
335 | | - # Assert output key was renamed correctly |
336 | | - assert "space-T1w_desc-brain_mask" in result_outputs |
337 | | - assert "space-T1w_desc-tight_brain_mask" not in result_outputs |
338 | | - assert result_outputs["space-T1w_desc-brain_mask"] == "brain_mask_data" |
339 | | - assert result_outputs["other_output"] == "other_data" |
| 325 | + # The output key should always be present |
| 326 | + assert any( |
| 327 | + k.startswith("space-T1w_desc-brain_mask") for k in result_outputs |
| 328 | + ), "Expected brain_mask key in outputs." |
| 329 | + # Should not have loose/tight keys |
| 330 | + assert not any( |
| 331 | + "loose_brain_mask" in k for k in result_outputs |
| 332 | + ), "Loose brain mask key should not be present." |
| 333 | + assert not any( |
| 334 | + "tight_brain_mask" in k for k in result_outputs |
| 335 | + ), "Tight brain mask key should not be present." |
| 336 | + # Should return the workflow unchanged |
| 337 | + assert result_wf == wf |
0 commit comments