"""Unit tests for python/q16_canonical.py.

These are the canonical Q16_16 roundtrip witnesses.  Every change to the Python
fixed-point shim must keep them green.
"""

import math

import pytest

from python.q16_canonical import (
    Q16_MAX_FLOAT,
    Q16_MIN_FLOAT,
    Q16_SCALE,
    float_to_q16,
    q16_to_float,
)


def test_float_to_q16_zero():
    assert float_to_q16(0.0) == 0


def test_float_to_q16_one():
    assert float_to_q16(1.0) == Q16_SCALE


def test_float_to_q16_negative():
    assert float_to_q16(-1.0) == -Q16_SCALE


def test_float_to_q16_pi_approx():
    raw = float_to_q16(math.pi)
    # π ≈ 3.1415926535 → raw ≈ 205887
    assert 205880 < raw < 205895


def test_q16_to_float_one():
    assert q16_to_float(Q16_SCALE) == 1.0


def test_roundtrip_typical_values():
    for x in [0.0, 1.0, -1.0, 3.1415926535, -1234.5678, 32767.5]:
        raw = float_to_q16(x)
        recovered = q16_to_float(raw)
        assert abs(recovered - x) < 1.5e-5


def test_rejects_nan():
    with pytest.raises(ValueError):
        float_to_q16(float("nan"))


def test_rejects_inf():
    with pytest.raises(ValueError):
        float_to_q16(float("inf"))


def test_clamps_max():
    raw = float_to_q16(1e12)
    assert q16_to_float(raw) <= Q16_MAX_FLOAT


def test_clamps_min():
    raw = float_to_q16(-1e12)
    assert q16_to_float(raw) >= Q16_MIN_FLOAT
