"""Test cases for the SQL module in the Numinar coding project backend.""" from typing import Any from typing import AsyncGenerator from unittest.mock import AsyncMock from unittest.mock import patch import pytest import pytest_asyncio from sqlalchemy.ext.asyncio import AsyncSession from sqlmodel import SQLModel # Assuming the module is named `database.py` and contains the provided code from backend.sql import create_db_and_tables from backend.sql import engine from backend.sql import sessionize @pytest_asyncio.fixture async def mock_async_sessionmaker() -> AsyncGenerator[AsyncMock, None]: """Fixture to mock the async sessionmaker for testing sessionize decorator. Yields: AsyncMock: A mocked async sessionmaker that returns a mocked AsyncSession. """ with patch("backend.sql.async_sessionmaker") as mock_sessionmaker: mock_session: AsyncMock = AsyncMock(spec=AsyncSession) mock_sessionmaker.return_value = AsyncMock(return_value=mock_session) yield mock_sessionmaker @pytest.mark.asyncio async def test_sessionize_decorator_with_no_session( mock_async_sessionmaker: AsyncMock, ) -> None: """Test the sessionize decorator when no session is provided. Verifies that the decorator creates a new session and passes it to the function, and that the function executes correctly. """ @sessionize async def test_func(session: AsyncSession | None = None) -> str: setattr(test_func, "session", session) # noqa: B010 return "success" result: str = await test_func() assert result == "success" assert test_func.session is not None # type: ignore @pytest.mark.asyncio async def test_sessionize_decorator_with_session( mock_async_sessionmaker: AsyncMock, ) -> None: """Test the sessionize decorator when a session is provided. Verifies that the decorator uses the provided session without creating a new one, and that the function executes correctly. """ @sessionize async def test_func(session: AsyncSession | None = None) -> str: setattr(test_func, "session", session) # noqa: B010 return "success" mock_session: AsyncMock = AsyncMock(spec=AsyncSession) result: str = await test_func(session=mock_session) assert result == "success" assert mock_session is test_func.session # type: ignore @pytest.mark.asyncio async def test_sessionize_decorator_error_handling( mock_async_sessionmaker: AsyncMock, ) -> None: """Test the sessionize decorator's error handling. Verifies that the decorator properly handles exceptions raised by the decorated function and ensures the session is created when none is provided. """ @sessionize async def test_func(session: AsyncSession) -> None: setattr(test_func, "session", session) # noqa: B010 raise ValueError("Test error") with pytest.raises(ValueError, match="Test error"): await test_func() @pytest.mark.asyncio @pytest.mark.parametrize( "func_return_value", ["result1", 42, None], ids=["string", "integer", "none"], ) async def test_sessionize_decorator_return_types( mock_async_sessionmaker: AsyncMock, func_return_value: Any ) -> None: """Test the sessionize decorator with different return types. Verifies that the decorator correctly handles various return types from the decorated function. Args: mock_async_sessionmaker: Mocked async sessionmaker. func_return_value: The value to be returned by the test function. """ @sessionize async def test_func(session: AsyncSession) -> Any: setattr(test_func, "session", session) # noqa: B010 return func_return_value result: Any = await test_func() assert result == func_return_value def test_create_db_and_tables() -> None: """Test the create_db_and_tables function. Verifies that the function correctly calls SQLModel.metadata.create_all with the synchronous engine. """ with patch.object(SQLModel.metadata, "create_all") as mock_create_all: create_db_and_tables() mock_create_all.assert_called_once_with(engine.sync_engine)