"""Tests for src/config.py - ConfigManager.""" import json import os from pathlib import Path import sys from unittest.mock import patch, MagicMock sys.path.insert(0, str(Path(__file__).parent.parent)) import pytest from src.config import ConfigManager class TestConfigManagerInit: def test_init_no_config_file(self, tmp_path, monkeypatch): cfg = ConfigManager(str(tmp_path / "nonexistent.json")) assert cfg.config["tvdb_api_key"] == "" assert cfg.config["default_episode_duration"] == 45 assert cfg.config["classification_thresholds"]["size_threshold_ratio"] == 0.3 def test_init_existing_config(self, config_file): cfg = ConfigManager(str(config_file)) assert cfg.config["tvdb_api_key"] == "test_api_key_12345" assert cfg.config["default_episode_duration"] == 45 def test_init_invalid_json(self, tmp_path): bad = tmp_path / "config.json" bad.write_text("{invalid json") cfg = ConfigManager(str(bad)) assert cfg.config["tvdb_api_key"] == "" def test_init_missing_keys_merged(self, tmp_path): partial = tmp_path / "config.json" partial.write_text(json.dumps({"tvdb_api_key": "abc"})) cfg = ConfigManager(str(partial)) assert cfg.config["default_episode_duration"] == 45 assert "classification_thresholds" in cfg.config def test_init_io_error(self, tmp_path, monkeypatch): cfg_path = tmp_path / "config.json" cfg_path.write_text("test") monkeypatch.setattr(Path, "exists", lambda self: True) original_open = open def mock_open(*args, **kwargs): raise PermissionError("denied") with patch("builtins.open", mock_open): cfg = ConfigManager(str(cfg_path)) assert cfg.config["tvdb_api_key"] == "" class TestConfigManagerApiKeys: def test_get_api_key_from_config(self, config_file): cfg = ConfigManager(str(config_file)) with patch.dict(os.environ, {}, clear=True): key = cfg.get_tvdb_api_key() assert key == "test_api_key_12345" def test_get_api_key_from_env(self, config_file, monkeypatch): cfg = ConfigManager(str(config_file)) monkeypatch.setenv("TVDB_API_KEY", "env_key_999") key = cfg.get_tvdb_api_key() assert key == "env_key_999" def test_get_api_key_empty_env(self, config_file, monkeypatch): cfg = ConfigManager(str(config_file)) monkeypatch.setenv("TVDB_API_KEY", " ") key = cfg.get_tvdb_api_key() assert key == "test_api_key_12345" def test_get_api_key_placeholder_rejected(self, empty_config_file): cfg = ConfigManager(str(empty_config_file)) cfg.config["tvdb_api_key"] = "YOUR_TVDB_API_KEY_HERE" assert cfg.get_tvdb_api_key() is None def test_get_api_key_env_placeholder_rejected(self, empty_config_file, monkeypatch): cfg = ConfigManager(str(empty_config_file)) monkeypatch.setenv("TVDB_API_KEY", "YOUR_TVDB_API_KEY_HERE") assert cfg.get_tvdb_api_key() is None def test_env_key_takes_priority(self, config_file, monkeypatch): cfg = ConfigManager(str(config_file)) monkeypatch.setenv("TVDB_API_KEY", "env_priority") assert cfg.get_tvdb_api_key() == "env_priority" class TestConfigManagerSettings: def test_get_default_episode_duration(self, config_file): cfg = ConfigManager(str(config_file)) assert cfg.get_default_episode_duration() == 45 def test_get_default_episode_duration_custom(self, tmp_path): f = tmp_path / "config.json" f.write_text(json.dumps({"default_episode_duration": 60})) cfg = ConfigManager(str(f)) assert cfg.get_default_episode_duration() == 60 def test_get_classification_thresholds(self, config_file): cfg = ConfigManager(str(config_file)) t = cfg.get_classification_thresholds() assert t["size_threshold_ratio"] == 0.3 assert t["duration_threshold_ratio"] == 0.4 def test_get_classification_thresholds_defaults(self, tmp_path): cfg = ConfigManager(str(tmp_path / "no.json")) t = cfg.get_classification_thresholds() assert t["size_threshold_ratio"] == 0.3 class TestConfigManagerUpdate: def test_update_api_key_success(self, tmp_path): cfg = ConfigManager(str(tmp_path / "config.json")) result = cfg.update_api_key("new_key_abc") assert result is True assert cfg.config["tvdb_api_key"] == "new_key_abc" stored = json.loads((tmp_path / "config.json").read_text()) assert stored["tvdb_api_key"] == "new_key_abc" def test_update_api_key_io_error(self, tmp_path): cfg = ConfigManager(str(tmp_path / "config.json")) cfg.update_api_key("new_key") cfg.config_file = Path("/nonexistent_dir/config.json") result = cfg.update_api_key("another_key") assert result is False class TestConfigManagerStatus: def test_print_config_status_no_key(self, tmp_path, capsys): cfg = ConfigManager(str(tmp_path / "no.json")) cfg.print_config_status() out = capsys.readouterr().out assert "Configuration file:" in out assert "Not configured" in out def test_print_config_status_with_key(self, config_file, capsys): cfg = ConfigManager(str(config_file)) cfg.print_config_status() out = capsys.readouterr().out assert "configured" in out def test_print_config_status_masked_short_key(self, tmp_path): f = tmp_path / "config.json" f.write_text(json.dumps({"tvdb_api_key": "ab"})) cfg = ConfigManager(str(f)) cfg.print_config_status()