-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from tomaroberts/unit-tests
Adds unit tests, coverage badge and comments, and updates GHA
- Loading branch information
Showing
14 changed files
with
258 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# Workflow to build nii2dcm and test different command line interface (CLI) options | ||
# Workflow to build nii2dcm, run unit tests and then execute command line interface (CLI) end-to-end | ||
|
||
name: Build nii2dcm | ||
|
||
|
@@ -7,7 +7,7 @@ on: | |
|
||
jobs: | ||
build-and-test: | ||
name: Build | ||
name: Build, Unit Tests & E2E | ||
|
||
runs-on: ${{ matrix.os }} | ||
|
||
|
@@ -57,6 +57,10 @@ jobs: | |
nii2dcm -h | ||
nii2dcm -v | ||
- name: Run unit tests | ||
run: | | ||
pytest tests/ | ||
- name: Test DicomMRISVR creation | ||
run: | | ||
# run nii2dcm | ||
|
@@ -65,3 +69,25 @@ jobs: | |
ls ./output | ||
# assert DICOM files exist | ||
[ -f "./output/IM_0001.dcm" ] && echo "Output DICOM file exists" || exit 1 | ||
- name: Build pytest coverage file | ||
run: | | ||
pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=nii2dcm tests/ | tee pytest-coverage.txt ; echo $? | ||
- name: Pytest coverage comment | ||
id: coverageComment | ||
uses: MishaKav/pytest-coverage-comment@main | ||
with: | ||
pytest-coverage-path: ./pytest-coverage.txt | ||
junitxml-path: ./pytest.xml | ||
|
||
- name: Update Coverage Badge | ||
uses: schneegans/[email protected] | ||
with: | ||
auth: ${{ secrets.PYTEST_COVERAGE_COMMENT }} | ||
gistID: 57ef8057d04f67dbe6e64df410b83079 | ||
filename: nii2dcm-pytest-coverage-comment.json | ||
label: Coverage Report | ||
message: ${{ steps.coverageComment.outputs.coverage }} | ||
color: ${{ steps.coverageComment.outputs.color }} | ||
namedLogo: python |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
import dunamai as _dunamai | ||
__version__ = _dunamai.get_version("nii2dcm", third_choice=_dunamai.Version.from_any_vcs).serialize() | ||
__version__ = _dunamai.get_version("nii2dcm", third_choice=_dunamai.Version.from_any_vcs).serialize() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import pytest | ||
import os | ||
import datetime | ||
|
||
from pydicom.dataset import FileMetaDataset, FileDataset | ||
|
||
from nii2dcm.dcm import Dicom | ||
from nii2dcm.modules.patient import Patient | ||
|
||
|
||
TRANSFER_SYNTAX_UID = '1.2.840.10008.1.2.1' | ||
DATE = datetime.datetime.now().strftime('%Y%m%d') | ||
PATIENT_ID = '12345678' | ||
PATIENT_SEX = '' | ||
IMAGE_TYPE = ['SECONDARY', 'DERIVED'] | ||
CHARACTER_SET = 'ISO_IR 100' | ||
|
||
MIN_UID_LENGTH = 10 # arbitrary just to check UID has some characters | ||
MAX_UID_LENGTH = 64 # DICOM standard max length | ||
|
||
class TestDicom: | ||
def setup_method(self): | ||
self.dicom = Dicom() | ||
|
||
def test_dicom(self): | ||
""" | ||
Tests some metadata in basic Dicom object | ||
""" | ||
assert self.dicom.file_meta.TransferSyntaxUID == TRANSFER_SYNTAX_UID | ||
assert self.dicom.ds.ContentDate == DATE | ||
assert self.dicom.ds.AcquisitionDate == DATE | ||
assert self.dicom.ds.SeriesDate == DATE | ||
assert self.dicom.ds.StudyDate == DATE | ||
|
||
def test_add_module(self): | ||
""" | ||
Tests add_module() method | ||
""" | ||
self.dicom.add_module(Patient()) | ||
assert self.dicom.ds.PatientID == PATIENT_ID | ||
assert self.dicom.ds.PatientSex == PATIENT_SEX | ||
|
||
def test_add_base_modules(self): | ||
""" | ||
Test metadata present following bulk method invocation via add_base_modules() | ||
""" | ||
self.dicom.add_base_modules() | ||
assert self.dicom.ds.SpecificCharacterSet == CHARACTER_SET | ||
assert self.dicom.ds.ImageType[0] == 'SECONDARY' | ||
assert self.dicom.ds.ImageType[1] == 'DERIVED' | ||
|
||
def test_get_file_meta(self): | ||
fm = self.dicom.get_file_meta() | ||
assert isinstance(fm, FileMetaDataset) | ||
|
||
def test_get_dataset(self): | ||
ds = self.dicom.get_dataset() | ||
assert isinstance(ds, FileDataset) | ||
|
||
def test_save_as(self): | ||
""" | ||
Test DICOM save (default save location: cwd) | ||
""" | ||
self.dicom.ds.save_as(self.dicom.filename) | ||
assert os.path.exists(self.dicom.filename) | ||
os.remove(self.dicom.filename) | ||
if os.path.exists(self.dicom.filename): | ||
raise Exception("Failed to delete temporary DICOM created during pytest process.") | ||
|
||
def test_init_study_tags(self): | ||
self.dicom.init_study_tags() | ||
assert isinstance(self.dicom.ds.StudyInstanceUID, str) | ||
assert self.dicom.ds.StudyInstanceUID.find(".") | ||
assert MIN_UID_LENGTH < len(self.dicom.ds.StudyInstanceUID) <= MAX_UID_LENGTH | ||
|
||
def test_init_series_tags(self): | ||
self.dicom.init_study_tags() | ||
assert isinstance(self.dicom.ds.SeriesInstanceUID, str) | ||
assert self.dicom.ds.SeriesInstanceUID.find(".") | ||
assert MIN_UID_LENGTH < len(self.dicom.ds.SeriesInstanceUID) <= MAX_UID_LENGTH | ||
|
||
assert len(str(self.dicom.ds.SeriesNumber)) == 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import os | ||
|
||
import pytest | ||
import nibabel as nib | ||
|
||
from nii2dcm import dcm_writer | ||
from nii2dcm.dcm import Dicom | ||
from nii2dcm.nii import Nifti | ||
|
||
|
||
NII_FILE_PATH = "tests/data/DicomMRISVR/t2-svr-atlas-35wk.nii.gz" | ||
INSTANCE_INDEX = 10 # dcm instances count from 1 | ||
SLICE_NUMBER = INSTANCE_INDEX-1 # nibabel slice array counts from 0 | ||
OUTPUT_DIR = "tests/data" | ||
OUTPUT_DCM_FILENAME = r'IM_%04d.dcm' % (INSTANCE_INDEX) | ||
OUTPUT_DCM_PATH = os.path.join(os.getcwd(), OUTPUT_DIR, OUTPUT_DCM_FILENAME) | ||
|
||
class TestDicomWriter: | ||
def setup_method(self): | ||
self.dicom = Dicom() | ||
self.nii = nib.load(NII_FILE_PATH) | ||
self.img_data = self.nii.get_fdata().astype("uint16") | ||
self.nii2dcm_parameters = Nifti.get_nii2dcm_parameters(self.nii) | ||
|
||
def test_write_slice(self): | ||
dcm_writer.write_slice(self.dicom, self.img_data, SLICE_NUMBER, OUTPUT_DIR) | ||
|
||
assert os.path.exists(OUTPUT_DCM_PATH) | ||
os.remove(OUTPUT_DCM_PATH) | ||
if os.path.exists(OUTPUT_DCM_PATH): | ||
raise Exception("Failed to delete temporary DICOM created during pytest process.") | ||
|
||
def test_transfer_nii_hdr_series_tags(self): | ||
dcm_writer.transfer_nii_hdr_series_tags(self.dicom, self.nii2dcm_parameters) | ||
assert self.dicom.ds.Rows == self.nii.shape[0] | ||
assert self.dicom.ds.Columns == self.nii.shape[1] | ||
|
||
def test_transfer_nii_hdr_instance_tags(self): | ||
dcm_writer.transfer_nii_hdr_instance_tags(self.dicom, self.nii2dcm_parameters, SLICE_NUMBER) | ||
assert self.dicom.ds.InstanceNumber == INSTANCE_INDEX | ||
|
||
def test_transfer_ref_dicom_series_tags(self): | ||
""" | ||
TODO: implement test | ||
""" | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import pytest | ||
|
||
from nii2dcm.nii import Nifti | ||
import nibabel as nib | ||
|
||
|
||
NII_FILE_PATH = "tests/data/DicomMRISVR/t2-svr-atlas-35wk.nii.gz" | ||
NII_VOXEL_DIMS = (180, 221, 180) | ||
NII_VOXEL_SPACING = (0.5, 0.5, 0.5) | ||
|
||
class TestNifti: | ||
def setup_method(self): | ||
self.nii = nib.load(NII_FILE_PATH) | ||
|
||
def test_get_nii2dcm_parameters(self): | ||
nii_parameters = Nifti.get_nii2dcm_parameters(self.nii) | ||
assert nii_parameters["Rows"] == NII_VOXEL_DIMS[0] | ||
assert nii_parameters["Columns"] == NII_VOXEL_DIMS[1] | ||
assert nii_parameters["NumberOfSlices"] == NII_VOXEL_DIMS[2] | ||
assert nii_parameters["AcquisitionMatrix"] == [0, NII_VOXEL_DIMS[0], NII_VOXEL_DIMS[1], 0] | ||
assert nii_parameters["dimX"] == NII_VOXEL_SPACING[0] | ||
assert nii_parameters["dimY"] == NII_VOXEL_SPACING[1] | ||
assert nii_parameters["SliceThickness"] == str(NII_VOXEL_SPACING[2]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import pytest | ||
import os, shutil | ||
import pydicom as pyd | ||
|
||
from nii2dcm.run import run_nii2dcm | ||
|
||
|
||
NII_FILE_PATH = "tests/data/DicomMRISVR/t2-svr-atlas-35wk.nii.gz" | ||
OUTPUT_DIR = "tests/data/tmp_dcm_dir" | ||
OUTPUT_DCM_PATH = os.path.join(os.getcwd(), OUTPUT_DIR) | ||
NUM_DICOM_FILES = 180 | ||
SINGLE_DICOM_FILENAME = "IM_0001.dcm" | ||
|
||
class TestRun: | ||
def setup_method(self): | ||
os.makedirs(OUTPUT_DCM_PATH, exist_ok=True) | ||
|
||
@pytest.mark.parametrize( | ||
"TEST_DICOM_TYPE, TEST_DCM_MODALITY", | ||
[ | ||
(None, ''), # basic DICOM with undefined modality | ||
("MR", "MR"), # MRI DICOM | ||
("SVR", "MR") # SVR DICOM hence MR modality | ||
] | ||
) | ||
def test_run_dicom_types(self, TEST_DICOM_TYPE, TEST_DCM_MODALITY): | ||
""" | ||
Test run_nii2dcm with different dicom_types | ||
""" | ||
run_nii2dcm( | ||
NII_FILE_PATH, | ||
OUTPUT_DCM_PATH, | ||
dicom_type=TEST_DICOM_TYPE | ||
) | ||
assert os.path.exists(os.path.join(OUTPUT_DCM_PATH, SINGLE_DICOM_FILENAME)) | ||
assert len(os.listdir(OUTPUT_DCM_PATH)) == NUM_DICOM_FILES | ||
|
||
ds = pyd.dcmread(os.path.join(OUTPUT_DCM_PATH, SINGLE_DICOM_FILENAME)) | ||
assert ds.Modality == TEST_DCM_MODALITY | ||
|
||
shutil.rmtree(OUTPUT_DCM_PATH) | ||
|
||
def test_run_reference_dicom(self): | ||
""" | ||
Test run_nii2dcm with different ref_dicom option | ||
""" | ||
# TODO: implement - will involve adding reference DICOM test dataset | ||
pass | ||
|
||
def teardown_method(self): | ||
""" | ||
Remove output DICOM directory in event of test failure | ||
""" | ||
if os.path.exists(OUTPUT_DCM_PATH): | ||
shutil.rmtree(OUTPUT_DCM_PATH) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import pytest | ||
from packaging import version | ||
|
||
from nii2dcm._version import __version__ | ||
|
||
|
||
class TestVersion: | ||
def test_version(self): | ||
assert isinstance(version.parse(__version__), version.Version) |