import os import tempfile import yaml from spectra.config import DEFAULT_CONFIG, _deep_merge, load_config class TestLoadConfig: def test_defaults_when_no_file(self): cfg = load_config(path="/nonexistent/.spectra/config.yaml") assert cfg["display"]["saturation"] == 0.5 assert cfg["display"]["orientation"] == 0 assert cfg["unsplash"]["access_key"] == "" assert cfg["schedule"]["interval_hours"] == 1 def test_load_specific_path(self): with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: yaml.dump({"display": {"saturation": 0.8}}, f) path = f.name try: cfg = load_config(path) assert cfg["display"]["saturation"] == 0.8 assert cfg["display"]["orientation"] == 0 finally: os.unlink(path) def test_missing_path_logs_and_uses_defaults(self): cfg = load_config("/nonexistent/path/config.yaml") assert cfg["display"]["saturation"] == 0.5 def test_partial_merge_does_not_remove_other_keys(self): with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: yaml.dump({"display": {"saturation": 0.3}}, f) path = f.name try: cfg = load_config(path) assert cfg["display"]["saturation"] == 0.3 assert cfg["display"]["resolution"]["width"] == 1600 assert cfg["unsplash"]["access_key"] == "" finally: os.unlink(path) def test_empty_file_uses_defaults(self): with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: f.write("") path = f.name try: cfg = load_config(path) assert cfg["display"]["saturation"] == 0.5 finally: os.unlink(path) def test_deep_merge_overrides_nested_key(self): base = {"a": {"b": 1, "c": 2}, "d": 3} override = {"a": {"b": 99}} _deep_merge(base, override) assert base["a"]["b"] == 99 assert base["a"]["c"] == 2 assert base["d"] == 3 def test_deep_merge_adds_new_keys(self): base = {"a": 1} override = {"b": 2} _deep_merge(base, override) assert base["a"] == 1 assert base["b"] == 2 def test_deep_merge_overrides_non_dict_with_dict(self): base = {"a": 1} override = {"a": {"b": 2}} _deep_merge(base, override) assert base["a"] == {"b": 2} def test_default_config_not_mutated_by_load(self): original_sat = DEFAULT_CONFIG["display"]["saturation"] with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: yaml.dump({"display": {"saturation": 0.9}}, f) path = f.name try: load_config(path) assert DEFAULT_CONFIG["display"]["saturation"] == original_sat finally: os.unlink(path) def test_default_config_not_mutated_by_multiple_loads(self): with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: yaml.dump({"unsplash": {"query": "cats"}}, f) path1 = f.name with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: yaml.dump({"unsplash": {"query": "dogs"}}, f) path2 = f.name try: c1 = load_config(path1) c2 = load_config(path2) assert c1["unsplash"]["query"] == "cats" assert c2["unsplash"]["query"] == "dogs" assert DEFAULT_CONFIG["unsplash"]["query"] == "" finally: os.unlink(path1) os.unlink(path2)