"""Tests for authentication Pydantic schemas. T17: Test Pydantic schemas for user authentication. """ import pytest from pydantic import ValidationError, EmailStr from datetime import datetime, timezone class TestUserRegister: """Tests for UserRegister schema.""" def test_valid_registration(self): """Test valid user registration data.""" # This will fail until schema is implemented from openrouter_monitor.schemas.auth import UserRegister data = UserRegister( email="test@example.com", password="SecurePass123!", password_confirm="SecurePass123!" ) assert data.email == "test@example.com" assert data.password == "SecurePass123!" assert data.password_confirm == "SecurePass123!" def test_invalid_email_format(self): """Test that invalid email format raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="email"): UserRegister( email="not-an-email", password="SecurePass123!", password_confirm="SecurePass123!" ) def test_password_too_short(self): """Test that password shorter than 12 chars raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="password"): UserRegister( email="test@example.com", password="Short1!", password_confirm="Short1!" ) def test_password_missing_uppercase(self): """Test that password without uppercase raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="password"): UserRegister( email="test@example.com", password="lowercase123!", password_confirm="lowercase123!" ) def test_password_missing_lowercase(self): """Test that password without lowercase raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="password"): UserRegister( email="test@example.com", password="UPPERCASE123!", password_confirm="UPPERCASE123!" ) def test_password_missing_digit(self): """Test that password without digit raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="password"): UserRegister( email="test@example.com", password="NoDigitsHere!", password_confirm="NoDigitsHere!" ) def test_password_missing_special_char(self): """Test that password without special char raises ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="password"): UserRegister( email="test@example.com", password="NoSpecialChars123", password_confirm="NoSpecialChars123" ) def test_passwords_do_not_match(self): """Test that mismatched passwords raise ValidationError.""" from openrouter_monitor.schemas.auth import UserRegister with pytest.raises(ValidationError, match="match"): UserRegister( email="test@example.com", password="SecurePass123!", password_confirm="DifferentPass123!" ) def test_password_strength_validator_called(self): """Test that validate_password_strength is called.""" from openrouter_monitor.schemas.auth import UserRegister # Valid password should pass data = UserRegister( email="test@example.com", password="ValidPass123!@#", password_confirm="ValidPass123!@#" ) assert data.password == "ValidPass123!@#" class TestUserLogin: """Tests for UserLogin schema.""" def test_valid_login(self): """Test valid login credentials.""" from openrouter_monitor.schemas.auth import UserLogin data = UserLogin( email="test@example.com", password="anypassword" ) assert data.email == "test@example.com" assert data.password == "anypassword" def test_invalid_email_format(self): """Test that invalid email format raises ValidationError.""" from openrouter_monitor.schemas.auth import UserLogin with pytest.raises(ValidationError, match="email"): UserLogin( email="not-an-email", password="password" ) def test_empty_password(self): """Test that empty password is allowed (validation happens elsewhere).""" from openrouter_monitor.schemas.auth import UserLogin data = UserLogin( email="test@example.com", password="" ) assert data.password == "" class TestUserResponse: """Tests for UserResponse schema.""" def test_valid_response(self): """Test valid user response.""" from openrouter_monitor.schemas.auth import UserResponse from datetime import datetime created_at = datetime(2024, 1, 1, 12, 0, 0) data = UserResponse( id=1, email="test@example.com", created_at=created_at, is_active=True ) assert data.id == 1 assert data.email == "test@example.com" assert data.created_at == created_at assert data.is_active is True def test_from_orm(self): """Test that UserResponse can be created from ORM model.""" from openrouter_monitor.schemas.auth import UserResponse from datetime import datetime # Mock ORM object class MockUser: id = 1 email = "test@example.com" created_at = datetime(2024, 1, 1, 12, 0, 0) is_active = True user = UserResponse.model_validate(MockUser()) assert user.id == 1 assert user.email == "test@example.com" class TestTokenResponse: """Tests for TokenResponse schema.""" def test_valid_token_response(self): """Test valid token response.""" from openrouter_monitor.schemas.auth import TokenResponse data = TokenResponse( access_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", token_type="bearer", expires_in=3600 ) assert data.access_token == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." assert data.token_type == "bearer" assert data.expires_in == 3600 def test_default_token_type(self): """Test that default token_type is 'bearer'.""" from openrouter_monitor.schemas.auth import TokenResponse data = TokenResponse( access_token="some_token", expires_in=3600 ) assert data.token_type == "bearer" class TestTokenData: """Tests for TokenData schema.""" def test_valid_token_data(self): """Test valid token data.""" from openrouter_monitor.schemas.auth import TokenData exp = datetime.now(timezone.utc) data = TokenData( user_id="123", exp=exp ) assert data.user_id == "123" assert data.exp == exp def test_user_id_from_sub(self): """Test that user_id can be extracted from sub claim.""" from openrouter_monitor.schemas.auth import TokenData exp = datetime.now(timezone.utc) # TokenData might be created from JWT payload with 'sub' field data = TokenData(user_id="456", exp=exp) assert data.user_id == "456" def test_user_id_integer_conversion(self): """Test that user_id handles integer IDs.""" from openrouter_monitor.schemas.auth import TokenData exp = datetime.now(timezone.utc) data = TokenData( user_id=123, # Integer ID exp=exp ) assert data.user_id == 123