300 lines
10 KiB
Python
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
|