"""Tests for the IXException + IXErrorCode error model (spec §8).""" from __future__ import annotations import pytest from ix.errors import IXErrorCode, IXException class TestIXErrorCode: """Every spec §8 code is present with its documented default message.""" def test_all_spec_codes_exist(self) -> None: expected = { "IX_000_000", "IX_000_002", "IX_000_004", "IX_000_005", "IX_000_006", "IX_000_007", "IX_001_000", "IX_001_001", "IX_002_000", "IX_002_001", } actual = {code.name for code in IXErrorCode} assert expected == actual def test_code_value_matches_name(self) -> None: # The enum value IS the string code. Tests at the call sites rely on # e.g. `IXErrorCode.IX_000_000.value == "IX_000_000"`. for code in IXErrorCode: assert code.value == code.name def test_default_messages_cover_spec_triggers(self) -> None: # Check a subset of the spec §8 trigger phrases show up in the default # message. We don't pin exact wording — just that the message is # recognisable for log-scraping. assert "request_ix" in IXErrorCode.IX_000_000.default_message assert "context" in IXErrorCode.IX_000_002.default_message assert "files" in IXErrorCode.IX_000_004.default_message assert "MIME" in IXErrorCode.IX_000_005.default_message assert "page" in IXErrorCode.IX_000_006.default_message.lower() assert "fetch" in IXErrorCode.IX_000_007.default_message.lower() assert "empty" in IXErrorCode.IX_001_000.default_message.lower() assert "use case" in IXErrorCode.IX_001_001.default_message.lower() assert "inference" in IXErrorCode.IX_002_000.default_message.lower() assert "structured output" in IXErrorCode.IX_002_001.default_message.lower() class TestIXException: def test_raise_returns_code_and_default_message(self) -> None: with pytest.raises(IXException) as exc_info: raise IXException(IXErrorCode.IX_000_000) exc = exc_info.value assert exc.code is IXErrorCode.IX_000_000 assert exc.detail is None s = str(exc) assert s.startswith("IX_000_000: ") assert "request_ix is None" in s assert "(detail=" not in s def test_exception_with_detail_includes_detail_in_str(self) -> None: exc = IXException(IXErrorCode.IX_000_007, detail="https://example/x.pdf: 404") s = str(exc) assert s.startswith("IX_000_007: ") assert "(detail=https://example/x.pdf: 404)" in s def test_exception_is_an_exception(self) -> None: exc = IXException(IXErrorCode.IX_001_001) assert isinstance(exc, Exception)