import pytest from fastapi import HTTPException from sqlalchemy.orm import Session from app.models.user import User from app.models.user_profile import UserProfile from app.schemas.user import UserCreate, UserUpdate from app.security import verify_password from app.services.user_service import ( create_user, delete_user, get_user_by_id, get_user_list, update_user, ) class TestGetUserList: def test_empty(self, db_session: Session): users = get_user_list(db_session) assert users == [] def test_with_users(self, db_session: Session): for i in range(3): user = User(email=f"test{i}@ex.com", username=f"user{i}", password="x") db_session.add(user) db_session.commit() users = get_user_list(db_session) assert len(users) == 3 def test_soft_deleted_excluded(self, db_session: Session): from datetime import datetime u1 = User(email="active@ex.com", username="active", password="x") u2 = User(email="deleted@ex.com", username="deleted", password="x", deleted_at=datetime.now()) db_session.add_all([u1, u2]) db_session.commit() users = get_user_list(db_session) assert len(users) == 1 assert users[0].email == "active@ex.com" class TestGetUserById: def test_found(self, db_session: Session): user = User(email="find@ex.com", username="find", password="x") db_session.add(user) db_session.commit() result = get_user_by_id(db_session, user.id) assert result.id == user.id assert result.email == "find@ex.com" def test_not_found(self, db_session: Session): with pytest.raises(HTTPException) as exc: get_user_by_id(db_session, "nonexistent") assert exc.value.status_code == 404 def test_soft_deleted(self, db_session: Session): from datetime import datetime user = User(email="gone@ex.com", username="gone", password="x", deleted_at=datetime.now()) db_session.add(user) db_session.commit() with pytest.raises(HTTPException) as exc: get_user_by_id(db_session, user.id) assert exc.value.status_code == 404 class TestCreateUser: def test_create(self, db_session: Session): data = UserCreate( email="new@ex.com", username="newuser", password="secret", full_name="New User", ) user = create_user(db_session, data) assert user.email == "new@ex.com" assert user.username == "newuser" assert verify_password("secret", user.password) profile = db_session.query(UserProfile).filter(UserProfile.user_id == user.id).first() assert profile is not None assert profile.full_name == "New User" def test_duplicate_email(self, db_session: Session): db_session.add(User(email="dup@ex.com", username="first", password="x")) db_session.commit() data = UserCreate( email="dup@ex.com", username="second", password="x", full_name="Dup", ) with pytest.raises(HTTPException) as exc: create_user(db_session, data) assert exc.value.status_code == 409 def test_duplicate_username(self, db_session: Session): data = UserCreate( email="a@ex.com", username="taken", password="x", full_name="A", ) create_user(db_session, data) dup = UserCreate( email="b@ex.com", username="taken", password="x", full_name="B", ) with pytest.raises(HTTPException) as exc: create_user(db_session, dup) assert exc.value.status_code == 409 class TestUpdateUser: def test_update_email(self, db_session: Session): user = User(email="old@ex.com", username="old", password="x") db_session.add(user) db_session.commit() data = UserUpdate(email="new@ex.com") updated = update_user(db_session, user.id, data) assert updated.email == "new@ex.com" def test_update_profile(self, db_session: Session): user = User(email="prof@ex.com", username="prof", password="x") db_session.add(user) db_session.flush() profile = UserProfile(user_id=user.id, full_name="Old Name") db_session.add(profile) db_session.commit() data = UserUpdate(full_name="Updated Name") updated = update_user(db_session, user.id, data) assert updated.profile.full_name == "Updated Name" def test_update_password(self, db_session: Session): user = User(email="pw@ex.com", username="pw", password="x") db_session.add(user) db_session.commit() data = UserUpdate(password="newsecret") update_user(db_session, user.id, data) db_session.refresh(user) assert verify_password("newsecret", user.password) def test_update_not_found(self, db_session: Session): data = UserUpdate(email="nope@ex.com") with pytest.raises(HTTPException) as exc: update_user(db_session, "nonexistent", data) assert exc.value.status_code == 404 def test_update_conflict_email(self, db_session: Session): User(email="existing@ex.com", username="existing", password="x") user = User(email="me@ex.com", username="me", password="x") db_session.add_all([User(email="existing@ex.com", username="existing", password="x"), user]) db_session.commit() data = UserUpdate(email="existing@ex.com") with pytest.raises(HTTPException) as exc: update_user(db_session, user.id, data) assert exc.value.status_code == 409 class TestDeleteUser: def test_soft_delete(self, db_session: Session): user = User(email="del@ex.com", username="del", password="x") db_session.add(user) db_session.commit() delete_user(db_session, user.id) assert user.deleted_at is not None def test_delete_not_found(self, db_session: Session): with pytest.raises(HTTPException) as exc: delete_user(db_session, "nonexistent") assert exc.value.status_code == 404