import os

from apistar import __version__, exceptions
from apistar.app import App
from apistar.main import setup_pythonpath
from apistar.test import CommandLineRunner

app = App()
runner = CommandLineRunner(app)


def test_help_flag():
    result = runner.invoke([])
    assert '--help' in result.output
    assert '--version' in result.output
    assert 'new' in result.output
    assert 'run' in result.output
    assert 'test' in result.output
    assert result.exit_code == 0


def test_version_flag():
    result = runner.invoke(['--version'])
    assert __version__ in result.output
    assert result.exit_code == 0


def test_new():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject', '--template', 'minimal'])
        assert os.path.exists('myproject')
        assert os.path.exists(os.path.join('myproject', 'app.py'))
        assert os.path.exists(os.path.join('myproject', 'tests.py'))


def test_do_not_overwrite_existing_project():
    with runner.isolated_filesystem():
        result = runner.invoke(['new', 'myproject', '--template', 'minimal'])
        assert result.exit_code == 0
        result = runner.invoke(['new', 'myproject', '--template', 'minimal'])
        assert result.exit_code != 0


def test_testsuite_minimal():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject', '--template', 'minimal'])
        os.chdir('myproject')
        setup_pythonpath()
        result = runner.invoke(['test'])
        assert '2 passed' in result.output
        assert result.exit_code == 0


def test_testsuite_standard():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject'])
        os.chdir('myproject')
        setup_pythonpath()
        result = runner.invoke(['test'])
        assert '2 passed' in result.output
        assert result.exit_code == 0

        # Add a failing test case.
        failing_test_module = os.path.join('tests', 'test_failure.py')
        with open(failing_test_module, 'w') as test_module:
            test_module.write('def test_failure():\n    raise Exception()\n')
        result = runner.invoke(['test'])
        assert '1 failed, 2 passed' in result.output
        assert result.exit_code != 0


def test_testsuite_missing_tests_module():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject', '--template', 'minimal'])
        os.chdir('myproject')
        setup_pythonpath()
        os.remove('tests.py')
        result = runner.invoke(['test'])
        assert isinstance(result.exception, exceptions.ConfigurationError)
        assert result.exit_code != 0


def test_missing_app_module():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject', '--template', 'minimal'])
        os.chdir('myproject')
        setup_pythonpath()
        os.remove('app.py')
        result = runner.invoke(['run'])
        assert isinstance(result.exception, exceptions.ConfigurationError)
        assert result.exit_code != 0


def test_misconfigured_app_module():
    with runner.isolated_filesystem():
        runner.invoke(['new', 'myproject', '--template', 'minimal'])
        os.chdir('myproject')
        setup_pythonpath()
        with open('app.py', 'w') as app_module:
            app_module.write('123\n')
        result = runner.invoke(['run'])
        assert isinstance(result.exception, exceptions.ConfigurationError)
        assert result.exit_code != 0
