"""
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()

[((11, 15, 11, 34), 'shutil.which', 'shutil.which', ({(11, 28, 11, 33): '"""pip"""'}, {}), "('pip')", False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((25, 9, 25, 36), 'nimporter.cd', 'nimporter.cd', ({(25, 22, 25, 35): '"""tests/proj1"""'}, {}), "('tests/proj1')", False, 'import nimporter\n'), ((27, 15, 27, 27), 'pathlib.Path', 'Path', ({(27, 20, 27, 26): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n'), ((28, 14, 28, 39), 'pathlib.Path', 'Path', ({(28, 19, 28, 38): '"""project1.egg-info"""'}, {}), "('project1.egg-info')", False, 'from pathlib import Path\n'), ((63, 9, 63, 36), 'nimporter.cd', 'nimporter.cd', ({(63, 22, 63, 35): '"""tests/proj1"""'}, {}), "('tests/proj1')", False, 'import nimporter\n'), ((65, 15, 65, 27), 'pathlib.Path', 'Path', ({(65, 20, 65, 26): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n'), ((66, 16, 66, 29), 'pathlib.Path', 'Path', ({(66, 21, 66, 28): '"""build"""'}, {}), "('build')", False, 'from pathlib import Path\n'), ((67, 14, 67, 39), 'pathlib.Path', 'Path', ({(67, 19, 67, 38): '"""project1.egg-info"""'}, {}), "('project1.egg-info')", False, 'from pathlib import Path\n'), ((104, 9, 104, 36), 'nimporter.cd', 'nimporter.cd', ({(104, 22, 104, 35): '"""tests/proj1"""'}, {}), "('tests/proj1')", False, 'import nimporter\n'), ((106, 15, 106, 27), 'pathlib.Path', 'Path', ({(106, 20, 106, 26): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n'), ((107, 14, 107, 39), 'pathlib.Path', 'Path', ({(107, 19, 107, 38): '"""project1.egg-info"""'}, {}), "('project1.egg-info')", False, 'from pathlib import Path\n'), ((122, 9, 122, 30), 'nimporter.cd', 'nimporter.cd', ({(122, 22, 122, 29): '"""../.."""'}, {}), "('../..')", False, 'import nimporter\n'), ((145, 9, 145, 36), 'nimporter.cd', 'nimporter.cd', ({(145, 22, 145, 35): '"""tests/proj1"""'}, {}), "('tests/proj1')", False, 'import nimporter\n'), ((147, 15, 147, 27), 'pathlib.Path', 'Path', ({(147, 20, 147, 26): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n'), ((148, 16, 148, 29), 'pathlib.Path', 'Path', ({(148, 21, 148, 28): '"""build"""'}, {}), "('build')", False, 'from pathlib import Path\n'), ((149, 14, 149, 39), 'pathlib.Path', 'Path', ({(149, 19, 149, 38): '"""project1.egg-info"""'}, {}), "('project1.egg-info')", False, 'from pathlib import Path\n'), ((167, 9, 167, 30), 'nimporter.cd', 'nimporter.cd', ({(167, 22, 167, 29): '"""../.."""'}, {}), "('../..')", False, 'import nimporter\n'), ((40, 27, 40, 74), 'nimporter.NimCompiler.get_compatible_compiler', 'nimporter.NimCompiler.get_compatible_compiler', ({}, {}), '()', False, 'import nimporter\n'), ((41, 32, 41, 79), 'nimporter.NimCompiler.get_installed_compilers', 'nimporter.NimCompiler.get_installed_compilers', ({}, {}), '()', False, 'import nimporter\n'), ((80, 27, 80, 74), 'nimporter.NimCompiler.get_compatible_compiler', 'nimporter.NimCompiler.get_compatible_compiler', ({}, {}), '()', False, 'import nimporter\n'), ((81, 32, 81, 79), 'nimporter.NimCompiler.get_installed_compilers', 'nimporter.NimCompiler.get_installed_compilers', ({}, {}), '()', False, 'import nimporter\n'), ((133, 19, 133, 30), 'proj1.baz', 'proj1.baz', ({}, {}), '()', False, 'import proj1\n'), ((178, 19, 178, 30), 'proj1.baz', 'proj1.baz', ({}, {}), '()', False, 'import proj1\n'), ((37, 29, 37, 51), 'pathlib.Path', 'Path', ({(37, 34, 37, 50): '"""nim-extensions"""'}, {}), "('nim-extensions')", False, 'from pathlib import Path\n'), ((43, 20, 45, 21), 'warnings.warn', 'warnings.warn', ({(44, 24, 44, 78): 'f"""No compatible C compiler installed: {installed_ccs}"""'}, {}), "(f'No compatible C compiler installed: {installed_ccs}')", False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((77, 29, 77, 51), 'pathlib.Path', 'Path', ({(77, 34, 77, 50): '"""nim-extensions"""'}, {}), "('nim-extensions')", False, 'from pathlib import Path\n'), ((83, 20, 85, 21), 'warnings.warn', 'warnings.warn', ({(84, 24, 84, 78): 'f"""No compatible C compiler installed: {installed_ccs}"""'}, {}), "(f'No compatible C compiler installed: {installed_ccs}')", False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((50, 24, 54, 25), 'warnings.warn', 'warnings.warn', ({(51, 28, 53, 39): '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    )", False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((72, 27, 72, 39), 'pathlib.Path', 'Path', ({(72, 32, 72, 38): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n'), ((90, 24, 94, 25), 'warnings.warn', 'warnings.warn', ({(91, 28, 93, 39): '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    )", False, 'import sys, os, subprocess, shutil, pkg_resources, json, warnings\n'), ((154, 27, 154, 39), 'pathlib.Path', 'Path', ({(154, 32, 154, 38): '"""dist"""'}, {}), "('dist')", False, 'from pathlib import Path\n')]