# tests/unit/models/schema/test_auth.py """Unit tests for auth Pydantic schemas.""" import pytest from pydantic import ValidationError from models.schema.auth import ( UserCreate, UserLogin, UserRegister, UserResponse, UserUpdate, ) @pytest.mark.unit @pytest.mark.schema class TestUserRegisterSchema: """Test UserRegister schema validation.""" def test_valid_registration(self): """Test valid registration data.""" user = UserRegister( email="test@example.com", username="testuser", password="password123", ) assert user.email == "test@example.com" assert user.username == "testuser" assert user.password == "password123" def test_username_normalized_to_lowercase(self): """Test username is normalized to lowercase.""" user = UserRegister( email="test@example.com", username="TestUser", password="password123", ) assert user.username == "testuser" def test_username_with_whitespace_invalid(self): """Test username with whitespace is invalid (validation before strip).""" with pytest.raises(ValidationError) as exc_info: UserRegister( email="test@example.com", username=" testuser ", password="password123", ) assert "username" in str(exc_info.value).lower() def test_invalid_email(self): """Test invalid email raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: UserRegister( email="not-an-email", username="testuser", password="password123", ) assert "email" in str(exc_info.value).lower() def test_invalid_username_special_chars(self): """Test username with special characters raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: UserRegister( email="test@example.com", username="test@user!", password="password123", ) assert "username" in str(exc_info.value).lower() def test_valid_username_with_underscore(self): """Test username with underscore is valid.""" user = UserRegister( email="test@example.com", username="test_user_123", password="password123", ) assert user.username == "test_user_123" def test_password_too_short(self): """Test password shorter than 6 characters raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: UserRegister( email="test@example.com", username="testuser", password="12345", ) assert "password" in str(exc_info.value).lower() def test_password_exactly_6_chars(self): """Test password with exactly 6 characters is valid.""" user = UserRegister( email="test@example.com", username="testuser", password="123456", ) assert user.password == "123456" def test_missing_required_fields(self): """Test missing required fields raises ValidationError.""" with pytest.raises(ValidationError): UserRegister(email="test@example.com") @pytest.mark.unit @pytest.mark.schema class TestUserLoginSchema: """Test UserLogin schema validation.""" def test_valid_login(self): """Test valid login data.""" login = UserLogin( email_or_username="testuser", password="password123", ) assert login.email_or_username == "testuser" assert login.password == "password123" def test_login_with_email(self): """Test login with email.""" login = UserLogin( email_or_username="test@example.com", password="password123", ) assert login.email_or_username == "test@example.com" def test_login_with_vendor_code(self): """Test login with optional vendor code.""" login = UserLogin( email_or_username="testuser", password="password123", vendor_code="VENDOR001", ) assert login.vendor_code == "VENDOR001" def test_email_or_username_stripped(self): """Test email_or_username is stripped of whitespace.""" login = UserLogin( email_or_username=" testuser ", password="password123", ) assert login.email_or_username == "testuser" @pytest.mark.unit @pytest.mark.schema class TestUserCreateSchema: """Test UserCreate schema validation.""" def test_valid_user_create(self): """Test valid user creation data.""" user = UserCreate( email="admin@example.com", username="adminuser", password="securepass", first_name="Admin", last_name="User", role="admin", ) assert user.email == "admin@example.com" assert user.role == "admin" def test_default_role_is_vendor(self): """Test default role is vendor.""" user = UserCreate( email="vendor@example.com", username="vendoruser", password="securepass", ) assert user.role == "vendor" def test_invalid_role(self): """Test invalid role raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: UserCreate( email="test@example.com", username="testuser", password="securepass", role="superadmin", ) assert "role" in str(exc_info.value).lower() def test_username_too_short(self): """Test username shorter than 3 characters raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: UserCreate( email="test@example.com", username="ab", password="securepass", ) assert "username" in str(exc_info.value).lower() def test_password_min_length(self): """Test password minimum length validation.""" with pytest.raises(ValidationError) as exc_info: UserCreate( email="test@example.com", username="testuser", password="12345", ) assert "password" in str(exc_info.value).lower() @pytest.mark.unit @pytest.mark.schema class TestUserUpdateSchema: """Test UserUpdate schema validation.""" def test_partial_update(self): """Test partial update with only some fields.""" update = UserUpdate(first_name="NewName") assert update.first_name == "NewName" assert update.username is None assert update.email is None def test_username_update_normalized(self): """Test username in update is normalized.""" update = UserUpdate(username="NewUser") assert update.username == "newuser" def test_invalid_role_update(self): """Test invalid role in update raises ValidationError.""" with pytest.raises(ValidationError): UserUpdate(role="superadmin") def test_valid_role_update(self): """Test valid role values.""" admin_update = UserUpdate(role="admin") vendor_update = UserUpdate(role="vendor") assert admin_update.role == "admin" assert vendor_update.role == "vendor" def test_empty_update(self): """Test empty update is valid (all fields optional).""" update = UserUpdate() assert update.model_dump(exclude_unset=True) == {} @pytest.mark.unit @pytest.mark.schema class TestUserResponseSchema: """Test UserResponse schema.""" def test_from_dict(self): """Test creating response from dict.""" from datetime import datetime data = { "id": 1, "email": "test@example.com", "username": "testuser", "role": "vendor", "is_active": True, "created_at": datetime.now(), "updated_at": datetime.now(), } response = UserResponse(**data) assert response.id == 1 assert response.email == "test@example.com" assert response.is_active is True def test_optional_last_login(self): """Test last_login is optional.""" from datetime import datetime data = { "id": 1, "email": "test@example.com", "username": "testuser", "role": "vendor", "is_active": True, "created_at": datetime.now(), "updated_at": datetime.now(), } response = UserResponse(**data) assert response.last_login is None