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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
"""Test BIDSValidator functionality.
git-annex and datalad are used to download a test data structure without the
actual file contents.
"""
import os
import pytest
import datalad.api
from bids_validator import BIDSValidator
HOME = os.path.expanduser('~')
TEST_DATA_DICT = {
'eeg_matchingpennies': (
'https://gin.g-node.org/sappelhoff/eeg_matchingpennies'
),
}
EXCLUDE_KEYWORDS = ['git', 'datalad', 'sourcedata', 'bidsignore']
def _download_test_data(test_data_dict, dsname):
"""Download test data using datalad."""
url = test_data_dict[dsname]
dspath = os.path.join(HOME, dsname)
datalad.api.clone(source=url, path=dspath)
return dspath
def _gather_test_files(dspath, exclude_keywords):
"""Get test files from dataset path, relative to dataset."""
files = []
for r, _, f in os.walk(dspath):
for file in f:
fname = os.path.join(r, file)
fname = fname.replace(dspath, '')
if not any(keyword in fname for keyword in exclude_keywords):
files.append(fname)
return files
dspath = _download_test_data(TEST_DATA_DICT, 'eeg_matchingpennies')
files = _gather_test_files(dspath, EXCLUDE_KEYWORDS)
@pytest.fixture(scope='module')
def validator():
"""Return a BIDSValidator instance."""
validator = BIDSValidator()
return validator
@pytest.mark.parametrize('fname', files)
def test_datasets(validator, fname):
"""Test that is_bids returns true for each file in a valid BIDS dataset."""
assert validator.is_bids(fname)
@pytest.mark.parametrize('fname, matches', [
('/T1w.json', True),
('/dataset_description.json', True),
('/README', True),
('/CHANGES', True),
('/participants.tsv', True),
('/sub-01/anat/sub-01_T1w.nii.gz', False),
])
def test_top_level(validator, fname, matches):
"""Test that is_top_level returns true for top-level files."""
assert validator.is_top_level(fname) is matches
@pytest.mark.parametrize('fname, matches', [
('/sourcedata/unstructured_data.nii.gz', True),
('/sourcedata/dicom_dir/xyz.dcm', True),
('/code/my_analysis/analysis.py', True),
('/derivatives/preproc/sub-01/anat/sub-01_desc-preproc_T1w.nii.gz', True),
('/stimuli/pic.jpg', True),
('/sub-01/anat/sub-01_T1w.nii.gz', False),
])
def test_associated_data(validator, fname, matches):
"""Test that is_associated_data returns true for associated data."""
assert validator.is_associated_data(fname) is matches
@pytest.mark.parametrize('fname, matches', [
('/sub-01/ses-1/sub-01_ses-1_scans.tsv', True),
('/sub-01/ses-1/sub-01_ses-1_scans.json', True),
('/sub-01/sub-01_scans.tsv', True),
('/sub-01/sub-01_scans.json', True),
('/sub-01/ses-1/sub-01_ses-1_task-rest_bold.json', True),
('/sub-01/sub-01_task-rest_bold.json', True),
('/sub-01/ses-1/sub-01_ses-1_asl.json', True),
('/sub-01/sub-01_asl.json', True),
('/sub-01/ses-1/sub-01_ses-1_pet.json', True),
('/sub-01/sub-01_pet.json', True),
('/sub-01/ses-1/sub-01_ses-1_proc-test_channels.tsv', True),
('/sub-01/ses-1/sub-01_ses-1_channels.json', True),
('/sub-01/sub-01_proc-test_channels.tsv', True),
('/sub-01/sub-01_channels.json', True),
('/sub-01/ses-1/sub-01_ses-1_space-CapTrak_electrodes.tsv', True),
('/sub-01/ses-1/sub-01_ses-1_coordsystem.json', True),
('/sub-01/sub-01_space-CapTrak_electrodes.tsv', True),
('/sub-01/sub-01_coordsystem.json', True),
('/sub-01/ses-1/sub-01_ses-1_motion.json', True),
('/sub-01/sub-01_motion.json', True),
('/sub-01/ses-1/sub-01_ses-1_TEM.json', True),
('/sub-01/sub-01_TEM.json', True),
('/sub-01/ses-1/sub-01_ses-1_nirs.json', True),
('/sub-01/sub-01_nirs.json', True),
# Mismatch sessions
('/sub-01/sub-01_ses-1_scans.tsv', False),
('/sub-01/sub-01_ses-1_scans.json', False),
('/sub-01/ses-1/sub-01_ses-2_scans.tsv', False),
# File-level
('/sub-01/ses-1/func/sub-01_ses-1_task-rest_bold.nii.gz', False),
('/sub-01/anat/sub-01_T1w.nii.gz', False),
])
def test_session_level(validator, fname, matches):
"""Test that is_session_level returns true for session level files."""
assert validator.is_session_level(fname) is matches
@pytest.mark.parametrize('fname, matches', [
('/sub-01/sub-01_sessions.tsv', True),
('/sub-01/sub-01_sessions.json', True),
('/sub-01/anat/sub-01_T1w.nii.gz', False),
])
def test_subject_level(validator, fname, matches):
"""Test that is_subject_level returns true for subject level files."""
assert validator.is_subject_level(fname) is matches
@pytest.mark.parametrize('fname, matches', [
('/phenotype/measure.tsv', True),
('/phenotype/measure.json', True),
('/sub-01/anat/sub-01_T1w.nii.gz', False),
])
def test_phenotpic(validator, fname, matches):
"""Test that is_phenotypic returns true for phenotypic files."""
assert validator.is_phenotypic(fname) is matches
@pytest.mark.parametrize('fname, matches', [
('/sub-01/ses-1/func/sub-01_ses-1_task-rest_bold.nii.gz', True),
('/sub-01/anat/sub-01_T1w.nii.gz', True),
])
def test_file_level(validator, fname, matches):
"""Test that is_file returns true for file level files."""
assert validator.is_file(fname) is matches
|