"""Tests for authentication-related database models.""" from datetime import datetime, timezone import pytest from sqlalchemy import create_engine from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import sessionmaker from local_deep_research.database.models import Base, User class TestUserModel: """Test suite for the User model.""" @pytest.fixture def engine(self): """Create an in-memory SQLite database for testing.""" engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) yield engine engine.dispose() @pytest.fixture def session(self, engine): """Create a database session for testing.""" Session = sessionmaker(bind=engine) session = Session() yield session session.close() def test_create_user(self, session): """Test creating a new user.""" user = User(username="testuser") session.add(user) session.commit() # Retrieve the user saved_user = session.query(User).filter_by(username="testuser").first() assert saved_user is not None assert saved_user.username == "testuser" assert saved_user.created_at is not None assert saved_user.database_version == 1 def test_unique_username_constraint(self, session): """Test that usernames must be unique.""" user1 = User(username="testuser") session.add(user1) session.commit() # Try to create another user with the same username user2 = User(username="testuser") session.add(user2) with pytest.raises(IntegrityError): session.commit() def test_user_timestamps(self, session): """Test that created_at is set correctly.""" user = User(username="testuser") # Before saving, created_at should be None assert user.created_at is None session.add(user) session.commit() # After saving, created_at should be set assert user.created_at is not None assert isinstance(user.created_at, datetime) # Update last_login user.last_login = datetime.now(timezone.utc) session.commit() # Verify last_login is set assert user.last_login is not None assert user.last_login >= user.created_at def test_user_last_login(self, session): """Test last_login timestamp.""" user = User(username="testuser") session.add(user) session.commit() # Initially last_login should be None assert user.last_login is None # Update last_login login_time = datetime.now(timezone.utc) user.last_login = login_time session.commit() # Verify last_login is set saved_user = session.query(User).filter_by(username="testuser").first() assert saved_user.last_login is not None assert abs((saved_user.last_login - login_time).total_seconds()) < 1 def test_user_representation(self): """Test string representation of User model.""" user = User(username="testuser") # Should have a meaningful string representation assert repr(user) == "" def test_database_path_property(self): """Test the database_path property generates consistent paths.""" user1 = User(username="testuser") user2 = User(username="testuser") user3 = User(username="different") # Same username should generate same path assert user1.database_path == user2.database_path # Different username should generate different path assert user1.database_path != user3.database_path # Path should have expected format assert user1.database_path.startswith("ldr_user_") assert user1.database_path.endswith(".db") def test_database_version_default(self, session): """Test that database_version defaults to 1.""" user = User(username="testuser") session.add(user) session.commit() assert user.database_version == 1 # Can update version user.database_version = 2 session.commit() saved_user = session.query(User).filter_by(username="testuser").first() assert saved_user.database_version == 2 def test_username_with_special_characters(self, session): """Test usernames with special characters.""" special_users = [ "user@email.com", "user-with-dashes", "user_with_underscores", "user.with.dots", "user123", "UPPERCASE", "مستخدم", # Arabic "用户", # Chinese "🎉user", # Emoji ] for username in special_users: user = User(username=username) session.add(user) session.commit() # All should be saved successfully assert session.query(User).count() == len(special_users) # Each should have a valid database path for username in special_users: user = session.query(User).filter_by(username=username).first() assert user is not None assert user.database_path.startswith("ldr_user_") assert user.database_path.endswith(".db") # Path should be filesystem-safe (no special chars) assert all(c.isalnum() or c in "_." for c in user.database_path) def test_user_query_operations(self, session): """Test various query operations on User model.""" # Create multiple users users = [] for i in range(5): user = User(username=f"user{i}") users.append(user) session.add(user) session.commit() # Query all users all_users = session.query(User).all() assert len(all_users) == 5 # Query by username user2 = session.query(User).filter_by(username="user2").first() assert user2 is not None assert user2.username == "user2" # Query ordered by created_at ordered_users = session.query(User).order_by(User.created_at).all() assert len(ordered_users) == 5 # Query with limit limited_users = session.query(User).limit(3).all() assert len(limited_users) == 3