EU-Utility/tests/unit/test_settings.py

300 lines
10 KiB
Python

"""
Unit tests for Settings service.
Tests cover:
- Settings initialization and loading
- Getting and setting values
- Default values
- Plugin enable/disable
- Settings reset
- Signal emission
"""
import pytest
import json
from pathlib import Path
from unittest.mock import patch, mock_open, MagicMock
from core.settings import Settings, get_settings
@pytest.mark.unit
class TestSettingsInitialization:
"""Test Settings initialization."""
def test_default_config_file(self):
"""Test default configuration file path."""
with patch('core.settings.Path.exists', return_value=False):
settings = Settings()
assert settings.config_file == Path("data/settings.json")
def test_custom_config_file(self, tmp_path):
"""Test custom configuration file path."""
config_file = tmp_path / "custom_settings.json"
settings = Settings(config_file=str(config_file))
assert settings.config_file == config_file
def test_load_existing_settings(self, tmp_path):
"""Test loading existing settings file."""
config_file = tmp_path / "settings.json"
saved_settings = {
"overlay_enabled": False,
"custom_key": "custom_value"
}
with open(config_file, 'w') as f:
json.dump(saved_settings, f)
settings = Settings(config_file=str(config_file))
assert settings.get("overlay_enabled") is False
assert settings.get("custom_key") == "custom_value"
def test_load_corrupted_settings(self, tmp_path):
"""Test loading corrupted settings file."""
config_file = tmp_path / "settings.json"
with open(config_file, 'w') as f:
f.write("not valid json")
# Should use defaults, not raise
settings = Settings(config_file=str(config_file))
assert settings.get("overlay_enabled") is True # Default value
@pytest.mark.unit
class TestGetAndSet:
"""Test getting and setting settings."""
def test_get_existing_value(self, tmp_path):
"""Test getting an existing setting value."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
# overlay_enabled is in defaults
assert settings.get("overlay_enabled") is True
def test_get_with_default(self, tmp_path):
"""Test getting a value with custom default."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
result = settings.get("nonexistent_key", "default_value")
assert result == "default_value"
def test_set_value(self, tmp_path):
"""Test setting a value."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
settings.set("test_key", "test_value")
assert settings.get("test_key") == "test_value"
def test_set_saves_to_file(self, tmp_path):
"""Test that set() saves to file."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
settings.set("test_key", "test_value")
# Read file directly
with open(config_file, 'r') as f:
saved = json.load(f)
assert saved["test_key"] == "test_value"
@pytest.mark.unit
class TestDefaultValues:
"""Test default values."""
def test_overlay_defaults(self, tmp_path):
"""Test overlay-related defaults."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
assert settings.get("overlay_enabled") is True
assert settings.get("overlay_opacity") == 0.9
assert settings.get("overlay_theme") == "dark"
def test_hotkey_defaults(self, tmp_path):
"""Test hotkey defaults."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
assert settings.get("hotkey_toggle") == "ctrl+shift+u"
assert settings.get("hotkey_search") == "ctrl+shift+f"
assert settings.get("hotkey_calculator") == "ctrl+shift+c"
def test_plugin_defaults(self, tmp_path):
"""Test plugin-related defaults."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
enabled = settings.get("enabled_plugins")
assert "universal_search" in enabled
assert "calculator" in enabled
assert "spotify_controller" in enabled
def test_all_defaults(self, tmp_path):
"""Test that all defaults are present."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
all_settings = settings.all_settings()
# Check all default keys are present
for key in Settings.DEFAULTS:
assert key in all_settings
@pytest.mark.unit
class TestPluginManagement:
"""Test plugin enable/disable functionality."""
def test_is_plugin_enabled(self, tmp_path):
"""Test checking if plugin is enabled."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
assert settings.is_plugin_enabled("universal_search") is True
assert settings.is_plugin_enabled("nonexistent_plugin") is False
def test_enable_plugin(self, tmp_path):
"""Test enabling a plugin."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
# First disable
settings.disable_plugin("test_plugin")
assert settings.is_plugin_enabled("test_plugin") is False
# Then enable
settings.enable_plugin("test_plugin")
assert settings.is_plugin_enabled("test_plugin") is True
def test_disable_plugin(self, tmp_path):
"""Test disabling a plugin."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
settings.enable_plugin("test_plugin")
assert settings.is_plugin_enabled("test_plugin") is True
settings.disable_plugin("test_plugin")
assert settings.is_plugin_enabled("test_plugin") is False
def test_disable_moves_to_disabled_list(self, tmp_path):
"""Test that disabling moves plugin to disabled list."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
settings.enable_plugin("test_plugin")
settings.disable_plugin("test_plugin")
disabled = settings.get("disabled_plugins")
assert "test_plugin" in disabled
def test_enable_removes_from_disabled_list(self, tmp_path):
"""Test that enabling removes plugin from disabled list."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
settings.enable_plugin("test_plugin")
settings.disable_plugin("test_plugin")
assert "test_plugin" in settings.get("disabled_plugins")
settings.enable_plugin("test_plugin")
assert "test_plugin" not in settings.get("disabled_plugins")
@pytest.mark.unit
class TestReset:
"""Test settings reset functionality."""
def test_reset_single_key(self, tmp_path):
"""Test resetting a single key to default."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
# Change value
settings.set("overlay_enabled", False)
assert settings.get("overlay_enabled") is False
# Reset
settings.reset("overlay_enabled")
assert settings.get("overlay_enabled") is True # Back to default
def test_reset_all(self, tmp_path):
"""Test resetting all settings to defaults."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
# Change multiple values
settings.set("overlay_enabled", False)
settings.set("overlay_opacity", 0.5)
settings.set("custom_key", "custom_value")
# Reset all
settings.reset()
assert settings.get("overlay_enabled") is True
assert settings.get("overlay_opacity") == 0.9
assert settings.get("custom_key") is None # Non-default key removed
@pytest.mark.unit
class TestSignals:
"""Test Qt signal emission."""
def test_signal_emitted_on_set(self, tmp_path):
"""Test that signal is emitted when setting a value."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
received = []
def on_setting_changed(key, value):
received.append((key, value))
settings.setting_changed.connect(on_setting_changed)
settings.set("test_key", "test_value")
assert len(received) == 1
assert received[0] == ("test_key", "test_value")
def test_signal_emitted_on_reset(self, tmp_path):
"""Test that signal is emitted when resetting."""
config_file = tmp_path / "settings.json"
settings = Settings(config_file=str(config_file))
received = []
def on_setting_changed(key, value):
received.append((key, value))
settings.set("overlay_enabled", False)
settings.setting_changed.connect(on_setting_changed)
settings.reset("overlay_enabled")
assert len(received) == 1
assert received[0][0] == "overlay_enabled"
assert received[0][1] is True # Default value
@pytest.mark.unit
class TestSingleton:
"""Test Settings singleton."""
def test_singleton_instance(self):
"""Test that get_settings returns same instance."""
# Note: Settings is not strictly a singleton, but get_settings caches
with patch('core.settings.Path.exists', return_value=False):
settings1 = get_settings()
settings2 = get_settings()
assert settings1 is settings2