from __future__ import annotations from typing import Callable from uuid import UUID from fastapi import HTTPException from fastapi.testclient import TestClient from app import app from core.auth.models import CurrentUser from v1.profile.dependencies import get_current_user, get_profile_service from v1.profile.schemas import ProfileResponse, ProfileUpdateRequest from v1.profile.service import ProfileService class FakeProfileService: """Fake service for integration testing.""" def __init__(self, profile: ProfileResponse) -> None: self._profile = profile async def get_me(self) -> ProfileResponse: if self._profile.id is None: raise HTTPException(status_code=404, detail="Profile not found") return self._profile async def update_me(self, update: ProfileUpdateRequest) -> ProfileResponse: if self._profile.id is None: raise HTTPException(status_code=404, detail="Profile not found") return ProfileResponse( id=self._profile.id, username=self._profile.username, display_name=( update.display_name if update.display_name is not None else self._profile.display_name ), avatar_url=( update.avatar_url if update.avatar_url is not None else self._profile.avatar_url ), bio=update.bio if update.bio is not None else self._profile.bio, ) async def get_by_username(self, username: str) -> ProfileResponse: if username != self._profile.username: raise HTTPException(status_code=404, detail="Profile not found") return self._profile def _override_profile_service( service: FakeProfileService, ) -> Callable[[], ProfileService]: def _get_service() -> ProfileService: return service # type: ignore[return-value] return _get_service def _override_current_user(user_id: UUID) -> Callable[[], CurrentUser]: def _get_user() -> CurrentUser: return CurrentUser(id=user_id) return _get_user def test_get_me_returns_profile() -> None: user_id = UUID("00000000-0000-0000-0000-000000000001") profile = ProfileResponse( id=str(user_id), username="demo", display_name="Demo User", avatar_url=None, bio=None, ) app.dependency_overrides[get_profile_service] = _override_profile_service( FakeProfileService(profile) ) app.dependency_overrides[get_current_user] = _override_current_user(user_id) client = TestClient(app) try: response = client.get("/api/v1/profile/me") assert response.status_code == 200 body = response.json() assert body["username"] == "demo" finally: app.dependency_overrides = {} def test_patch_me_updates_profile() -> None: user_id = UUID("00000000-0000-0000-0000-000000000001") profile = ProfileResponse( id=str(user_id), username="demo", display_name="Demo User", avatar_url=None, bio=None, ) app.dependency_overrides[get_profile_service] = _override_profile_service( FakeProfileService(profile) ) app.dependency_overrides[get_current_user] = _override_current_user(user_id) client = TestClient(app) try: response = client.patch( "/api/v1/profile/me", json={"display_name": "Updated"}, ) assert response.status_code == 200 body = response.json() assert body["display_name"] == "Updated" finally: app.dependency_overrides = {} def test_get_profile_by_username() -> None: profile = ProfileResponse( id="00000000-0000-0000-0000-000000000001", username="demo", display_name="Demo User", avatar_url=None, bio=None, ) app.dependency_overrides[get_profile_service] = _override_profile_service( FakeProfileService(profile) ) client = TestClient(app) try: response = client.get("/api/v1/profile/demo") assert response.status_code == 200 body = response.json() assert body["username"] == "demo" finally: app.dependency_overrides = {} def test_profile_not_found_returns_problem_details() -> None: profile = ProfileResponse( id="00000000-0000-0000-0000-000000000001", username="demo", display_name="Demo User", avatar_url=None, bio=None, ) app.dependency_overrides[get_profile_service] = _override_profile_service( FakeProfileService(profile) ) client = TestClient(app) try: response = client.get("/api/v1/profile/unknown") assert response.status_code == 404 assert response.headers["content-type"].startswith("application/problem+json") body = response.json() assert body["title"] == "Not Found" assert body["status"] == 404 finally: app.dependency_overrides = {} def test_patch_me_validation_error_returns_problem_details() -> None: user_id = UUID("00000000-0000-0000-0000-000000000001") profile = ProfileResponse( id=str(user_id), username="demo", display_name="Demo User", avatar_url=None, bio=None, ) app.dependency_overrides[get_profile_service] = _override_profile_service( FakeProfileService(profile) ) app.dependency_overrides[get_current_user] = _override_current_user(user_id) client = TestClient(app) try: response = client.patch("/api/v1/profile/me", json={}) assert response.status_code == 422 assert response.headers["content-type"].startswith("application/problem+json") body = response.json() assert body["title"] == "Unprocessable Content" assert body["status"] == 422 finally: app.dependency_overrides = {}