[kimi] Add matrix config loader utility (#680) #742
@@ -2,22 +2,22 @@
|
||||
# Serves lighting, environment, and feature settings to the Matrix frontend.
|
||||
|
||||
lighting:
|
||||
ambient_color: "#1a1a2e"
|
||||
ambient_intensity: 0.4
|
||||
ambient_color: "#FFAA55" # Warm amber (Workshop warmth)
|
||||
ambient_intensity: 0.5
|
||||
point_lights:
|
||||
- color: "#FFD700"
|
||||
- color: "#FFAA55" # Warm amber (Workshop center light)
|
||||
intensity: 1.2
|
||||
position: { x: 0, y: 5, z: 0 }
|
||||
- color: "#3B82F6"
|
||||
- color: "#3B82F6" # Cool blue (Matrix accent)
|
||||
intensity: 0.8
|
||||
position: { x: -5, y: 3, z: -5 }
|
||||
- color: "#A855F7"
|
||||
- color: "#A855F7" # Purple accent
|
||||
intensity: 0.6
|
||||
position: { x: 5, y: 3, z: 5 }
|
||||
|
||||
environment:
|
||||
rain_enabled: false
|
||||
starfield_enabled: true
|
||||
starfield_enabled: true # Cool blue starfield (Matrix feel)
|
||||
fog_color: "#0f0f23"
|
||||
fog_density: 0.02
|
||||
|
||||
@@ -26,3 +26,8 @@ features:
|
||||
visitor_avatars: true
|
||||
pip_familiar: true
|
||||
workshop_portal: true
|
||||
|
||||
agents:
|
||||
default_count: 5
|
||||
max_count: 20
|
||||
agents: []
|
||||
|
||||
266
src/infrastructure/matrix_config.py
Normal file
266
src/infrastructure/matrix_config.py
Normal file
@@ -0,0 +1,266 @@
|
||||
"""Matrix configuration loader utility.
|
||||
|
||||
Provides a typed dataclass for Matrix world configuration and a loader
|
||||
that fetches settings from YAML with sensible defaults.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PointLight:
|
||||
"""A single point light in the Matrix world."""
|
||||
|
||||
color: str = "#FFFFFF"
|
||||
intensity: float = 1.0
|
||||
position: dict[str, float] = field(default_factory=lambda: {"x": 0, "y": 0, "z": 0})
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "PointLight":
|
||||
"""Create a PointLight from a dictionary with defaults."""
|
||||
return cls(
|
||||
color=data.get("color", "#FFFFFF"),
|
||||
intensity=data.get("intensity", 1.0),
|
||||
position=data.get("position", {"x": 0, "y": 0, "z": 0}),
|
||||
)
|
||||
|
||||
|
||||
def _default_point_lights_factory() -> list[PointLight]:
|
||||
"""Factory function for default point lights."""
|
||||
return [
|
||||
PointLight(
|
||||
color="#FFAA55", # Warm amber (Workshop)
|
||||
intensity=1.2,
|
||||
position={"x": 0, "y": 5, "z": 0},
|
||||
),
|
||||
PointLight(
|
||||
color="#3B82F6", # Cool blue (Matrix)
|
||||
intensity=0.8,
|
||||
position={"x": -5, "y": 3, "z": -5},
|
||||
),
|
||||
PointLight(
|
||||
color="#A855F7", # Purple accent
|
||||
intensity=0.6,
|
||||
position={"x": 5, "y": 3, "z": 5},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class LightingConfig:
|
||||
"""Lighting configuration for the Matrix world."""
|
||||
|
||||
ambient_color: str = "#FFAA55" # Warm amber (Workshop warmth)
|
||||
ambient_intensity: float = 0.5
|
||||
point_lights: list[PointLight] = field(default_factory=_default_point_lights_factory)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "LightingConfig":
|
||||
"""Create a LightingConfig from a dictionary with defaults."""
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
point_lights_data = data.get("point_lights", [])
|
||||
point_lights = (
|
||||
[PointLight.from_dict(pl) for pl in point_lights_data]
|
||||
if point_lights_data
|
||||
else _default_point_lights_factory()
|
||||
)
|
||||
|
||||
return cls(
|
||||
ambient_color=data.get("ambient_color", "#FFAA55"),
|
||||
ambient_intensity=data.get("ambient_intensity", 0.5),
|
||||
point_lights=point_lights,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class EnvironmentConfig:
|
||||
"""Environment settings for the Matrix world."""
|
||||
|
||||
rain_enabled: bool = False
|
||||
starfield_enabled: bool = True
|
||||
fog_color: str = "#0f0f23"
|
||||
fog_density: float = 0.02
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "EnvironmentConfig":
|
||||
"""Create an EnvironmentConfig from a dictionary with defaults."""
|
||||
if data is None:
|
||||
data = {}
|
||||
return cls(
|
||||
rain_enabled=data.get("rain_enabled", False),
|
||||
starfield_enabled=data.get("starfield_enabled", True),
|
||||
fog_color=data.get("fog_color", "#0f0f23"),
|
||||
fog_density=data.get("fog_density", 0.02),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class FeaturesConfig:
|
||||
"""Feature toggles for the Matrix world."""
|
||||
|
||||
chat_enabled: bool = True
|
||||
visitor_avatars: bool = True
|
||||
pip_familiar: bool = True
|
||||
workshop_portal: bool = True
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "FeaturesConfig":
|
||||
"""Create a FeaturesConfig from a dictionary with defaults."""
|
||||
if data is None:
|
||||
data = {}
|
||||
return cls(
|
||||
chat_enabled=data.get("chat_enabled", True),
|
||||
visitor_avatars=data.get("visitor_avatars", True),
|
||||
pip_familiar=data.get("pip_familiar", True),
|
||||
workshop_portal=data.get("workshop_portal", True),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
"""Configuration for a single Matrix agent."""
|
||||
|
||||
name: str = ""
|
||||
role: str = ""
|
||||
enabled: bool = True
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "AgentConfig":
|
||||
"""Create an AgentConfig from a dictionary with defaults."""
|
||||
return cls(
|
||||
name=data.get("name", ""),
|
||||
role=data.get("role", ""),
|
||||
enabled=data.get("enabled", True),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentsConfig:
|
||||
"""Agent registry configuration."""
|
||||
|
||||
default_count: int = 5
|
||||
max_count: int = 20
|
||||
agents: list[AgentConfig] = field(default_factory=list)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "AgentsConfig":
|
||||
"""Create an AgentsConfig from a dictionary with defaults."""
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
agents_data = data.get("agents", [])
|
||||
agents = [AgentConfig.from_dict(a) for a in agents_data] if agents_data else []
|
||||
|
||||
return cls(
|
||||
default_count=data.get("default_count", 5),
|
||||
max_count=data.get("max_count", 20),
|
||||
agents=agents,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MatrixConfig:
|
||||
"""Complete Matrix world configuration.
|
||||
|
||||
Combines lighting, environment, features, and agent settings
|
||||
into a single configuration object.
|
||||
"""
|
||||
|
||||
lighting: LightingConfig = field(default_factory=LightingConfig)
|
||||
environment: EnvironmentConfig = field(default_factory=EnvironmentConfig)
|
||||
features: FeaturesConfig = field(default_factory=FeaturesConfig)
|
||||
agents: AgentsConfig = field(default_factory=AgentsConfig)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "MatrixConfig":
|
||||
"""Create a MatrixConfig from a dictionary with defaults for missing sections."""
|
||||
if data is None:
|
||||
data = {}
|
||||
return cls(
|
||||
lighting=LightingConfig.from_dict(data.get("lighting")),
|
||||
environment=EnvironmentConfig.from_dict(data.get("environment")),
|
||||
features=FeaturesConfig.from_dict(data.get("features")),
|
||||
agents=AgentsConfig.from_dict(data.get("agents")),
|
||||
)
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Convert the configuration to a plain dictionary."""
|
||||
return {
|
||||
"lighting": {
|
||||
"ambient_color": self.lighting.ambient_color,
|
||||
"ambient_intensity": self.lighting.ambient_intensity,
|
||||
"point_lights": [
|
||||
{
|
||||
"color": pl.color,
|
||||
"intensity": pl.intensity,
|
||||
"position": pl.position,
|
||||
}
|
||||
for pl in self.lighting.point_lights
|
||||
],
|
||||
},
|
||||
"environment": {
|
||||
"rain_enabled": self.environment.rain_enabled,
|
||||
"starfield_enabled": self.environment.starfield_enabled,
|
||||
"fog_color": self.environment.fog_color,
|
||||
"fog_density": self.environment.fog_density,
|
||||
},
|
||||
"features": {
|
||||
"chat_enabled": self.features.chat_enabled,
|
||||
"visitor_avatars": self.features.visitor_avatars,
|
||||
"pip_familiar": self.features.pip_familiar,
|
||||
"workshop_portal": self.features.workshop_portal,
|
||||
},
|
||||
"agents": {
|
||||
"default_count": self.agents.default_count,
|
||||
"max_count": self.agents.max_count,
|
||||
"agents": [
|
||||
{"name": a.name, "role": a.role, "enabled": a.enabled}
|
||||
for a in self.agents.agents
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def load_from_yaml(path: str | Path) -> MatrixConfig:
|
||||
"""Load Matrix configuration from a YAML file.
|
||||
|
||||
Missing keys are filled with sensible defaults. If the file
|
||||
cannot be read or parsed, returns a fully default configuration.
|
||||
|
||||
Args:
|
||||
path: Path to the YAML configuration file.
|
||||
|
||||
Returns:
|
||||
A MatrixConfig instance with loaded or default values.
|
||||
"""
|
||||
path = Path(path)
|
||||
|
||||
if not path.exists():
|
||||
logger.warning("Matrix config file not found: %s, using defaults", path)
|
||||
return MatrixConfig()
|
||||
|
||||
try:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
raw_data = yaml.safe_load(f)
|
||||
|
||||
if not isinstance(raw_data, dict):
|
||||
logger.warning("Matrix config invalid format, using defaults")
|
||||
return MatrixConfig()
|
||||
|
||||
return MatrixConfig.from_dict(raw_data)
|
||||
|
||||
except yaml.YAMLError as exc:
|
||||
logger.warning("Matrix config YAML parse error: %s, using defaults", exc)
|
||||
return MatrixConfig()
|
||||
except OSError as exc:
|
||||
logger.warning("Matrix config read error: %s, using defaults", exc)
|
||||
return MatrixConfig()
|
||||
331
tests/unit/test_matrix_config.py
Normal file
331
tests/unit/test_matrix_config.py
Normal file
@@ -0,0 +1,331 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user