From 9e88e793a6fd6da0e4cdbe181609c06a96b2d0fd Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Tue, 23 Jul 2024 15:19:23 +0100
Subject: [PATCH] TEST: Test ensuring that imcp does not modify data

---
 fsl/tests/__init__.py       |  8 ++++
 fsl/tests/test_dicom.py     |  2 +-
 fsl/tests/test_immv_imcp.py | 83 ++++++++++++++++++++++++++++++++-----
 3 files changed, 81 insertions(+), 12 deletions(-)

diff --git a/fsl/tests/__init__.py b/fsl/tests/__init__.py
index a758db12..2846ee5c 100644
--- a/fsl/tests/__init__.py
+++ b/fsl/tests/__init__.py
@@ -10,6 +10,7 @@
 import              os
 import              sys
 import              glob
+import              hashlib
 import              shutil
 import              fnmatch
 import              logging
@@ -439,3 +440,10 @@ def make_random_mask(filename, shape, xform, premask=None, minones=1):
     img.save(filename)
 
     return img
+
+
+def sha256(filename):
+    hashobj = hashlib.sha256()
+    with open(filename, 'rb') as f:
+        hashobj.update(f.read())
+    return hashobj.hexdigest()
diff --git a/fsl/tests/test_dicom.py b/fsl/tests/test_dicom.py
index dfda97f2..ca68ebd8 100644
--- a/fsl/tests/test_dicom.py
+++ b/fsl/tests/test_dicom.py
@@ -151,7 +151,7 @@ def test_scanDir():
         datafile = op.join(datadir, 'example_dicom.tbz2')
 
         with tarfile.open(datafile) as f:
-            f.extractall()
+            f.extractall(filter='data')
 
         series = fsldcm.scanDir('.')
         assert len(series) == 2
diff --git a/fsl/tests/test_immv_imcp.py b/fsl/tests/test_immv_imcp.py
index 7b3e3fcb..b4b80ffc 100644
--- a/fsl/tests/test_immv_imcp.py
+++ b/fsl/tests/test_immv_imcp.py
@@ -7,22 +7,26 @@
 
 from __future__ import print_function
 
+import              gzip
+import itertools as it
+import os.path   as op
+import              os
+import              shutil
+import              tempfile
 
+from unittest import mock
 
-import os.path    as op
-import               os
-import               shutil
-import               tempfile
-
-import numpy as np
+import numpy   as np
 import nibabel as nib
 
-import fsl.utils.imcp        as imcp
-import fsl.data.image        as fslimage
+import fsl.utils.imcp    as imcp
+import fsl.utils.tempdir as tempdir
+import fsl.data.image    as fslimage
 
-from fsl.tests import make_random_image
-from fsl.tests import make_dummy_file
-from fsl.tests import looks_like_image
+from fsl.tests import (make_random_image,
+                       make_dummy_file,
+                       looks_like_image,
+                       sha256)
 
 
 real_print = print
@@ -315,3 +319,60 @@ def test_imcp_shouldPass(move=False):
 
 def test_immv_shouldPass():
     test_imcp_shouldPass(move=True)
+
+
+def test_imcp_data_unmodified():
+    """Test that the data in an imcp'd image file is not modified. """
+
+    dtypes = [
+       np.int16,
+       np.int32,
+       np.float32,
+       np.float64]
+
+    slints = [(None, None), (1, 0), (3, 1.5)]
+
+    for dtype, (slope, inter) in it.product(dtypes, slints):
+        with tempdir.tempdir():
+            data = np.random.randint(1, 100, (10, 10, 10)).astype(dtype)
+            hdr  = nib.Nifti1Header()
+            hdr.set_data_dtype(dtype)
+            hdr.set_data_shape((10, 10, 10))
+            hdr.set_slope_inter(slope, inter)
+            hdr.set_sform(np.eye(4))
+
+            # write header/data separately, as otherwise
+            # nibabel will automatically rescale the data
+            with open('image.nii', 'wb') as f:
+                hdr.write_to(f)
+                f.write(data.tobytes())
+
+            # Input/output formats the same,
+            # should induce a straight file copy
+            imcp.imcp('image.nii', 'copied.nii', useDefaultExt=False)
+
+            # uncompresed->compressed will cause imcp
+            # to load in the image, rather than doing a
+            # file copy
+            with mock.patch.dict(os.environ, FSLOUTPUTTYPE='NIFTI_GZ'):
+                imcp.imcp('image.nii', 'converted.nii.gz', useDefaultExt=True)
+
+            # copied files should be identical
+            assert sha256('image.nii') == sha256('copied.nii')
+
+            # Converted files should have the same
+            # data, slope, and intercept. Read result
+            # header/data separately to avoid nibabel
+            # auto-rescaling.
+            with gzip.open('converted.nii.gz', 'rb') as f:
+                gothdr    = nib.Nifti1Header.from_fileobj(f)
+                databytes = f.read()
+
+            gotdata = np.frombuffer(databytes, dtype=dtype).reshape((10, 10, 10))
+
+            # Data should be binary identical
+            assert np.all(gotdata == data)
+
+            if slope is None: slope = 1
+            if inter is None: inter = 0
+            assert np.all(np.isclose(gothdr.get_slope_inter(), (slope, inter)))
-- 
GitLab