#! /opt/local/bin/python
# -*- coding: utf-8 -*-

# PyNX - Python tools for Nano-structures Crystallography
#   (c) 2018-present : ESRF-European Synchrotron Radiation Facility
#       authors:
#         Vincent Favre-Nicolin, favre@esrf.fr

"""
This package includes tests for the CDI command-line scripts.
"""
import copy
import os
import sys
import glob
import platform
import subprocess
import unittest
import tempfile
import shutil
# import warnings
# from functools import wraps
from pynx.cdi.test.test_cdi import make_cdi_data_file, make_cdi_support_file, \
    make_cdi_mask_file, make_cdi_flatfield_file
from pynx.processing_unit import has_opencl, has_cuda

has_mpi = False
try:
    import mpi4py

    if shutil.which('mpiexec') is not None:
        has_mpi = True
except ImportError:
    pass

exclude_cuda = False
exclude_opencl = False
if 'PYNX_PU' in os.environ:
    if 'opencl' in os.environ['PYNX_PU'].lower():
        exclude_cuda = True
    elif 'cuda' in os.environ['PYNX_PU'].lower():
        exclude_opencl = True

if 'opencl' in sys.argv or '--opencl' in sys.argv or not has_cuda:
    exclude_cuda = True
if 'cuda' in sys.argv or '--cuda' in sys.argv or not has_opencl:
    exclude_opencl = True

oldparse = True if 'oldparse' in sys.argv or '--oldparse' in sys.argv else False
liveplot = True if 'liveplot' in sys.argv or '--liveplot' in sys.argv \
                   or 'live_plot' in sys.argv or '--live_plot' in sys.argv else False


# def ignore_warnings(func):
#     @wraps(func)
#     def inner(self, *args, **kwargs):
#         with warnings.catch_warnings():
#             warnings.simplefilter("ignore")
#             res = func(self, *args, **kwargs)
#         return res
#     return inner


class TestCDIRunner(unittest.TestCase):
    """
    Class for tests of the CDI runner scripts
    """

    @classmethod
    def setUpClass(cls):
        # Directory contents will automatically get cleaned up on deletion
        cls.tmp_dir_obj = tempfile.TemporaryDirectory()
        cls.tmp_dir = cls.tmp_dir_obj.name
        cls.my_envs = []
        if not exclude_cuda:
            cls.my_envs.append(os.environ.copy())
            cls.my_envs[-1]["PYNX_PU"] = "cuda"
        if not exclude_opencl:
            cls.my_envs.append(os.environ.copy())
            cls.my_envs[-1]["PYNX_PU"] = "opencl"

    @unittest.skipUnless(oldparse, f"old parsing tests not selected")
    def test_cdi_runner_id01_3d_cxi_old(self):
        path = make_cdi_data_file(shape=(128, 128, 128), file_type='cxi', dir=self.tmp_dir)
        # test npy, npz ahd h5 for mask (filename will used a MiXed case)
        mask_path1 = make_cdi_mask_file(shape=(128, 128, 128), file_type='npy', dir=self.tmp_dir)
        mask_path2 = make_cdi_mask_file(shape=(128, 128, 128), file_type='npz', dir=self.tmp_dir)
        mask_path3 = make_cdi_mask_file(shape=(128, 128, 128), file_type='h5', dir=self.tmp_dir)
        # Test npy, npz and h5 for flatfield (2D and 3D)
        flat_path1 = make_cdi_flatfield_file(shape=(128, 128), file_type='npy', dir=self.tmp_dir)
        flat_path2 = make_cdi_flatfield_file(shape=(128, 128, 128), file_type='npz', dir=self.tmp_dir)
        flat_path3 = make_cdi_flatfield_file(shape=(128, 128), file_type='h5', dir=self.tmp_dir)
        # Test support, with different sizes
        support_path1 = make_cdi_support_file(shape=(128, 128, 128), dir=self.tmp_dir)
        support_path2 = make_cdi_support_file(shape=(50, 50, 50), dir=self.tmp_dir)
        support_path3 = make_cdi_support_file(shape=(130, 130, 130), dir=self.tmp_dir)
        args = ['pynx-cdi-id01', 'data=%s' % path, "nb_raar=50", "nb_hio=50",
                "nb_er=50", "support_update_period=20"]
        # Test sequentially several options. Could also try combined options..
        algo1 = "(Sup*ER**10)**2,psf=5,psf_filter=None,DetwinRAAR**10*Sup*RAAR**50"
        algo2 = "(Sup*ER**10)**2,psf_init=gaussian@1,DetwinRAAR**10*Sup*RAAR**50"
        voptions = [[], ["roi=16,112,16,112,16,112"], ["positivity"], ["detwin=0"], ["output_format=npz"],
                    ["support_size=50"], ["support_size=50", "support=sphere"],
                    ["support_size=50", "support=cube"], ["support_only_shrink"],
                    ["support_update_border_n=3"],
                    ["rebin=2"], ["rebin=2,1,2"], ["mask_interp=16,2"], ["mask=%s" % mask_path1],
                    ["mask=%s" % mask_path2], ["mask=%s" % mask_path3], ["psf=pseudo-voigt,1,0.05,10"],
                    ["psf=gaussian,1,10", "psf_filter=tukey"],
                    ['algo=%s' % algo1], ['algo=%s' % algo2],
                    ["flatfield=%s" % flat_path1], ["flatfield=%s" % flat_path2], ["flatfield=%s" % flat_path3],
                    ["support=%s" % support_path1], ["support=%s" % support_path2],
                    ["support=%s" % support_path3],
                    ["support_threshold=0.25", "verbose=10"],
                    ["support_threshold=0.24,0.26", "verbose=10"],
                    ["support_threshold=0.24,0.26", "nb_run=2", "verbose=10"],
                    ]
        # Also test all options as saved in a *.txt file
        voptions += [v + ["as_parameters_file"] for v in voptions]
        for my_env in self.my_envs:
            for options in voptions:
                option_string = ' '.join(options)
                if "as_parameters_file" in options:
                    with tempfile.NamedTemporaryFile(mode='w', suffix=".txt",
                                                     dir=self.tmp_dir, delete=False) as partxt:
                        for v in args[1:] + options:
                            if v != "as_parameters_file":
                                if '=' in v:
                                    partxt.write(f"{v}\n")
                                else:
                                    partxt.write(f"{v} = True\n")
                        com = args[:1] + [partxt.name]
                else:
                    com = args + options
                with self.subTest(option=option_string, command=com):
                    with subprocess.Popen(com, stderr=subprocess.PIPE,
                                          stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                        stdout, stderr = p.communicate(timeout=200)
                        res = p.returncode
                        msg = "Failed command-line:"
                        for a in p.args:
                            msg += " " + a
                        msg += "\n"
                        self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())

    def test_cdi_runner_id01_3d_cxi(self):
        path = make_cdi_data_file(shape=(128, 128, 128), file_type='cxi', dir=self.tmp_dir)
        # test npy, npz ahd h5 for mask (filename will used a MiXed case)
        mask_path1 = make_cdi_mask_file(shape=(128, 128, 128), file_type='npy', dir=self.tmp_dir)
        mask_path2 = make_cdi_mask_file(shape=(128, 128, 128), file_type='npz', dir=self.tmp_dir)
        mask_path3 = make_cdi_mask_file(shape=(128, 128, 128), file_type='h5', dir=self.tmp_dir)
        # Test npy, npz and h5 for flatfield (2D and 3D)
        flat_path1 = make_cdi_flatfield_file(shape=(128, 128), file_type='npy', dir=self.tmp_dir)
        flat_path2 = make_cdi_flatfield_file(shape=(128, 128, 128), file_type='npz', dir=self.tmp_dir)
        flat_path3 = make_cdi_flatfield_file(shape=(128, 128), file_type='h5', dir=self.tmp_dir)
        # Test support, with different sizes
        support_path1 = make_cdi_support_file(shape=(128, 128, 128), dir=self.tmp_dir)
        support_path2 = make_cdi_support_file(shape=(50, 50, 50), dir=self.tmp_dir)
        support_path3 = make_cdi_support_file(shape=(130, 130, 130), dir=self.tmp_dir)
        args = ['pynx-cdi-id01', '--data', '%s' % path, "--nb_raar", "50", "--nb_hio", "50",
                "--nb_er", "50", "--support_update_period", "20"]
        # Test sequentially several options. Could also try combined options..
        algo1 = "(Sup*ER**10)**2,psf=5,psf_filter=None,DetwinRAAR**10*Sup*RAAR**50"
        algo2 = "(Sup*ER**10)**2,psf_init=gaussian@1,DetwinRAAR**10*Sup*RAAR**50"
        for my_env in self.my_envs:
            for options in [[], ["--roi", "16", "112", "16", "112", "16", "112"],
                            ["--positivity"], ["--detwin", "0"], ["--output_format", "npz"],
                            ["--support_size", "50"], ["--support_size", "50", "--support", "sphere"],
                            ["--support_size", "50", "--support", "cube"], ["--support_only_shrink"],
                            ["--support_update_border_n", "3"],
                            ["--rebin", "2"], ["--rebin", "2", "1", "2"], ["--mask_interp", "16", "2"],
                            ["--mask", "%s" % mask_path1],
                            ["--mask", "%s" % mask_path2], ["--mask", "%s" % mask_path3],
                            ["--psf", "pseudo-voigt,1,0.05,10"],
                            ["--psf", "gaussian,1,10", "--psf_filter", "tukey"],
                            ['--algo', '%s' % algo1], ['--algo', '%s' % algo2],
                            ["--flatfield", "%s" % flat_path1], ["--flatfield", "%s" % flat_path2],
                            ["--flatfield", "%s" % flat_path3],
                            ["--support", "%s" % support_path1], ["--support", "%s" % support_path2],
                            ["--support", "%s" % support_path3],
                            ["--support_threshold", "0.25", "--verbose", "10"],
                            ["--support_threshold", "0.24", "0.26", "--verbose", "10"],
                            ["--support_threshold", "0.24", "0.26", "--nb_run", "2", "--verbose", "10"],
                            ]:
                option_string = ""
                for s in options:
                    option_string += s + " "
                with self.subTest(option=option_string, command=' '.join(args + options)):
                    with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                          stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                        stdout, stderr = p.communicate(timeout=200)
                        res = p.returncode
                        msg = "Failed command-line:"
                        for a in p.args:
                            msg += " " + a
                        msg += "\n"
                        self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    @unittest.skipUnless(liveplot, "live plot tests skipped")
    def test_cdi_runner_id01_3d_cxi_liveplot_old(self):
        path = make_cdi_data_file(shape=(128, 128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['pynx-cdi-id01', 'data=%s' % path, 'live_plot']
        option_string = ""
        for my_env in self.my_envs:
            for options in [[]]:
                for s in options:
                    option_string += s + " "
                with self.subTest(option=option_string, command=' '.join(args + options)):
                    with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                          stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                        stdout, stderr = p.communicate(timeout=200)
                        res = p.returncode
                        self.assertFalse(res, msg=stderr.decode())

    @unittest.skipUnless(liveplot, "live plot tests skipped")
    def test_cdi_runner_id01_3d_cxi_liveplot(self):
        path = make_cdi_data_file(shape=(128, 128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['pynx-cdi-id01', '--data', '%s' % path, '--live_plot']
        option_string = ""
        for my_env in self.my_envs:
            for options in [[]]:
                for s in options:
                    option_string += s + " "
                with self.subTest(option=option_string, command=' '.join(args + options)):
                    with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                          stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                        stdout, stderr = p.communicate(timeout=200)
                        res = p.returncode
                        self.assertFalse(res, msg=stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    def test_cdi_runner_id01_2d_cxi_old(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['pynx-cdi-id01', 'data=%s' % path, "nb_raar=50", "nb_hio=50",
                "nb_er=50", "support_update_period=20"]
        # Test support, with different sizes
        support_path1 = make_cdi_support_file(shape=(128, 128), dir=self.tmp_dir)
        support_path2 = make_cdi_support_file(shape=(50, 50), dir=self.tmp_dir)
        support_path3 = make_cdi_support_file(shape=(130, 130), dir=self.tmp_dir)
        # Test sequentially several options. Could also try combined options..
        voptions = [[], ["roi=16,112,16,112"], ["positivity"], ["detwin=0"], ["output_format=npz"],
                    ["support_size=50"], ["support_size=50 support=circle"],
                    ["support_size=50 support=square"], ["support_only_shrink"], ["support_update_border_n=3"],
                    ["rebin=2"], ["rebin=2,1"], ["nb_run=3", "nb_run_keep=1"], ["mask_interp=16,2"],
                    ["support=%s" % support_path1], ["support=%s" % support_path2], ["support=%s" % support_path3]]
        for my_env, options in zip(self.my_envs, voptions):
            option_string = ""
            for s in options:
                option_string += s + " "
            with self.subTest(option=option_string, command=' '.join(args + options)):
                with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                      stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                    stdout, stderr = p.communicate(timeout=200)
                    res = p.returncode
                    msg = "Failed command-line:"
                    for a in p.args:
                        msg += " " + a
                    msg += "\n"
                    self.assertFalse(res, msg=msg + stderr.decode())

    def test_cdi_runner_id01_2d_cxi(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['pynx-cdi-id01', '--data', '%s' % path, "--nb_raar", "50", "--nb_hio", "50",
                "--nb_er", "50", "--support_update_period", "20"]
        # Test support, with different sizes
        support_path1 = make_cdi_support_file(shape=(128, 128), dir=self.tmp_dir)
        support_path2 = make_cdi_support_file(shape=(50, 50), dir=self.tmp_dir)
        support_path3 = make_cdi_support_file(shape=(130, 130), dir=self.tmp_dir)
        # Test sequentially several options. Could also try combined options..
        voptions = [[], ["--roi", "16", "112", "16", "112"], ["--positivity"],
                    ["--detwin", "0"], ["--output_format", "npz"],
                    ["--support_size", "50"], ["--support_size", "50", "support", "circle"],
                    ["--support_size", "50", "--support", "square"],
                    ["--support_only_shrink"], ["--support_update_border_n", "3"],
                    ["--rebin", "2"], ["--rebin", "2", "1"], ["--nb_run", "3", "--nb_run_keep", "1"],
                    ["--mask_interp", "16", "2"],
                    ["--support", "%s" % support_path1], ["--support", "%s" % support_path2],
                    ["--support", "%s" % support_path3]]
        for my_env, options in zip(self.my_envs, voptions):
            option_string = ""
            for s in options:
                option_string += s + " "
            with self.subTest(option=option_string, command=' '.join(args + options)):
                with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                      stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                    stdout, stderr = p.communicate(timeout=200)
                    res = p.returncode
                    msg = "Failed command-line:"
                    for a in p.args:
                        msg += " " + a
                    msg += "\n"
                    self.assertFalse(res, msg=msg + stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    @unittest.skipUnless(liveplot, "live plot tests skipped")
    def test_cdi_runner_id01_2d_cxi_liveplot_old(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        for my_env in self.my_envs:
            with subprocess.Popen(['pynx-cdi-id01', 'data=%s' % path, 'live_plot'], stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE,
                                  cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                self.assertFalse(res, msg=stderr.decode())

    @unittest.skipUnless(liveplot, "live plot tests skipped")
    def test_cdi_runner_id01_2d_cxi_liveplot(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        for my_env in self.my_envs:
            with subprocess.Popen(['pynx-cdi-id01', '--data', '%s' % path, '--live_plot'],
                                  stderr=subprocess.PIPE, stdout=subprocess.PIPE,
                                  cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                self.assertFalse(res, msg=stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    @unittest.skipIf(has_mpi is False, 'no MPI support')
    @unittest.skipIf(platform.system() in ['Windows', 'Darwin'], 'not testing MPI on macOS or Windows')
    def test_cdi_runner_id01_2d_cxi_mpi_run_old(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['timeout', '60', 'mpiexec', '-n', '2', 'pynx-cdi-id01', 'data=%s' % path, "nb_raar=50",
                "nb_hio=50", "nb_er=50", "support_update_period=20", "mpi=run",
                "nb_run=4", "nb_run_keep=2"]
        # Test several options. Could also try combined options..
        for my_env, options in zip(self.my_envs, [[]]):
            with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stderr.decode())

    @unittest.skipIf(has_mpi is False, 'no MPI support')
    @unittest.skipIf(platform.system() in ['Windows', 'Darwin'], 'not testing MPI on macOS or Windows')
    def test_cdi_runner_id01_2d_cxi_mpi_run(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        args = ['timeout', '60', 'mpiexec', '-n', '2', 'pynx-cdi-id01',
                '--data', '%s' % path, "--nb_raar", "50",
                "--nb_hio", "50", "--nb_er", "50", "--support_update_period", "20",
                "--mpi", "run", "--nb_run", "4", "--nb_run_keep", "2"]
        # Test several options. Could also try combined options..
        for my_env, options in zip(self.my_envs, [[]]):
            with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    @unittest.skipIf(has_mpi is False, 'no MPI support')
    @unittest.skipIf(platform.system() in ['Windows', 'Darwin'], 'not testing MPI on macOS or Windows')
    def test_cdi_runner_id01_2d_cxi_mpi_scan_old(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        for i in range(2):
            os.system("ln -sf %s %s/scan%02d.cxi" % (path, self.tmp_dir, i))
        path = self.tmp_dir + "/scan%02d.cxi"
        args = ['timeout', '60', 'mpiexec', '-n', '2', 'pynx-cdi-id01', 'data=' + path, "nb_raar=50",
                "nb_hio=50", "nb_er=50", "support_update_period=20", "mpi=scan", "scan=0,1"]
        # Test several options. Could also try combined options..
        for my_env, options in zip(self.my_envs, [[]]):
            with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stderr.decode())

    @unittest.skipIf(has_mpi is False, 'no MPI support')
    @unittest.skipIf(platform.system() in ['Windows', 'Darwin'], 'not testing MPI on macOS or Windows')
    def test_cdi_runner_id01_2d_cxi_mpi_scan(self):
        path = make_cdi_data_file(shape=(128, 128), file_type='cxi', dir=self.tmp_dir)
        for i in range(2):
            os.system("ln -sf %s %s/scan%02d.cxi" % (path, self.tmp_dir, i))
        path = self.tmp_dir + "/scan%02d.cxi"
        args = ['timeout', '60', 'mpiexec', '-n', '2', 'pynx-cdi-id01',
                '--data', path, "--nb_raar", "50",
                "--nb_hio", "50", "--nb_er", "50", "--support_update_period", "20",
                "--mpi", "scan", "--scan", "0,1"]
        # Test several options. Could also try combined options..
        for my_env, options in zip(self.my_envs, [[]]):
            with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                stdout, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    def test_cdi_runner_simul_old(self):
        my_envs = []
        if has_cuda and 'opencl' not in sys.argv and not exclude_cuda:
            my_envs.append(os.environ.copy())
            my_envs[-1]["PYNX_PU"] = "cuda"
        if has_opencl and 'cuda' not in sys.argv and not exclude_opencl:
            my_envs.append(os.environ.copy())
            my_envs[-1]["PYNX_PU"] = "opencl"
        args = ['pynx-cdi-simulation', 'size=80', 'obj_radius=15',
                'nb_raar=50', 'nb_hio=50', 'nb_er=50']
        for my_env in my_envs:
            for ndim in (2, 3):
                for options in [[],
                                ['formula_phase=2*(x*x+0.5*y*y)'],
                                ['obj_shape=cube'],
                                ['obj_shape=octahedron'],
                                ['obj_shape=dodecahedron'],
                                ['support_threshold=0.25,0.26'],
                                ['support_threshold=0.25,0.26', 'nb_run=2'],
                                ]:
                    option_string = f"ndim={ndim} "
                    for s in options:
                        option_string += s + " "
                    with self.subTest(option=option_string, command=' '.join(args + options)):
                        with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                              stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                            stdout, stderr = p.communicate(timeout=200)
                            res = p.returncode
                            msg = "Failed command-line:"
                            for a in p.args:
                                msg += " " + a
                            msg += "\n"
                            self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())

    def test_cdi_runner_simul(self):
        my_envs = []
        if has_cuda and 'opencl' not in sys.argv and not exclude_cuda:
            my_envs.append(os.environ.copy())
            my_envs[-1]["PYNX_PU"] = "cuda"
        if has_opencl and 'cuda' not in sys.argv and not exclude_opencl:
            my_envs.append(os.environ.copy())
            my_envs[-1]["PYNX_PU"] = "opencl"
        args = ['pynx-cdi-simulation', '--size', '80', '--obj_radius', '15',
                '--nb_raar', '50', '--nb_hio', '50', '--nb_er', '50']
        for my_env in my_envs:
            for ndim in (2, 3):
                for options in [[],
                                ['--formula_phase', '2*(x*x+0.5*y*y)'],
                                ['--obj_shape', 'cube'],
                                ['--obj_shape', 'octahedron'],
                                ['--obj_shape', 'dodecahedron'],
                                ['--support_threshold', '0.25'],
                                ['--support_threshold', '0.25', '0.26'],
                                ['--support_threshold', '0.25', '0.26', '--nb_run', '2'],
                                ]:
                    option_string = f"ndim={ndim} "
                    for s in options:
                        option_string += s + " "
                    with self.subTest(option=option_string, command=' '.join(args + options)):
                        with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                              stdout=subprocess.PIPE, cwd=self.tmp_dir, env=my_env) as p:
                            stdout, stderr = p.communicate(timeout=200)
                            res = p.returncode
                            msg = "Failed command-line:"
                            for a in p.args:
                                msg += " " + a
                            msg += "\n"
                            self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())

    def test_cdi_analysis(self):
        com = f"rm -f {os.path.join(self.tmp_dir, '*LLK*.cxi')} {os.path.join(self.tmp_dir, 'data.cxi')}"
        with self.subTest(com):
            os.system(com)

        # Create one cxi data file and 3 results
        args = ['pynx-cdi-simulation', '--data2cxi', '--nbrun', '3', '--save', 'final']
        with self.subTest(command=' '.join(args)):
            with subprocess.Popen(args, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
                stdout0, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stdout0.decode() + stderr.decode())

        with subprocess.Popen(['ls', '-la', self.tmp_dir], stderr=subprocess.PIPE,
                              stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
            stdout1, stderr = p.communicate(timeout=200)

        args = ['pynx-cdi-analysis'] + glob.glob(f"{os.path.join(self.tmp_dir, '*LLK*.cxi')}")
        for options in [['--modes'],
                        ['--modes', '2'],
                        ['--average'],
                        ['--prtf'],
                        ['--modes', '--prtf', '--average'],
                        ['--modes', '--real'],
                        ]:
            with self.subTest(options=options, command=' '.join(args + options)):
                with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                      stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
                    stdout, stderr = p.communicate(timeout=200)
                    res = p.returncode
                    msg = "Failed command-line:"
                    for a in p.args:
                        msg += " " + a
                    # msg += stdout0.decode() + "\n"
                    # msg += stdout1.decode() + "\n"
                    # msg += f"{os.path.join(self.tmp_dir, '*LLK*.cxi')}\n"
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir), '*LLK*.cxi'}")) + '\n'
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir), '*.cxi'}")) + '\n'
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir,'*')}")) + '\n'
                    self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())

    @unittest.skipUnless(oldparse, "old parsing tests not selected")
    def test_cdi_analysis_old(self):
        com = f"rm -f {os.path.join(self.tmp_dir, '*LLK*.cxi')} {os.path.join(self.tmp_dir, 'data.cxi')}"
        with self.subTest(com):
            os.system(com)

        # Create one cxi data file and 3 results
        args = ['pynx-cdi-simulation', '--data2cxi', '--nbrun', '3', '--save', 'final']
        with self.subTest(command=' '.join(args)):
            with subprocess.Popen(args, stderr=subprocess.PIPE,
                                  stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
                stdout0, stderr = p.communicate(timeout=200)
                res = p.returncode
                msg = "Failed command-line:"
                for a in p.args:
                    msg += " " + a
                msg += "\n"
                self.assertFalse(res, msg=msg + stdout0.decode() + stderr.decode())

        with subprocess.Popen(['ls', '-la', self.tmp_dir], stderr=subprocess.PIPE,
                              stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
            stdout1, stderr = p.communicate(timeout=200)

        args = ['pynx-cdi-analysis'] + glob.glob(f"{os.path.join(self.tmp_dir, '*LLK*.cxi')}")
        for options in [['modes'],
                        ['modes=2'],
                        ['average'],
                        ['prtf'],
                        ['modes', 'prtf', 'average'],
                        ['modes', 'real'],
                        ]:
            with self.subTest(options=options, command=' '.join(args + options)):
                with subprocess.Popen(args + options, stderr=subprocess.PIPE,
                                      stdout=subprocess.PIPE, cwd=self.tmp_dir) as p:
                    stdout, stderr = p.communicate(timeout=200)
                    res = p.returncode
                    msg = "Failed command-line:"
                    for a in p.args:
                        msg += " " + a
                    # msg += stdout0.decode() + "\n"
                    # msg += stdout1.decode() + "\n"
                    # msg += f"{os.path.join(self.tmp_dir, '*LLK*.cxi')}\n"
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir), '*LLK*.cxi'}")) + '\n'
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir), '*.cxi'}")) + '\n'
                    # msg += str(glob.glob(f"{os.path.join(self.tmp_dir,'*')}")) + '\n'
                    self.assertFalse(res, msg=msg + stdout.decode() + stderr.decode())


def suite():
    if False:
        # hack to temporarily remove some tests
        for s in dir(TestCDIRunner):
            if 'test_' in s and 'analysis' not in s:
                exec(f"del TestCDIRunner.{s}")

    loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
    test_suite = unittest.TestSuite([loadTests(TestCDIRunner)])
    return test_suite


if __name__ == '__main__':
    res = unittest.TextTestRunner(verbosity=2, descriptions=False).run(suite())
