You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

79 lines
3.3 KiB

from pathlib import Path
import pytest
import yaml
from src.config_loader import load_config
from src.exceptions import ConfigurationError
DEFAULT = Path(__file__).parents[1] / "config" / "default.yaml"
def write_yaml(tmp_path: Path, values: dict[str, object]) -> Path:
path = tmp_path / "experiment.yaml"
path.write_text(yaml.safe_dump(values), encoding="utf-8")
return path
def test_recursive_merge_and_experiment_precedence(tmp_path: Path) -> None:
path = write_yaml(tmp_path, {"detector": {"confidence_threshold": 0.8}, "experiment": {"location": "lab"}})
config = load_config(DEFAULT, path)
assert config.detector.confidence_threshold == 0.8
assert config.detector.iou_threshold == 0.5
assert config.experiment.location == "lab"
assert config.experiment.experiment_id == "phase1_default"
def test_cli_override_is_last(tmp_path: Path) -> None:
path = write_yaml(tmp_path, {"detector": {"confidence_threshold": 0.6}})
config = load_config(DEFAULT, path, {"detector": {"confidence_threshold": 0.7}})
assert config.detector.confidence_threshold == 0.7
@pytest.mark.parametrize("override", [
{"detector": {"confidence_threshold": 1.1}},
{"evaluation_region": {"x1": -0.1}},
{"evaluation_region": {"x1": 0.9, "x2": 0.8}},
{"input": {"type": "video", "video_path": None}},
{"tracker": {"match_thresh": 1.1}},
{"crossing": {"minimum_track_points": 1}},
{"performance": {"skip_frames": 1}},
{"face": {"process_every_n_frames": 0}},
{"face": {"roi_height_ratio": 1.1}},
{"face": {"min_detection_confidence": -0.1}},
{"head_pose": {"ema_alpha": 0.0}},
{"head_pose": {"max_abs_angle": 0}},
{"face_logging": {"flush_interval_frames": 0}},
{"turn_detection": {"signage_yaw_direction": "sideways"}},
{"turn_detection": {"baseline_strategy": "unknown"}},
{"turn_detection": {"baseline_min_samples": 0}},
{"turn_detection": {"subtle_threshold_deg": 25, "weak_threshold_deg": 20}},
{"turn_detection": {"min_pose_estimation_rate_for_evaluation": 1.1}},
{"turn_logging": {"flush_interval_frames": 0}},
{"audio": {"backend": "unknown"}},
{"audio": {"volume": 1.1}},
{"audio": {"overlap_policy": "mix"}},
{"voice_prompt": {"mode": "random"}},
{"voice_prompt": {"trigger_strategy": "unknown"}},
{"voice_prompt": {"response_window_sec": 0}},
{"voice_prompt": {"fixed_position_axis": "z"}},
{"voice_logging": {"flush_interval_frames": 0}},
{"person_state": {"min_track_duration_sec": -1}},
{"person_state_logging": {"flush_interval_frames": 0}},
{"unified_logging": {"flush_interval_frames": 0}},
{"analysis": {"alpha": 1.0}},
{"analysis": {"response_rate_test": "bad"}},
{"gui": {"preview_max_fps": 0}},
{"gui": {"enabled": "yes"}},
{"pilot_diagnostics": {"min_valid_voice_analysis_rate": 1.1}},
{"pilot_diagnostics": {"max_condition_valid_count_ratio": 0.5}},
])
def test_invalid_config(tmp_path: Path, override: dict[str, object]) -> None:
with pytest.raises(ConfigurationError):
load_config(DEFAULT, write_yaml(tmp_path, override))
def test_skip_frames_allowed_when_tracker_disabled(tmp_path: Path) -> None:
path = write_yaml(tmp_path, {"tracker": {"enabled": False}, "performance": {"skip_frames": 2}})
assert load_config(DEFAULT, path).performance.skip_frames == 2