134 lines
4.1 KiB
Python
134 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Tests for config_template.py — issue #696"""
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import pytest
|
|
from pathlib import Path
|
|
|
|
# Add parent dir for import
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
|
from config_template import ConfigTemplate, _deep_merge, _get_dotted, _diff_dicts, _validate_config
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_config_dir(tmp_path):
|
|
"""Create a temp config dir with base + overlay files."""
|
|
import yaml
|
|
base = {
|
|
"model": {"name": "base-model", "temperature": 0.7},
|
|
"cron": {"enabled": False, "interval": 300},
|
|
"display": {"colors": True},
|
|
}
|
|
overlay = {
|
|
"model": {"temperature": 0.9},
|
|
"cron": {"enabled": True},
|
|
"logging": {"level": "DEBUG"},
|
|
}
|
|
with open(tmp_path / "base.yaml", "w") as f:
|
|
yaml.dump(base, f)
|
|
with open(tmp_path / "test.overlay.yaml", "w") as f:
|
|
yaml.dump(overlay, f)
|
|
return tmp_path
|
|
|
|
|
|
class TestDeepMerge:
|
|
def test_overlay_wins(self):
|
|
base = {"a": 1, "b": 2}
|
|
overlay = {"b": 99}
|
|
result = _deep_merge(base, overlay)
|
|
assert result == {"a": 1, "b": 99}
|
|
|
|
def test_deep_merge_nested(self):
|
|
base = {"model": {"name": "x", "temp": 0.7}}
|
|
overlay = {"model": {"temp": 0.9}}
|
|
result = _deep_merge(base, overlay)
|
|
assert result["model"]["name"] == "x"
|
|
assert result["model"]["temp"] == 0.9
|
|
|
|
def test_new_keys_added(self):
|
|
base = {"a": 1}
|
|
overlay = {"b": 2}
|
|
result = _deep_merge(base, overlay)
|
|
assert result == {"a": 1, "b": 2}
|
|
|
|
def test_originals_unchanged(self):
|
|
base = {"a": {"inner": 1}}
|
|
overlay = {"a": {"inner": 99}}
|
|
_deep_merge(base, overlay)
|
|
assert base["a"]["inner"] == 1
|
|
|
|
|
|
class TestDottedAccess:
|
|
def test_simple_key(self):
|
|
assert _get_dotted({"a": 1}, "a") == 1
|
|
|
|
def test_nested_key(self):
|
|
assert _get_dotted({"a": {"b": {"c": 42}}}, "a.b.c") == 42
|
|
|
|
def test_missing_key_returns_default(self):
|
|
assert _get_dotted({"a": 1}, "x", "fallback") == "fallback"
|
|
|
|
def test_partial_path(self):
|
|
assert _get_dotted({"a": 1}, "a.b.c", None) is None
|
|
|
|
|
|
class TestDiff:
|
|
def test_no_diff(self):
|
|
assert _diff_dicts({"a": 1}, {"a": 1}) == []
|
|
|
|
def test_changed_value(self):
|
|
diffs = _diff_dicts({"a": 1}, {"a": 2})
|
|
assert len(diffs) == 1
|
|
assert diffs[0]["type"] == "changed"
|
|
|
|
def test_added_key(self):
|
|
diffs = _diff_dicts({"a": 1}, {"a": 1, "b": 2})
|
|
added = [d for d in diffs if d["type"] == "added_in_overlay"]
|
|
assert len(added) == 1
|
|
assert added[0]["key"] == "b"
|
|
|
|
|
|
class TestValidation:
|
|
def test_valid_config(self):
|
|
config = {"model": {"name": "x"}, "provider": {"name": "y"}}
|
|
assert _validate_config(config) == []
|
|
|
|
def test_missing_model(self):
|
|
warnings = _validate_config({"provider": {}})
|
|
assert any("model" in w for w in warnings)
|
|
|
|
|
|
class TestConfigTemplate:
|
|
def test_load(self, tmp_config_dir):
|
|
t = ConfigTemplate(str(tmp_config_dir))
|
|
merged = t.load("test")
|
|
assert merged["model"]["name"] == "base-model"
|
|
assert merged["model"]["temperature"] == 0.9
|
|
assert merged["cron"]["enabled"] is True
|
|
assert merged["logging"]["level"] == "DEBUG"
|
|
|
|
def test_get_dotted(self, tmp_config_dir):
|
|
t = ConfigTemplate(str(tmp_config_dir))
|
|
t.load("test")
|
|
assert t.get("model.temperature") == 0.9
|
|
assert t.get("nonexistent", "default") == "default"
|
|
|
|
def test_diff(self, tmp_config_dir):
|
|
t = ConfigTemplate(str(tmp_config_dir))
|
|
t.load("test")
|
|
diffs = t.diff()
|
|
assert len(diffs) > 0
|
|
|
|
def test_unknown_env_raises(self, tmp_config_dir):
|
|
t = ConfigTemplate(str(tmp_config_dir))
|
|
with pytest.raises(ValueError, match="Unknown environment"):
|
|
t.load("nonexistent")
|
|
|
|
def test_list_environments(self):
|
|
envs = ConfigTemplate.list_environments()
|
|
assert "dev" in envs
|
|
assert "prod" in envs
|
|
assert "cron" in envs
|
|
assert "gateway" in envs
|