#!/usr/bin/env python3
"""Tests of verify_exact.py: what it must accept, and every way it must refuse. Run: python test_verify_exact.py (verify_exact.py beside it)."""
import os
import subprocess
import sys
import tempfile

HERE = os.path.dirname(os.path.abspath(__file__))
SCRIPT = os.path.join(HERE, "verify_exact.py")
GOOD = "side,2\n0.5,0.5,0\n1.5,0.5,0\n0.5,1.5,0\n1.5,1.5,0\n"   # 4 unit squares in a box of 2: all touching, exactly fitting
TILTED = "side,3\n1.5,1.5,0.5\n"                                  # t = 1/2: cos = 3/5, sin = 4/5, one exact unit square turned
CASES = [
    # name, file, options, the exit code wanted, text wanted in the output
    ("exact fit, touching allowed", GOOD, [], 0, "PASS"),
    ("the count asked for", GOOD, ["--squares=4"], 0, "PASS"),
    ("one square short of the count", GOOD, ["--squares=5"], 1, "FAIL"),
    ("one square over the count", GOOD, ["--squares=3"], 1, "FAIL"),
    ("a turned exact unit square", TILTED, ["--squares=1"], 0, "unit squares exact"),
    ("a corner outside by a hair", "side,2\n0.5,0.5,0\n1.5000000000000000000000001,0.5,0\n", [], 1, "corners outside the box: 1"),
    ("under the origin by a hair", "side,2\n0.4999999999999999999999999,0.5,0\n", [], 1, "corners outside the box: 1"),
    ("two squares overlapping by a hair", "side,3\n0.5,0.5,0\n1.4999999999999999999999999,0.5,0\n", [], 1, "overlapping pairs: 1"),
    ("the same square twice", "side,3\n1,1,0\n1,1,0\n", [], 1, "overlapping pairs: 1"),
    ("one turned into another", "side,5\n2,2,0\n2.9,2,0.414\n", [], 1, "overlapping pairs: 1"),
    ("corner to corner, touching", "side,3\n0.5,0.5,0\n1.5,1.5,0\n", [], 0, "overlapping pairs: 0"),
    ("no squares", "side,2\n", [], 1, "FAIL"),
    ("a box of no size", "side,0\n", [], 1, "FAIL"),
    ("a negative box", "side,-1\n0,0,0\n", [], 1, "FAIL"),
    ("no side line", "0.5,0.5,0\n", [], 2, "REFUSED"),
    ("two side lines", "side,2\nside,3\n0.5,0.5,0\n", [], 2, "REFUSED"),
    ("rounded corners, a tiny square", "side,2\n0,0,0.1,0,0.1,0.1,0,0.1\n", [], 2, "REFUSED"),
    ("rounded corners, a unit square", "side,2\n0,0,1,0,1,1,0,1\n", [], 2, "REFUSED"),
    ("mixed forms, exact last", "side,4\n0,0,1,0,1,1,0,1\n2.5,2.5,0\n", [], 2, "REFUSED"),
    ("mixed forms, corners last", "side,4\n2.5,2.5,0\n0,0,1,0,1,1,0,1\n", [], 2, "REFUSED"),
    ("an angle column as well", "side,4\n0,2.5,2.5,0\n", [], 2, "REFUSED"),
    ("not a number", "side,2\nabc,0.5,0\n", [], 2, "REFUSED"),
    ("not a number: nan", "side,2\nnan,0.5,0\n", [], 2, "REFUSED"),
    ("not a number: infinity", "side,inf\n0.5,0.5,0\n", [], 2, "REFUSED"),
    ("a match within epsilon", GOOD, ["--reference=2.00000000001", "--epsilon=1e-10"], 0, "MATCH at"),
    ("on the edge of epsilon", GOOD, ["--reference=2.0000000001", "--epsilon=1e-10"], 0, "MATCH at"),
    ("just past epsilon", GOOD, ["--reference=2.0000000001000000000000001", "--epsilon=1e-10"], 1, "NO MATCH"),
    ("the difference printed exactly", GOOD, ["--reference=1.9999999999999999999999999"], 0, "+0.0000000000000000000000001"),
    ("a bad packing is no match, however close", "side,3\n1,1,0\n1,1,0\n", ["--reference=3", "--epsilon=1"], 1, "NO MATCH"),
]
failed = 0
with tempfile.TemporaryDirectory() as folder:
    for name, text, options, code, wanted in CASES:
        path = os.path.join(folder, "case.csv")
        with open(path, "w", encoding="utf-8") as f:
            f.write(text)
        run = subprocess.run([sys.executable, "-I", SCRIPT, path] + options, capture_output=True, text=True)
        good = run.returncode == code and wanted in run.stdout
        failed += not good
        print(f"{'ok  ' if good else 'FAIL'} {name}" + ("" if good else f": exit {run.returncode}, wanted {code}; {run.stdout.strip()} {run.stderr.strip()}"))
print(f"{len(CASES) - failed} of {len(CASES)} tests passed")
sys.exit(1 if failed else 0)
