""" Test suite for UserRepository with async/support. This module contains comprehensive tests for all UserRepository methods using mongomock-motor for in-memory MongoDB testing. """ import pytest from bson import ObjectId from mongomock.mongo_client import MongoClient from pymongo.errors import DuplicateKeyError from app.database.repositories.user_repository import UserRepository from app.models.user import UserCreate, UserUpdate @pytest.fixture def in_memory_repository(): """Create an in-memory UserRepository for testing.""" client = MongoClient() db = client.test_database repo = UserRepository(db) repo.initialize() return repo @pytest.fixture def sample_user_create(): """Sample UserCreate data for testing.""" return UserCreate( username="testuser", email="test@example.com", password="#TestPassword123", role="user" ) @pytest.fixture def sample_user_update(): """Sample UserUpdate data for testing.""" return UserUpdate( username="updateduser", email="updated@example.com", role="admin" ) class TestUserRepositoryCreation: """Tests for user creation functionality.""" def test_i_can_create_user(self, in_memory_repository, sample_user_create): """Test successful user creation.""" # Act created_user = in_memory_repository.create_user(sample_user_create) # Assert assert created_user is not None assert created_user.username == sample_user_create.username assert created_user.email == sample_user_create.email assert created_user.role == sample_user_create.role assert created_user.is_active is True assert created_user.id is not None assert created_user.created_at is not None assert created_user.updated_at is not None assert created_user.hashed_password != sample_user_create.password # Should be hashed def test_i_cannot_create_user_with_duplicate_username(self, in_memory_repository, sample_user_create): """Test that creating user with duplicate username raises DuplicateKeyError.""" # Arrange in_memory_repository.create_user(sample_user_create) # Act & Assert with pytest.raises(DuplicateKeyError) as exc_info: in_memory_repository.create_user(sample_user_create) assert "already exists" in str(exc_info.value) class TestUserRepositoryFinding: """Tests for user finding functionality.""" def test_i_can_find_user_by_id(self, in_memory_repository, sample_user_create): """Test finding user by valid ID.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) # Act found_user = in_memory_repository.find_user_by_id(str(created_user.id)) # Assert assert found_user is not None assert found_user.id == created_user.id assert found_user.username == created_user.username assert found_user.email == created_user.email def test_i_cannot_find_user_by_invalid_id(self, in_memory_repository): """Test that invalid ObjectId returns None.""" # Act found_user = in_memory_repository.find_user_by_id("invalid_id") # Assert assert found_user is None def test_i_cannot_find_user_by_nonexistent_id(self, in_memory_repository): """Test that nonexistent but valid ObjectId returns None.""" # Arrange nonexistent_id = str(ObjectId()) # Act found_user = in_memory_repository.find_user_by_id(nonexistent_id) # Assert assert found_user is None def test_i_can_find_user_by_username(self, in_memory_repository, sample_user_create): """Test finding user by username.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) # Act found_user = in_memory_repository.find_user_by_username(sample_user_create.username) # Assert assert found_user is not None assert found_user.username == created_user.username assert found_user.id == created_user.id def test_i_cannot_find_user_by_nonexistent_username(self, in_memory_repository): """Test that nonexistent username returns None.""" # Act found_user = in_memory_repository.find_user_by_username("nonexistent") # Assert assert found_user is None def test_i_can_find_user_by_email(self, in_memory_repository, sample_user_create): """Test finding user by email.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) # Act found_user = in_memory_repository.find_user_by_email(str(sample_user_create.email)) # Assert assert found_user is not None assert found_user.email == created_user.email assert found_user.id == created_user.id def test_i_cannot_find_user_by_nonexistent_email(self, in_memory_repository): """Test that nonexistent email returns None.""" # Act found_user = in_memory_repository.find_user_by_email("nonexistent@example.com") # Assert assert found_user is None class TestUserRepositoryUpdate: """Tests for user update functionality.""" def test_i_can_update_user(self, in_memory_repository, sample_user_create, sample_user_update): """Test successful user update.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) original_updated_at = created_user.updated_at # Act updated_user = in_memory_repository.update_user(str(created_user.id), sample_user_update) # Assert assert updated_user is not None assert updated_user.username == sample_user_update.username assert updated_user.email == sample_user_update.email assert updated_user.role == sample_user_update.role assert updated_user.id == created_user.id def test_i_cannot_update_user_with_invalid_id(self, in_memory_repository, sample_user_update): """Test that updating with invalid ID returns None.""" # Act result = in_memory_repository.update_user("invalid_id", sample_user_update) # Assert assert result is None def test_i_can_update_user_with_partial_data(self, in_memory_repository, sample_user_create): """Test updating user with partial data.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) partial_update = UserUpdate(username="newusername") # Act updated_user = in_memory_repository.update_user(str(created_user.id), partial_update) # Assert assert updated_user is not None assert updated_user.username == "newusername" assert updated_user.email == created_user.email # Should remain unchanged assert updated_user.role == created_user.role # Should remain unchanged def test_i_can_update_user_with_empty_data(self, in_memory_repository, sample_user_create): """Test updating user with empty data returns current user.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) empty_update = UserUpdate() # Act result = in_memory_repository.update_user(str(created_user.id), empty_update) # Assert assert result is not None assert result.username == created_user.username assert result.email == created_user.email class TestUserRepositoryDeletion: """Tests for user deletion functionality.""" def test_i_can_delete_user(self, in_memory_repository, sample_user_create): """Test successful user deletion.""" # Arrange created_user = in_memory_repository.create_user(sample_user_create) # Act deletion_result = in_memory_repository.delete_user(str(created_user.id)) # Assert assert deletion_result is True # Verify user is actually deleted found_user = in_memory_repository.find_user_by_id(str(created_user.id)) assert found_user is None def test_i_cannot_delete_user_with_invalid_id(self, in_memory_repository): """Test that deleting with invalid ID returns False.""" # Act result = in_memory_repository.delete_user("invalid_id") # Assert assert result is False def test_i_cannot_delete_nonexistent_user(self, in_memory_repository): """Test that deleting nonexistent user returns False.""" # Arrange nonexistent_id = str(ObjectId()) # Act result = in_memory_repository.delete_user(nonexistent_id) # Assert assert result is False class TestUserRepositoryUtilities: """Tests for utility methods.""" def test_i_can_count_users(self, in_memory_repository, sample_user_create): """Test counting users.""" # Arrange initial_count = in_memory_repository.count_users() in_memory_repository.create_user(sample_user_create) # Act final_count = in_memory_repository.count_users() # Assert assert final_count == initial_count + 1 def test_i_can_check_user_exists(self, in_memory_repository, sample_user_create): """Test checking if user exists.""" # Arrange in_memory_repository.create_user(sample_user_create) # Act exists = in_memory_repository.user_exists(sample_user_create.username) not_exists = in_memory_repository.user_exists("nonexistent") # Assert assert exists is True assert not_exists is False