"""
异常类测试
测试自定义异常
"""
import pytest
from xll_kit.database.exceptions import (
    DatabaseError,
    SQLBuilderError,
    ConnectionError,
    ExecutionError,
    ValidationError,
    TableNotFoundError,
)


class TestDatabaseError:
    """DatabaseError 基础异常测试"""

    def test_raise_database_error(self):
        """测试抛出 DatabaseError"""
        with pytest.raises(DatabaseError, match="Test error"):
            raise DatabaseError("Test error")

    def test_database_error_inheritance(self):
        """测试 DatabaseError 继承关系"""
        assert issubclass(DatabaseError, Exception)


class TestSQLBuilderError:
    """SQLBuilderError 测试"""

    def test_raise_sql_builder_error(self):
        """测试抛出 SQLBuilderError"""
        with pytest.raises(SQLBuilderError, match="Build failed"):
            raise SQLBuilderError("Build failed")

    def test_sql_builder_error_inheritance(self):
        """测试继承关系"""
        assert issubclass(SQLBuilderError, DatabaseError)

    def test_catch_as_database_error(self):
        """测试可以作为 DatabaseError 捕获"""
        with pytest.raises(DatabaseError):
            raise SQLBuilderError("Test")


class TestConnectionError:
    """ConnectionError 测试"""

    def test_raise_connection_error(self):
        """测试抛出 ConnectionError"""
        with pytest.raises(ConnectionError, match="Connection failed"):
            raise ConnectionError("Connection failed")

    def test_connection_error_inheritance(self):
        """测试继承关系"""
        assert issubclass(ConnectionError, DatabaseError)


class TestExecutionError:
    """ExecutionError 测试"""

    def test_raise_execution_error(self):
        """测试抛出 ExecutionError"""
        with pytest.raises(ExecutionError, match="Execution failed"):
            raise ExecutionError("Execution failed")

    def test_execution_error_with_sql(self):
        """测试带 SQL 的 ExecutionError"""
        error = ExecutionError(
            "Execution failed",
            sql="SELECT * FROM users",
            params={'id': 1}
        )

        assert error.sql == "SELECT * FROM users"
        assert error.params == {'id': 1}

    def test_execution_error_str_with_sql(self):
        """测试带 SQL 的字符串表示"""
        error = ExecutionError(
            "Execution failed",
            sql="SELECT * FROM users WHERE id = :id",
            params={'id': 1}
        )

        error_str = str(error)
        assert "Execution failed" in error_str
        assert "SQL:" in error_str

    def test_execution_error_str_without_sql(self):
        """测试不带 SQL 的字符串表示"""
        error = ExecutionError("Execution failed")

        error_str = str(error)
        assert error_str == "Execution failed"
        assert "SQL:" not in error_str


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

    def test_raise_validation_error(self):
        """测试抛出 ValidationError"""
        with pytest.raises(ValidationError, match="Invalid data"):
            raise ValidationError("Invalid data")

    def test_validation_error_inheritance(self):
        """测试继承关系"""
        assert issubclass(ValidationError, DatabaseError)


class TestTableNotFoundError:
    """TableNotFoundError 测试"""

    def test_raise_table_not_found_error(self):
        """测试抛出 TableNotFoundError"""
        with pytest.raises(TableNotFoundError):
            raise TableNotFoundError("users")

    def test_table_not_found_error_message(self):
        """测试错误消息"""
        error = TableNotFoundError("users")

        assert error.table_name == "users"
        assert "users" in str(error)
        assert "not found" in str(error).lower()

    def test_table_not_found_error_inheritance(self):
        """测试继承关系"""
        assert issubclass(TableNotFoundError, DatabaseError)


class TestExceptionHierarchy:
    """测试异常层级"""

    def test_all_inherit_from_database_error(self):
        """测试所有异常都继承自 DatabaseError"""
        exceptions = [
            SQLBuilderError,
            ConnectionError,
            ExecutionError,
            ValidationError,
            TableNotFoundError,
        ]

        for exc_class in exceptions:
            assert issubclass(exc_class, DatabaseError)

    def test_catch_all_with_database_error(self):
        """测试可以用 DatabaseError 捕获所有子异常"""
        exceptions_to_test = [
            SQLBuilderError("test"),
            ConnectionError("test"),
            ExecutionError("test"),
            ValidationError("test"),
            TableNotFoundError("test"),
        ]

        for exc in exceptions_to_test:
            with pytest.raises(DatabaseError):
                raise exc