"""
Test to make sure that libraries built with Nimporter can be installed via Pip.
"""

import sys, os, subprocess, shutil, pkg_resources, json, warnings
from pathlib import Path
import pytest
import nimporter

PYTHON = 'python' if sys.platform == 'win32' else 'python3'
PIP = 'pip' if shutil.which('pip') else 'pip3'

@pytest.mark.integration_test
def test_ensure_nimporter_installed():
    "Make sure that Nimporter is installed before running integration tests."
    libs = {lib.key.lower() for lib in pkg_resources.working_set}
    assert 'nimporter' in libs, (
        f'Nimporter is not installed. Please install via:'
        f'`{PIP} install .` before running the integration tests.'
    )

@pytest.mark.integration_test
def test_create_sdist():
    "Test the successful creation of a source distribution."
    with nimporter.cd('tests/proj1'):
        subprocess.Popen(f'{PYTHON} setup.py sdist'.split()).wait()
        dist = Path('dist')
        egg = Path('project1.egg-info')
        try:
            assert dist.exists()
            assert egg.exists()
            targets = list(dist.glob('project1*'))
            assert len(targets) == 1
            assert targets[0].exists()

            # Make sure the appropriate compiler is being used
            for extension in Path('nim-extensions').iterdir():
                (nim_build_data_file,) = extension.glob('*json')
                nim_build_data = json.loads(nim_build_data_file.read_text())
                expected = nimporter.NimCompiler.get_compatible_compiler()
                installed_ccs = nimporter.NimCompiler.get_installed_compilers()
                if not expected:
                    warnings.warn(
                        f'No compatible C compiler installed: {installed_ccs}'
                    )
                else:
                    cc_path = installed_ccs[expected]
                    actual = nim_build_data['linkcmd'].split()[0].strip()
                    if not actual.startswith(cc_path.stem):
                        warnings.warn(
                            f'Nim used a different C compiler than what Python '
                            f'expects. Python uses {cc_path.stem} and Nim used '
                            f'{actual}'
                        )
        finally:
            shutil.rmtree(str(dist.absolute()))
            shutil.rmtree(str(egg.absolute()))


@pytest.mark.integration_test
def test_create_bdist():
    "Test the successful create of a wheel."
    with nimporter.cd('tests/proj1'):
        subprocess.Popen(f'{PYTHON} setup.py bdist_wheel'.split()).wait()
        dist = Path('dist')
        build = Path('build')
        egg = Path('project1.egg-info')
        try:
            assert dist.exists()
            assert build.exists()
            assert egg.exists()
            targets = list(Path('dist').glob('project1*.whl'))
            assert len(targets) == 1
            assert targets[0].exists()

            # Make sure the appropriate compiler is being used
            for extension in Path('nim-extensions').iterdir():
                (nim_build_data_file,) = extension.glob('*json')
                nim_build_data = json.loads(nim_build_data_file.read_text())
                expected = nimporter.NimCompiler.get_compatible_compiler()
                installed_ccs = nimporter.NimCompiler.get_installed_compilers()
                if not expected:
                    warnings.warn(
                        f'No compatible C compiler installed: {installed_ccs}'
                    )
                else:
                    cc_path = installed_ccs[expected]
                    actual = nim_build_data['linkcmd'].split()[0].strip()
                    if not actual.startswith(cc_path.stem):
                        warnings.warn(
                            f'Nim used a different C compiler than what Python '
                            f'expects. Python uses {cc_path.stem} and Nim used '
                            f'{actual}'
                        )
        finally:
            shutil.rmtree(str(dist.absolute()))
            shutil.rmtree(str(build.absolute()))
            shutil.rmtree(str(egg.absolute()))


@pytest.mark.slow_integration_test
def test_install_sdist():
    "Make sure that the project can be installed by Pip"
    with nimporter.cd('tests/proj1'):
        subprocess.Popen(f'{PYTHON} setup.py sdist'.split()).wait()
        dist = Path('dist')
        egg = Path('project1.egg-info')
        try:
            assert dist.exists()
            assert egg.exists()
            targets = list(dist.glob('project1*'))
            assert len(targets) == 1
            (target,) = targets
            assert target.exists()
            subprocess.Popen(f'{PIP} install {target}'.split()).wait()
        finally:
            shutil.rmtree(str(dist.absolute()))
            shutil.rmtree(str(egg.absolute()))

    # Make sure that `tests/proj1` is not imported as a SimpleNamespace and that
    # the installed library in `site-packages` is used.
    with nimporter.cd('../..'):
        try:
            import proj1
            assert proj1
            import proj1.performance
            assert proj1.performance
            import proj1.lib1
            assert proj1.lib1
            assert proj1.foo
            assert proj1.bar
            assert proj1.baz
            assert proj1.baz() == 1
        except Exception as e:
            warnings.warn(str(e))

        # Cannot delete a DLL in use by another process on Windows
        if sys.platform != 'win32':
            subprocess.Popen(f'{PIP} uninstall project1 -y'.split()).wait()


@pytest.mark.slow_integration_test
def test_install_bdist():
    "Make sure that the wheel can be installed by Pip"
    with nimporter.cd('tests/proj1'):
        subprocess.Popen(f'{PYTHON} setup.py bdist_wheel'.split()).wait()
        dist = Path('dist')
        build = Path('build')
        egg = Path('project1.egg-info')
        try:
            assert dist.exists()
            assert build.exists()
            assert egg.exists()
            targets = list(Path('dist').glob('project1*.whl'))
            assert len(targets) == 1
            wheel = targets[0]
            assert wheel.exists()
            subprocess.Popen(f'{PIP} install {wheel}'.split()).wait()

        finally:
            shutil.rmtree(str(dist.absolute()))
            shutil.rmtree(str(build.absolute()))
            shutil.rmtree(str(egg.absolute()))

    # Make sure that `tests/proj1` is not imported as a SimpleNamespace and that
    # the installed library in `site-packages` is used.
    with nimporter.cd('../..'):
        try:
            import proj1
            assert proj1
            import proj1.performance
            assert proj1.performance
            import proj1.lib1
            assert proj1.lib1
            assert proj1.foo
            assert proj1.bar
            assert proj1.baz
            assert proj1.baz() == 1
        except Exception as e:
            warnings.warn(str(e))

        # Cannot delete a DLL in use by another process on Windows
        if sys.platform != 'win32':
            subprocess.Popen(f'{PIP} uninstall project1 -y'.split()).wait()

[((287, 306), 'shutil.which', 'shutil.which', (['"""pip"""'], {}), "('pip')\n", (299, 306), False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((825, 852), 'nimporter.cd', 'nimporter.cd', (['"""tests/proj1"""'], {}), "('tests/proj1')\n", (837, 852), False, 'import nimporter\n'), ((937, 949), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (941, 949), False, 'from pathlib import Path\n'), ((964, 989), 'pathlib.Path', 'Path', (['"""project1.egg-info"""'], {}), "('project1.egg-info')\n", (968, 989), False, 'from pathlib import Path\n'), ((2488, 2515), 'nimporter.cd', 'nimporter.cd', (['"""tests/proj1"""'], {}), "('tests/proj1')\n", (2500, 2515), False, 'import nimporter\n'), ((2606, 2618), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (2610, 2618), False, 'from pathlib import Path\n'), ((2635, 2648), 'pathlib.Path', 'Path', (['"""build"""'], {}), "('build')\n", (2639, 2648), False, 'from pathlib import Path\n'), ((2663, 2688), 'pathlib.Path', 'Path', (['"""project1.egg-info"""'], {}), "('project1.egg-info')\n", (2667, 2688), False, 'from pathlib import Path\n'), ((4300, 4327), 'nimporter.cd', 'nimporter.cd', (['"""tests/proj1"""'], {}), "('tests/proj1')\n", (4312, 4327), False, 'import nimporter\n'), ((4412, 4424), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (4416, 4424), False, 'from pathlib import Path\n'), ((4439, 4464), 'pathlib.Path', 'Path', (['"""project1.egg-info"""'], {}), "('project1.egg-info')\n", (4443, 4464), False, 'from pathlib import Path\n'), ((5028, 5049), 'nimporter.cd', 'nimporter.cd', (['"""../.."""'], {}), "('../..')\n", (5040, 5049), False, 'import nimporter\n'), ((5743, 5770), 'nimporter.cd', 'nimporter.cd', (['"""tests/proj1"""'], {}), "('tests/proj1')\n", (5755, 5770), False, 'import nimporter\n'), ((5861, 5873), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (5865, 5873), False, 'from pathlib import Path\n'), ((5890, 5903), 'pathlib.Path', 'Path', (['"""build"""'], {}), "('build')\n", (5894, 5903), False, 'from pathlib import Path\n'), ((5918, 5943), 'pathlib.Path', 'Path', (['"""project1.egg-info"""'], {}), "('project1.egg-info')\n", (5922, 5943), False, 'from pathlib import Path\n'), ((6600, 6621), 'nimporter.cd', 'nimporter.cd', (['"""../.."""'], {}), "('../..')\n", (6612, 6621), False, 'import nimporter\n'), ((1491, 1538), 'nimporter.NimCompiler.get_compatible_compiler', 'nimporter.NimCompiler.get_compatible_compiler', ([], {}), '()\n', (1536, 1538), False, 'import nimporter\n'), ((1571, 1618), 'nimporter.NimCompiler.get_installed_compilers', 'nimporter.NimCompiler.get_installed_compilers', ([], {}), '()\n', (1616, 1618), False, 'import nimporter\n'), ((3236, 3283), 'nimporter.NimCompiler.get_compatible_compiler', 'nimporter.NimCompiler.get_compatible_compiler', ([], {}), '()\n', (3281, 3283), False, 'import nimporter\n'), ((3316, 3363), 'nimporter.NimCompiler.get_installed_compilers', 'nimporter.NimCompiler.get_installed_compilers', ([], {}), '()\n', (3361, 3363), False, 'import nimporter\n'), ((5354, 5365), 'proj1.baz', 'proj1.baz', ([], {}), '()\n', (5363, 5365), False, 'import proj1\n'), ((6926, 6937), 'proj1.baz', 'proj1.baz', ([], {}), '()\n', (6935, 6937), False, 'import proj1\n'), ((1288, 1310), 'pathlib.Path', 'Path', (['"""nim-extensions"""'], {}), "('nim-extensions')\n", (1292, 1310), False, 'from pathlib import Path\n'), ((1672, 1741), 'warnings.warn', 'warnings.warn', (['f"""No compatible C compiler installed: {installed_ccs}"""'], {}), "(f'No compatible C compiler installed: {installed_ccs}')\n", (1685, 1741), False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((3033, 3055), 'pathlib.Path', 'Path', (['"""nim-extensions"""'], {}), "('nim-extensions')\n", (3037, 3055), False, 'from pathlib import Path\n'), ((3417, 3486), 'warnings.warn', 'warnings.warn', (['f"""No compatible C compiler installed: {installed_ccs}"""'], {}), "(f'No compatible C compiler installed: {installed_ccs}')\n", (3430, 3486), False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((2022, 2156), 'warnings.warn', 'warnings.warn', (['f"""Nim used a different C compiler than what Python expects. Python uses {cc_path.stem} and Nim used {actual}"""'], {}), "(\n    f'Nim used a different C compiler than what Python expects. Python uses {cc_path.stem} and Nim used {actual}'\n    )\n", (2035, 2156), False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((2828, 2840), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (2832, 2840), False, 'from pathlib import Path\n'), ((3767, 3901), 'warnings.warn', 'warnings.warn', (['f"""Nim used a different C compiler than what Python expects. Python uses {cc_path.stem} and Nim used {actual}"""'], {}), "(\n    f'Nim used a different C compiler than what Python expects. Python uses {cc_path.stem} and Nim used {actual}'\n    )\n", (3780, 3901), False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((6083, 6095), 'pathlib.Path', 'Path', (['"""dist"""'], {}), "('dist')\n", (6087, 6095), False, 'from pathlib import Path\n')]