From 32ebb63895cca948914829fe29bf52ffc6b4f98e Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Tue, 9 Nov 2021 09:01:54 +0100 Subject: [PATCH] enh: initial commit to begin with some unit tests Sets up a barebones infrastructure for testing, hopefully to give a kickstart to the work on #40. cc/ @celprov, @sebastientourbier --- eddymotion/conftest.py | 68 ++++++++++++++++++++++++++++ eddymotion/tests/test_dmri.py | 23 ++++++++++ eddymotion/tests/test_estimator.py | 23 ++++++++++ eddymotion/tests/test_integration.py | 23 ++++++++++ eddymotion/tests/test_model.py | 42 +++++++++++++++++ eddymotion/tests/test_version.py | 64 ++++++++++++++++++++++++++ 6 files changed, 243 insertions(+) create mode 100644 eddymotion/conftest.py create mode 100644 eddymotion/tests/test_dmri.py create mode 100644 eddymotion/tests/test_estimator.py create mode 100644 eddymotion/tests/test_integration.py create mode 100644 eddymotion/tests/test_model.py create mode 100644 eddymotion/tests/test_version.py diff --git a/eddymotion/conftest.py b/eddymotion/conftest.py new file mode 100644 index 00000000..cf30d8fc --- /dev/null +++ b/eddymotion/conftest.py @@ -0,0 +1,68 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""py.test configuration.""" +import os +from pathlib import Path +import numpy +import nibabel +import pytest + +test_data_env = os.getenv("TEST_DATA_HOME", str(Path.home() / "eddy-tests")) +test_output_dir = os.getenv("TEST_OUTPUT_DIR") +test_workdir = os.getenv("TEST_WORK_DIR") +data_dir = Path(__file__).parent / "tests" / "data" + + +def pytest_report_header(config): + return f"""\ +TEST_DATA_HOME={test_data_env}s +TEST_OUTPUT_DIR={test_output_dir or ' (output files will be discarded)'}. +TEST_WORK_DIR={test_workdir or ' (intermediate files will be discarded)'}. +""" + + +@pytest.fixture(autouse=True) +def doctest_imports(doctest_namespace): + """Populates doctests with some conveniency imports.""" + doctest_namespace["np"] = numpy + doctest_namespace["nb"] = nibabel + doctest_namespace["os"] = os + doctest_namespace["Path"] = Path + + +@pytest.fixture +def outdir(): + """Determine if test artifacts should be stored somewhere or deleted.""" + return None if test_output_dir is None else Path(test_output_dir) + + +@pytest.fixture +def datadir(): + """Return a data path outside the package's structure (i.e., large datasets).""" + return Path(test_data_env) + + +@pytest.fixture +def pkg_datadir(): + """Return a data path inside the package's structure (i.e., small, empty files).""" + return data_dir diff --git a/eddymotion/tests/test_dmri.py b/eddymotion/tests/test_dmri.py new file mode 100644 index 00000000..405257c3 --- /dev/null +++ b/eddymotion/tests/test_dmri.py @@ -0,0 +1,23 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""Unit tests exercising the dMRI data structure.""" diff --git a/eddymotion/tests/test_estimator.py b/eddymotion/tests/test_estimator.py new file mode 100644 index 00000000..a30a16f6 --- /dev/null +++ b/eddymotion/tests/test_estimator.py @@ -0,0 +1,23 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""Unit tests exercising the estimator.""" \ No newline at end of file diff --git a/eddymotion/tests/test_integration.py b/eddymotion/tests/test_integration.py new file mode 100644 index 00000000..60918591 --- /dev/null +++ b/eddymotion/tests/test_integration.py @@ -0,0 +1,23 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""Integration tests.""" diff --git a/eddymotion/tests/test_model.py b/eddymotion/tests/test_model.py new file mode 100644 index 00000000..5a6e6d94 --- /dev/null +++ b/eddymotion/tests/test_model.py @@ -0,0 +1,42 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""Unit tests exercising models.""" +import pytest +import numpy as np +from eddymotion import model + + +def test_trivial_model(): + """Check the implementation of the trivial B0 model.""" + + # Should not allow initialization without a B0 + with pytest.raises(ValueError): + model.TrivialB0Model(gtab=np.eye(4)) + + _S0 = np.random.normal(size=(10, 10, 10)) + + tmodel = model.TrivialB0Model(gtab=np.eye(4), S0=_S0) + + assert tmodel.fit() is None + + assert np.all(_S0 == tmodel.predict((1, 0, 0))) diff --git a/eddymotion/tests/test_version.py b/eddymotion/tests/test_version.py new file mode 100644 index 00000000..277cb3ed --- /dev/null +++ b/eddymotion/tests/test_version.py @@ -0,0 +1,64 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# +# Copyright 2021 The NiPreps Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# We support and encourage derived works from this project, please read +# about our expectations at +# +# https://www.nipreps.org/community/licensing/ +# +"""Test _version.py.""" +import sys +from collections import namedtuple +from pkg_resources import DistributionNotFound +from importlib import reload +import eddymotion + + +def test_version_scm0(monkeypatch): + """Retrieve the version via setuptools_scm.""" + + class _version: + __version__ = "10.0.0" + + monkeypatch.setitem(sys.modules, "eddymotion._version", _version) + reload(eddymotion) + assert eddymotion.__version__ == "10.0.0" + + +def test_version_scm1(monkeypatch): + """Retrieve the version via pkg_resources.""" + monkeypatch.setitem(sys.modules, "eddymotion._version", None) + + def _dist(name): + Distribution = namedtuple("Distribution", ["name", "version"]) + return Distribution(name, "success") + + monkeypatch.setattr("pkg_resources.get_distribution", _dist) + reload(eddymotion) + assert eddymotion.__version__ == "success" + + +def test_version_scm2(monkeypatch): + """Check version could not be interpolated.""" + monkeypatch.setitem(sys.modules, "eddymotion._version", None) + + def _raise(name): + raise DistributionNotFound("No get_distribution mock") + + monkeypatch.setattr("pkg_resources.get_distribution", _raise) + reload(eddymotion) + assert eddymotion.__version__ == "unknown"