"""Tests for validation utilities.""" import pytest from gondulf.utils.validation import ( mask_email, normalize_client_id, validate_redirect_uri, extract_domain_from_url, validate_email ) class TestMaskEmail: """Tests for mask_email function.""" def test_mask_email_basic(self): """Test basic email masking.""" assert mask_email("user@example.com") == "u***@example.com" def test_mask_email_long_local(self): """Test masking email with long local part.""" assert mask_email("verylongusername@example.com") == "v***@example.com" def test_mask_email_single_char_local(self): """Test masking email with single character local part.""" # Should return unchanged if local part is only 1 character assert mask_email("a@example.com") == "a@example.com" def test_mask_email_no_at_sign(self): """Test masking invalid email without @ sign.""" assert mask_email("notanemail") == "notanemail" def test_mask_email_empty_string(self): """Test masking empty string.""" assert mask_email("") == "" class TestNormalizeClientId: """Tests for normalize_client_id function.""" def test_normalize_basic_https(self): """Test normalizing basic HTTPS URL.""" assert normalize_client_id("https://example.com/") == "https://example.com/" def test_normalize_remove_default_port(self): """Test normalizing URL with default HTTPS port.""" assert normalize_client_id("https://example.com:443/") == "https://example.com/" def test_normalize_preserve_non_default_port(self): """Test normalizing URL with non-default port.""" assert normalize_client_id("https://example.com:8443/") == "https://example.com:8443/" def test_normalize_preserve_path(self): """Test normalizing URL with path.""" assert normalize_client_id("https://example.com/app") == "https://example.com/app" def test_normalize_preserve_query(self): """Test normalizing URL with query string.""" assert normalize_client_id("https://example.com/?foo=bar") == "https://example.com/?foo=bar" def test_normalize_http_scheme_raises_error(self): """Test that HTTP scheme raises ValueError.""" with pytest.raises(ValueError, match="must use https scheme"): normalize_client_id("http://example.com/") def test_normalize_no_scheme_raises_error(self): """Test that missing scheme raises ValueError.""" with pytest.raises(ValueError, match="must use https scheme"): normalize_client_id("example.com") class TestValidateRedirectUri: """Tests for validate_redirect_uri function.""" def test_validate_same_origin(self): """Test redirect URI with same origin as client_id.""" assert validate_redirect_uri( "https://example.com/callback", "https://example.com/" ) is True def test_validate_different_path_same_origin(self): """Test redirect URI with different path but same origin.""" assert validate_redirect_uri( "https://example.com/auth/callback", "https://example.com/" ) is True def test_validate_subdomain(self): """Test redirect URI on subdomain of client_id.""" assert validate_redirect_uri( "https://app.example.com/callback", "https://example.com/" ) is True def test_validate_different_domain_fails(self): """Test redirect URI on completely different domain fails.""" assert validate_redirect_uri( "https://evil.com/callback", "https://example.com/" ) is False def test_validate_localhost_http_allowed(self): """Test that localhost can use HTTP.""" assert validate_redirect_uri( "http://localhost/callback", "https://example.com/" ) is True def test_validate_127_0_0_1_http_allowed(self): """Test that 127.0.0.1 can use HTTP.""" assert validate_redirect_uri( "http://127.0.0.1:8000/callback", "https://example.com/" ) is True def test_validate_http_non_localhost_fails(self): """Test that HTTP on non-localhost fails.""" assert validate_redirect_uri( "http://example.com/callback", "https://example.com/" ) is False def test_validate_malformed_uri_fails(self): """Test that malformed URI fails gracefully.""" assert validate_redirect_uri( "not a url", "https://example.com/" ) is False class TestExtractDomainFromUrl: """Tests for extract_domain_from_url function.""" def test_extract_domain_basic(self): """Test extracting domain from basic URL.""" assert extract_domain_from_url("https://example.com/") == "example.com" def test_extract_domain_with_path(self): """Test extracting domain from URL with path.""" assert extract_domain_from_url("https://example.com/path/to/page") == "example.com" def test_extract_domain_with_port(self): """Test extracting domain from URL with port.""" assert extract_domain_from_url("https://example.com:8443/") == "example.com" def test_extract_domain_subdomain(self): """Test extracting subdomain.""" assert extract_domain_from_url("https://blog.example.com/") == "blog.example.com" def test_extract_domain_no_hostname_raises_error(self): """Test that URL without hostname raises ValueError.""" with pytest.raises(ValueError, match="URL has no hostname"): extract_domain_from_url("file:///path/to/file") def test_extract_domain_invalid_url_raises_error(self): """Test that invalid URL raises ValueError.""" with pytest.raises(ValueError, match="Invalid URL"): extract_domain_from_url("not a url") class TestValidateEmail: """Tests for validate_email function.""" def test_validate_email_basic(self): """Test validating basic email.""" assert validate_email("user@example.com") is True def test_validate_email_with_plus(self): """Test validating email with plus sign.""" assert validate_email("user+tag@example.com") is True def test_validate_email_with_dots(self): """Test validating email with dots.""" assert validate_email("first.last@example.com") is True def test_validate_email_subdomain(self): """Test validating email with subdomain.""" assert validate_email("user@mail.example.com") is True def test_validate_email_no_at_sign(self): """Test that email without @ sign fails.""" assert validate_email("notanemail") is False def test_validate_email_no_domain(self): """Test that email without domain fails.""" assert validate_email("user@") is False def test_validate_email_no_local_part(self): """Test that email without local part fails.""" assert validate_email("@example.com") is False def test_validate_email_no_tld(self): """Test that email without TLD fails.""" assert validate_email("user@example") is False def test_validate_email_empty_string(self): """Test that empty string fails.""" assert validate_email("") is False