"""
领域层异常类单元测试
"""

import pytest

from packages.domain.exceptions import (
    DomainError,
    NotFoundError,
    QuotaExceededError,
    ValidationError,
)


class TestDomainError:
    """DomainError 基类测试"""

    def test_is_exception(self):
        assert issubclass(DomainError, Exception)

    def test_raise_and_catch(self):
        with pytest.raises(DomainError):
            raise DomainError("test error")

    def test_error_message(self):
        err = DomainError("something went wrong")
        assert str(err) == "something went wrong"

    def test_empty_message(self):
        err = DomainError("")
        assert str(err) == ""


class TestNotFoundError:
    """NotFoundError 测试"""

    def test_is_domain_error(self):
        assert issubclass(NotFoundError, DomainError)

    def test_raise_and_catch_as_domain(self):
        with pytest.raises(DomainError):
            raise NotFoundError("resource not found")

    def test_raise_and_catch_specific(self):
        with pytest.raises(NotFoundError):
            raise NotFoundError("not found")

    def test_error_message(self):
        err = NotFoundError("user 123 not found")
        assert "user 123 not found" in str(err)


class TestValidationError:
    """ValidationError 测试"""

    def test_is_domain_error(self):
        assert issubclass(ValidationError, DomainError)

    def test_raise_and_catch_as_domain(self):
        with pytest.raises(DomainError):
            raise ValidationError("invalid input")

    def test_raise_and_catch_specific(self):
        with pytest.raises(ValidationError):
            raise ValidationError("validation failed")

    def test_error_message(self):
        err = ValidationError("name cannot be empty")
        assert "name cannot be empty" in str(err)


class TestQuotaExceededError:
    """QuotaExceededError 测试"""

    def test_is_domain_error(self):
        assert issubclass(QuotaExceededError, DomainError)

    def test_constructor_sets_attributes(self):
        err = QuotaExceededError(dimension="storage", limit=1024.0, used=2048.0)
        assert err.dimension == "storage"
        assert err.limit == 1024.0
        assert err.used == 2048.0

    def test_error_message_format(self):
        err = QuotaExceededError(dimension="storage", limit=1024.0, used=2048.0)
        msg = str(err)
        assert "storage" in msg
        assert "2048.0" in msg
        assert "1024.0" in msg
        assert "Quota exceeded" in msg

    def test_raise_and_catch_as_domain(self):
        with pytest.raises(DomainError):
            raise QuotaExceededError("projects", 10, 15)

    def test_raise_and_catch_specific(self):
        with pytest.raises(QuotaExceededError):
            raise QuotaExceededError("render", 5, 10)

    def test_zero_limit(self):
        err = QuotaExceededError(dimension="test", limit=0.0, used=1.0)
        assert err.limit == 0.0
        assert err.used == 1.0

    def test_negative_values(self):
        """负数也能存（领域层不做额外校验）"""
        err = QuotaExceededError(dimension="test", limit=-5.0, used=-3.0)
        assert err.limit == -5.0
        assert err.used == -3.0

    def test_large_values(self):
        err = QuotaExceededError(dimension="storage", limit=1e9, used=1.5e9)
        assert err.limit == 1e9
        assert err.used == 1.5e9
