case0 / tests /test_prebaked.py
HusseinEid's picture
Case Zero - initial public release (fully local: Qwen2.5-1.5B via llama.cpp + Supertonic, custom pixel-noir SPA via gradio.Server)
414dc55
"""The shipped pre-baked case pool must be valid and fair: every file parses as a CaseFile,
IDs are unique and stable, the solver passes, and each case reads well (human suspects with a
gender mix, a real culprit). These cases are served instantly on New Case, so a broken one
would reach players directly.
"""
from __future__ import annotations
import re
import pytest
from case_zero.persistence.case_store import load_case
from case_zero.persistence.paths import prebaked_cases_dir
from case_zero.solver.checker import check
_POOL = sorted(prebaked_cases_dir().glob("*.json")) if prebaked_cases_dir().is_dir() else []
_BAD_ROLE = re.compile(
r"\b(detective|officer|investigator|police|inspector|sergeant|constable|cop|agent)\b",
re.IGNORECASE,
)
@pytest.mark.skipif(not _POOL, reason="no pre-baked pool present")
def test_pool_ids_unique_and_stable() -> None:
cases = [load_case(p) for p in _POOL]
ids = [c.case_id for c in cases]
assert len(set(ids)) == len(ids), "duplicate case IDs in the pool"
# The stable scheme the player shares: CASE-0001, CASE-0002, ...
for c, p in zip(cases, _POOL):
assert c.case_id == p.stem, f"file {p.name} does not match its case_id {c.case_id}"
@pytest.mark.skipif(not _POOL, reason="no pre-baked pool present")
@pytest.mark.parametrize("path", _POOL, ids=lambda p: p.stem)
def test_pool_case_is_solvable_and_well_formed(path) -> None:
case = load_case(path)
assert check(case).ok, f"{path.name} is not solvable"
assert case.title and len(case.title.strip()) >= 4
assert case.victim.name.strip()
names = [s.name.strip() for s in case.suspects]
assert len(set(n.lower() for n in names)) == len(names), "duplicate suspect names"
for s in case.suspects:
assert not _BAD_ROLE.search(s.role), f"detective-like suspect role: {s.role}"
assert not _BAD_ROLE.search(s.name), f"detective-like suspect name: {s.name}"
assert any((s.visual.gender or "").lower().startswith("f") for s in case.suspects), (
"no female suspect in the cast"
)
assert (case.culprit.method_narrative or "").strip(), "culprit has no method narrative"