import sys
import tempfile
import os
import zipfile
import datetime
import time
import subprocess
import stat

import pytest

import pkg_resources

from setuptools.tests.textwrap import DALS
from setuptools.tests import contexts
from setuptools.tests import environment


try:
    unicode
except NameError:
    unicode = str

def timestamp(dt):
    """
    Return a timestamp for a local, naive datetime instance.
    """
    try:
        return dt.timestamp()
    except AttributeError:
        # Python 3.2 and earlier
        return time.mktime(dt.timetuple())

class EggRemover(unicode):
    def __call__(self):
        if self in sys.path:
            sys.path.remove(self)
        if os.path.exists(self):
            os.remove(self)

class TestZipProvider(object):
    finalizers = []

    ref_time = datetime.datetime(2013, 5, 12, 13, 25, 0)
    "A reference time for a file modification"

    @classmethod
    def setup_class(cls):
        "create a zip egg and add it to sys.path"
        egg = tempfile.NamedTemporaryFile(suffix='.egg', delete=False)
        zip_egg = zipfile.ZipFile(egg, 'w')
        zip_info = zipfile.ZipInfo()
        zip_info.filename = 'mod.py'
        zip_info.date_time = cls.ref_time.timetuple()
        zip_egg.writestr(zip_info, 'x = 3\n')
        zip_info = zipfile.ZipInfo()
        zip_info.filename = 'data.dat'
        zip_info.date_time = cls.ref_time.timetuple()
        zip_egg.writestr(zip_info, 'hello, world!')
        zip_egg.close()
        egg.close()

        sys.path.append(egg.name)
        cls.finalizers.append(EggRemover(egg.name))

    @classmethod
    def teardown_class(cls):
        for finalizer in cls.finalizers:
            finalizer()

    def test_resource_filename_rewrites_on_change(self):
        """
        If a previous call to get_resource_filename has saved the file, but
        the file has been subsequently mutated with different file of the
        same size and modification time, it should not be overwritten on a
        subsequent call to get_resource_filename.
        """
        import mod
        manager = pkg_resources.ResourceManager()
        zp = pkg_resources.ZipProvider(mod)
        filename = zp.get_resource_filename(manager, 'data.dat')
        actual = datetime.datetime.fromtimestamp(os.stat(filename).st_mtime)
        assert actual == self.ref_time
        f = open(filename, 'w')
        f.write('hello, world?')
        f.close()
        ts = timestamp(self.ref_time)
        os.utime(filename, (ts, ts))
        filename = zp.get_resource_filename(manager, 'data.dat')
        f = open(filename)
        assert f.read() == 'hello, world!'
        manager.cleanup_resources()

class TestResourceManager(object):
    def test_get_cache_path(self):
        mgr = pkg_resources.ResourceManager()
        path = mgr.get_cache_path('foo')
        type_ = str(type(path))
        message = "Unexpected type from get_cache_path: " + type_
        assert isinstance(path, (unicode, str)), message


class TestIndependence:
    """
    Tests to ensure that pkg_resources runs independently from setuptools.
    """
    def test_setuptools_not_imported(self):
        """
        In a separate Python environment, import pkg_resources and assert
        that action doesn't cause setuptools to be imported.
        """
        lines = (
            'import pkg_resources',
            'import sys',
            'assert "setuptools" not in sys.modules, '
                '"setuptools was imported"',
        )
        cmd = [sys.executable, '-c', '; '.join(lines)]
        subprocess.check_call(cmd)



class TestEggInfoDistutils(object):

    version = '1.11.0.dev0+2329eae'
    setup_script = DALS("""
        from distutils.core import setup

        setup(
            name='foo',
            py_modules=['hello'],
            version='%s',
        )
        """)

    def _create_project(self):
        with open('setup.py', 'w') as f:
            f.write(self.setup_script % self.version)

        with open('hello.py', 'w') as f:
            f.write(DALS("""
                def run():
                    print('hello')
                """))

    @pytest.yield_fixture
    def env(self):
        class Environment(str):
            pass
        with contexts.tempdir(prefix='setuptools-test.') as env_dir:
            env = Environment(env_dir)
            os.chmod(env_dir, stat.S_IRWXU)
            subs = 'home', 'lib', 'scripts', 'data', 'egg-base'
            env.paths = dict(
                (dirname, os.path.join(env_dir, dirname))
                for dirname in subs
            )
            list(map(os.mkdir, env.paths.values()))
            config = os.path.join(env.paths['home'], '.pydistutils.cfg')
            with open(config, 'w') as f:
                f.write(DALS("""
                    [egg_info]
                    egg-base = %(egg-base)s
                    """ % env.paths))
            yield env

    def test_egg_base_installed_egg_info(self, tmpdir_cwd, env):
        self._create_project()

        environ = os.environ.copy().update(
            HOME=env.paths['home'],
        )
        cmd = [
            'install',
            '--home', env.paths['home'],
            '--install-lib', env.paths['lib'],
            '--install-scripts', env.paths['scripts'],
            '--install-data', env.paths['data'],
        ]
        code, data = environment.run_setup_py(
            cmd=cmd,
            pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
            data_stream=1,
            env=environ,
        )
        if code:
            raise AssertionError(data)

        actual = self._find_egg_info_file(env.paths['lib'])
        # On Py3k it can be e.g. foo-1.11.0.dev0_2329eae-py3.4.egg-info
        # but 2.7 doesn't add the Python version, so to be expedient we
        # just check our start and end, omitting the potential version num
        assert actual.startswith('foo-' + self.version.replace('+', '_'))
        assert actual.endswith('.egg-info')
        # this requirement parsing will raise a VersionConflict unless the
        # .egg-info file is parsed (see #419 on BitBucket)
        req = pkg_resources.Requirement.parse('foo>=1.9')
        dist = pkg_resources.WorkingSet([env.paths['lib']]).find(req)
        assert dist.version == self.version

    def _find_egg_info_file(self, root):
        # expect exactly one result
        result = (filename for dirpath, dirnames, filenames in os.walk(root)
                  for filename in filenames if filename.endswith('.egg-info'))
        result, = result
        return result


@@ -4942,26 +4942,29 @@
 est_
-egg_base_installed
+version_resolved_from
 _egg

Rename test to match intention.