"""Unit tests for validation logic.""" import pytest from src.validation import ValidationError, validate_email, validate_first_name, validate_phone class TestFirstNameValidation: """Tests for validate_first_name function.""" def test_valid_first_name(self): """Test that valid firstName passes validation.""" validate_first_name("Alice") # No exception = pass def test_empty_string_raises_error(self): """Test that empty string raises ValidationError.""" with pytest.raises(ValidationError, match="firstName cannot be empty"): validate_first_name("") def test_whitespace_only_raises_error(self): """Test that whitespace-only string raises ValidationError.""" with pytest.raises(ValidationError, match="firstName cannot be empty"): validate_first_name(" ") class TestEmailValidation: """Tests for validate_email function.""" def test_valid_email(self): """Test that valid email passes validation.""" validate_email("test@example.com") # No exception = pass def test_valid_email_with_subdomain(self): """Test that email with subdomain passes validation.""" validate_email("user@mail.example.com") def test_valid_email_with_plus(self): """Test that email with plus sign passes validation.""" validate_email("user+tag@example.com") def test_invalid_email_no_at(self): """Test that email without @ raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid email format"): validate_email("notanemail") def test_invalid_email_no_domain(self): """Test that email without domain raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid email format"): validate_email("user@") def test_invalid_email_no_tld(self): """Test that email without TLD raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid email format"): validate_email("user@example") def test_none_is_allowed(self): """Test that None passes validation (optional field).""" validate_email(None) # No exception = pass def test_empty_string_is_allowed(self): """Test that empty string passes validation (optional field).""" validate_email("") # No exception = pass class TestPhoneValidation: """Tests for validate_phone function.""" def test_valid_phone_with_plus(self): """Test that valid E.164 phone with + passes validation.""" validate_phone("+41791234567") def test_valid_phone_without_plus(self): """Test that valid E.164 phone without + passes validation.""" validate_phone("41791234567") def test_valid_us_phone(self): """Test that valid US phone passes validation.""" validate_phone("+14155551234") def test_invalid_phone_with_invalid_chars(self): """Test that phone with invalid characters raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid phone format"): validate_phone("abc123") def test_invalid_phone_too_long(self): """Test that phone too long raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid phone format"): validate_phone("+123456789012345678") # More than 15 digits def test_invalid_phone_starts_with_zero(self): """Test that phone starting with 0 raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid phone format"): validate_phone("+0791234567") def test_invalid_phone_has_letters(self): """Test that phone with letters raises ValidationError.""" with pytest.raises(ValidationError, match="Invalid phone format"): validate_phone("+41abc1234567") def test_none_is_allowed(self): """Test that None passes validation (optional field).""" validate_phone(None) # No exception = pass def test_empty_string_is_allowed(self): """Test that empty string passes validation (optional field).""" validate_phone("") # No exception = pass