""" Tests for user management endpoints. """ from __future__ import annotations import uuid import pytest from httpx import AsyncClient from cpv3.modules.users.models import User class TestListUsersEndpoint: """Tests for GET /api/users/.""" async def test_list_users_authenticated( self, auth_client: AsyncClient, test_user: User ): """Test listing users as authenticated user.""" response = await auth_client.get("/api/users/") assert response.status_code == 200 data = response.json() assert isinstance(data, list) async def test_list_users_unauthenticated(self, async_client: AsyncClient): """Test listing users without auth returns 401.""" response = await async_client.get("/api/users/") assert response.status_code == 401 class TestCreateUserEndpoint: """Tests for POST /api/users/.""" async def test_create_user_as_staff(self, staff_client: AsyncClient): """Test staff can create a new user.""" response = await staff_client.post( "/api/users/", json={ "username": "newcreateduser", "email": "newcreated@example.com", "password": "password123", "first_name": "New", "last_name": "Created", }, ) assert response.status_code == 201 data = response.json() assert data["username"] == "newcreateduser" assert data["email"] == "newcreated@example.com" async def test_create_user_unauthenticated(self, async_client: AsyncClient): """Test creating user without auth returns 401.""" response = await async_client.post( "/api/users/", json={ "username": "newuser", "email": "new@example.com", "password": "password123", }, ) assert response.status_code == 401 class TestMeEndpoint: """Tests for GET /api/users/me/.""" async def test_me_returns_current_user( self, auth_client: AsyncClient, test_user: User ): """Test getting current user info.""" response = await auth_client.get("/api/users/me/") assert response.status_code == 200 data = response.json() assert data["username"] == test_user.username assert data["email"] == test_user.email assert data["id"] == str(test_user.id) async def test_me_unauthenticated(self, async_client: AsyncClient): """Test getting current user without auth returns 401.""" response = await async_client.get("/api/users/me/") assert response.status_code == 401 class TestRetrieveUserEndpoint: """Tests for GET /api/users/{user_id}/.""" async def test_retrieve_own_user(self, auth_client: AsyncClient, test_user: User): """Test user can retrieve their own info.""" response = await auth_client.get(f"/api/users/{test_user.id}/") assert response.status_code == 200 data = response.json() assert data["id"] == str(test_user.id) assert data["username"] == test_user.username async def test_retrieve_other_user_as_staff( self, staff_client: AsyncClient, test_user: User ): """Test staff can retrieve other user's info.""" response = await staff_client.get(f"/api/users/{test_user.id}/") assert response.status_code == 200 data = response.json() assert data["id"] == str(test_user.id) async def test_retrieve_nonexistent_user(self, auth_client: AsyncClient): """Test retrieving nonexistent user returns 404.""" fake_id = uuid.uuid4() response = await auth_client.get(f"/api/users/{fake_id}/") assert response.status_code == 404 assert response.json()["detail"] == "Not found" async def test_retrieve_other_user_forbidden( self, auth_client: AsyncClient, other_user: User ): """Test regular user cannot retrieve other user's info.""" response = await auth_client.get(f"/api/users/{other_user.id}/") assert response.status_code == 403 assert response.json()["detail"] == "Forbidden" class TestPatchUserEndpoint: """Tests for PATCH /api/users/{user_id}/.""" async def test_patch_own_user(self, auth_client: AsyncClient, test_user: User): """Test user can update their own info.""" response = await auth_client.patch( f"/api/users/{test_user.id}/", json={"first_name": "Updated", "last_name": "Name"}, ) assert response.status_code == 200 data = response.json() assert data["first_name"] == "Updated" assert data["last_name"] == "Name" async def test_patch_other_user_as_staff( self, staff_client: AsyncClient, test_user: User ): """Test staff can update other user's info.""" response = await staff_client.patch( f"/api/users/{test_user.id}/", json={"first_name": "StaffUpdated"}, ) assert response.status_code == 200 data = response.json() assert data["first_name"] == "StaffUpdated" async def test_patch_nonexistent_user(self, auth_client: AsyncClient): """Test patching nonexistent user returns 404.""" fake_id = uuid.uuid4() response = await auth_client.patch( f"/api/users/{fake_id}/", json={"first_name": "Test"}, ) assert response.status_code == 404 async def test_patch_other_user_forbidden( self, auth_client: AsyncClient, other_user: User ): """Test regular user cannot update other user's info.""" response = await auth_client.patch( f"/api/users/{other_user.id}/", json={"first_name": "Hacked"}, ) assert response.status_code == 403 class TestDeleteUserEndpoint: """Tests for DELETE /api/users/{user_id}/.""" async def test_delete_own_user(self, auth_client: AsyncClient, test_user: User): """Test user can delete (deactivate) their own account.""" response = await auth_client.delete(f"/api/users/{test_user.id}/") assert response.status_code == 204 async def test_delete_other_user_as_staff( self, staff_client: AsyncClient, test_user: User ): """Test staff can delete other user's account.""" response = await staff_client.delete(f"/api/users/{test_user.id}/") assert response.status_code == 204 async def test_delete_nonexistent_user(self, auth_client: AsyncClient): """Test deleting nonexistent user returns 404.""" fake_id = uuid.uuid4() response = await auth_client.delete(f"/api/users/{fake_id}/") assert response.status_code == 404 async def test_delete_other_user_forbidden( self, auth_client: AsyncClient, other_user: User ): """Test regular user cannot delete other user's account.""" response = await auth_client.delete(f"/api/users/{other_user.id}/") assert response.status_code == 403