from __future__ import annotations import pytest import v1.auth.gateway as auth_gateway_module from v1.auth.schemas import ( AuthTokenResponse, AuthUserByEmailResponse, AuthUser, LoginRequest, RefreshRequest, SignupRequest, ) from v1.auth.service import AuthService, AuthServiceGateway class FakeGateway(AuthServiceGateway): def __init__(self, response: AuthTokenResponse) -> None: self._response = response async def signup(self, request: SignupRequest) -> AuthTokenResponse: return self._response async def login(self, request: LoginRequest) -> AuthTokenResponse: return self._response async def refresh(self, request: RefreshRequest) -> AuthTokenResponse: return self._response async def logout(self, refresh_token: str | None) -> None: return None async def get_user_by_email(self, email: str) -> AuthUserByEmailResponse: return AuthUserByEmailResponse( id="user-1", email=email, created_at="2026-02-24T00:00:00Z", email_confirmed_at=None, ) @pytest.mark.asyncio async def test_signup_maps_response() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) service = AuthService(gateway=FakeGateway(token_response)) result = await service.signup( SignupRequest(username="demo", email="user@example.com", password="secret123") ) assert result.access_token == "access" assert result.refresh_token == "refresh" assert result.user.id == "user-1" class LogoutAssertingGateway(AuthServiceGateway): def __init__(self, expected_refresh_token: str) -> None: self._expected_refresh_token = expected_refresh_token async def signup(self, request: SignupRequest) -> AuthTokenResponse: raise NotImplementedError async def login(self, request: LoginRequest) -> AuthTokenResponse: raise NotImplementedError async def refresh(self, request: RefreshRequest) -> AuthTokenResponse: raise NotImplementedError async def logout(self, refresh_token: str | None) -> None: assert refresh_token == self._expected_refresh_token async def get_user_by_email(self, email: str) -> AuthUserByEmailResponse: raise NotImplementedError @pytest.mark.asyncio async def test_logout_forwards_refresh_token() -> None: service = AuthService(gateway=LogoutAssertingGateway("refresh-token")) await service.logout("refresh-token") @pytest.mark.asyncio async def test_get_user_by_email_forwards_to_gateway() -> None: user = AuthUser(id="user-1", email="user@example.com") token_response = AuthTokenResponse( access_token="access", refresh_token="refresh", expires_in=3600, token_type="bearer", user=user, ) service = AuthService(gateway=FakeGateway(token_response)) result = await service.get_user_by_email("user@example.com") assert result.email == "user@example.com" @pytest.mark.asyncio async def test_supabase_signup_passes_username_in_metadata( monkeypatch: pytest.MonkeyPatch, ) -> None: captured_payload: dict[str, object] = {} class FakeSupabaseAuth: def sign_up(self, payload: dict[str, object]) -> object: captured_payload.update(payload) class _User: id = "user-1" email = "user@example.com" class _Session: access_token = "access" refresh_token = "refresh" expires_in = 3600 token_type = "bearer" class _Response: user = _User() session = _Session() return _Response() class FakeClient: auth = FakeSupabaseAuth() monkeypatch.setattr(auth_gateway_module, "create_client", lambda *_: FakeClient()) gateway = auth_gateway_module.SupabaseAuthGateway() await gateway.signup( SignupRequest( username="demo", email="user@example.com", password="secret123", ) ) assert captured_payload["data"] == {"username": "demo"}