"""Test cases for invoking mypyc on the command line.

These are slow -- do not add test cases unless you have a very good reason to do so.
"""

from __future__ import annotations

import glob
import os
import os.path
import re
import subprocess
import sys

from mypy.test.config import test_temp_dir
from mypy.test.data import DataDrivenTestCase
from mypy.test.helpers import normalize_error_messages
from mypyc.test.testutil import MypycDataSuite, assert_test_output

files = ["commandline.test"]


base_path = os.path.join(os.path.dirname(__file__), "..", "..")

python3_path = sys.executable


class TestCommandLine(MypycDataSuite):
    files = files
    base_path = test_temp_dir
    optional_out = True

    def run_case(self, testcase: DataDrivenTestCase) -> None:
        # Parse options from test case description (arguments must not have spaces)
        text = "\n".join(testcase.input)
        m = re.search(r"# *cmd: *(.*)", text)
        assert m is not None, 'Test case missing "# cmd: <files>" section'
        args = m.group(1).split()

        # Write main program to run (not compiled)
        program = "_%s.py" % testcase.name
        program_path = os.path.join(test_temp_dir, program)
        with open(program_path, "w") as f:
            f.write(text)

        env = os.environ.copy()
        env["PYTHONPATH"] = base_path

        out = b""
        try:
            # Compile program
            cmd = subprocess.run(
                [sys.executable, "-m", "mypyc", *args],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                cwd="tmp",
                env=env,
            )
            if "ErrorOutput" in testcase.name or cmd.returncode != 0:
                out += cmd.stdout
            elif "WarningOutput" in testcase.name:
                # Strip out setuptools build related output since we're only
                # interested in the messages emitted during compilation.
                messages, _, _ = cmd.stdout.partition(b"running build_ext")
                out += messages

            if cmd.returncode == 0:
                # Run main program
                out += subprocess.check_output([python3_path, program], cwd="tmp")
        finally:
            suffix = "pyd" if sys.platform == "win32" else "so"
            so_paths = glob.glob(f"tmp/**/*.{suffix}", recursive=True)
            for path in so_paths:
                os.remove(path)

        # Strip out 'tmp/' from error message paths in the testcase output,
        # due to a mismatch between this test and mypy's test suite.
        expected = [x.replace("tmp/", "") for x in testcase.output]

        # Verify output
        actual = normalize_error_messages(out.decode().splitlines())
        assert_test_output(testcase, actual, "Invalid output", expected=expected)
