"""
Test that a process launched through an aliased directory reports its modules
under that directory, so LLDB does not duplicate the modules it already has.

The target is created from a junction to the build directory. LLDB must report
the executable and the DLL next to it with the path the Windows loader
recorded, which keeps the junction, rather than with the resolved path, which
does not. Otherwise LLDB adds a second module for each file and the breakpoints
get a location in both.
"""

import os
import subprocess

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


@requireWindows
@skipIfRemote
class TestModuleAliasedPath(TestBase):
    NO_DEBUG_INFO_TESTCASE = True

    def make_junction(self, real_dir):
        """Create a junction to real_dir, skipping the test if the host can't
        create one."""
        alias_dir = real_dir + ".alias"
        try:
            if os.path.lexists(alias_dir):
                os.rmdir(alias_dir)
            subprocess.run(
                'mklink /J "%s" "%s"' % (alias_dir, real_dir),
                shell=True,
                check=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.PIPE,
                text=True,
            )
        except (OSError, subprocess.CalledProcessError) as e:
            detail = getattr(e, "stderr", None) or e
            self.skipTest("could not create a junction: %s" % detail)
        self.addTearDownHook(lambda: os.rmdir(alias_dir))
        self.assertNotEqual(os.path.realpath(alias_dir), alias_dir)
        return alias_dir

    def test_launch_through_aliased_path(self):
        self.build()

        alias_dir = self.make_junction(self.getBuildDir())

        target = self.dbg.CreateTarget(os.path.join(alias_dir, "a.out"))
        self.assertTrue(target, VALID_TARGET)
        main_bkpt = target.BreakpointCreateBySourceRegex(
            "break main", lldb.SBFileSpec("main.c")
        )
        foo_bkpt = target.BreakpointCreateBySourceRegex(
            "break here", lldb.SBFileSpec("foo.c")
        )
        self.assertEqual(main_bkpt.GetNumLocations(), 1)

        process = target.LaunchSimple(None, None, self.get_process_working_directory())
        self.assertState(process.GetState(), lldb.eStateStopped)
        self.assertIsNotNone(
            lldbutil.get_one_thread_stopped_at_breakpoint(process, main_bkpt)
        )

        lib_name = self.platformContext.getFullLibName("foo")
        for name in ["a.out", lib_name]:
            paths = [
                m.GetFileSpec().fullpath
                for m in target.module_iter()
                if m.GetFileSpec().GetFilename() == name
            ]
            self.assertEqual(len(paths), 1, "one module for %s: %s" % (name, paths))
            self.assertTrue(
                paths[0].lower().startswith(alias_dir.lower()),
                "%s is reported under the junction" % paths[0],
            )

        for bkpt in [main_bkpt, foo_bkpt]:
            self.assertEqual(bkpt.GetNumLocations(), 1)
            self.assertEqual(bkpt.GetNumResolvedLocations(), 1)

        process.Continue()
        self.assertIsNotNone(
            lldbutil.get_one_thread_stopped_at_breakpoint(process, foo_bkpt)
        )
