From 605d531538178fad8ac7624f44d8a8332fdbb6f7 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Thu, 5 Sep 2019 16:22:47 +0100
Subject: [PATCH] TEST: update dicom tests

---
 tests/test_dicom.py | 154 ++++++++++++++++++++++++++++++++------------
 1 file changed, 113 insertions(+), 41 deletions(-)

diff --git a/tests/test_dicom.py b/tests/test_dicom.py
index 70b5117bc..5354e86e2 100644
--- a/tests/test_dicom.py
+++ b/tests/test_dicom.py
@@ -1,14 +1,21 @@
 #!/usr/bin/env python
 #
-# test_dicom.py -
-#
-# Author: Paul McCarthy <pauldmccarthy@gmail.com>
+# These tests require an internet connection, and will only work on linux.
 #
 
-import os.path as op
-import            tarfile
+import os.path        as op
+import                   os
+import functools      as ft
+import subprocess     as sp
+import                   tarfile
+import                   zipfile
+import                   random
+import                   string
+import                   binascii
+import                   contextlib
+import urllib.request as request
+from   unittest import   mock
 
-import mock
 import pytest
 
 import fsl.data.dicom    as fsldcm
@@ -21,14 +28,35 @@ datadir = op.join(op.dirname(__file__), 'testdata')
 pytestmark = pytest.mark.dicomtest
 
 
-def setup_module():
+@contextlib.contextmanager
+def install_dcm2niix(version='1.0.20190902'):
+    filenames = {
+        '1.0.20190902' : 'v1.0.20190902/dcm2niix_lnx.zip',
+        '1.0.20190410' : 'v1.0.20190410/dcm2niix_11-Apr-2019_lnx.zip',
+        '1.0.20181125' : 'v1.0.20181125/dcm2niix_25-Nov-2018_lnx.zip',
+        '1.0.20171017' : 'v1.0.20171017/dcm2niix_18-Oct-2017_lnx.zip',
+    }
+    prefix = 'https://github.com/rordenlab/dcm2niix/releases/download/'
+    url    = prefix + filenames[version]
 
-    if not fsldcm.enabled():
-        raise RuntimeError('dcm2niix is not present - tests cannot be run')
+    with tempdir.tempdir() as td:
+        request.urlretrieve(url, 'dcm2niix.zip')
 
+        with zipfile.ZipFile('dcm2niix.zip', 'r') as f:
+            f.extractall('.')
+
+        os.chmod(op.join(td, 'dcm2niix'), 0o755)
+
+        path = op.pathsep.join((op.abspath('.'), os.environ['PATH']))
+
+        with mock.patch.dict('os.environ', {'PATH' : path}):
+            try:
+                yield
+            finally:
+                fsldcm.installedVersion.invalidate()
 
-def test_disabled():
 
+def test_disabled():
     with mock.patch('fsl.data.dicom.enabled', return_value=False):
         with pytest.raises(RuntimeError):
             fsldcm.scanDir('.')
@@ -36,20 +64,37 @@ def test_disabled():
             fsldcm.loadSeries({})
 
 
+
+def test_installedVersion():
+    tests = [
+        ('1.0.20190902', (1, 0, 2019, 9, 2)),
+        ('1.0.20181125', (1, 0, 2018, 11, 25)),
+        ('1.0.20171017', (1, 0, 2017, 10, 17))]
+
+    for version, expect in tests:
+        fsldcm.installedVersion.invalidate()
+        with install_dcm2niix(version):
+            got = fsldcm.installedVersion()
+            assert got == expect
+
+
+
 def test_enabled():
 
     try:
-        fsldcm.enabled.invalidate()
-        assert fsldcm.enabled()
-        fsldcm.enabled.invalidate()
+        with install_dcm2niix('1.0.20190902'):
+            fsldcm.installedVersion.invalidate()
+            assert fsldcm.enabled()
+
         # test dcm2niix not present
         with mock.patch('subprocess.check_output',
                         side_effect=Exception()):
+            fsldcm.installedVersion.invalidate()
             assert not fsldcm.enabled()
 
-
         # test presence of different versions
         tests = [(b'version v2.1.20191212', True),
+                 (b'version v1.0.20190902', True),
                  (b'version v1.0.20171216', True),
                  (b'version v1.0.20171215', True),
                  (b'version v1.0.20171214', False),
@@ -59,19 +104,19 @@ def test_enabled():
                  (b'version blurgh',        False)]
 
         for verstr, expected in tests:
-            fsldcm.enabled.invalidate()
+            fsldcm.installedVersion.invalidate()
             with mock.patch('subprocess.check_output', return_value=verstr):
                 assert fsldcm.enabled() == expected
 
     finally:
-        fsldcm.enabled.invalidate()
+        fsldcm.installedVersion.invalidate()
 
 
 def test_scanDir():
 
-    with tempdir.tempdir() as td:
+    with install_dcm2niix():
 
-        series = fsldcm.scanDir(td)
+        series = fsldcm.scanDir('.')
         assert len(series) == 0
 
         datafile = op.join(datadir, 'example_dicom.tbz2')
@@ -79,42 +124,69 @@ def test_scanDir():
         with tarfile.open(datafile) as f:
             f.extractall()
 
-        series = fsldcm.scanDir(td)
-        assert len(series) == 3
+        series = fsldcm.scanDir('.')
+        assert len(series) == 2
 
         for s in series:
             assert (s['PatientName'] == 'MCCARTHY_PAUL' or
                     s['PatientName'] == 'MCCARTHY_PAUL_2')
 
 
+def test_sersiesCRC():
+    RANDOM = object()
+    tests = [
+        ({'SeriesInstanceUID' : 'hello-world'},            '2983461467'),
+        ({'SeriesInstanceUID' : RANDOM, 'EchoNumber' : 0}, RANDOM),
+        ({'SeriesInstanceUID' : RANDOM, 'EchoNumber' : 1}, RANDOM),
+        ({'SeriesInstanceUID' : RANDOM, 'EchoNumber' : 2}, RANDOM),
+        ({'SeriesInstanceUID' : RANDOM, 'EchoNumber' : 3}, RANDOM),
+    ]
+
+    for series, expect in tests:
+        series = dict(series)
+        if expect is RANDOM:
+            expect = ''.join(random.choices(
+                string.ascii_letters + string.digits, k=30))
+            series['SeriesInstanceUID'] = expect
+            expect = str(binascii.crc32(expect.encode()))
+        echo = series.get('EchoNumber', 0)
+        if echo > 1:
+            expect += '.{}'.format(echo)
+        assert fsldcm.seriesCRC(series) == expect
+
+
 def test_loadSeries():
 
-    with tempdir.tempdir() as td:
+    # test a pre-CRC and a post-CRC version
+    for version in ('1.0.20190410', '1.0.20190902'):
 
-        datafile = op.join(datadir, 'example_dicom.tbz2')
+        with install_dcm2niix(version):
 
-        with tarfile.open(datafile) as f:
-            f.extractall()
+            datafile = op.join(datadir, 'example_dicom.tbz2')
+
+            with tarfile.open(datafile) as f:
+                f.extractall()
 
-        series   = fsldcm.scanDir(td)
-        expShape = (512, 512, 1)
-        explens  = [1, 2]
+            dcmdir   = os.getcwd()
+            series   = fsldcm.scanDir(dcmdir)
+            expShape = (512, 512, 1)
+            explens  = [1, 1]
 
-        for s, explen in zip(series, explens):
+            for s, explen in zip(series, explens):
 
-            imgs = fsldcm.loadSeries(s)
+                imgs = fsldcm.loadSeries(s)
 
-            assert len(imgs) == explen
+                assert len(imgs) == explen
 
-            for img in imgs:
+                for img in imgs:
 
-                assert img.dicomDir               == td
-                assert img.shape                  == expShape
-                assert img[:].shape               == expShape
-                assert img.getMeta('PatientName') == 'MCCARTHY_PAUL' or \
-                       img.getMeta('PatientName') == 'MCCARTHY_PAUL_2'
-                assert 'PatientName'                      in img.metaKeys()
-                assert 'MCCARTHY_PAUL'                    in img.metaValues() or \
-                       'MCCARTHY_PAUL_2'                  in img.metaValues()
-                assert ('PatientName', 'MCCARTHY_PAUL')   in img.metaItems() or \
-                       ('PatientName', 'MCCARTHY_PAUL_2') in img.metaItems()
+                    assert img.dicomDir               == dcmdir
+                    assert img.shape                  == expShape
+                    assert img[:].shape               == expShape
+                    assert img.getMeta('PatientName') == 'MCCARTHY_PAUL' or \
+                           img.getMeta('PatientName') == 'MCCARTHY_PAUL_2'
+                    assert 'PatientName'                      in img.metaKeys()
+                    assert 'MCCARTHY_PAUL'                    in img.metaValues() or \
+                           'MCCARTHY_PAUL_2'                  in img.metaValues()
+                    assert ('PatientName', 'MCCARTHY_PAUL')   in img.metaItems() or \
+                           ('PatientName', 'MCCARTHY_PAUL_2') in img.metaItems()
-- 
GitLab