from __future__ import annotations from pathlib import Path from dovla_cil.config.schema import ( DoVLACILConfig, apply_cli_overrides, load_config, load_config_dict, save_resolved_config, ) def test_load_default_config() -> None: config = load_config() assert isinstance(config, DoVLACILConfig) assert config.sim.backend == "toy" assert config.sim.seed == 0 assert config.sim.params == {} assert config.generation.backend == "toy" assert config.generation.k > 0 def test_env_overrides(monkeypatch) -> None: monkeypatch.setenv("DOVLA_CIL_GENERATION__K", "12") monkeypatch.setenv("DOVLA_CIL_SIM__SEED", "42") monkeypatch.setenv("OPENCLAUDE_MODEL", "mock-model") config = load_config() assert config.generation.k == 12 assert config.sim.seed == 42 assert config.vlm.model == "mock-model" def test_config_file_loads() -> None: config = load_config("configs/toy/generate_cil_k4.yaml") assert config.generation.k == 4 assert config.generation.output_dir == "outputs/config_toy/cil_k4" assert config.sim.backend == "toy" def test_all_experiment_configs_load_as_dicts() -> None: paths = sorted(Path("configs").glob("*/*.yaml")) assert paths for path in paths: payload = load_config_dict(path) assert isinstance(payload, dict) assert "seed" in payload def test_large_templates_have_safe_defaults() -> None: config = load_config("configs/large/generate_cil_maniskill_template.yaml") assert config.seed == 0 assert config.sim.backend == "maniskill" assert config.sim.params["env_id"] == "PickCube-v1" assert config.generation.output_dir == "data/cil_maniskill_k32" def test_env_expansion(monkeypatch, tmp_path: Path) -> None: config_path = tmp_path / "config.yaml" config_path.write_text( "generation:\n" " output_dir: ${DOVLA_TMP_ROOT}/cil\n" " k: 4\n", encoding="utf-8", ) monkeypatch.setenv("DOVLA_TMP_ROOT", str(tmp_path / "expanded")) payload = load_config_dict(config_path) assert payload["generation"]["output_dir"] == str(tmp_path / "expanded" / "cil") def test_env_expansion_default_value(monkeypatch) -> None: monkeypatch.delenv("DOVLA_MISSING_ROOT", raising=False) payload = load_config_dict( "configs/toy/generate_cil_k4.yaml", overrides=["generation.output_dir=${DOVLA_MISSING_ROOT:-outputs/fallback}/cil"], ) assert payload["generation"]["output_dir"] == "outputs/fallback/cil" def test_cli_override_utility() -> None: payload = load_config_dict( "configs/toy/train_dovla_small.yaml", overrides=["training.epochs=3", "model.hidden_dim=96", "sim.params.foo=bar", "sim.params.enabled=true"], # noqa: E501 ) config = DoVLACILConfig.from_dict(payload) assert config.training.epochs == 3 assert config.model.hidden_dim == 96 assert config.sim.params["foo"] == "bar" assert config.sim.params["enabled"] is True def test_typed_loader_accepts_cli_overrides() -> None: config = load_config( "configs/toy/train_dovla_small.yaml", overrides=["training.epochs=2", "model.hidden_dim=80"], ) assert config.training.epochs == 2 assert config.model.hidden_dim == 80 def test_apply_cli_overrides_and_save_resolved(tmp_path: Path) -> None: payload = {"training": {"epochs": 1}, "paths": {"out": "${HOME}/runs"}} apply_cli_overrides(payload, ["training.epochs=2", "paths.out=/tmp/run"]) path = save_resolved_config(payload, tmp_path) assert payload["training"]["epochs"] == 2 assert payload["paths"]["out"] == "/tmp/run" assert path == tmp_path / "resolved_config.yaml" assert path.exists()