""" Tests for the LLMError exception hierarchy (Core). """ import pytest from llm_connect.exceptions import ( LLMError, LLMConfigurationError, LLMAPIError, LLMRateLimitError, LLMTimeoutError, LLMSubprocessError, ) class TestLLMErrorHierarchy: def test_all_are_subclasses_of_llm_error(self): assert issubclass(LLMConfigurationError, LLMError) assert issubclass(LLMAPIError, LLMError) assert issubclass(LLMRateLimitError, LLMError) assert issubclass(LLMTimeoutError, LLMError) assert issubclass(LLMSubprocessError, LLMError) def test_rate_limit_is_api_error(self): assert issubclass(LLMRateLimitError, LLMAPIError) def test_all_are_exceptions(self): assert issubclass(LLMError, Exception) class TestLLMError: def test_basic_message(self): err = LLMError("something went wrong") assert str(err) == "something went wrong" def test_context_appears_in_str(self): err = LLMError("oops", context={"provider": "openai"}) assert "provider=openai" in str(err) def test_cause_is_chained(self): cause = ValueError("root cause") err = LLMError("wrapper", cause=cause) assert err.__cause__ is cause def test_empty_context_does_not_appear(self): err = LLMError("clean message", context={}) assert str(err) == "clean message" class TestLLMAPIError: def test_has_status_code(self): err = LLMAPIError("bad request", status_code=400) assert err.status_code == 400 def test_has_response_body(self): err = LLMAPIError("error", status_code=500, response_body='{"error": "oops"}') assert err.response_body == '{"error": "oops"}' def test_defaults(self): err = LLMAPIError("minimal") assert err.status_code == 0 assert err.response_body == "" def test_rate_limit_inherits_status_code(self): err = LLMRateLimitError("too many", status_code=429) assert err.status_code == 429 assert isinstance(err, LLMAPIError) class TestLLMSubprocessError: def test_has_return_code(self): err = LLMSubprocessError("cli failed", return_code=1) assert err.return_code == 1 def test_has_stderr(self): err = LLMSubprocessError("cli failed", stderr="error output") assert err.stderr == "error output" def test_defaults(self): err = LLMSubprocessError("minimal") assert err.return_code == 1 assert err.stderr == "" class TestRaiseAndCatch: def test_catch_as_llm_error(self): with pytest.raises(LLMError): raise LLMConfigurationError("no key") def test_catch_api_error_as_llm_error(self): with pytest.raises(LLMError): raise LLMAPIError("http error", status_code=502) def test_catch_rate_limit_as_api_error(self): with pytest.raises(LLMAPIError): raise LLMRateLimitError("429", status_code=429)