02.11.05 — Plugins de rapport#
Dossier source : src/ocarina/opinionated/plugins/reports/
pretty_print_results, results_to_json, generate_docx_proof, timing. Tous opt-in. Exécutables séquentiellement ou en parallèle via run_plugins.
pretty_print_results#
# src/ocarina/opinionated/plugins/reports/pretty_print_results.py
def pretty_print_results(results: TestCycleResults, *, with_colors: bool = False) -> None:
"""Display the full test results."""
Campaign
• Suite
> Test case 1
» PASSED
> Test case 2
» FAILED
→ Error message
⫸ At step 3
> Test case 3
» SKIPPED
Test results:
1 FAILED | 1 PASSED | 1 SKIPPED
| Aspect | Détail |
|---|
| Hiérarchie | 3 niveaux : campagne •, suite >, cas » |
| Niveaux | PASSED (vert), FAILED (rouge), SKIPPED (gris). |
| Erreur | Message + step number où ça a fail (« At step 3 ») |
| Summary | Comptage agrégé en bas |
results_to_json#
def generate_json_results(*, results: TestCycleResults, output_dir: Path, logger: ILogger) -> None:
"""Write test results to a JSON file in results_dir."""
output_dir.mkdir(parents=True, exist_ok=True)
max_stem_length = 8
max_attempts = 500
for _ in range(max_attempts):
filename = f"{uuid.uuid4().hex[:max_stem_length]}.json"
file_path = output_dir / filename
if not file_path.exists():
break
else:
raise RuntimeError(f"Can't generate unique JSON filename in: {output_dir}.")
{
"Campaign": {
"Suite": {
"test_case": [
{"status": "success" | "fail", "error": "..."},
counter,
metadata
]
}
}
}
def _result_to_serializable(v: Any) -> dict[str, str]:
if is_ok(v):
return {"status": "success"}
if is_fail(v):
return {"status": "fail", "error": str(v.error)}
raise TypeError(f"Expected Ok or Fail instances, but got: {type(v)}")
Le filename est un UUID hex de 8 chars → 16⁸ ≈ 4 milliards d’options. Pas de collision dans la pratique. 500 retries de sécurité.