74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
"""Config loading and validation — the instrument's shape can't drift."""
|
||
|
||
import shutil
|
||
|
||
import pytest
|
||
|
||
from diaglib import list_industries, load_config
|
||
from tests.conftest import CONFIGS
|
||
|
||
|
||
def test_contact_center_loads(config):
|
||
assert config.industry == "contact_center"
|
||
assert config.version == "1.0"
|
||
assert len(config.competencies) == 12
|
||
assert [d.id for d in config.dimensions] == [
|
||
"strategy_value", "foundations", "delivery", "sustain"]
|
||
# 4 dimensions × 3 competencies — the heatmap contract
|
||
for d in config.dimensions:
|
||
assert sum(1 for c in config.competencies if c.dimension == d.id) == 3
|
||
assert config.foundational_competencies == [
|
||
"process_discovery", "data_readiness", "technical_architecture"]
|
||
assert [d.id for d in config.value_drivers] == [
|
||
"deflection_lift", "aht_reduction", "attrition_reduction"]
|
||
|
||
|
||
def test_capping_bands_pinned(config):
|
||
bands = {k: (v.realized_low, v.realized_high)
|
||
for k, v in config.capping_heuristic.items()}
|
||
assert bands == {
|
||
1: (0.00, 0.15), 2: (0.25, 0.40), 3: (0.50, 0.65),
|
||
4: (0.65, 0.85), 5: (0.80, 1.00),
|
||
}
|
||
|
||
|
||
def test_every_competency_has_five_levels_and_vignette(config):
|
||
for c in config.competencies:
|
||
assert set(c.level_descriptors) == {1, 2, 3, 4, 5}
|
||
assert c.failure_vignette
|
||
assert c.description
|
||
|
||
|
||
def test_unlock_costs_reachable(config):
|
||
# Every foundational competency can be lifted 1→5 in the CC config.
|
||
for cid in config.foundational_competencies:
|
||
for level in (1, 2, 3, 4):
|
||
lift = config.lift_cost(cid, level)
|
||
assert lift is not None, f"{cid} lift {level}->{level + 1} missing"
|
||
assert lift.cost_low <= lift.cost_high
|
||
|
||
|
||
def test_stub_config_loads(stub_config):
|
||
assert stub_config.industry == "financial_services"
|
||
assert stub_config.value_drivers == []
|
||
assert len(stub_config.competencies) == 12 # model comes from base
|
||
|
||
|
||
def test_list_industries():
|
||
assert list_industries(CONFIGS) == ["contact_center", "financial_services"]
|
||
|
||
|
||
def test_overlay_may_not_redefine_base_keys(tmp_path):
|
||
shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml")
|
||
(tmp_path / "rogue.yaml").write_text(
|
||
"extends: base\nindustry: rogue\ncompetencies: []\n", encoding="utf-8")
|
||
with pytest.raises(ValueError, match="base-only"):
|
||
load_config("rogue", tmp_path)
|
||
|
||
|
||
def test_overlay_must_extend_base(tmp_path):
|
||
shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml")
|
||
(tmp_path / "loner.yaml").write_text("industry: loner\n", encoding="utf-8")
|
||
with pytest.raises(ValueError, match="extends"):
|
||
load_config("loner", tmp_path)
|