Files
Tunetti/tests/test_config.py
NikkeDoy 93f5239ef7
Some checks failed
SonarQube Code Quality Scan / SonarQube Scan (push) Failing after 2m37s
| Add tests
2026-06-03 18:53:24 +03:00

126 lines
5.1 KiB
Python

"""Tests for the config module (config.py)."""
import json
import os
import tempfile
from pathlib import Path
from unittest import mock
import pytest
# We import the module under test after patching CONFIG_DIR so that
# the module-level SETTINGS dict is loaded from a temp location.
@pytest.fixture(autouse=True)
def _patch_config_paths(monkeypatch, tmp_path):
"""Redirect CONFIG_DIR to a tmp_path so tests don't touch ~/.config."""
config_dir = tmp_path / ".config" / "tunetti"
monkeypatch.setattr("config.CONFIG_DIR", config_dir)
monkeypatch.setattr("config.CONFIG_FILE", config_dir / "config.json")
monkeypatch.setattr("config._LEGACY_FILE", tmp_path / "tunetti_config.json")
# Also reset SETTINGS and DEFAULT_CONFIG after patching
import config as cfg
cfg.SETTINGS = cfg.load_config()
return cfg
# ── Tests ─────────────────────────────────────────────────────────────────────
class TestLoadConfig:
def test_first_launch_creates_defaults(self, _patch_config_paths):
"""On first launch, no config exists → defaults are written to disk."""
cfg = _patch_config_paths
assert cfg.CONFIG_FILE.exists()
assert cfg.SETTINGS["volume"] == 50
assert cfg.SETTINGS["max_history"] == 5000
assert cfg.SETTINGS["discord_rpc_enabled"] is True
def test_loads_existing_config(self, _patch_config_paths):
"""Loading an existing config merges user values over defaults."""
cfg = _patch_config_paths
cfg.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
user_config = {"volume": 75, "max_history": 100}
cfg.CONFIG_FILE.write_text(json.dumps(user_config))
loaded = cfg.load_config()
assert loaded["volume"] == 75
assert loaded["max_history"] == 100
# default keys still present
assert loaded["discord_rpc_enabled"] is True
def test_corrupt_config_falls_back_to_defaults(self, _patch_config_paths):
"""Corrupt JSON should be ignored and defaults returned."""
cfg = _patch_config_paths
cfg.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
cfg.CONFIG_FILE.write_text("not valid json")
loaded = cfg.load_config()
assert loaded["volume"] == 50 # default
# The corrupt file is not overwritten, but defaults are returned
def test_legacy_migration(self, _patch_config_paths):
"""Legacy config in project dir is migrated to XDG location."""
cfg = _patch_config_paths
# Remove the config that was created by the fixture so migration runs
cfg.CONFIG_FILE.unlink(missing_ok=True)
cfg.SETTINGS = dict(cfg.DEFAULT_CONFIG)
legacy = {**cfg.DEFAULT_CONFIG, "volume": 90}
# Legacy file location is the parent of the "real" config dir (tmp_path)
cfg._LEGACY_FILE.write_text(json.dumps(legacy))
loaded = cfg.load_config()
assert loaded["volume"] == 90
# Legacy file should be renamed
assert not cfg._LEGACY_FILE.exists()
assert cfg._LEGACY_FILE.with_suffix(".json.migrated").exists()
class TestSaveConfig:
def test_save_config_persists(self, _patch_config_paths):
"""save_config writes merged config to disk."""
cfg = _patch_config_paths
cfg.save_config({"volume": 30, "visualizer_enabled": False})
data = json.loads(cfg.CONFIG_FILE.read_text())
assert data["volume"] == 30
assert data["visualizer_enabled"] is False
def test_save_volume_clamps(self, _patch_config_paths):
"""save_volume clamps values between 0 and 100."""
cfg = _patch_config_paths
cfg.save_volume(-10)
assert cfg.SETTINGS["volume"] == 0
cfg.save_volume(150)
assert cfg.SETTINGS["volume"] == 100
cfg.save_volume(42)
assert cfg.SETTINGS["volume"] == 42
def test_save_setting_updates_memory_and_disk(self, _patch_config_paths):
"""save_setting updates both in-memory SETTINGS and persisted config."""
cfg = _patch_config_paths
cfg.save_setting("max_history", 999)
assert cfg.SETTINGS["max_history"] == 999
data = json.loads(cfg.CONFIG_FILE.read_text())
assert data["max_history"] == 999
class TestGetSetting:
def test_returns_set_value(self, _patch_config_paths):
"""get_setting returns the current in-memory value."""
cfg = _patch_config_paths
cfg.SETTINGS["volume"] = 88
assert cfg.get_setting("volume") == 88
def test_returns_default_for_missing(self, _patch_config_paths):
"""get_setting falls back to DEFAULT_CONFIG for missing keys."""
cfg = _patch_config_paths
# Remove from SETTINGS
cfg.SETTINGS.pop("volume", None)
assert cfg.get_setting("volume") == cfg.DEFAULT_CONFIG["volume"]
def test_nonexistent_key_returns_none(self, _patch_config_paths):
"""get_setting returns None for keys not in either dict."""
cfg = _patch_config_paths
assert cfg.get_setting("nonexistent_key") is None