File size: 3,232 Bytes
aef1f5a
3c4c67b
 
 
 
 
aef1f5a
 
 
 
 
3c4c67b
 
aef1f5a
 
 
 
 
 
 
 
 
 
 
 
 
3c4c67b
 
aef1f5a
 
 
3c4c67b
aef1f5a
 
 
3c4c67b
aef1f5a
 
 
 
 
 
3c4c67b
 
aef1f5a
 
 
3c4c67b
aef1f5a
 
 
 
 
3c4c67b
aef1f5a
 
 
 
3c4c67b
 
aef1f5a
 
 
 
 
 
 
3c4c67b
aef1f5a
3c4c67b
aef1f5a
 
 
3c4c67b
 
aef1f5a
 
 
 
 
 
 
3c4c67b
aef1f5a
 
 
3c4c67b
aef1f5a
3c4c67b
aef1f5a
 
3c4c67b
aef1f5a
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Tests for the data adapter."""

from __future__ import annotations

from typing import TYPE_CHECKING

from stroke_deepisles_demo.data.adapter import (
    LocalDataset,
    build_local_dataset,
    parse_subject_id,
)

if TYPE_CHECKING:
    from pathlib import Path


def test_parse_subject_id_extracts_correctly() -> None:
    """Test extracting subject ID from BIDS filename."""
    # Valid cases
    assert parse_subject_id("sub-stroke0005_ses-02_dwi.nii.gz") == "sub-stroke0005"
    assert parse_subject_id("sub-stroke0149_ses-02_adc.nii.gz") == "sub-stroke0149"
    assert parse_subject_id("sub-stroke1234_ses-02_lesion-msk.nii.gz") == "sub-stroke1234"

    # Invalid cases
    assert parse_subject_id("random_file.nii.gz") is None
    assert parse_subject_id("sub-strokeABC_ses-02_dwi.nii.gz") is None  # Non-digit ID


def test_build_local_dataset_matches_files(synthetic_isles_dir: Path) -> None:
    """Test that files are correctly matched by subject ID."""
    dataset = build_local_dataset(synthetic_isles_dir)

    assert isinstance(dataset, LocalDataset)
    assert len(dataset) == 2  # synthetic_isles_dir creates 2 subjects
    assert dataset.list_case_ids() == ["sub-stroke0001", "sub-stroke0002"]

    # Verify matching logic
    case1 = dataset.get_case("sub-stroke0001")
    assert case1["dwi"].name == "sub-stroke0001_ses-02_dwi.nii.gz"
    assert case1["adc"].name == "sub-stroke0001_ses-02_adc.nii.gz"
    assert case1["ground_truth"] is not None
    assert case1["ground_truth"].name == "sub-stroke0001_ses-02_lesion-msk.nii.gz"


def test_get_case_returns_case_files(synthetic_isles_dir: Path) -> None:
    """Test retrieval of cases by ID and index."""
    dataset = build_local_dataset(synthetic_isles_dir)

    # By ID
    case_by_id = dataset.get_case("sub-stroke0001")
    assert isinstance(case_by_id, dict)
    assert "dwi" in case_by_id
    assert "adc" in case_by_id

    # By Index
    case_by_idx = dataset.get_case(0)
    assert isinstance(case_by_idx, dict)
    assert case_by_id == case_by_idx  # Should be the same case


def test_build_local_dataset_skips_incomplete(
    synthetic_isles_dir: Path,
) -> None:
    """Test that incomplete cases (missing ADC) are skipped."""
    # Delete ADC for subject 2
    adc_file = synthetic_isles_dir / "Images-ADC" / "sub-stroke0002_ses-02_adc.nii.gz"
    adc_file.unlink()

    dataset = build_local_dataset(synthetic_isles_dir)

    # Subject 2 should be gone
    assert len(dataset) == 1
    assert dataset.list_case_ids() == ["sub-stroke0001"]


def test_build_local_dataset_handles_missing_mask(
    synthetic_isles_dir: Path,
) -> None:
    """Test that missing mask results in ground_truth=None (if allowed)."""
    # NOTE: Adapter currently allows missing mask?
    # Spec says: "ground_truth=mask_file if mask_file.exists() else None"
    # So yes, it should load but with None.

    # Delete Mask for subject 2
    mask_file = synthetic_isles_dir / "Masks" / "sub-stroke0002_ses-02_lesion-msk.nii.gz"
    mask_file.unlink()

    dataset = build_local_dataset(synthetic_isles_dir)

    # Subject 2 should still exist
    assert len(dataset) == 2

    case2 = dataset.get_case("sub-stroke0002")
    assert case2.get("ground_truth") is None