diff --git a/backend/tests/models/test_user.py b/backend/tests/models/test_user.py index f988e08..bf3077f 100644 --- a/backend/tests/models/test_user.py +++ b/backend/tests/models/test_user.py @@ -1,8 +1,13 @@ # tests/models/test_user.py import uuid +import pytest +from datetime import datetime +from sqlalchemy.exc import IntegrityError from app.models.user import User + def test_create_user(db_session): + """Test creating a basic user.""" # Arrange user_id = uuid.uuid4() new_user = User( @@ -26,4 +31,244 @@ def test_create_user(db_session): assert created_user is not None assert created_user.email == "test@example.com" assert created_user.first_name == "Test" - assert created_user.preferences == {"theme": "dark"} \ No newline at end of file + assert created_user.last_name == "User" + assert created_user.phone_number == "1234567890" + assert created_user.is_active is True + assert created_user.is_superuser is False + assert created_user.preferences == {"theme": "dark"} + # UUID should be preserved + assert created_user.id == user_id + # Timestamps should be set + assert isinstance(created_user.created_at, datetime) + assert isinstance(created_user.updated_at, datetime) + + +def test_update_user(db_session): + """Test updating an existing user.""" + # Arrange - Create a user + user_id = uuid.uuid4() + user = User( + id=user_id, + email="update@example.com", + password_hash="hashedpassword", + first_name="Before", + last_name="Update", + ) + db_session.add(user) + db_session.commit() + + # Record the original creation timestamp + original_created_at = user.created_at + + # Act - Update the user + user.first_name = "After" + user.last_name = "Updated" + user.phone_number = "9876543210" + user.preferences = {"theme": "light", "notifications": True} + db_session.commit() + + # Fetch the updated user to verify changes were persisted + updated_user = db_session.query(User).filter_by(id=user_id).first() + + # Assert + assert updated_user.first_name == "After" + assert updated_user.last_name == "Updated" + assert updated_user.phone_number == "9876543210" + assert updated_user.preferences == {"theme": "light", "notifications": True} + # created_at shouldn't change on update + assert updated_user.created_at == original_created_at + # updated_at should be newer than created_at + assert updated_user.updated_at > original_created_at + + +def test_delete_user(db_session): + """Test deleting a user.""" + # Arrange - Create a user + user_id = uuid.uuid4() + user = User( + id=user_id, + email="delete@example.com", + password_hash="hashedpassword", + first_name="Delete", + last_name="Me", + ) + db_session.add(user) + db_session.commit() + + # Act - Delete the user + db_session.delete(user) + db_session.commit() + + # Assert + deleted_user = db_session.query(User).filter_by(id=user_id).first() + assert deleted_user is None + + +def test_user_unique_email_constraint(db_session): + """Test that users cannot have duplicate emails.""" + # Arrange - Create a user + user1 = User( + id=uuid.uuid4(), + email="duplicate@example.com", + password_hash="hashedpassword", + first_name="First", + last_name="User", + ) + db_session.add(user1) + db_session.commit() + + # Act & Assert - Try to create another user with the same email + user2 = User( + id=uuid.uuid4(), + email="duplicate@example.com", # Same email + password_hash="differenthash", + first_name="Second", + last_name="User", + ) + db_session.add(user2) + + # Should raise IntegrityError due to unique constraint + with pytest.raises(IntegrityError): + db_session.commit() + + # Rollback for cleanup + db_session.rollback() + + +def test_user_required_fields(db_session): + """Test that required fields are enforced.""" + # Test each required field by creating a user without it + + # Missing email + user_no_email = User( + id=uuid.uuid4(), + # email is missing + password_hash="hashedpassword", + first_name="Test", + last_name="User", + ) + db_session.add(user_no_email) + with pytest.raises(IntegrityError): + db_session.commit() + db_session.rollback() + + # Missing password_hash + user_no_password = User( + id=uuid.uuid4(), + email="nopassword@example.com", + # password_hash is missing + first_name="Test", + last_name="User", + ) + db_session.add(user_no_password) + with pytest.raises(IntegrityError): + db_session.commit() + db_session.rollback() + + # Missing first_name + user_no_firstname = User( + id=uuid.uuid4(), + email="nofirstname@example.com", + password_hash="hashedpassword", + # first_name is missing + last_name="User", + ) + db_session.add(user_no_firstname) + with pytest.raises(IntegrityError): + db_session.commit() + db_session.rollback() + + # Missing last_name + user_no_lastname = User( + id=uuid.uuid4(), + email="nolastname@example.com", + password_hash="hashedpassword", + first_name="Test", + # last_name is missing + ) + db_session.add(user_no_lastname) + with pytest.raises(IntegrityError): + db_session.commit() + db_session.rollback() + + +def test_user_defaults(db_session): + """Test that default values are correctly set.""" + # Arrange - Create a minimal user with only required fields + minimal_user = User( + id=uuid.uuid4(), + email="minimal@example.com", + password_hash="hashedpassword", + first_name="Minimal", + last_name="User", + ) + db_session.add(minimal_user) + db_session.commit() + + # Act - Retrieve the user + created_user = db_session.query(User).filter_by(email="minimal@example.com").first() + + # Assert - Check default values + assert created_user.is_active is True # Default should be True + assert created_user.is_superuser is False # Default should be False + assert created_user.phone_number is None # Optional field + assert created_user.preferences is None # Optional field + + +def test_user_string_representation(db_session): + """Test the string representation of a user.""" + # Arrange + user = User( + id=uuid.uuid4(), + email="repr@example.com", + password_hash="hashedpassword", + first_name="String", + last_name="Repr", + ) + + # Act & Assert + assert str(user) == "" + assert repr(user) == "" + + +def test_user_with_complex_json_preferences(db_session): + """Test storing and retrieving complex JSON preferences.""" + # Arrange - Create a user with nested JSON preferences + complex_preferences = { + "theme": { + "mode": "dark", + "colors": { + "primary": "#333", + "secondary": "#666" + } + }, + "notifications": { + "email": True, + "sms": False, + "push": { + "enabled": True, + "quiet_hours": [22, 7] + } + }, + "tags": ["important", "family", "events"] + } + + user = User( + id=uuid.uuid4(), + email="complex@example.com", + password_hash="hashedpassword", + first_name="Complex", + last_name="JSON", + preferences=complex_preferences + ) + db_session.add(user) + db_session.commit() + + # Act - Retrieve the user + retrieved_user = db_session.query(User).filter_by(email="complex@example.com").first() + + # Assert - The complex JSON should be preserved + assert retrieved_user.preferences == complex_preferences + assert retrieved_user.preferences["theme"]["colors"]["primary"] == "#333" + assert retrieved_user.preferences["notifications"]["push"]["quiet_hours"] == [22, 7] + assert "important" in retrieved_user.preferences["tags"] \ No newline at end of file