import pytest pytest.importorskip("yaml") from utils.config import Config, apply_overrides, deep_merge, load_config, parse_override # noqa: E402 def test_deep_merge_is_recursive(): merged = deep_merge({"a": {"b": 1, "c": 2}}, {"a": {"c": 3}, "d": 4}) assert merged == {"a": {"b": 1, "c": 3}, "d": 4} def test_parse_override_literals(): assert parse_override("train.lr=1e-3") == ("train.lr", 1e-3) assert parse_override("train.amp=False") == ("train.amp", False) assert parse_override("model.backbone.name=tiny_conv") == ("model.backbone.name", "tiny_conv") def test_apply_overrides_creates_missing_nodes(): cfg = apply_overrides({}, ["a.b.c=1"]) assert cfg == {"a": {"b": {"c": 1}}} def test_load_config_with_base(tmp_path): (tmp_path / "base.yaml").write_text("train:\n lr: 0.1\n epochs: 10\n", encoding="utf-8") (tmp_path / "child.yaml").write_text( "_base_: ./base.yaml\ntrain:\n lr: 0.01\nwork_dir: runs/x\n", encoding="utf-8" ) cfg = load_config(tmp_path / "child.yaml", ["train.epochs=2"]) assert isinstance(cfg, Config) assert cfg.train.lr == 0.01 assert cfg.train.epochs == 2 assert cfg.get_path("work_dir") == "runs/x" def test_load_config_detects_cycle(tmp_path): (tmp_path / "a.yaml").write_text("_base_: ./b.yaml\n", encoding="utf-8") (tmp_path / "b.yaml").write_text("_base_: ./a.yaml\n", encoding="utf-8") with pytest.raises(ValueError, match="循环引用"): load_config(tmp_path / "a.yaml") def test_project_configs_are_loadable(): cfg = load_config("configs/train/baseline.yaml") assert cfg["model"]["name"] == "defect_net" assert cfg["data"]["train"]["dataset"]["name"] == "film_defect" assert len(cfg["classes"]) > 0