# Exam 1 Tests - Problem 1 (10 of 20 points)
import pytest
import subprocess
import re
import math

basename = "p1"

def run_with_args(filename, *args):
    try:
        args = [str(a) for a in args]
        command = ["python3", filename + ".py", *args]
        return subprocess.check_output(command, text=True).rstrip("\n")
    except subprocess.CalledProcessError as e:
        print(f"\nProgram crashed with exit code {e.returncode}")
        if e.output:
            print(f"Output before crash: {e.output}")
        if e.stderr:
            print(f"Error message: {e.stderr}")
        raise AssertionError() from None

# Test cases: ( (input_fahrenheit,), (expected_temperature, expected_string) )
test_cases = [
    ((68,), (20.0, "is nice")), # 20 C
    ((41,), (5.0, "put a coat on")), # 5 C
    ((212,), (100.0, "would be a world record. Are you sure?")), # 100 C (above record high)

    # World record checks
    ((140,), (60.0, "would be a world record. Are you sure?")), # Above high record
    ((-130,), (-90.0, "would be a world record. Are you sure?")), # Below low record
    ((134.1,), (56.72222222222222, "is hot")), # Exact high record (not >)
    ((-128.6,), (-89.22222222222223, "is ice")), # Exact low record (not <)

    # Temperature category checks
    ((86,), (30.0, "is hot")),      # 30 C (>= 25)
    ((77,), (25.0, "is hot")),      # 25 C (>= 25)
    ((76,), (24.444444444444443, "is nice")), # ~24.4 C (>= 15)
    ((59,), (15.0, "is nice")),     # 15 C (>= 15)
    ((58,), (14.444444444444445, "put a coat on")), # ~14.4 C (> 0)
    ((33,), (0.5555555555555556, "put a coat on")), # ~0.6 C (> 0)
    ((32,), (0.0, "is ice")),       # 0 C (<= 0)
    ((-4,), (-20.0, "is ice")),     # -20 C (<= 0)
]

@pytest.mark.parametrize("test_case", test_cases)
def test_temperature_conversion(test_case):
    """ Tests whether correct temperature is present in the output. """
    args, (expected_temp, expected_str) = test_case
    output = run_with_args(basename, *args)

    floats = [float(f) for f in re.findall(r"[-+]?(?:\d*\.*\d+)", output)]
    assert any([math.isclose(f, expected_temp, rel_tol=0.01) for f in floats])

@pytest.mark.parametrize("test_case", test_cases)
def test_string_output(test_case):
    """Tests the string output against expected results."""
    args, (expected_temp, expected_str) = test_case
    output = run_with_args(basename, *args)

    output_str = output.split(" ", maxsplit=1)[1]

    assert output_str == expected_str 

if __name__ == "__main__":
    import sys
    if "--one" in sys.argv:
        flags = "-xvs"
    else:
        flags = "-v"
    pytest.main(["p1_test.py", flags,  "-p", "no:faulthandler"])
