webdrop-bridge/tests/unit/test_settings_dialog.py
claudi 55f2ddf4b1
Some checks are pending
Tests & Quality Checks / Test on Python 3.11 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.10 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-2 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-2 (push) Waiting to run
Tests & Quality Checks / Build Artifacts (push) Blocked by required conditions
Tests & Quality Checks / Build Artifacts-1 (push) Blocked by required conditions
feat: Add branding import/export functionality and enhance settings dialog with new fields
2026-04-15 16:26:38 +02:00

374 lines
13 KiB
Python

"""Tests for settings dialog."""
from pathlib import Path
from unittest.mock import patch
import pytest
from webdrop_bridge.config import Config
from webdrop_bridge.ui.settings_dialog import SettingsDialog
@pytest.fixture
def sample_config(tmp_path):
"""Create sample configuration."""
return Config(
app_name="WebDrop Bridge",
app_version="1.0.0",
log_level="INFO",
log_file=None,
allowed_roots=[Path("/home"), Path("/data")],
allowed_urls=["http://example.com", "http://*.test.com"],
webapp_url="http://localhost:8080",
window_width=800,
window_height=600,
window_title="WebDrop Bridge v1.0.0",
enable_logging=True,
)
class TestSettingsDialogInitialization:
"""Test settings dialog initialization."""
def test_dialog_creation(self, qtbot, sample_config):
"""Test dialog can be created."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog is not None
assert dialog.windowTitle() == "Settings"
def test_dialog_has_tabs(self, qtbot, sample_config):
"""Test dialog has all required tabs."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs is not None
assert dialog.tabs.count() == 8 # General + Branding + previous 6 tabs
def test_dialog_has_general_tab(self, qtbot, sample_config):
"""Test General tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(0) == "General"
def test_dialog_has_branding_tab(self, qtbot, sample_config):
"""Test Branding tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(1) == "Branding"
def test_dialog_has_web_source_tab(self, qtbot, sample_config):
"""Test Web Source tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(2) == "Web Source"
def test_dialog_has_paths_tab(self, qtbot, sample_config):
"""Test Paths tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(3) == "Paths"
def test_dialog_has_urls_tab(self, qtbot, sample_config):
"""Test URLs tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(4) == "URLs"
def test_dialog_has_logging_tab(self, qtbot, sample_config):
"""Test Logging tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(5) == "Logging"
def test_dialog_has_window_tab(self, qtbot, sample_config):
"""Test Window tab exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(6) == "Window"
def test_dialog_has_profiles_tab(self, qtbot, sample_config):
"""Test Setups tab exists with clearer wording."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.tabText(7) == "Setups"
def test_profiles_actions_have_explanatory_tooltips(self, qtbot, sample_config):
"""Test profile/config actions expose helpful explanations."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert "this device" in dialog.save_profile_btn.toolTip().lower()
assert "backup" in dialog.export_btn.toolTip().lower()
assert "json" in dialog.import_btn.toolTip().lower()
def test_branding_editor_fields_are_initialized(
self, qtbot, sample_config, monkeypatch, tmp_path
):
"""Test branding tab exposes editable fields for the selected template."""
monkeypatch.setenv("WEBDROP_BRANDING_DIR", str(tmp_path / "branding"))
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.branding_display_name_input.text() == "Default"
assert dialog.branding_app_name_input.text() == "WebDrop Bridge"
assert "WebDrop Bridge" in dialog.branding_window_title_input.text()
assert dialog.branding_logo_path_input is not None
assert dialog.browse_branding_logo_btn is not None
assert dialog.branding_preview_name_label.text() == "Default"
assert dialog.branding_preview_icon_label.pixmap() is not None
assert not dialog.branding_preview_icon_label.pixmap().isNull()
assert dialog.export_branding_btn is not None
assert dialog.import_branding_btn is not None
assert dialog.delete_branding_btn is not None
def test_save_branding_as_creates_custom_template(
self, qtbot, sample_config, monkeypatch, tmp_path
):
"""Test edited branding can be saved as a new reusable template."""
monkeypatch.setenv("WEBDROP_BRANDING_DIR", str(tmp_path / "branding"))
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
logo_path = tmp_path / "customer-logo.png"
logo_path.write_bytes(b"fake-png-data")
dialog.branding_display_name_input.setText("Customer A")
dialog.branding_logo_path_input.setText(str(logo_path))
with patch("PySide6.QtWidgets.QInputDialog.getText", return_value=("Customer A", True)):
dialog._save_branding_as()
assert dialog.branding_manager.has_template("customer_a")
assert dialog.branding_combo.findData("customer_a") >= 0
class TestPathsTab:
"""Test Paths configuration tab."""
def test_paths_loaded_from_config(self, qtbot, sample_config):
"""Test paths are loaded from configuration."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
items = [dialog.paths_list.item(i).text() for i in range(dialog.paths_list.count())]
assert len(items) == 2
# Paths are normalized (backslashes on Windows)
assert any("home" in item for item in items)
assert any("data" in item for item in items)
def test_add_path_button_exists(self, qtbot, sample_config):
"""Test Add Path button exists."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.tabs.currentWidget() is not None
class TestURLsTab:
"""Test URLs configuration tab."""
def test_urls_loaded_from_config(self, qtbot, sample_config):
"""Test URLs are loaded from configuration."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
items = [dialog.urls_list.item(i).text() for i in range(dialog.urls_list.count())]
assert len(items) == 2
assert "http://example.com" in items
assert "http://*.test.com" in items
class TestLoggingTab:
"""Test Logging configuration tab."""
def test_log_level_set_from_config(self, qtbot, sample_config):
"""Test log level is set from configuration."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.log_level_combo.currentText() == "INFO"
def test_log_levels_available(self, qtbot, sample_config):
"""Test all log levels are available."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
levels = [dialog.log_level_combo.itemText(i) for i in range(dialog.log_level_combo.count())]
assert "DEBUG" in levels
assert "INFO" in levels
assert "WARNING" in levels
assert "ERROR" in levels
assert "CRITICAL" in levels
class TestWindowTab:
"""Test Window configuration tab."""
def test_window_width_set_from_config(self, qtbot, sample_config):
"""Test window width is set from configuration."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.width_spin.value() == 800
def test_window_height_set_from_config(self, qtbot, sample_config):
"""Test window height is set from configuration."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.height_spin.value() == 600
def test_window_width_has_min_max(self, qtbot, sample_config):
"""Test window width spinbox has min/max."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.width_spin.minimum() == 400
assert dialog.width_spin.maximum() == 5000
def test_window_height_has_min_max(self, qtbot, sample_config):
"""Test window height spinbox has min/max."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.height_spin.minimum() == 300
assert dialog.height_spin.maximum() == 5000
class TestProfilesTab:
"""Test profiles management tab."""
def test_profiles_list_initialized(self, qtbot, sample_config):
"""Test profiles list is initialized."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
assert dialog.profiles_list is not None
assert dialog.profiles_help_label.wordWrap() is True
class TestConfigDataRetrieval:
"""Test getting configuration data from dialog."""
def test_get_config_data_from_dialog(self, qtbot, sample_config):
"""Test retrieving configuration data from dialog."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
config_data = dialog.get_config_data()
assert config_data["app_name"] == "WebDrop Bridge"
assert config_data["log_level"] == "INFO"
assert config_data["window_width"] == 800
assert config_data["window_height"] == 600
def test_get_config_data_validates(self, qtbot, sample_config):
"""Test get_config_data returns valid configuration data."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
# All default values are valid
config_data = dialog.get_config_data()
assert config_data is not None
assert config_data["window_width"] == 800
def test_get_config_data_with_modified_values(self, qtbot, sample_config):
"""Test get_config_data returns modified values."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
# Modify values
dialog.width_spin.setValue(1024)
dialog.height_spin.setValue(768)
dialog.log_level_combo.setCurrentText("DEBUG")
config_data = dialog.get_config_data()
assert config_data["window_width"] == 1024
assert config_data["window_height"] == 768
assert config_data["log_level"] == "DEBUG"
class TestApplyConfigData:
"""Test applying configuration data to dialog."""
def test_apply_config_data_updates_paths(self, qtbot, sample_config):
"""Test applying config data updates paths."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
new_config = {
"app_name": "Test",
"app_version": "1.0.0",
"log_level": "INFO",
"log_file": None,
"allowed_roots": ["/new/path", "/another/path"],
"allowed_urls": [],
"webapp_url": "http://localhost",
"window_width": 800,
"window_height": 600,
"enable_logging": True,
}
dialog._apply_config_data(new_config)
items = [dialog.paths_list.item(i).text() for i in range(dialog.paths_list.count())]
assert "/new/path" in items
assert "/another/path" in items
def test_apply_config_data_updates_urls(self, qtbot, sample_config):
"""Test applying config data updates URLs."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
new_config = {
"app_name": "Test",
"app_version": "1.0.0",
"log_level": "INFO",
"log_file": None,
"allowed_roots": [],
"allowed_urls": ["http://new.com", "http://test.org"],
"webapp_url": "http://localhost",
"window_width": 800,
"window_height": 600,
"enable_logging": True,
}
dialog._apply_config_data(new_config)
items = [dialog.urls_list.item(i).text() for i in range(dialog.urls_list.count())]
assert "http://new.com" in items
assert "http://test.org" in items
def test_apply_config_data_updates_window_size(self, qtbot, sample_config):
"""Test applying config data updates window size."""
dialog = SettingsDialog(sample_config)
qtbot.addWidget(dialog)
new_config = {
"app_name": "Test",
"app_version": "1.0.0",
"log_level": "INFO",
"log_file": None,
"allowed_roots": [],
"allowed_urls": [],
"webapp_url": "http://localhost",
"window_width": 1280,
"window_height": 1024,
"enable_logging": True,
}
dialog._apply_config_data(new_config)
assert dialog.width_spin.value() == 1280
assert dialog.height_spin.value() == 1024