# `Projects/veritell-langchain/tests/test_fail_open_semantics.py`
import pytest

from veritell_langchain.errors import ServiceUnavailableError, VeritellTimeoutError
from veritell_langchain.fail_open import fail_open_or_raise
from veritell_langchain.schema import SCHEMA_VERSION, VeritellEvaluationResult


def test_c14_fail_open_false_raises_on_timeout() -> None:
    with pytest.raises(VeritellTimeoutError):
        fail_open_or_raise(
            exc=VeritellTimeoutError("timeout"),
            fail_open=False,
        )


def test_c14_fail_open_true_returns_default_on_timeout() -> None:
    result = fail_open_or_raise(
        exc=VeritellTimeoutError("timeout"),
        fail_open=True,
    )
    assert isinstance(result, VeritellEvaluationResult)
    assert result.schema_version == SCHEMA_VERSION
    assert result.extra.get("fail_open") is True
    assert result.extra.get("reason") == "timeout"


def test_c14_fail_open_false_raises_on_service_unavailable() -> None:
    with pytest.raises(ServiceUnavailableError):
        fail_open_or_raise(
            exc=ServiceUnavailableError("503"),
            fail_open=False,
        )


def test_c14_fail_open_true_returns_default_on_service_unavailable() -> None:
    result = fail_open_or_raise(
        exc=ServiceUnavailableError("503"),
        fail_open=True,
    )
    assert result.schema_version == SCHEMA_VERSION
    assert result.extra.get("fail_open") is True
    assert result.extra.get("reason") == "service_unavailable"


def test_c14_fail_open_true_does_not_swallow_other_errors() -> None:
    class OtherError(RuntimeError):
        pass

    with pytest.raises(OtherError):
        fail_open_or_raise(
            exc=OtherError("boom"),
            fail_open=True,
        )
