From 19d2949ae45e0c340de5ee05be6e8b31926fbe7f Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Sun, 4 Mar 2018 12:15:00 +0000
Subject: [PATCH] unit tests for wrapper functions, and more for wrapperutils

---
 tests/__init__.py          |  26 ++--
 tests/test_wrappers.py     | 265 +++++++++++++++++++++++++++++++++++++
 tests/test_wrapperutils.py |  40 +++++-
 3 files changed, 311 insertions(+), 20 deletions(-)
 create mode 100644 tests/test_wrappers.py

diff --git a/tests/__init__.py b/tests/__init__.py
index 13d510658..723ed0f1d 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -21,29 +21,27 @@ import nibabel   as nib
 
 from six import StringIO
 
-import fsl.data.image as fslimage
+import fsl.data.image                     as fslimage
+from   fsl.utils.tempdir import              tempdir
+from   fsl.utils.platform import platform as fslplatform
 
 
 logging.getLogger().setLevel(logging.WARNING)
 
 
-
 @contextlib.contextmanager
-def tempdir():
-    """Returnsa context manager which creates and returns a temporary
-    directory, and then deletes it on exit.
-    """
+def mockFSLDIR():
 
-    testdir = tempfile.mkdtemp()
-    prevdir = os.getcwd()
-    try:
-
-        os.chdir(testdir)
-        yield testdir
+    oldval = fslplatform.fsldir
 
+    try:
+        with tempdir() as td:
+            fsldir = op.join(td, 'fsl')
+            os.makedirs(fsldir)
+            fslplatform.fsldir = fsldir
+            yield fsldir
     finally:
-        os.chdir(prevdir)
-        shutil.rmtree(testdir)
+        fslplatform.fsldir = oldval
 
 
 def touch(fname):
diff --git a/tests/test_wrappers.py b/tests/test_wrappers.py
new file mode 100644
index 000000000..1e366a166
--- /dev/null
+++ b/tests/test_wrappers.py
@@ -0,0 +1,265 @@
+#!/usr/bin/env python
+#
+# test_wrappers.py -
+#
+# Author: Paul McCarthy <pauldmccarthy@gmail.com>
+#
+
+import os.path   as op
+import itertools as it
+
+import fsl.wrappers                       as fw
+import fsl.utils.assertions               as asrt
+import fsl.utils.run                      as run
+
+from . import mockFSLDIR
+
+
+def checkResult(cmd, base, args):
+    """We can't control the order in which command line args are generated,
+    so we need to test all possible orderings.
+
+    :arg cmd:  Generated command
+    :arg base: Beginning of expected command
+    :arg args: Sequence of expected arguments
+    """
+    permutations = it.permutations(args, len(args))
+    possible     = [' '.join([base] + list(p))  for p in permutations]
+
+    return any([cmd == p for p in possible])
+
+
+def test_bet():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        bet      = op.join(fsldir, 'bin', 'bet')
+        result   = fw.bet('input', 'output', mask=True, c=(10, 20, 30))
+        expected = (bet + ' input output', ('-m', '-c 10 20 30'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_robustfov():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        rfov     = op.join(fsldir, 'bin', 'robustfov')
+        result   = fw.robustfov('input', 'output', b=180)
+        expected = (rfov + ' -i input', ('-r output', '-b 180'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_eddy_cuda():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        eddy     = op.join(fsldir, 'bin', 'eddy_cuda')
+        result   = fw.eddy_cuda('imain', 'mask', 'index', 'acqp',
+                                'bvecs', 'bvals', 'out', dont_mask_output=True)
+        expected = (eddy, ('--imain=imain',
+                           '--mask=mask',
+                           '--index=index',
+                           '--acqp=acqp',
+                           '--bvecs=bvecs',
+                           '--bvals=bvals',
+                           '--out=out',
+                           '--dont_mask_output'))
+
+        assert checkResult(result.output[0], *expected)
+
+
+def test_topup():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        topup    = op.join(fsldir, 'bin', 'topup')
+        result   = fw.topup('imain', 'datain', minmet=1)
+        expected = topup + ' --imain=imain --datain=datain --minmet=1'
+        assert result.output[0] == expected
+
+
+def test_flirt():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        flirt    = op.join(fsldir, 'bin', 'flirt')
+        result   = fw.flirt('src', 'ref', usesqform=True, anglerep='euler')
+        expected = (flirt + ' -in src -ref ref',
+                    ('-usesqform', '-anglerep euler'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_applyxfm():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        flirt    = op.join(fsldir, 'bin', 'flirt')
+        result   = fw.applyxfm('src', 'ref', 'mat', 'out', interp='trilinear')
+        expected = (flirt + ' -in src -ref ref',
+                    ('-applyxfm',
+                     '-out out',
+                     '-init mat',
+                     '-interp trilinear'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_invxfm():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        cnvxfm   = op.join(fsldir, 'bin', 'convert_xfm')
+        result   = fw.invxfm('mat', 'output')
+        expected = cnvxfm + ' -omat output -inverse mat'
+        assert result.output[0] == expected
+
+
+def test_concatxfm():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        cnvxfm   = op.join(fsldir, 'bin', 'convert_xfm')
+        result   = fw.concatxfm('mat1', 'mat2', 'output')
+        expected = cnvxfm + ' -omat output -concat mat2 mat1'
+        assert result.output[0] == expected
+
+
+def test_mcflirt():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        mcflirt  = op.join(fsldir, 'bin', 'mcflirt')
+        result   = fw.mcflirt('input', out='output', cost='normcorr', dof=12)
+        expected = (mcflirt + ' -in input',
+                    ('-out output',
+                     '-cost normcorr',
+                     '-dof 12'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_fnirt():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        fnirt    = op.join(fsldir, 'bin', 'fnirt')
+        result   = fw.fnirt('src', 'ref', iout='iout', fout='fout',
+                            subsamp=(8, 6, 4, 2))
+        expected = (fnirt + ' --in=src --ref=ref',
+                    ('--iout=iout',
+                     '--fout=fout',
+                     '--subsamp=8,6,4,2'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_applywarp():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        applywarp = op.join(fsldir, 'bin', 'applywarp')
+        result    = fw.applywarp('src', 'ref', 'out', 'warp', abs=True, super=True)
+        expected  = (applywarp + ' --in=src --ref=ref --out=out --warp=warp',
+                     ('--abs', '--super'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_invwarp():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        invwarp  = op.join(fsldir, 'bin', 'invwarp')
+        result   = fw.invwarp('warp', 'ref', 'out',
+                              rel=True, noconstraint=True)
+        expected = (invwarp + ' --warp=warp --ref=ref --out=out',
+                     ('--rel', '--noconstraint'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_convertwarp():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        cnvwarp  = op.join(fsldir, 'bin', 'convertwarp')
+        result   = fw.convertwarp('out', 'ref', absout=True, jacobian=True)
+        expected = (cnvwarp + ' --ref=ref --out=out',
+                     ('--absout', '--jacobian'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_fugue():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        fugue    = op.join(fsldir, 'bin', 'fugue')
+        result   = fw.fugue(input='input', warp='warp',
+                            median=True, dwell=10)
+        expected = (fugue, ('--in=input',
+                            '--warp=warp',
+                            '--median',
+                            '--dwell=10'))
+        assert checkResult(result.output[0], *expected)
+
+
+
+def test_sigloss():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        sigloss  = op.join(fsldir, 'bin', 'sigloss')
+        result   = fw.sigloss('input', 'sigloss', mask='mask', te=0.5)
+        expected = (sigloss + ' --in input --sigloss sigloss',
+                    ('--mask mask', '--te 0.5'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_melodic():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        melodic  = op.join(fsldir, 'bin', 'melodic')
+        result   = fw.melodic('input', dim=50, mask='mask', Oall=True)
+        expected = (melodic + ' --in=input',
+                    ('--dim=50', '--mask=mask', '--Oall'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_fsl_regfilt():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        regfilt  = op.join(fsldir, 'bin', 'fsl_regfilt')
+        result   = fw.fsl_regfilt('input', 'output', 'design',
+                                  filter=(1, 2, 3, 4), vn=True)
+        expected = (regfilt + ' --in=input --out=output --design=design',
+                    ('--filter=1,2,3,4', '--vn'))
+        assert checkResult(result.output[0], *expected)
+
+
+
+def test_fslreorient2std():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        r2std    = op.join(fsldir, 'bin', 'fslreorient2std')
+        result   = fw.fslreorient2std('input', 'output')
+        expected = r2std + ' input output'
+        assert result.output[0] == expected
+
+
+def test_fslroi():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        fslroi   = op.join(fsldir, 'bin', 'fslroi')
+
+        result   = fw.fslroi('input', 'output', 1, 10)
+        expected = fslroi + ' input output 1 10'
+        assert result.output[0] == expected
+
+        result   = fw.fslroi('input', 'output', 1, 10, 2, 20, 3, 30)
+        expected = fslroi + ' input output 1 10 2 20 3 30'
+        assert result.output[0] == expected
+
+        result   = fw.fslroi('input', 'output', 1, 10, 2, 20, 3, 30, 4, 40)
+        expected = fslroi + ' input output 1 10 2 20 3 30 4 40'
+        assert result.output[0] == expected
+
+
+def test_slicer():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        slicer   = op.join(fsldir, 'bin', 'slicer')
+        result   = fw.slicer('input1', 'input2', i=(20, 100), x=(20, 'x.png'))
+        expected = slicer + ' input1 input2 -i 20 100 -x 20 x.png'
+        assert result.output[0] == expected
+
+
+def test_cluster():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        cluster  = op.join(fsldir, 'bin', 'cluster')
+        result   = fw.cluster('input', 'thresh',
+                              fractional=True, osize='osize')
+        expected = (cluster + ' --in=input --thresh=thresh',
+                    ('--fractional', '--osize=osize'))
+        assert checkResult(result.output[0], *expected)
+
+
+def test_fslmaths():
+    with asrt.disabled(), run.dryrun(), mockFSLDIR() as fsldir:
+        cmd    = op.join(fsldir, 'bin', 'fslmaths')
+        result = fw.fslmaths('input') \
+            .abs().bin().binv().recip().Tmean().Tstd().Tmin().Tmax() \
+            .fillh().ero().dilM().dilF().add('addim').sub('subim') \
+            .mul('mulim').div('divim').mas('masim').rem('remim')   \
+            .thr('thrim').uthr('uthrim').inm('inmim').bptf(1, 10).run('output')
+
+        expected = [cmd, 'input',
+                    '-abs', '-bin', '-binv', '-recip', '-Tmean', '-Tstd',
+                    '-Tmin', '-Tmax', '-fillh', '-ero', '-dilM', '-dilF',
+                    '-add addim', '-sub subim', '-mul mulim', '-div divim',
+                    '-mas masim', '-rem remim', '-thr thrim', '-uthr uthrim',
+                    '-inm inmim', '-bptf 1 10', 'output']
+        expected = ' '.join(expected)
+
+        assert result.output[0] == expected
+
+        # TODO test LOAD output
diff --git a/tests/test_wrapperutils.py b/tests/test_wrapperutils.py
index 658909ae9..ef5a6fd4f 100644
--- a/tests/test_wrapperutils.py
+++ b/tests/test_wrapperutils.py
@@ -5,8 +5,9 @@
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
 
-import os
-import shlex
+import os.path as op
+import            os
+import            shlex
 
 import pytest
 
@@ -14,9 +15,13 @@ import numpy as np
 import nibabel as nib
 
 import fsl.utils.tempdir         as tempdir
+import fsl.utils.run             as run
 import fsl.wrappers.wrapperutils as wutils
 
 
+from . import mockFSLDIR
+
+
 def test_applyArgStyle():
 
     kwargs = {
@@ -160,10 +165,6 @@ def test_namedPositionals():
         result = wutils.namedPositionals(func, args)
         assert list(result) == list(expected)
 
-# TODO
-#  - test _FileOrImage LOAD tuple order
-
-
 
 def test_fileOrArray():
 
@@ -231,6 +232,7 @@ def test_fileOrImage():
 
         img1     = nib.nifti1.Nifti1Image(np.array([[1,  2], [ 3,  4]]), np.eye(4))
         img2     = nib.nifti1.Nifti1Image(np.array([[5,  6], [ 7,  8]]), np.eye(4))
+        img3     = nib.nifti1.Nifti1Image(np.array([[1,  2], [ 3,  4]]), np.eye(4))
         expected = np.array([[5, 12], [21, 32]])
         nib.save(img1, 'img1.nii')
         nib.save(img2, 'img2.nii')
@@ -271,6 +273,12 @@ def test_fileOrImage():
         result = func(img1, img2=img2, output=wutils.LOAD)['output']
         assert np.all(result.get_data() == expected)
 
+        # in-memory image, file, file
+        result = func(img3, img2='img2.nii', output='output.nii')
+        assert np.all(nib.load('output.nii').get_data() == expected)
+        os.remove('output.nii')
+
+
 
 def test_chained_fileOrImageAndArray():
     @wutils.fileOrImage('image')
@@ -291,3 +299,23 @@ def test_chained_fileOrImageAndArray():
         func('image.nii',  array)
         func( image,      'array.txt')
         func( image,       array)
+
+
+def test_cmdwrapper():
+    @wutils.cmdwrapper
+    def func(a, b):
+        return ['func', str(a), str(b)]
+
+    with run.dryrun():
+        assert func(1, 2)[0] == 'func 1 2'
+
+
+
+def test_fslwrapper():
+    @wutils.fslwrapper
+    def func(a, b):
+        return ['func', str(a), str(b)]
+
+    with run.dryrun(), mockFSLDIR() as fsldir:
+        expected = '{} 1 2'.format(op.join(fsldir, 'bin', 'func'))
+        assert func(1, 2)[0] == expected
-- 
GitLab