import re
import sys

from joblib.testing import check_subprocess_call, raises


def test_check_subprocess_call():
    code = "\n".join(
        ["result = 1 + 2 * 3", "print(result)", "my_list = [1, 2, 3]", "print(my_list)"]
    )

    check_subprocess_call([sys.executable, "-c", code])

    # Now checking stdout with a regex
    check_subprocess_call(
        [sys.executable, "-c", code],
        # Regex needed for platform-specific line endings
        stdout_regex=r"7\s{1,2}\[1, 2, 3\]",
    )


def test_check_subprocess_call_non_matching_regex():
    code = "42"
    non_matching_pattern = "_no_way_this_matches_anything_"

    with raises(ValueError) as excinfo:
        check_subprocess_call(
            [sys.executable, "-c", code], stdout_regex=non_matching_pattern
        )
    excinfo.match("Unexpected stdout.+{}".format(non_matching_pattern))


def test_check_subprocess_call_wrong_command():
    wrong_command = "_a_command_that_does_not_exist_"
    with raises(OSError):
        check_subprocess_call([wrong_command])


def test_check_subprocess_call_non_zero_return_code():
    code_with_non_zero_exit = "\n".join(
        [
            "import sys",
            'print("writing on stdout")',
            'sys.stderr.write("writing on stderr")',
            "sys.exit(123)",
        ]
    )

    pattern = re.compile(
        "Non-zero return code: 123.+"
        "Stdout:\nwriting on stdout.+"
        "Stderr:\nwriting on stderr",
        re.DOTALL,
    )

    with raises(ValueError) as excinfo:
        check_subprocess_call([sys.executable, "-c", code_with_non_zero_exit])
    excinfo.match(pattern)


def test_check_subprocess_call_timeout():
    code_timing_out = "\n".join(
        [
            "import time",
            "import sys",
            'print("before sleep on stdout")',
            "sys.stdout.flush()",
            'sys.stderr.write("before sleep on stderr")',
            "sys.stderr.flush()",
            # We need to sleep for at least 2 * timeout seconds in case the SIGKILL
            # is triggered.
            "time.sleep(10)",
            'print("process should have be killed before")',
            "sys.stdout.flush()",
        ]
    )

    pattern = re.compile(
        "Non-zero return code:.+"
        "Stdout:\nbefore sleep on stdout\\s+"
        "Stderr:\nbefore sleep on stderr",
        re.DOTALL,
    )

    with raises(ValueError) as excinfo:
        check_subprocess_call([sys.executable, "-c", code_timing_out], timeout=1)
    excinfo.match(pattern)
