webdrop-bridge/tests/unit/test_restricted_web_view.py
claudi 705969cdba
Some checks failed
Tests & Quality Checks / Test on Python 3.11 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.12 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.11-1 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.12-1 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.10 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.11-2 (push) Has been cancelled
Tests & Quality Checks / Test on Python 3.12-2 (push) Has been cancelled
Tests & Quality Checks / Build Artifacts (push) Has been cancelled
Tests & Quality Checks / Build Artifacts-1 (push) Has been cancelled
feat: enhance web engine view with profile isolation and add cache clearing functionality
2026-03-03 10:22:14 +01:00

179 lines
6.5 KiB
Python

"""Unit tests for RestrictedWebEngineView URL filtering."""
from unittest.mock import MagicMock, patch
from PySide6.QtCore import QUrl
from PySide6.QtWebEngineCore import QWebEngineNavigationRequest
from webdrop_bridge.ui.restricted_web_view import RestrictedWebEngineView
def _create_mock_request(url: str) -> MagicMock:
"""Create properly mocked navigation request.
Args:
url: URL string to mock
Returns:
Properly mocked QWebEngineNavigationRequest
"""
request = MagicMock(spec=QWebEngineNavigationRequest)
request.url = MagicMock(return_value=QUrl(url))
return request
class TestRestrictedWebEngineView:
"""Test URL whitelist enforcement."""
def test_no_restrictions_empty_list(self, qtbot):
"""Test that empty allowed_urls means no restrictions."""
view = RestrictedWebEngineView([])
# Mock navigation request
request = _create_mock_request("https://example.com/page")
# Should not reject any URL
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_no_restrictions_none(self, qtbot):
"""Test that None allowed_urls means no restrictions."""
view = RestrictedWebEngineView(None)
request = _create_mock_request("https://blocked.com/page")
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_exact_domain_match(self, qtbot):
"""Test exact domain matching."""
view = RestrictedWebEngineView(["example.com"])
request = _create_mock_request("https://example.com/page")
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_exact_domain_mismatch(self, qtbot):
"""Test that mismatched domains are rejected."""
view = RestrictedWebEngineView(["example.com"])
request = _create_mock_request("https://other.com/page")
with patch("webdrop_bridge.ui.restricted_web_view.QDesktopServices"):
view._on_navigation_requested(request)
request.reject.assert_called_once()
def test_wildcard_pattern_match(self, qtbot):
"""Test wildcard pattern matching."""
view = RestrictedWebEngineView(["*.example.com"])
request = _create_mock_request("https://sub.example.com/page")
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_wildcard_pattern_mismatch(self, qtbot):
"""Test that non-matching wildcard patterns are rejected."""
view = RestrictedWebEngineView(["*.example.com"])
request = _create_mock_request("https://example.org/page")
with patch("webdrop_bridge.ui.restricted_web_view.QDesktopServices"):
view._on_navigation_requested(request)
request.reject.assert_called_once()
def test_localhost_allowed(self, qtbot):
"""Test that localhost is allowed."""
view = RestrictedWebEngineView(["localhost"])
request = _create_mock_request("http://localhost:8000/page")
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_file_url_always_allowed(self, qtbot):
"""Test that file:// URLs are always allowed."""
view = RestrictedWebEngineView(["example.com"])
request = _create_mock_request("file:///var/www/index.html")
view._on_navigation_requested(request)
request.reject.assert_not_called()
def test_multiple_allowed_urls(self, qtbot):
"""Test multiple allowed URLs."""
view = RestrictedWebEngineView(["example.com", "test.org"])
# First allowed URL
request1 = _create_mock_request("https://example.com/page")
view._on_navigation_requested(request1)
request1.reject.assert_not_called()
# Second allowed URL
request2 = _create_mock_request("https://test.org/page")
view._on_navigation_requested(request2)
request2.reject.assert_not_called()
# Non-allowed URL
request3 = _create_mock_request("https://blocked.com/page")
with patch("webdrop_bridge.ui.restricted_web_view.QDesktopServices"):
view._on_navigation_requested(request3)
request3.reject.assert_called_once()
def test_rejected_url_opens_system_browser(self, qtbot):
"""Test that rejected URLs open in system browser."""
view = RestrictedWebEngineView(["allowed.com"])
request = _create_mock_request("https://blocked.com/page")
with patch("webdrop_bridge.ui.restricted_web_view.QDesktopServices.openUrl") as mock_open:
view._on_navigation_requested(request)
request.reject.assert_called_once()
# Check that openUrl was called with a QUrl
mock_open.assert_called_once()
class TestURLAllowedLogic:
"""Test _is_url_allowed method directly."""
def test_is_url_allowed_empty_list(self, qtbot):
"""Test that empty whitelist allows all URLs."""
view = RestrictedWebEngineView([])
assert view._is_url_allowed(QUrl("https://anything.com")) is True
def test_is_url_allowed_file_scheme(self, qtbot):
"""Test that file:// URLs are always allowed."""
view = RestrictedWebEngineView(["example.com"])
assert view._is_url_allowed(QUrl("file:///app/index.html")) is True
def test_is_url_allowed_exact_match(self, qtbot):
"""Test exact domain match."""
view = RestrictedWebEngineView(["example.com"])
assert view._is_url_allowed(QUrl("https://example.com/page")) is True
assert view._is_url_allowed(QUrl("https://other.com/page")) is False
def test_is_url_allowed_with_port(self, qtbot):
"""Test domain matching with port number."""
view = RestrictedWebEngineView(["localhost"])
assert view._is_url_allowed(QUrl("http://localhost:8000/page")) is True
def test_is_url_allowed_wildcard(self, qtbot):
"""Test wildcard pattern matching."""
view = RestrictedWebEngineView(["*.example.com", "localhost"])
# Wildcard *.example.com will match sub.example.com
assert view._is_url_allowed(QUrl("https://sub.example.com/page")) is True
# *.example.com will also match example.com (fnmatch behavior)
assert view._is_url_allowed(QUrl("https://example.com/page")) is True
# But not other domains
assert view._is_url_allowed(QUrl("https://other.org/page")) is False
# localhost should work
assert view._is_url_allowed(QUrl("http://localhost:3000")) is True