#!/usr/bin/env python

from StringIO import StringIO
import unittest, sys
from nipype.utils import nipype_cmd
from contextlib import contextmanager

@contextmanager
def capture_sys_output():
    caputure_out, capture_err = StringIO(), StringIO()
    current_out, current_err = sys.stdout, sys.stderr
    try:
        sys.stdout, sys.stderr = caputure_out, capture_err
        yield caputure_out, capture_err
    finally:
        sys.stdout, sys.stderr = current_out, current_err


class TestNipypeCMD(unittest.TestCase):

    def test_main_returns_2_on_empty(self):
        with self.assertRaises(SystemExit) as cm:
            with capture_sys_output() as (stdout, stderr):
                nipype_cmd.main(['nipype_cmd'])
        
        exit_exception = cm.exception
        self.assertEqual(exit_exception.code, 2)
        
        self.assertEqual(stderr.getvalue(), 
"""usage: nipype_cmd [-h] module interface
nipype_cmd: error: too few arguments
""")
        self.assertEqual(stdout.getvalue(), '')
        
    def test_main_returns_0_on_help(self):
        with self.assertRaises(SystemExit) as cm:
            with capture_sys_output() as (stdout, stderr):
                nipype_cmd.main(['nipype_cmd', '-h'])
        
        exit_exception = cm.exception
        self.assertEqual(exit_exception.code, 0)
        
        self.assertEqual(stderr.getvalue(), '')
        self.assertEqual(stdout.getvalue(),
"""usage: nipype_cmd [-h] module interface

Nipype interface runner

positional arguments:
  module      Module name
  interface   Interface name

optional arguments:
  -h, --help  show this help message and exit
""")
    
    def test_list_nipy_interfacesp(self):
        with self.assertRaises(SystemExit) as cm:
            with capture_sys_output() as (stdout, stderr):
                nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy'])
        
        exit_exception = cm.exception
        self.assertEqual(exit_exception.code, 0)
        
        self.assertEqual(stderr.getvalue(), '')
        self.assertEqual(stdout.getvalue(),
"""Available Interfaces:
	SpaceTimeRealigner
	Similarity
	ComputeMask
	FitGLM
	EstimateContrast
	FmriRealign4d
""")

    def test_run_4d_realign_without_arguments(self):
        with self.assertRaises(SystemExit) as cm:
            with capture_sys_output() as (stdout, stderr):
                nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d'])
        
        exit_exception = cm.exception
        self.assertEqual(exit_exception.code, 2)
        
        self.assertEqual(stderr.getvalue(),
"""usage: nipype_cmd nipype.interfaces.nipy FmriRealign4d [-h]
                                                       [--between_loops BETWEEN_LOOPS]
                                                       [--ignore_exception IGNORE_EXCEPTION]
                                                       [--loops LOOPS]
                                                       [--slice_order SLICE_ORDER]
                                                       [--speedup SPEEDUP]
                                                       [--start START]
                                                       [--time_interp TIME_INTERP]
                                                       [--tr_slices TR_SLICES]
                                                       in_file tr
nipype_cmd nipype.interfaces.nipy FmriRealign4d: error: too few arguments
""")
        self.assertEqual(stdout.getvalue(), '')
        
    def test_run_4d_realign_help(self):
        with self.assertRaises(SystemExit) as cm:
            with capture_sys_output() as (stdout, stderr):
                nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d', '-h'])
        
        exit_exception = cm.exception
        self.assertEqual(exit_exception.code, 0)
        
        self.assertEqual(stderr.getvalue(), '')
        self.assertEqual(stdout.getvalue(),
"""usage: nipype_cmd nipype.interfaces.nipy FmriRealign4d [-h]
                                                       [--between_loops BETWEEN_LOOPS]
                                                       [--ignore_exception IGNORE_EXCEPTION]
                                                       [--loops LOOPS]
                                                       [--slice_order SLICE_ORDER]
                                                       [--speedup SPEEDUP]
                                                       [--start START]
                                                       [--time_interp TIME_INTERP]
                                                       [--tr_slices TR_SLICES]
                                                       in_file tr

Run FmriRealign4d

positional arguments:
  in_file               (a list of items which are an existing file name) File
                        to realign
  tr                    (a float) TR in seconds

optional arguments:
  -h, --help            show this help message and exit
  --between_loops BETWEEN_LOOPS
                        (a list of items which are an integer, nipype default
                        value: [5]) loops used to realign different runs
  --ignore_exception IGNORE_EXCEPTION
                        (a boolean, nipype default value: False) Print an
                        error message instead of throwing an exception in case
                        the interface fails to run
  --loops LOOPS         (a list of items which are an integer, nipype default
                        value: [5]) loops within each run
  --slice_order SLICE_ORDER
                        (a list of items which are an integer) 0 based slice
                        order. This would be equivalent to
                        enteringnp.argsort(spm_slice_order) for this field.
                        This effectsinterleaved acquisition. This field will
                        be deprecated infuture Nipy releases and be replaced
                        by actual sliceacquisition times. requires:
                        time_interp
  --speedup SPEEDUP     (a list of items which are an integer, nipype default
                        value: [5]) successive image sub-sampling factors for
                        acceleration
  --start START         (a float, nipype default value: 0.0) time offset into
                        TR to align slices to
  --time_interp TIME_INTERP
                        (True) Assume smooth changes across time e.g., fmri
                        series. If you don't want slice timing correction set
                        this to undefined requires: slice_order
  --tr_slices TR_SLICES
                        (a float) TR slices requires: time_interp
""")


if __name__ == '__main__':
    unittest.main()
@@ -3904,2802 +3904,139 @@
 sert
-Equal(stdout.getvalue(),%0A%22%22%22usage: nipype_cmd nipype.interfaces.nipy FmriRealign4d %5B-h%5D%0A                                                       %5B--between_loops BETWEEN_LOOPS%5D%0A                                                       %5B--ignore_exception IGNORE_EXCEPTION%5D%0A                                                       %5B--loops LOOPS%5D%0A                                                       %5B--slice_order SLICE_ORDER%5D%0A                                                       %5B--speedup SPEEDUP%5D%0A                                                       %5B--start START%5D%0A                                                       %5B--time_interp TIME_INTERP%5D%0A                                                       %5B--tr_slices TR_SLICES%5D%0A                                                       in_file tr%0A%0ARun FmriRealign4d%0A%0Apositional arguments:%0A  in_file               (a list of items which are an existing file name) File%0A                        to realign%0A  tr                    (a float) TR in seconds%0A%0Aoptional arguments:%0A  -h, --help            show this help message and exit%0A  --between_loops BETWEEN_LOOPS%0A                        (a list of items which are an integer, nipype default%0A                        value: %5B5%5D) loops used to realign different runs%0A  --ignore_exception IGNORE_EXCEPTION%0A                        (a boolean, nipype default value: False) Print an%0A                        error message instead of throwing an exception in case%0A                        the interface fails to run%0A  --loops LOOPS         (a list of items which are an integer, nipype default%0A                        value: %5B5%5D) loops within each run%0A  --slice_order SLICE_ORDER%0A                        (a list of items which are an integer) 0 based slice%0A                        order. This would be equivalent to%0A                        enteringnp.argsort(spm_slice_order) for this field.%0A                        This effectsinterleaved acquisition. This field will%0A                        be deprecated infuture Nipy releases and be replaced%0A                        by actual sliceacquisition times. requires:%0A                        time_interp%0A  --speedup SPEEDUP     (a list of items which are an integer, nipype default%0A                        value: %5B5%5D) successive image sub-sampling factors for%0A                        acceleration%0A  --start START         (a float, nipype default value: 0.0) time offset into%0A                        TR to align slices to%0A  --time_interp TIME_INTERP%0A                        (True) Assume smooth changes across time e.g., fmri%0A                        series. If you don't want slice timing correction set%0A                        this to undefined requires: slice_order%0A  --tr_slices TR_SLICES%0A                        (a float) TR slices requires: time_interp%0A%22%22%22)%0A
+True(%22loops used to realign different runs%22 in stdout.getvalue())%0A        self.assertTrue(%22Run FmriRealign4d%22 in stdout.getvalue())
 %0A%0Aif

make the tests more robust