import py
import tox
import pytest
import os
import sys
import tox.config
from tox.venv import *  # noqa
from tox.hookspecs import hookimpl
from tox.interpreters import NoInterpreterInfo


# def test_global_virtualenv(capfd):
#    v = VirtualEnv()
#    l = v.list()
#    assert l
#    out, err = capfd.readouterr()
#    assert not out
#    assert not err
#


def test_getdigest(tmpdir):
    assert getdigest(tmpdir) == "0" * 32


def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession):
    config = newconfig([], """
        [testenv:python]
        basepython=%s
    """ % sys.executable)
    venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
    interp = venv.getsupportedinterpreter()
    # realpath needed for debian symlinks
    assert py.path.local(interp).realpath() == py.path.local(sys.executable).realpath()
    monkeypatch.setattr(sys, 'platform', "win32")
    monkeypatch.setattr(venv.envconfig, 'basepython', 'jython')
    pytest.raises(tox.exception.UnsupportedInterpreter, venv.getsupportedinterpreter)
    monkeypatch.undo()
    monkeypatch.setattr(venv.envconfig, "envname", "py1")
    monkeypatch.setattr(venv.envconfig, 'basepython', 'notexistingpython')
    pytest.raises(tox.exception.InterpreterNotFound, venv.getsupportedinterpreter)
    monkeypatch.undo()
    # check that we properly report when no version_info is present
    info = NoInterpreterInfo(name=venv.name)
    info.executable = "something"
    monkeypatch.setattr(config.interpreters, "get_info", lambda *args, **kw: info)
    pytest.raises(tox.exception.InvocationError, venv.getsupportedinterpreter)


def test_create(monkeypatch, mocksession, newconfig):
    config = newconfig([], """
        [testenv:py123]
    """)
    envconfig = config.envconfigs['py123']
    venv = VirtualEnv(envconfig, session=mocksession)
    assert venv.path == envconfig.envdir
    assert not venv.path.check()
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) >= 1
    args = l[0].args
    assert "virtualenv" == str(args[2])
    if sys.platform != "win32":
        # realpath is needed for stuff like the debian symlinks
        assert py.path.local(sys.executable).realpath() == py.path.local(args[0]).realpath()
        # assert Envconfig.toxworkdir in args
        assert venv.getcommandpath("easy_install", cwd=py.path.local())
    interp = venv._getliveconfig().python
    assert interp == venv.envconfig.python_info.executable
    assert venv.path_config.check(exists=False)


@pytest.mark.skipif("sys.platform == 'win32'")
def test_commandpath_venv_precendence(tmpdir, monkeypatch,
                                      mocksession, newconfig):
    config = newconfig([], """
        [testenv:py123]
    """)
    envconfig = config.envconfigs['py123']
    venv = VirtualEnv(envconfig, session=mocksession)
    tmpdir.ensure("easy_install")
    monkeypatch.setenv("PATH", str(tmpdir), prepend=os.pathsep)
    envconfig.envbindir.ensure("easy_install")
    p = venv.getcommandpath("easy_install")
    assert py.path.local(p).relto(envconfig.envbindir), p


def test_create_sitepackages(monkeypatch, mocksession, newconfig):
    config = newconfig([], """
        [testenv:site]
        sitepackages=True

        [testenv:nosite]
        sitepackages=False
    """)
    envconfig = config.envconfigs['site']
    venv = VirtualEnv(envconfig, session=mocksession)
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) >= 1
    args = l[0].args
    assert "--system-site-packages" in map(str, args)
    mocksession._clearmocks()

    envconfig = config.envconfigs['nosite']
    venv = VirtualEnv(envconfig, session=mocksession)
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) >= 1
    args = l[0].args
    assert "--system-site-packages" not in map(str, args)
    assert "--no-site-packages" not in map(str, args)


def test_install_deps_wildcard(newmocksession):
    mocksession = newmocksession([], """
        [tox]
        distshare = {toxworkdir}/distshare
        [testenv:py123]
        deps=
            {distshare}/dep1-*
    """)
    venv = mocksession.getenv("py123")
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    distshare = venv.session.config.distshare
    distshare.ensure("dep1-1.0.zip")
    distshare.ensure("dep1-1.1.zip")

    tox_testenv_install_deps(action=action, venv=venv)
    assert len(l) == 2
    args = l[-1].args
    assert l[-1].cwd == venv.envconfig.config.toxinidir
    assert "pip" in str(args[0])
    assert args[1] == "install"
    args = [arg for arg in args if str(arg).endswith("dep1-1.1.zip")]
    assert len(args) == 1


def test_install_deps_indexserver(newmocksession):
    mocksession = newmocksession([], """
        [tox]
        indexserver =
            abc = ABC
            abc2 = ABC
        [testenv:py123]
        deps=
            dep1
            :abc:dep2
            :abc2:dep3
    """)
    venv = mocksession.getenv('py123')
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    l[:] = []

    tox_testenv_install_deps(action=action, venv=venv)
    # two different index servers, two calls
    assert len(l) == 3
    args = " ".join(l[0].args)
    assert "-i " not in args
    assert "dep1" in args

    args = " ".join(l[1].args)
    assert "-i ABC" in args
    assert "dep2" in args
    args = " ".join(l[2].args)
    assert "-i ABC" in args
    assert "dep3" in args


def test_install_deps_pre(newmocksession):
    mocksession = newmocksession([], """
        [testenv]
        pip_pre=true
        deps=
            dep1
    """)
    venv = mocksession.getenv('python')
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    l[:] = []

    tox_testenv_install_deps(action=action, venv=venv)
    assert len(l) == 1
    args = " ".join(l[0].args)
    assert "--pre " in args
    assert "dep1" in args


def test_installpkg_indexserver(newmocksession, tmpdir):
    mocksession = newmocksession([], """
        [tox]
        indexserver =
            default = ABC
    """)
    venv = mocksession.getenv('python')
    l = mocksession._pcalls
    p = tmpdir.ensure("distfile.tar.gz")
    mocksession.installpkg(venv, p)
    # two different index servers, two calls
    assert len(l) == 1
    args = " ".join(l[0].args)
    assert "-i ABC" in args


def test_install_recreate(newmocksession, tmpdir):
    pkg = tmpdir.ensure("package.tar.gz")
    mocksession = newmocksession(['--recreate'], """
        [testenv]
        deps=xyz
    """)
    venv = mocksession.getenv('python')

    action = mocksession.newaction(venv, "update")
    venv.update(action)
    mocksession.installpkg(venv, pkg)
    mocksession.report.expect("verbosity0", "*create*")
    venv.update(action)
    mocksession.report.expect("verbosity0", "*recreate*")


def test_install_sdist_extras(newmocksession):
    mocksession = newmocksession([], """
        [testenv]
        extras = testing
            development
    """)
    venv = mocksession.getenv('python')
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    l[:] = []

    venv.installpkg('distfile.tar.gz', action=action)
    assert 'distfile.tar.gz[testing,development]' in l[-1].args


def test_develop_extras(newmocksession, tmpdir):
    mocksession = newmocksession([], """
        [testenv]
        extras = testing
            development
    """)
    venv = mocksession.getenv('python')
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    l[:] = []

    venv.developpkg(tmpdir, action=action)
    expected = "%s[testing,development]" % tmpdir.strpath
    assert expected in l[-1].args


def test_env_variables_added_to_needs_reinstall(tmpdir, mocksession, newconfig, monkeypatch):
    tmpdir.ensure("setup.py")
    monkeypatch.setenv("TEMP_PASS_VAR", "123")
    monkeypatch.setenv("TEMP_NOPASS_VAR", "456")
    config = newconfig([], """
        [testenv:python]
        passenv = temp_pass_var
        setenv =
            CUSTOM_VAR = 789
    """)

    venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
    action = mocksession.newaction(venv, "hello")

    venv._needs_reinstall(tmpdir, action)

    l = mocksession._pcalls
    assert len(l) == 2
    env = l[0].env

    # should have access to setenv vars
    assert 'CUSTOM_VAR' in env
    assert env['CUSTOM_VAR'] == '789'

    # should have access to passenv vars
    assert 'TEMP_PASS_VAR' in env
    assert env['TEMP_PASS_VAR'] == "123"

    # should also have access to full invocation environment,
    # for backward compatibility, and to match behavior of venv.run_install_command()
    assert 'TEMP_NOPASS_VAR' in env
    assert env["TEMP_NOPASS_VAR"] == "456"


def test_test_hashseed_is_in_output(newmocksession):
    original_make_hashseed = tox.config.make_hashseed
    tox.config.make_hashseed = lambda: '123456789'
    try:
        mocksession = newmocksession([], '''
            [testenv]
        ''')
    finally:
        tox.config.make_hashseed = original_make_hashseed
    venv = mocksession.getenv('python')
    action = mocksession.newaction(venv, "update")
    venv.update(action)
    venv.test()
    mocksession.report.expect("verbosity0", "python runtests: PYTHONHASHSEED='123456789'")


def test_test_runtests_action_command_is_in_output(newmocksession):
    mocksession = newmocksession([], '''
        [testenv]
        commands = echo foo bar
    ''')
    venv = mocksession.getenv('python')
    action = mocksession.newaction(venv, "update")
    venv.update(action)
    venv.test()
    mocksession.report.expect("verbosity0", "*runtests*commands?0? | echo foo bar")


def test_install_error(newmocksession, monkeypatch):
    mocksession = newmocksession(['--recreate'], """
        [testenv]
        deps=xyz
        commands=
            qwelkqw
    """)
    venv = mocksession.getenv('python')
    venv.test()
    mocksession.report.expect("error", "*not find*qwelkqw*")
    assert venv.status == "commands failed"


def test_install_command_not_installed(newmocksession, monkeypatch):
    mocksession = newmocksession(['--recreate'], """
        [testenv]
        commands=
            pytest
    """)
    venv = mocksession.getenv('python')
    venv.test()
    mocksession.report.expect("warning", "*test command found but not*")
    assert venv.status == 0


def test_install_command_whitelisted(newmocksession, monkeypatch):
    mocksession = newmocksession(['--recreate'], """
        [testenv]
        whitelist_externals = pytest
                              xy*
        commands=
            pytest
            xyz
    """)
    venv = mocksession.getenv('python')
    venv.test()
    mocksession.report.expect("warning", "*test command found but not*",
                              invert=True)
    assert venv.status == "commands failed"


@pytest.mark.skipif("not sys.platform.startswith('linux')")
def test_install_command_not_installed_bash(newmocksession):
    mocksession = newmocksession(['--recreate'], """
        [testenv]
        commands=
            bash
    """)
    venv = mocksession.getenv('python')
    venv.test()
    mocksession.report.expect("warning", "*test command found but not*")


def test_install_python3(tmpdir, newmocksession):
    if not py.path.local.sysfind('python3.3'):
        pytest.skip("needs python3.3")
    mocksession = newmocksession([], """
        [testenv:py123]
        basepython=python3.3
        deps=
            dep1
            dep2
    """)
    venv = mocksession.getenv('py123')
    action = mocksession.newaction(venv, "getenv")
    tox_testenv_create(action=action, venv=venv)
    l = mocksession._pcalls
    assert len(l) == 1
    args = l[0].args
    assert str(args[2]) == 'virtualenv'
    l[:] = []
    action = mocksession.newaction(venv, "hello")
    venv._install(["hello"], action=action)
    assert len(l) == 1
    args = l[0].args
    assert "pip" in args[0]
    for x in args:
        assert "--download-cache" not in args, args


class TestCreationConfig:

    def test_basic(self, newconfig, mocksession, tmpdir):
        config = newconfig([], "")
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        cconfig = venv._getliveconfig()
        assert cconfig.matches(cconfig)
        path = tmpdir.join("configdump")
        cconfig.writeconfig(path)
        newconfig = CreationConfig.readconfig(path)
        assert newconfig.matches(cconfig)
        assert cconfig.matches(newconfig)

    def test_matchingdependencies(self, newconfig, mocksession):
        config = newconfig([], """
            [testenv]
            deps=abc
        """)
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        cconfig = venv._getliveconfig()
        config = newconfig([], """
            [testenv]
            deps=xyz
        """)
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        otherconfig = venv._getliveconfig()
        assert not cconfig.matches(otherconfig)

    def test_matchingdependencies_file(self, newconfig, mocksession):
        config = newconfig([], """
            [tox]
            distshare={toxworkdir}/distshare
            [testenv]
            deps=abc
                 {distshare}/xyz.zip
        """)
        xyz = config.distshare.join("xyz.zip")
        xyz.ensure()
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        cconfig = venv._getliveconfig()
        assert cconfig.matches(cconfig)
        xyz.write("hello")
        newconfig = venv._getliveconfig()
        assert not cconfig.matches(newconfig)

    def test_matchingdependencies_latest(self, newconfig, mocksession):
        config = newconfig([], """
            [tox]
            distshare={toxworkdir}/distshare
            [testenv]
            deps={distshare}/xyz-*
        """)
        config.distshare.ensure("xyz-1.2.0.zip")
        xyz2 = config.distshare.ensure("xyz-1.2.1.zip")
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        cconfig = venv._getliveconfig()
        md5, path = cconfig.deps[0]
        assert path == xyz2
        assert md5 == path.computehash()

    def test_python_recreation(self, tmpdir, newconfig, mocksession):
        pkg = tmpdir.ensure("package.tar.gz")
        config = newconfig([], "")
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        cconfig = venv._getliveconfig()
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        assert not venv.path_config.check()
        mocksession.installpkg(venv, pkg)
        assert venv.path_config.check()
        assert mocksession._pcalls
        args1 = map(str, mocksession._pcalls[0].args)
        assert 'virtualenv' in " ".join(args1)
        mocksession.report.expect("*", "*create*")
        # modify config and check that recreation happens
        mocksession._clearmocks()
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        mocksession.report.expect("*", "*reusing*")
        mocksession._clearmocks()
        action = mocksession.newaction(venv, "update")
        cconfig.python = py.path.local("balla")
        cconfig.writeconfig(venv.path_config)
        venv.update(action)
        mocksession.report.expect("verbosity0", "*recreate*")

    def test_dep_recreation(self, newconfig, mocksession):
        config = newconfig([], "")
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        cconfig = venv._getliveconfig()
        cconfig.deps[:] = [("1" * 32, "xyz.zip")]
        cconfig.writeconfig(venv.path_config)
        mocksession._clearmocks()
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        mocksession.report.expect("*", "*recreate*")

    def test_develop_recreation(self, newconfig, mocksession):
        config = newconfig([], "")
        envconfig = config.envconfigs['python']
        venv = VirtualEnv(envconfig, session=mocksession)
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        cconfig = venv._getliveconfig()
        cconfig.usedevelop = True
        cconfig.writeconfig(venv.path_config)
        mocksession._clearmocks()
        action = mocksession.newaction(venv, "update")
        venv.update(action)
        mocksession.report.expect("verbosity0", "*recreate*")


class TestVenvTest:

    def test_envbinddir_path(self, newmocksession, monkeypatch):
        monkeypatch.setenv("PIP_RESPECT_VIRTUALENV", "1")
        mocksession = newmocksession([], """
            [testenv:python]
            commands=abc
        """)
        venv = mocksession.getenv("python")
        action = mocksession.newaction(venv, "getenv")
        monkeypatch.setenv("PATH", "xyz")
        l = []
        monkeypatch.setattr("py.path.local.sysfind", classmethod(
                            lambda *args, **kwargs: l.append(kwargs) or 0 / 0))

        with pytest.raises(ZeroDivisionError):
            venv._install(list('123'), action=action)
        assert l.pop()["paths"] == [venv.envconfig.envbindir]
        with pytest.raises(ZeroDivisionError):
            venv.test(action)
        assert l.pop()["paths"] == [venv.envconfig.envbindir]
        with pytest.raises(ZeroDivisionError):
            venv.run_install_command(['qwe'], action=action)
        assert l.pop()["paths"] == [venv.envconfig.envbindir]
        monkeypatch.setenv("PIP_RESPECT_VIRTUALENV", "1")
        monkeypatch.setenv("PIP_REQUIRE_VIRTUALENV", "1")
        monkeypatch.setenv("__PYVENV_LAUNCHER__", "1")
        pytest.raises(ZeroDivisionError, "venv.run_install_command(['qwe'], action=action)")
        assert 'PIP_RESPECT_VIRTUALENV' not in os.environ
        assert 'PIP_REQUIRE_VIRTUALENV' not in os.environ
        assert '__PYVENV_LAUNCHER__' not in os.environ

    def test_pythonpath_usage(self, newmocksession, monkeypatch):
        monkeypatch.setenv("PYTHONPATH", "/my/awesome/library")
        mocksession = newmocksession([], """
            [testenv:python]
            commands=abc
        """)
        venv = mocksession.getenv("python")
        action = mocksession.newaction(venv, "getenv")
        venv.run_install_command(['qwe'], action=action)
        assert 'PYTHONPATH' not in os.environ
        mocksession.report.expect("warning", "*Discarding $PYTHONPATH from environment*")

        l = mocksession._pcalls
        assert len(l) == 1
        assert 'PYTHONPATH' not in l[0].env

        # passenv = PYTHONPATH allows PYTHONPATH to stay in environment
        monkeypatch.setenv("PYTHONPATH", "/my/awesome/library")
        mocksession = newmocksession([], """
            [testenv:python]
            commands=abc
            passenv = PYTHONPATH
        """)
        venv = mocksession.getenv("python")
        action = mocksession.newaction(venv, "getenv")
        venv.run_install_command(['qwe'], action=action)
        assert 'PYTHONPATH' in os.environ
        mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")

        l = mocksession._pcalls
        assert len(l) == 2
        assert l[1].env['PYTHONPATH'] == '/my/awesome/library'


# FIXME this test fails when run in isolation - find what this depends on
# AssertionError: found warning('*Discarding $PYTHONPATH [...]
def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatch):
    pkg = tmpdir.ensure("package.tar.gz")
    monkeypatch.setenv("X123", "123")
    monkeypatch.setenv("YY", "456")
    config = newconfig([], """
        [testenv:python]
        commands=python -V
        passenv = x123
        setenv =
            ENV_VAR = value
            PYTHONPATH = value
    """)
    mocksession._clearmocks()

    venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
    mocksession.installpkg(venv, pkg)
    venv.test()

    l = mocksession._pcalls
    assert len(l) == 2
    for x in l:
        env = x.env
        assert env is not None
        assert 'ENV_VAR' in env
        assert env['ENV_VAR'] == 'value'
        assert env['VIRTUAL_ENV'] == str(venv.path)
        assert env['X123'] == "123"
        assert 'PYTHONPATH' in env
        assert env['PYTHONPATH'] == 'value'
    # all env variables are passed for installation
    assert l[0].env["YY"] == "456"
    assert "YY" not in l[1].env

    assert set(["ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"])\
        .issubset(l[1].env)

    # setenv does not trigger PYTHONPATH warnings
    mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")

    # for e in os.environ:
    #    assert e in env


def test_installpkg_no_upgrade(tmpdir, newmocksession):
    pkg = tmpdir.ensure("package.tar.gz")
    mocksession = newmocksession([], "")
    venv = mocksession.getenv('python')
    venv.just_created = True
    venv.envconfig.envdir.ensure(dir=1)
    mocksession.installpkg(venv, pkg)
    l = mocksession._pcalls
    assert len(l) == 1
    assert '-U' not in l[0].args


def test_installpkg_upgrade(newmocksession, tmpdir):
    pkg = tmpdir.ensure("package.tar.gz")
    mocksession = newmocksession([], "")
    venv = mocksession.getenv('python')
    assert not hasattr(venv, 'just_created')
    mocksession.installpkg(venv, pkg)
    l = mocksession._pcalls
    assert len(l) == 1
    index = l[0].args.index(str(pkg))
    assert index >= 0
    assert '-U' in l[0].args[:index]
    assert '--no-deps' in l[0].args[:index]


def test_run_install_command(newmocksession):
    mocksession = newmocksession([], "")
    venv = mocksession.getenv('python')
    venv.just_created = True
    venv.envconfig.envdir.ensure(dir=1)
    action = mocksession.newaction(venv, "hello")
    venv.run_install_command(packages=["whatever"], action=action)
    l = mocksession._pcalls
    assert len(l) == 1
    assert 'pip' in l[0].args[0]
    assert 'install' in l[0].args
    env = l[0].env
    assert env is not None


def test_run_custom_install_command(newmocksession):
    mocksession = newmocksession([], """
        [testenv]
        install_command=easy_install {opts} {packages}
    """)
    venv = mocksession.getenv('python')
    venv.just_created = True
    venv.envconfig.envdir.ensure(dir=1)
    action = mocksession.newaction(venv, "hello")
    venv.run_install_command(packages=["whatever"], action=action)
    l = mocksession._pcalls
    assert len(l) == 1
    assert 'easy_install' in l[0].args[0]
    assert l[0].args[1:] == ['whatever']


def test_command_relative_issue26(newmocksession, tmpdir, monkeypatch):
    mocksession = newmocksession([], """
        [testenv]
    """)
    x = tmpdir.ensure("x")
    venv = mocksession.getenv("python")
    x2 = venv.getcommandpath("./x", cwd=tmpdir)
    assert x == x2
    mocksession.report.not_expect("warning", "*test command found but not*")
    x3 = venv.getcommandpath("/bin/bash", cwd=tmpdir)
    assert x3 == "/bin/bash"
    mocksession.report.not_expect("warning", "*test command found but not*")
    monkeypatch.setenv("PATH", str(tmpdir))
    x4 = venv.getcommandpath("x", cwd=tmpdir)
    assert x4.endswith(os.sep + 'x')
    mocksession.report.expect("warning", "*test command found but not*")


def test_ignore_outcome_failing_cmd(newmocksession):
    mocksession = newmocksession([], """
        [testenv]
        commands=testenv_fail
        ignore_outcome=True
    """)

    venv = mocksession.getenv('python')
    venv.test()
    assert venv.status == "ignored failed command"
    mocksession.report.expect("warning", "*command failed but result from "
                                         "testenv is ignored*")


def test_tox_testenv_create(newmocksession):
    l = []

    class Plugin:
        @hookimpl
        def tox_testenv_create(self, action, venv):
            l.append(1)

        @hookimpl
        def tox_testenv_install_deps(self, action, venv):
            l.append(2)

    mocksession = newmocksession([], """
        [testenv]
        commands=testenv_fail
        ignore_outcome=True
    """, plugins=[Plugin()])

    venv = mocksession.getenv('python')
    venv.update(action=mocksession.newaction(venv, "getenv"))
    assert l == [1, 2]


def test_tox_testenv_pre_post(newmocksession):
    l = []

    class Plugin:
        @hookimpl
        def tox_runtest_pre(self, venv):
            l.append('started')

        @hookimpl
        def tox_runtest_post(self, venv):
            l.append('finished')

    mocksession = newmocksession([], """
        [testenv]
        commands=testenv_fail
    """, plugins=[Plugin()])

    venv = mocksession.getenv('python')
    venv.status = None
    assert l == []
    mocksession.runtestenv(venv)
    assert l == ['started', 'finished']
