"""Coverage tests for notifications/url_builder.py — build_notification_url.""" from unittest.mock import MagicMock, patch import pytest from local_deep_research.notifications.url_builder import ( build_notification_url, ) from local_deep_research.security.url_validator import URLValidationError MODULE = "local_deep_research.notifications.url_builder" class TestBuildNotificationUrlWithSnapshot: def test_with_external_url(self): url = build_notification_url( "/research/123", settings_snapshot={"app.external_url": "https://myapp.com"}, validate=False, ) assert url == "https://myapp.com/research/123" def test_with_host_and_port(self): url = build_notification_url( "/research/456", settings_snapshot={ "app.external_url": "", "app.host": "0.0.0.0", "app.port": 8080, }, validate=False, ) assert "8080" in url assert "/research/456" in url def test_fallback_base(self): url = build_notification_url( "/test", fallback_base="http://fallback:9999", validate=False, ) assert url == "http://fallback:9999/test" class TestBuildNotificationUrlWithManager: def test_with_settings_manager(self): mock_sm = MagicMock() mock_sm.get_setting.side_effect = lambda key, **kw: { "app.external_url": "https://managed.com", "app.host": "localhost", "app.port": 5000, }.get(key, kw.get("default")) url = build_notification_url( "/research/789", settings_manager=mock_sm, validate=False, ) assert "managed.com" in url or "research/789" in url class TestBuildNotificationUrlValidation: def test_valid_url_passes(self): url = build_notification_url( "/research/123", settings_snapshot={"app.external_url": "https://valid.example.com"}, validate=True, ) assert "valid.example.com" in url def test_invalid_url_raises(self): with pytest.raises(URLValidationError): build_notification_url( "/test", settings_snapshot={ "app.external_url": "not-a-valid-url://???", }, validate=True, ) def test_validation_disabled(self): url = build_notification_url( "/test", validate=False, ) assert isinstance(url, str) class TestBuildNotificationUrlExceptions: def test_build_error_wraps_as_url_validation_error(self): with ( patch( f"{MODULE}.build_base_url_from_settings", side_effect=RuntimeError("build fail"), ), pytest.raises(URLValidationError), ): build_notification_url("/test") def test_url_validation_error_reraises(self): with ( patch( f"{MODULE}.build_base_url_from_settings", side_effect=URLValidationError("bad url"), ), pytest.raises(URLValidationError, match="bad url"), ): build_notification_url("/test") class TestBuildNotificationUrlDefaults: def test_default_fallback_base(self): url = build_notification_url("/path", validate=False) assert "localhost:5000" in url def test_empty_path(self): url = build_notification_url("", validate=False) assert isinstance(url, str)