Skip to content

Commit 65f2e66

Browse files
committed
Add tests
1 parent 106fb72 commit 65f2e66

File tree

3 files changed

+336
-0
lines changed

3 files changed

+336
-0
lines changed

tests/nifti/test_roi.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""
2+
Test the ndimage module
3+
"""
4+
import pytest
5+
6+
import numpy as np
7+
8+
from boyle.nifti.roi import largest_connected_component
9+
10+
11+
def test_largest_cc():
12+
""" Check the extraction of the largest connected component.
13+
"""
14+
a = np.zeros((6, 6, 6))
15+
pytest.raises(ValueError, largest_connected_component, a)
16+
a[1:3, 1:3, 1:3] = 1
17+
np.testing.assert_equal(a, largest_connected_component(a))
18+
b = a.copy()
19+
b[5, 5, 5] = 1
20+
np.testing.assert_equal(a, largest_connected_component(b))

tests/utils/test_cache_mixin.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
Test the _utils.cache_mixin module
3+
"""
4+
import os
5+
import shutil
6+
import tempfile
7+
import json
8+
import glob
9+
10+
from sklearn.externals.joblib import Memory
11+
12+
import boyle
13+
from boyle.utils import cache_mixin
14+
15+
16+
def f(x):
17+
# A simple test function
18+
return x
19+
20+
21+
def test__safe_cache_dir_creation():
22+
# Test the _safe_cache function that is supposed to flush the
23+
# cache if the nibabel version changes
24+
try:
25+
temp_dir = tempfile.mkdtemp()
26+
mem = Memory(cachedir=temp_dir)
27+
version_file = os.path.join(temp_dir, 'joblib', 'module_versions.json')
28+
assert not os.path.exists(version_file)
29+
# First test that a version file get created
30+
cache_mixin._safe_cache(mem, f)
31+
assert os.path.exists(version_file)
32+
# Test that it does not get recreated during the same session
33+
os.unlink(version_file)
34+
cache_mixin._safe_cache(mem, f)
35+
assert not os.path.exists(version_file)
36+
finally:
37+
if os.path.exists(temp_dir):
38+
shutil.rmtree(temp_dir)
39+
40+
41+
def test__safe_cache_flush():
42+
# Test the _safe_cache function that is supposed to flush the
43+
# cache if the nibabel version changes
44+
try:
45+
temp_dir = tempfile.mkdtemp()
46+
mem = Memory(cachedir=temp_dir)
47+
version_file = os.path.join(temp_dir, 'joblib', 'module_versions.json')
48+
# Create an mock version_file with old module versions
49+
with open(version_file, 'w') as f:
50+
json.dump({"nibabel": [0, 0]}, f)
51+
# Create some store structure
52+
nibabel_dir = os.path.join(temp_dir, 'joblib', 'nibabel_')
53+
os.makedirs(nibabel_dir)
54+
55+
# First turn off version checking
56+
boyle.CHECK_CACHE_VERSION = False
57+
cache_mixin._safe_cache(mem, f)
58+
assert os.path.exists(nibabel_dir)
59+
60+
# Second turn on version checking
61+
boyle.CHECK_CACHE_VERSION = True
62+
# Make sure that the check will run again
63+
cache_mixin.__CACHE_CHECKED = {}
64+
with open(version_file, 'w') as f:
65+
json.dump({"nibabel": [0, 0]}, f)
66+
cache_mixin._safe_cache(mem, f)
67+
assert os.path.exists(version_file)
68+
assert not os.path.exists(nibabel_dir)
69+
finally:
70+
pass
71+
# if os.path.exists(temp_dir):
72+
# shutil.rmtree(temp_dir)
73+
74+
75+
def test_cache_memory_level():
76+
temp_dir = tempfile.mkdtemp()
77+
job_glob = os.path.join(temp_dir, 'joblib', 'nilearn', 'tests',
78+
'test_cache_mixin', 'f', '*')
79+
mem = Memory(cachedir=temp_dir, verbose=0)
80+
cache_mixin.cache(f, mem, func_memory_level=2, memory_level=1)(2)
81+
assert len(glob.glob(job_glob)) == 0
82+
cache_mixin.cache(f, Memory(cachedir=None))(2)
83+
assert len(glob.glob(job_glob)) == 0
84+
cache_mixin.cache(f, mem, func_memory_level=2, memory_level=3)(2)
85+
assert len(glob.glob(job_glob)) == 2
86+
cache_mixin.cache(f, mem)(3)
87+
assert len(glob.glob(job_glob)) == 3

tests/utils/test_numpy_conversions.py

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
"""
2+
Test the numpy_conversions module
3+
"""
4+
import pytest
5+
6+
import numpy as np
7+
import os
8+
9+
from boyle.utils.numpy_conversions import as_ndarray
10+
11+
12+
def are_arrays_identical(arr1, arr2):
13+
"""Check if two 1-dimensional array point to the same buffer.
14+
15+
The check is performed only on the first value of the arrays. For
16+
this test to be reliable, arr2 must not point to a subset of arr1.
17+
For example, if arr2 = arr1[1:] has been executed just before calling
18+
this function, the test will FAIL, even if the same buffer is used by
19+
both arrays. arr2 = arr1[:1] will succeed though.
20+
21+
dtypes are not supposed to be identical.
22+
"""
23+
# Modify the first value in arr1 twice, and see if corresponding
24+
# value in arr2 has changed. Changing the value twice is required, since
25+
# the original value could be the first value that we use.
26+
27+
orig1 = arr1[0]
28+
orig2 = arr2[0]
29+
30+
arr1[0] = 0
31+
if arr2[0] != orig2:
32+
arr1[0] = orig1
33+
return True
34+
35+
arr1[0] = 1
36+
if arr2[0] != orig2:
37+
arr1[0] = orig1
38+
return True
39+
40+
arr1[0] = orig1
41+
return False
42+
43+
44+
def test_are_array_identical():
45+
arr1 = np.ones(4)
46+
orig1 = arr1.copy()
47+
48+
arr2 = arr1
49+
orig2 = arr2.copy()
50+
51+
assert(are_arrays_identical(arr1, arr2))
52+
np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
53+
np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
54+
55+
arr2 = arr1[:1]
56+
orig2 = arr2.copy()
57+
assert(are_arrays_identical(arr1, arr2))
58+
np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
59+
np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
60+
61+
arr2 = arr1[1:]
62+
orig2 = arr2.copy()
63+
assert(not are_arrays_identical(arr1, arr2))
64+
np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
65+
np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
66+
67+
arr2 = arr1.copy()
68+
orig2 = arr2.copy()
69+
assert(not are_arrays_identical(arr1, arr2))
70+
np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
71+
np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
72+
73+
74+
def test_as_ndarray():
75+
# All test cases
76+
# input dtype, input order, should copy, output dtype, output order, copied
77+
test_cases = [
78+
# no-op
79+
(np.float, "C", False, None, None, False),
80+
(np.float, "F", False, None, None, False),
81+
82+
# simple copy
83+
(np.float, "C", True, None, None, True),
84+
(np.float, "F", True, None, None, True),
85+
86+
# dtype provided, identical
87+
(np.float, "C", False, np.float, None, False),
88+
(np.float, "F", False, np.float, None, False),
89+
90+
# dtype changed
91+
(np.float, "C", False, np.float32, None, True),
92+
(np.float, "F", False, np.float32, None, True),
93+
94+
# dtype and order provided, but identical
95+
(np.float, "C", False, np.float, "C", False),
96+
(np.float, "F", False, np.float, "F", False),
97+
98+
# order provided, unchanged
99+
(np.float, "C", False, None, "C", False),
100+
(np.float, "F", False, None, "F", False),
101+
(np.float, "C", True, None, "C", True),
102+
(np.float, "F", True, None, "F", True),
103+
104+
# order provided, changed
105+
(np.float, "C", False, None, "F", True),
106+
(np.float, "F", False, None, "C", True),
107+
(np.float, "C", True, None, "F", True),
108+
(np.float, "F", True, None, "C", True),
109+
110+
# Special case for int8 <-> bool conversion.
111+
(np.int8, "C", False, np.bool, None, False),
112+
(np.int8, "F", False, np.bool, None, False),
113+
(np.int8, "C", False, np.bool, "C", False),
114+
(np.int8, "F", False, np.bool, "F", False),
115+
(np.int8, "C", False, np.bool, "F", True),
116+
(np.int8, "F", False, np.bool, "C", True),
117+
118+
(np.int8, "C", True, np.bool, None, True),
119+
(np.int8, "F", True, np.bool, None, True),
120+
(np.int8, "C", True, np.bool, "C", True),
121+
(np.int8, "F", True, np.bool, "F", True),
122+
123+
(np.bool, "C", False, np.int8, None, False),
124+
(np.bool, "F", False, np.int8, None, False),
125+
(np.bool, "C", False, np.int8, "C", False),
126+
(np.bool, "F", False, np.int8, "F", False),
127+
(np.bool, "C", False, np.int8, "F", True),
128+
(np.bool, "F", False, np.int8, "C", True),
129+
130+
(np.bool, "C", True, np.int8, None, True),
131+
(np.bool, "F", True, np.int8, None, True),
132+
(np.bool, "C", True, np.int8, "C", True),
133+
(np.bool, "F", True, np.int8, "F", True),
134+
]
135+
136+
shape = (10, 11)
137+
for case in test_cases:
138+
in_dtype, in_order, copy, out_dtype, out_order, copied = case
139+
arr1 = np.ones(shape, dtype=in_dtype, order=in_order)
140+
arr2 = as_ndarray(arr1,
141+
copy=copy, dtype=out_dtype, order=out_order)
142+
assert (not are_arrays_identical(arr1[0], arr2[0]) == copied), str(case)
143+
if out_dtype is None:
144+
assert (arr2.dtype == in_dtype), str(case)
145+
else:
146+
assert (arr2.dtype == out_dtype), str(case)
147+
148+
result_order = out_order if out_order is not None else in_order
149+
if result_order == "F":
150+
assert (arr2.flags["F_CONTIGUOUS"]), str(case)
151+
else:
152+
assert (arr2.flags["C_CONTIGUOUS"]), str(case)
153+
154+
# memmap
155+
filename = os.path.join(os.path.dirname(__file__), "data", "mmap.dat")
156+
157+
# same dtype, no copy requested
158+
arr1 = np.memmap(filename, dtype='float32', mode='w+', shape=(5,))
159+
arr2 = as_ndarray(arr1)
160+
assert(not are_arrays_identical(arr1, arr2))
161+
162+
# same dtype, copy requested
163+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite', shape=(5,))
164+
arr2 = as_ndarray(arr1, copy=True)
165+
assert(not are_arrays_identical(arr1, arr2))
166+
167+
# different dtype
168+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite', shape=(5,))
169+
arr2 = as_ndarray(arr1, dtype=np.int)
170+
assert(arr2.dtype == np.int)
171+
assert(not are_arrays_identical(arr1, arr2))
172+
173+
# same dtype, explicitly provided: must copy
174+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite', shape=(5,))
175+
arr2 = as_ndarray(arr1, dtype=np.float32)
176+
assert(arr2.dtype == np.float32)
177+
assert(not are_arrays_identical(arr1, arr2))
178+
179+
# same dtype, order provided
180+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite', shape=(10, 10))
181+
arr2 = as_ndarray(arr1, order="F")
182+
assert(arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"])
183+
assert(arr2.dtype == arr1.dtype)
184+
assert(not are_arrays_identical(arr1[0], arr2[0]))
185+
186+
# same dtype, order unchanged but provided
187+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite',
188+
shape=(10, 10), order="F")
189+
arr2 = as_ndarray(arr1, order="F")
190+
assert(arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"])
191+
assert(arr2.dtype == arr1.dtype)
192+
assert(not are_arrays_identical(arr1[0], arr2[0]))
193+
194+
# dtype and order specified
195+
arr1 = np.memmap(filename, dtype='float32', mode='readwrite',
196+
shape=(10, 10), order="F")
197+
arr2 = as_ndarray(arr1, order="F", dtype=np.int32)
198+
assert(arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"])
199+
assert(arr2.dtype == np.int32)
200+
assert(not are_arrays_identical(arr1[0], arr2[0]))
201+
202+
# list
203+
# same dtype, no copy requested
204+
arr1 = [0, 1, 2, 3]
205+
arr2 = as_ndarray(arr1)
206+
assert(not are_arrays_identical(arr1, arr2))
207+
208+
# same dtype, copy requested
209+
arr1 = [0, 1, 2, 3]
210+
arr2 = as_ndarray(arr1, copy=True)
211+
assert(not are_arrays_identical(arr1, arr2))
212+
213+
# different dtype
214+
arr1 = [0, 1, 2, 3]
215+
arr2 = as_ndarray(arr1, dtype=np.float)
216+
assert(arr2.dtype == np.float)
217+
assert(not are_arrays_identical(arr1, arr2))
218+
219+
# order specified
220+
arr1 = [[0, 1, 2, 3], [0, 1, 2, 3]]
221+
arr2 = as_ndarray(arr1, dtype=np.float, order="F")
222+
assert(arr2.dtype == np.float)
223+
assert(arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"])
224+
assert(not are_arrays_identical(arr1[0], arr2[0]))
225+
226+
# Unhandled cases
227+
pytest.raises(ValueError, as_ndarray, "test string")
228+
pytest.raises(ValueError, as_ndarray, [], order="invalid")
229+

0 commit comments

Comments
 (0)