"""
Error-path tests for the 'launch' command (e4s_cl/cli/commands/launch.py).

These tests verify that the command fails gracefully (non-zero exit) when
given incomplete or inconsistent arguments, and that a valid minimal invocation
succeeds in dry-run mode.  No MPI installation, container runtime, or network
access is required.
"""

import tests
from e4s_cl import EXIT_SUCCESS
from e4s_cl.variables import set_dry_run
from e4s_cl.model.profile import Profile
from e4s_cl.cli.commands.launch import COMMAND


class LaunchErrorPathTest(tests.TestCase):
    """Argument-validation error paths for LaunchCommand.main()."""

    def setUp(self):
        self.resetStorage()
        set_dry_run(False)

    def tearDown(self):
        set_dry_run(False)
        Profile.controller().unselect()
        self.resetStorage()

    # ------------------------------------------------------------------
    # Cases that must fail before any container or MPI call is made
    # ------------------------------------------------------------------

    def test_no_cmd_fails(self):
        """launch with no executable after the options must fail."""
        self.assertNotCommandReturnValue(
            EXIT_SUCCESS, COMMAND,
            ['--backend', 'containerless', '--image', 'some.img'])

    def test_missing_backend_without_profile_fails(self):
        """launch without --backend and no selected profile must fail."""
        self.assertNotCommandReturnValue(
            EXIT_SUCCESS, COMMAND, ['mpirun', '-n', '2', 'hostname'])

    def test_missing_image_without_profile_fails(self):
        """launch with --backend but no --image and no profile must fail."""
        self.assertNotCommandReturnValue(
            EXIT_SUCCESS, COMMAND,
            ['--backend', 'containerless', 'mpirun', 'hostname'])

    # ------------------------------------------------------------------
    # Cases that must succeed in dry-run mode
    # ------------------------------------------------------------------

    def test_barebones_backend_no_image_dry_run(self):
        """'barebones' backend is exempt from the image requirement."""
        set_dry_run(True)
        self.assertCommandReturnValue(
            EXIT_SUCCESS, COMMAND,
            ['--backend', 'barebones', 'mpirun', 'hostname'])

    def test_full_minimal_invocation_dry_run(self):
        """launch with backend + image + launcher + program succeeds in dry-run."""
        set_dry_run(True)
        self.assertCommandReturnValue(
            EXIT_SUCCESS, COMMAND,
            ['--backend', 'containerless', '--image', 'my.sif',
             'mpirun', '-n', '1', 'hostname'])


class LaunchProfileFallbackTest(tests.TestCase):
    """launch reads missing flags from a selected profile."""

    def setUp(self):
        self.resetStorage()
        set_dry_run(True)
        ctrl = Profile.controller()
        profile = ctrl.create({
            'name': 'test_profile',
            'backend': 'containerless',
            'image': 'profile.sif',
        })
        ctrl.select(profile)

    def tearDown(self):
        set_dry_run(False)
        Profile.controller().unselect()
        self.resetStorage()

    def test_launch_uses_profile_backend_and_image(self):
        """Specifying --profile supplies backend and image without extra flags."""
        # Pass --profile explicitly so the test is independent of parser
        # construction order (the parser default is evaluated at first use and
        # may be cached before setUp selects a profile).
        self.assertCommandReturnValue(
            EXIT_SUCCESS, COMMAND,
            ['--profile', 'test_profile', 'mpirun', '-n', '1', 'hostname'])
