""" Behavioral tests for url_utils module. Tests the normalize_url function for URL normalization. """ import pytest class TestNormalizeUrlWithScheme: """Tests for URLs that already have a scheme.""" def test_https_url_unchanged(self): """HTTPS URL is returned unchanged.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("https://example.com") == "https://example.com" def test_http_url_unchanged(self): """HTTP URL is returned unchanged.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("http://example.com") == "http://example.com" def test_https_with_port_unchanged(self): """HTTPS URL with port is unchanged.""" from local_deep_research.utilities.url_utils import normalize_url assert ( normalize_url("https://example.com:8080") == "https://example.com:8080" ) def test_http_with_port_unchanged(self): """HTTP URL with port is unchanged.""" from local_deep_research.utilities.url_utils import normalize_url assert ( normalize_url("http://example.com:8080") == "http://example.com:8080" ) def test_https_with_path_unchanged(self): """HTTPS URL with path is unchanged.""" from local_deep_research.utilities.url_utils import normalize_url assert ( normalize_url("https://example.com/path") == "https://example.com/path" ) class TestNormalizeUrlMalformed: """Tests for malformed URLs with missing slashes.""" def test_http_colon_missing_slashes(self): """http:example.com gets slashes added.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("http:example.com") == "http://example.com" def test_https_colon_missing_slashes(self): """https:example.com gets slashes added.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("https:example.com") == "https://example.com" class TestNormalizeUrlDoubleSlashPrefix: """Tests for URLs starting with //.""" def test_double_slash_prefix_removed(self): """// prefix is handled and scheme added.""" from local_deep_research.utilities.url_utils import normalize_url # //example.com should get scheme based on whether it's private result = normalize_url("//example.com") assert result.startswith("http://") or result.startswith("https://") assert "example.com" in result class TestNormalizeUrlLocalhost: """Tests for localhost URLs.""" def test_localhost_gets_http(self): """localhost gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("localhost") == "http://localhost" def test_localhost_with_port_gets_http(self): """localhost:port gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("localhost:11434") == "http://localhost:11434" def test_127_0_0_1_gets_http(self): """127.0.0.1 gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("127.0.0.1") == "http://127.0.0.1" def test_127_0_0_1_with_port_gets_http(self): """127.0.0.1:port gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("127.0.0.1:8080") == "http://127.0.0.1:8080" class TestNormalizeUrlPrivateIPs: """Tests for private IP addresses.""" def test_10_x_gets_http(self): """10.x.x.x gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("10.0.0.1") == "http://10.0.0.1" def test_172_16_x_gets_http(self): """172.16.x.x gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("172.16.0.1") == "http://172.16.0.1" def test_192_168_x_gets_http(self): """192.168.x.x gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("192.168.1.1") == "http://192.168.1.1" def test_private_ip_with_port_gets_http(self): """Private IP with port gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("192.168.1.1:3000") == "http://192.168.1.1:3000" class TestNormalizeUrlPublicHosts: """Tests for public hostnames.""" def test_public_hostname_gets_https(self): """Public hostname gets https:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("example.com") == "https://example.com" def test_public_hostname_with_port_gets_https(self): """Public hostname with port gets https:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("example.com:443") == "https://example.com:443" def test_api_subdomain_gets_https(self): """API subdomain gets https:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("api.openai.com") == "https://api.openai.com" def test_public_ip_gets_https(self): """Public IP address gets https:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("8.8.8.8") == "https://8.8.8.8" class TestNormalizeUrlLocalDomain: """Tests for .local mDNS domains.""" def test_local_domain_gets_http(self): """host.local gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("myserver.local") == "http://myserver.local" def test_local_domain_with_port_gets_http(self): """host.local:port gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert ( normalize_url("myserver.local:8080") == "http://myserver.local:8080" ) class TestNormalizeUrlIPv6: """Tests for IPv6 addresses.""" def test_bracketed_ipv6_loopback(self): """Bracketed IPv6 loopback gets http://.""" from local_deep_research.utilities.url_utils import normalize_url result = normalize_url("[::1]") assert result == "http://[::1]" def test_bracketed_ipv6_public(self): """Bracketed public IPv6 gets https://.""" from local_deep_research.utilities.url_utils import normalize_url result = normalize_url("[2001:4860:4860::8888]") assert result == "https://[2001:4860:4860::8888]" class TestNormalizeUrlWhitespace: """Tests for whitespace handling.""" def test_strips_leading_whitespace(self): """Leading whitespace is stripped.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url(" https://example.com") == "https://example.com" def test_strips_trailing_whitespace(self): """Trailing whitespace is stripped.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("https://example.com ") == "https://example.com" def test_strips_both_whitespace(self): """Both leading and trailing whitespace is stripped.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url(" https://example.com ") == "https://example.com" class TestNormalizeUrlEmpty: """Tests for empty URL handling.""" def test_empty_string_raises(self): """Empty string raises ValueError.""" from local_deep_research.utilities.url_utils import normalize_url with pytest.raises(ValueError) as excinfo: normalize_url("") assert "empty" in str(excinfo.value).lower() def test_whitespace_only_returns_bare_scheme(self): """Whitespace-only string returns bare https:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url # Edge case: whitespace passes initial check (truthy) # but after stripping becomes empty hostname # Implementation adds https:// to empty string result = normalize_url(" ") # This is current behavior - returns 'https://' assert result == "https://" class TestNormalizeUrlWithPath: """Tests for URLs with paths.""" def test_hostname_with_path_gets_scheme(self): """Hostname with path gets appropriate scheme.""" from local_deep_research.utilities.url_utils import normalize_url result = normalize_url("example.com/api/v1") assert result == "https://example.com/api/v1" def test_localhost_with_path_gets_http(self): """localhost with path gets http://.""" from local_deep_research.utilities.url_utils import normalize_url result = normalize_url("localhost:8080/api") assert result == "http://localhost:8080/api" class TestNormalizeUrlEdgeCases: """Tests for edge cases.""" def test_0_0_0_0_is_private(self): """0.0.0.0 gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("0.0.0.0") == "http://0.0.0.0" def test_link_local_is_private(self): """169.254.x.x (link-local) gets http:// scheme.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("169.254.0.1") == "http://169.254.0.1" class TestIsPrivateIPExport: """Tests for is_private_ip re-export.""" def test_is_private_ip_exported(self): """is_private_ip is exported from url_utils.""" from local_deep_research.utilities.url_utils import is_private_ip # Should be callable assert callable(is_private_ip) # Should work assert is_private_ip("127.0.0.1") is True assert is_private_ip("8.8.8.8") is False class TestNormalizeUrlRealWorldExamples: """Tests with real-world URL examples.""" def test_ollama_default_url(self): """Ollama default URL (localhost:11434).""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("localhost:11434") == "http://localhost:11434" def test_openai_api_url(self): """OpenAI API URL.""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("api.openai.com") == "https://api.openai.com" def test_searxng_local_url(self): """SearXNG local instance URL.""" from local_deep_research.utilities.url_utils import normalize_url assert ( normalize_url("192.168.1.100:8888") == "http://192.168.1.100:8888" ) def test_docker_internal_url(self): """Docker internal network URL (172.17.x.x).""" from local_deep_research.utilities.url_utils import normalize_url assert normalize_url("172.17.0.2:5000") == "http://172.17.0.2:5000"