332 lines
12 KiB
Python
332 lines
12 KiB
Python
"""Tests for the matrix configuration loader utility."""
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
from infrastructure.matrix_config import (
|
|
AgentConfig,
|
|
AgentsConfig,
|
|
EnvironmentConfig,
|
|
FeaturesConfig,
|
|
LightingConfig,
|
|
MatrixConfig,
|
|
PointLight,
|
|
load_from_yaml,
|
|
)
|
|
|
|
|
|
class TestPointLight:
|
|
"""Tests for PointLight dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""PointLight has correct defaults."""
|
|
pl = PointLight()
|
|
assert pl.color == "#FFFFFF"
|
|
assert pl.intensity == 1.0
|
|
assert pl.position == {"x": 0, "y": 0, "z": 0}
|
|
|
|
def test_from_dict_full(self):
|
|
"""PointLight.from_dict loads all fields."""
|
|
data = {
|
|
"color": "#FF0000",
|
|
"intensity": 2.5,
|
|
"position": {"x": 1, "y": 2, "z": 3},
|
|
}
|
|
pl = PointLight.from_dict(data)
|
|
assert pl.color == "#FF0000"
|
|
assert pl.intensity == 2.5
|
|
assert pl.position == {"x": 1, "y": 2, "z": 3}
|
|
|
|
def test_from_dict_partial(self):
|
|
"""PointLight.from_dict fills missing fields with defaults."""
|
|
data = {"color": "#00FF00"}
|
|
pl = PointLight.from_dict(data)
|
|
assert pl.color == "#00FF00"
|
|
assert pl.intensity == 1.0
|
|
assert pl.position == {"x": 0, "y": 0, "z": 0}
|
|
|
|
|
|
class TestLightingConfig:
|
|
"""Tests for LightingConfig dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""LightingConfig has correct Workshop+Matrix blend defaults."""
|
|
cfg = LightingConfig()
|
|
assert cfg.ambient_color == "#FFAA55" # Warm amber (Workshop)
|
|
assert cfg.ambient_intensity == 0.5
|
|
assert len(cfg.point_lights) == 3
|
|
# First light is warm amber center
|
|
assert cfg.point_lights[0].color == "#FFAA55"
|
|
# Second light is cool blue (Matrix)
|
|
assert cfg.point_lights[1].color == "#3B82F6"
|
|
|
|
def test_from_dict_full(self):
|
|
"""LightingConfig.from_dict loads all fields."""
|
|
data = {
|
|
"ambient_color": "#123456",
|
|
"ambient_intensity": 0.8,
|
|
"point_lights": [
|
|
{"color": "#ABCDEF", "intensity": 1.5, "position": {"x": 1, "y": 1, "z": 1}}
|
|
],
|
|
}
|
|
cfg = LightingConfig.from_dict(data)
|
|
assert cfg.ambient_color == "#123456"
|
|
assert cfg.ambient_intensity == 0.8
|
|
assert len(cfg.point_lights) == 1
|
|
assert cfg.point_lights[0].color == "#ABCDEF"
|
|
|
|
def test_from_dict_empty_list_uses_defaults(self):
|
|
"""Empty point_lights list triggers default lights."""
|
|
data = {"ambient_color": "#000000", "point_lights": []}
|
|
cfg = LightingConfig.from_dict(data)
|
|
assert cfg.ambient_color == "#000000"
|
|
assert len(cfg.point_lights) == 3 # Default lights
|
|
|
|
def test_from_dict_none(self):
|
|
"""LightingConfig.from_dict handles None."""
|
|
cfg = LightingConfig.from_dict(None)
|
|
assert cfg.ambient_color == "#FFAA55"
|
|
assert len(cfg.point_lights) == 3
|
|
|
|
|
|
class TestEnvironmentConfig:
|
|
"""Tests for EnvironmentConfig dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""EnvironmentConfig has correct defaults."""
|
|
cfg = EnvironmentConfig()
|
|
assert cfg.rain_enabled is False
|
|
assert cfg.starfield_enabled is True # Matrix starfield
|
|
assert cfg.fog_color == "#0f0f23"
|
|
assert cfg.fog_density == 0.02
|
|
|
|
def test_from_dict_full(self):
|
|
"""EnvironmentConfig.from_dict loads all fields."""
|
|
data = {
|
|
"rain_enabled": True,
|
|
"starfield_enabled": False,
|
|
"fog_color": "#FFFFFF",
|
|
"fog_density": 0.1,
|
|
}
|
|
cfg = EnvironmentConfig.from_dict(data)
|
|
assert cfg.rain_enabled is True
|
|
assert cfg.starfield_enabled is False
|
|
assert cfg.fog_color == "#FFFFFF"
|
|
assert cfg.fog_density == 0.1
|
|
|
|
def test_from_dict_partial(self):
|
|
"""EnvironmentConfig.from_dict fills missing fields."""
|
|
data = {"rain_enabled": True}
|
|
cfg = EnvironmentConfig.from_dict(data)
|
|
assert cfg.rain_enabled is True
|
|
assert cfg.starfield_enabled is True # Default
|
|
assert cfg.fog_color == "#0f0f23"
|
|
|
|
|
|
class TestFeaturesConfig:
|
|
"""Tests for FeaturesConfig dataclass."""
|
|
|
|
def test_default_values_all_enabled(self):
|
|
"""FeaturesConfig defaults to all features enabled."""
|
|
cfg = FeaturesConfig()
|
|
assert cfg.chat_enabled is True
|
|
assert cfg.visitor_avatars is True
|
|
assert cfg.pip_familiar is True
|
|
assert cfg.workshop_portal is True
|
|
|
|
def test_from_dict_full(self):
|
|
"""FeaturesConfig.from_dict loads all fields."""
|
|
data = {
|
|
"chat_enabled": False,
|
|
"visitor_avatars": False,
|
|
"pip_familiar": False,
|
|
"workshop_portal": False,
|
|
}
|
|
cfg = FeaturesConfig.from_dict(data)
|
|
assert cfg.chat_enabled is False
|
|
assert cfg.visitor_avatars is False
|
|
assert cfg.pip_familiar is False
|
|
assert cfg.workshop_portal is False
|
|
|
|
def test_from_dict_partial(self):
|
|
"""FeaturesConfig.from_dict fills missing fields."""
|
|
data = {"chat_enabled": False}
|
|
cfg = FeaturesConfig.from_dict(data)
|
|
assert cfg.chat_enabled is False
|
|
assert cfg.visitor_avatars is True # Default
|
|
assert cfg.pip_familiar is True
|
|
assert cfg.workshop_portal is True
|
|
|
|
|
|
class TestAgentConfig:
|
|
"""Tests for AgentConfig dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""AgentConfig has correct defaults."""
|
|
cfg = AgentConfig()
|
|
assert cfg.name == ""
|
|
assert cfg.role == ""
|
|
assert cfg.enabled is True
|
|
|
|
def test_from_dict_full(self):
|
|
"""AgentConfig.from_dict loads all fields."""
|
|
data = {"name": "Timmy", "role": "guide", "enabled": False}
|
|
cfg = AgentConfig.from_dict(data)
|
|
assert cfg.name == "Timmy"
|
|
assert cfg.role == "guide"
|
|
assert cfg.enabled is False
|
|
|
|
|
|
class TestAgentsConfig:
|
|
"""Tests for AgentsConfig dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""AgentsConfig has correct defaults."""
|
|
cfg = AgentsConfig()
|
|
assert cfg.default_count == 5
|
|
assert cfg.max_count == 20
|
|
assert cfg.agents == []
|
|
|
|
def test_from_dict_with_agents(self):
|
|
"""AgentsConfig.from_dict loads agent list."""
|
|
data = {
|
|
"default_count": 10,
|
|
"max_count": 50,
|
|
"agents": [
|
|
{"name": "Timmy", "role": "guide", "enabled": True},
|
|
{"name": "Helper", "role": "assistant"},
|
|
],
|
|
}
|
|
cfg = AgentsConfig.from_dict(data)
|
|
assert cfg.default_count == 10
|
|
assert cfg.max_count == 50
|
|
assert len(cfg.agents) == 2
|
|
assert cfg.agents[0].name == "Timmy"
|
|
assert cfg.agents[1].enabled is True # Default
|
|
|
|
|
|
class TestMatrixConfig:
|
|
"""Tests for MatrixConfig dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""MatrixConfig has correct composite defaults."""
|
|
cfg = MatrixConfig()
|
|
assert isinstance(cfg.lighting, LightingConfig)
|
|
assert isinstance(cfg.environment, EnvironmentConfig)
|
|
assert isinstance(cfg.features, FeaturesConfig)
|
|
assert isinstance(cfg.agents, AgentsConfig)
|
|
# Check the blend
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
assert cfg.environment.starfield_enabled is True
|
|
assert cfg.features.chat_enabled is True
|
|
|
|
def test_from_dict_full(self):
|
|
"""MatrixConfig.from_dict loads all sections."""
|
|
data = {
|
|
"lighting": {"ambient_color": "#000000"},
|
|
"environment": {"rain_enabled": True},
|
|
"features": {"chat_enabled": False},
|
|
"agents": {"default_count": 3},
|
|
}
|
|
cfg = MatrixConfig.from_dict(data)
|
|
assert cfg.lighting.ambient_color == "#000000"
|
|
assert cfg.environment.rain_enabled is True
|
|
assert cfg.features.chat_enabled is False
|
|
assert cfg.agents.default_count == 3
|
|
|
|
def test_from_dict_partial(self):
|
|
"""MatrixConfig.from_dict fills missing sections with defaults."""
|
|
data = {"lighting": {"ambient_color": "#111111"}}
|
|
cfg = MatrixConfig.from_dict(data)
|
|
assert cfg.lighting.ambient_color == "#111111"
|
|
assert cfg.environment.starfield_enabled is True # Default
|
|
assert cfg.features.pip_familiar is True # Default
|
|
|
|
def test_from_dict_none(self):
|
|
"""MatrixConfig.from_dict handles None."""
|
|
cfg = MatrixConfig.from_dict(None)
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
assert cfg.features.chat_enabled is True
|
|
|
|
def test_to_dict_roundtrip(self):
|
|
"""MatrixConfig.to_dict produces serializable output."""
|
|
cfg = MatrixConfig()
|
|
data = cfg.to_dict()
|
|
assert isinstance(data, dict)
|
|
assert "lighting" in data
|
|
assert "environment" in data
|
|
assert "features" in data
|
|
assert "agents" in data
|
|
# Verify point lights are included
|
|
assert len(data["lighting"]["point_lights"]) == 3
|
|
|
|
|
|
class TestLoadFromYaml:
|
|
"""Tests for load_from_yaml function."""
|
|
|
|
def test_loads_valid_yaml(self, tmp_path: Path):
|
|
"""load_from_yaml reads a valid YAML file."""
|
|
config_path = tmp_path / "matrix.yaml"
|
|
data = {
|
|
"lighting": {"ambient_color": "#TEST11"},
|
|
"features": {"chat_enabled": False},
|
|
}
|
|
config_path.write_text(yaml.safe_dump(data))
|
|
|
|
cfg = load_from_yaml(config_path)
|
|
assert cfg.lighting.ambient_color == "#TEST11"
|
|
assert cfg.features.chat_enabled is False
|
|
|
|
def test_missing_file_returns_defaults(self, tmp_path: Path):
|
|
"""load_from_yaml returns defaults when file doesn't exist."""
|
|
config_path = tmp_path / "nonexistent.yaml"
|
|
cfg = load_from_yaml(config_path)
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
assert cfg.features.chat_enabled is True
|
|
|
|
def test_empty_file_returns_defaults(self, tmp_path: Path):
|
|
"""load_from_yaml returns defaults for empty file."""
|
|
config_path = tmp_path / "empty.yaml"
|
|
config_path.write_text("")
|
|
cfg = load_from_yaml(config_path)
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
|
|
def test_invalid_yaml_returns_defaults(self, tmp_path: Path):
|
|
"""load_from_yaml returns defaults for invalid YAML."""
|
|
config_path = tmp_path / "invalid.yaml"
|
|
config_path.write_text("not: valid: yaml: [")
|
|
cfg = load_from_yaml(config_path)
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
assert cfg.features.chat_enabled is True
|
|
|
|
def test_non_dict_yaml_returns_defaults(self, tmp_path: Path):
|
|
"""load_from_yaml returns defaults when YAML is not a dict."""
|
|
config_path = tmp_path / "list.yaml"
|
|
config_path.write_text("- item1\n- item2")
|
|
cfg = load_from_yaml(config_path)
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
|
|
def test_loads_actual_config_file(self):
|
|
"""load_from_yaml can load the project's config/matrix.yaml."""
|
|
repo_root = Path(__file__).parent.parent.parent
|
|
config_path = repo_root / "config" / "matrix.yaml"
|
|
if not config_path.exists():
|
|
pytest.skip("config/matrix.yaml not found")
|
|
|
|
cfg = load_from_yaml(config_path)
|
|
# Verify it loaded with expected values
|
|
assert cfg.lighting.ambient_color == "#FFAA55"
|
|
assert len(cfg.lighting.point_lights) == 3
|
|
assert cfg.environment.starfield_enabled is True
|
|
assert cfg.features.workshop_portal is True
|
|
|
|
def test_str_path_accepted(self, tmp_path: Path):
|
|
"""load_from_yaml accepts string path."""
|
|
config_path = tmp_path / "matrix.yaml"
|
|
config_path.write_text(yaml.safe_dump({"lighting": {"ambient_intensity": 0.9}}))
|
|
|
|
cfg = load_from_yaml(str(config_path))
|
|
assert cfg.lighting.ambient_intensity == 0.9
|