# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import unicode_literals

import json
import os
import shutil
import subprocess
import sys
import tempfile
import unittest

from mozfile.mozfile import NamedTemporaryFile

from mozunit import main

from mach.logging import LoggingManager

from mozbuild.base import (
    BadEnvironmentException,
    MachCommandBase,
    MozbuildObject,
    ObjdirMismatchException,
    PathArgument,
)

from mozbuild.backend.configenvironment import ConfigEnvironment
from buildconfig import topsrcdir, topobjdir


curdir = os.path.dirname(__file__)
log_manager = LoggingManager()


class TestMozbuildObject(unittest.TestCase):
    def setUp(self):
        self._old_cwd = os.getcwd()
        self._old_env = dict(os.environ)
        os.environ.pop('MOZCONFIG', None)
        os.environ.pop('MOZ_OBJDIR', None)

    def tearDown(self):
        os.chdir(self._old_cwd)
        os.environ.clear()
        os.environ.update(self._old_env)

    def get_base(self, topobjdir=None):
        return MozbuildObject(topsrcdir, None, log_manager, topobjdir=topobjdir)

    def test_objdir_config_guess(self):
        base = self.get_base()

        with NamedTemporaryFile() as mozconfig:
            os.environ[b'MOZCONFIG'] = mozconfig.name

            self.assertIsNotNone(base.topobjdir)
            self.assertEqual(len(base.topobjdir.split()), 1)
            self.assertTrue(base.topobjdir.endswith(base._config_guess))
            self.assertTrue(os.path.isabs(base.topobjdir))
            self.assertTrue(base.topobjdir.startswith(topsrcdir))

    def test_objdir_trailing_slash(self):
        """Trailing slashes in topobjdir should be removed."""
        base = self.get_base()

        with NamedTemporaryFile() as mozconfig:
            mozconfig.write('mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/')
            mozconfig.flush()
            os.environ[b'MOZCONFIG'] = mozconfig.name

            self.assertEqual(base.topobjdir, os.path.join(base.topsrcdir,
                'foo'))
            self.assertTrue(base.topobjdir.endswith('foo'))

    def test_objdir_config_status(self):
        """Ensure @CONFIG_GUESS@ is handled when loading mozconfig."""
        base = self.get_base()
        cmd = base._normalize_command(
            [os.path.join(topsrcdir, 'build', 'autoconf', 'config.guess')],
            True)
        guess = subprocess.check_output(cmd, cwd=topsrcdir).strip()

        # There may be symlinks involved, so we use real paths to ensure
        # path consistency.
        d = os.path.realpath(tempfile.mkdtemp())
        try:
            mozconfig = os.path.join(d, 'mozconfig')
            with open(mozconfig, 'wt') as fh:
                fh.write('mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/@CONFIG_GUESS@')
            print('Wrote mozconfig %s' % mozconfig)

            topobjdir = os.path.join(d, 'foo', guess)
            os.makedirs(topobjdir)

            # Create a fake topsrcdir.
            guess_path = os.path.join(d, 'build', 'autoconf', 'config.guess')
            os.makedirs(os.path.dirname(guess_path))
            shutil.copy(os.path.join(topsrcdir, 'build', 'autoconf',
                'config.guess',), guess_path)

            mozinfo = os.path.join(topobjdir, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump(dict(
                    topsrcdir=d,
                    mozconfig=mozconfig,
                ), fh)

            os.environ[b'MOZCONFIG'] = mozconfig.encode('utf-8')
            os.chdir(topobjdir)

            obj = MozbuildObject.from_environment(
                detect_virtualenv_mozinfo=False)

            self.assertEqual(obj.topobjdir, topobjdir)
        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    def test_relative_objdir(self):
        """Relative defined objdirs are loaded properly."""
        d = os.path.realpath(tempfile.mkdtemp())
        try:
            mozconfig = os.path.join(d, 'mozconfig')
            with open(mozconfig, 'wt') as fh:
                fh.write('mk_add_options MOZ_OBJDIR=./objdir')

            topobjdir = os.path.join(d, 'objdir')
            os.mkdir(topobjdir)

            mozinfo = os.path.join(topobjdir, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump(dict(
                    topsrcdir=d,
                    mozconfig=mozconfig,
                ), fh)

            os.environ[b'MOZCONFIG'] = mozconfig.encode('utf-8')
            child = os.path.join(topobjdir, 'foo', 'bar')
            os.makedirs(child)
            os.chdir(child)

            obj = MozbuildObject.from_environment(
                detect_virtualenv_mozinfo=False)

            self.assertEqual(obj.topobjdir, topobjdir)

        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    @unittest.skipIf(not hasattr(os, 'symlink'), 'symlinks not available.')
    def test_symlink_objdir(self):
        """Objdir that is a symlink is loaded properly."""
        d = os.path.realpath(tempfile.mkdtemp())
        try:
            topobjdir_real = os.path.join(d, 'objdir')
            topobjdir_link = os.path.join(d, 'objlink')

            os.mkdir(topobjdir_real)
            os.symlink(topobjdir_real, topobjdir_link)

            mozconfig = os.path.join(d, 'mozconfig')
            with open(mozconfig, 'wt') as fh:
                fh.write('mk_add_options MOZ_OBJDIR=%s' % topobjdir_link)

            mozinfo = os.path.join(topobjdir_real, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump(dict(
                    topsrcdir=d,
                    mozconfig=mozconfig,
                ), fh)

            os.chdir(topobjdir_link)
            obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)
            self.assertEqual(obj.topobjdir, topobjdir_real)

            os.chdir(topobjdir_real)
            obj = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)
            self.assertEqual(obj.topobjdir, topobjdir_real)

        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    def test_mach_command_base_inside_objdir(self):
        """Ensure a MachCommandBase constructed from inside the objdir works."""

        d = os.path.realpath(tempfile.mkdtemp())

        try:
            topobjdir = os.path.join(d, 'objdir')
            os.makedirs(topobjdir)

            topsrcdir = os.path.join(d, 'srcdir')
            os.makedirs(topsrcdir)

            mozinfo = os.path.join(topobjdir, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump(dict(
                    topsrcdir=topsrcdir,
                ), fh)

            os.chdir(topobjdir)

            class MockMachContext(object):
                pass

            context = MockMachContext()
            context.cwd = topobjdir
            context.topdir = topsrcdir
            context.settings = None
            context.log_manager = None
            context.detect_virtualenv_mozinfo=False

            o = MachCommandBase(context)

            self.assertEqual(o.topobjdir, topobjdir)
            self.assertEqual(o.topsrcdir, topsrcdir)

        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    def test_objdir_is_srcdir_rejected(self):
        """Ensure the srcdir configurations are rejected."""
        d = os.path.realpath(tempfile.mkdtemp())

        try:
            # The easiest way to do this is to create a mozinfo.json with data
            # that will never happen.
            mozinfo = os.path.join(d, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump({'topsrcdir': d}, fh)

            os.chdir(d)

            with self.assertRaises(BadEnvironmentException):
                MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)

        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    def test_objdir_mismatch(self):
        """Ensure MachCommandBase throwing on objdir mismatch."""
        d = os.path.realpath(tempfile.mkdtemp())

        try:
            real_topobjdir = os.path.join(d, 'real-objdir')
            os.makedirs(real_topobjdir)

            topobjdir = os.path.join(d, 'objdir')
            os.makedirs(topobjdir)

            topsrcdir = os.path.join(d, 'srcdir')
            os.makedirs(topsrcdir)

            mozconfig = os.path.join(d, 'mozconfig')
            with open(mozconfig, 'wt') as fh:
                fh.write('mk_add_options MOZ_OBJDIR=%s' % real_topobjdir)

            mozinfo = os.path.join(topobjdir, 'mozinfo.json')
            with open(mozinfo, 'wt') as fh:
                json.dump(dict(
                    topsrcdir=topsrcdir,
                    mozconfig=mozconfig,
                ), fh)

            os.chdir(topobjdir)

            with self.assertRaises(ObjdirMismatchException):
                MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)

        finally:
            os.chdir(self._old_cwd)
            shutil.rmtree(d)

    def test_config_guess(self):
        # It's difficult to test for exact values from the output of
        # config.guess because they vary depending on platform.
        base = self.get_base()
        result = base._config_guess

        self.assertIsNotNone(result)
        self.assertGreater(len(result), 0)

    def test_config_environment(self):
        base = self.get_base(topobjdir=topobjdir)

        ce = base.config_environment
        self.assertIsInstance(ce, ConfigEnvironment)

        self.assertEqual(base.defines, ce.defines)
        self.assertEqual(base.substs, ce.substs)

        self.assertIsInstance(base.defines, dict)
        self.assertIsInstance(base.substs, dict)

    def test_get_binary_path(self):
        base = self.get_base(topobjdir=topobjdir)

        platform = sys.platform

        # We should ideally use the config.status from the build. Let's install
        # a fake one.
        substs = [
            ('MOZ_APP_NAME', 'awesomeapp'),
            ('MOZ_BUILD_APP', 'awesomeapp'),
        ]
        if sys.platform.startswith('darwin'):
            substs.append(('OS_ARCH', 'Darwin'))
            substs.append(('BIN_SUFFIX', ''))
            substs.append(('MOZ_MACBUNDLE_NAME', 'Nightly.app'))
        elif sys.platform.startswith(('win32', 'cygwin')):
            substs.append(('OS_ARCH', 'WINNT'))
            substs.append(('BIN_SUFFIX', '.exe'))
        else:
            substs.append(('OS_ARCH', 'something'))
            substs.append(('BIN_SUFFIX', ''))

        base._config_environment = ConfigEnvironment(base.topsrcdir,
            base.topobjdir, substs=substs)

        p = base.get_binary_path('xpcshell', False)
        if platform.startswith('darwin'):
            self.assertTrue(p.endswith('Contents/MacOS/xpcshell'))
        elif platform.startswith(('win32', 'cygwin')):
            self.assertTrue(p.endswith('xpcshell.exe'))
        else:
            self.assertTrue(p.endswith('dist/bin/xpcshell'))

        p = base.get_binary_path(validate_exists=False)
        if platform.startswith('darwin'):
            self.assertTrue(p.endswith('Contents/MacOS/awesomeapp'))
        elif platform.startswith(('win32', 'cygwin')):
            self.assertTrue(p.endswith('awesomeapp.exe'))
        else:
            self.assertTrue(p.endswith('dist/bin/awesomeapp'))

        p = base.get_binary_path(validate_exists=False, where="staged-package")
        if platform.startswith('darwin'):
            self.assertTrue(p.endswith('awesomeapp/Nightly.app/Contents/MacOS/awesomeapp'))
        elif platform.startswith(('win32', 'cygwin')):
            self.assertTrue(p.endswith('awesomeapp\\awesomeapp.exe'))
        else:
            self.assertTrue(p.endswith('awesomeapp/awesomeapp'))

        self.assertRaises(Exception, base.get_binary_path, where="somewhere")

        p = base.get_binary_path('foobar', validate_exists=False)
        if platform.startswith('win32'):
            self.assertTrue(p.endswith('foobar.exe'))
        else:
            self.assertTrue(p.endswith('foobar'))

class TestPathArgument(unittest.TestCase):
    def test_path_argument(self):
        # Absolute path
        p = PathArgument("/obj/foo", "/src", "/obj", "/src")
        self.assertEqual(p.relpath(), "foo")
        self.assertEqual(p.srcdir_path(), "/src/foo")
        self.assertEqual(p.objdir_path(), "/obj/foo")

        # Relative path within srcdir
        p = PathArgument("foo", "/src", "/obj", "/src")
        self.assertEqual(p.relpath(), "foo")
        self.assertEqual(p.srcdir_path(), "/src/foo")
        self.assertEqual(p.objdir_path(), "/obj/foo")

        # Relative path within subdirectory
        p = PathArgument("bar", "/src", "/obj", "/src/foo")
        self.assertEqual(p.relpath(), "foo/bar")
        self.assertEqual(p.srcdir_path(), "/src/foo/bar")
        self.assertEqual(p.objdir_path(), "/obj/foo/bar")

        # Relative path within objdir
        p = PathArgument("foo", "/src", "/obj", "/obj")
        self.assertEqual(p.relpath(), "foo")
        self.assertEqual(p.srcdir_path(), "/src/foo")
        self.assertEqual(p.objdir_path(), "/obj/foo")

        # "." path
        p = PathArgument(".", "/src", "/obj", "/src/foo")
        self.assertEqual(p.relpath(), "foo")
        self.assertEqual(p.srcdir_path(), "/src/foo")
        self.assertEqual(p.objdir_path(), "/obj/foo")

        # Nested src/obj directories
        p = PathArgument("bar", "/src", "/src/obj", "/src/obj/foo")
        self.assertEqual(p.relpath(), "foo/bar")
        self.assertEqual(p.srcdir_path(), "/src/foo/bar")
        self.assertEqual(p.objdir_path(), "/src/obj/foo/bar")

if __name__ == '__main__':
    main()
