"""Unit tests for exploit detectors and the exploit record schema.""" from __future__ import annotations from fable_selfplay.detectors import DETECTOR_REGISTRY, ExploitRecord REQUIRED_KEYS = {"exploit_id", "name", "description", "detector", "kernel_version"} def test_registry_is_populated(): assert isinstance(DETECTOR_REGISTRY, dict) assert DETECTOR_REGISTRY, "no detectors registered" for name, detector in DETECTOR_REGISTRY.items(): assert isinstance(name, str) and name assert detector is not None def test_every_shipped_exploit_names_a_registered_detector(exploit_records): for record in exploit_records: detector = record.get("detector") assert detector in DETECTOR_REGISTRY, ( f"{record.get('exploit_id')} references unknown detector {detector!r}" ) def test_shipped_exploit_records_have_required_fields(exploit_records): for record in exploit_records: missing = REQUIRED_KEYS - set(record) assert not missing, ( f"{record.get('exploit_id', '?')} missing fields: {sorted(missing)}" ) def test_exploit_ids_are_unique(exploit_records): ids = [record["exploit_id"] for record in exploit_records] assert len(ids) == len(set(ids)), f"duplicate exploit ids in {ids}" def test_exploit_record_round_trip(exploit_records): for raw in exploit_records: record = ExploitRecord.from_dict(raw) rebuilt = record.to_dict() for key in REQUIRED_KEYS: assert rebuilt[key] == raw[key], (key, rebuilt[key], raw[key]) def test_clean_population_triggers_no_detectors(small_honest_result): assert not list(getattr(small_honest_result, "exploits", []) or [])