78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from collections import Counter
|
|
from dataclasses import asdict
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from .test_runner import TestResult
|
|
|
|
|
|
class Reporter:
|
|
def __init__(self, results: list[TestResult], run_meta: dict[str, Any], output_dir: str) -> None:
|
|
self.results = results
|
|
self.run_meta = run_meta
|
|
self.output_dir = Path(output_dir)
|
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def summary_counts(self) -> Counter:
|
|
return Counter(r.status for r in self.results)
|
|
|
|
def print_summary(self) -> None:
|
|
c = self.summary_counts()
|
|
total = len(self.results)
|
|
print("\n== Didactyl Test Results ==")
|
|
print(f"Run: {self.run_meta.get('run_timestamp', 'unknown')}")
|
|
print(f"Agent base URL: {self.run_meta.get('base_url', 'unknown')}")
|
|
print("")
|
|
for k in ["pass", "fail", "error", "timeout", "skip"]:
|
|
print(f"{k.capitalize():<8}: {c.get(k, 0)}")
|
|
print(f"Total : {total}")
|
|
|
|
def print_details(self) -> None:
|
|
bad = [r for r in self.results if r.status in {"fail", "error", "timeout"}]
|
|
if not bad:
|
|
return
|
|
print("\n-- Non-passing tests --")
|
|
for r in bad:
|
|
print(f"[{r.status.upper()}] {r.suite}::{r.name}")
|
|
print(f" {r.message}")
|
|
if r.agent_errors:
|
|
print(f" Agent errors: {len(r.agent_errors)}")
|
|
|
|
def write_json(self, path: str = "results.json") -> Path:
|
|
p = self.output_dir / path
|
|
payload = {
|
|
"run_meta": self.run_meta,
|
|
"results": [asdict(r) for r in self.results],
|
|
"summary": dict(self.summary_counts()),
|
|
}
|
|
p.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
return p
|
|
|
|
def write_text(self, path: str = "results.txt") -> Path:
|
|
p = self.output_dir / path
|
|
c = self.summary_counts()
|
|
lines = [
|
|
"== Didactyl Test Results ==",
|
|
f"Run: {self.run_meta.get('run_timestamp', 'unknown')}",
|
|
f"Agent base URL: {self.run_meta.get('base_url', 'unknown')}",
|
|
"",
|
|
f"Pass: {c.get('pass', 0)}",
|
|
f"Fail: {c.get('fail', 0)}",
|
|
f"Error: {c.get('error', 0)}",
|
|
f"Timeout: {c.get('timeout', 0)}",
|
|
f"Skip: {c.get('skip', 0)}",
|
|
f"Total: {len(self.results)}",
|
|
"",
|
|
]
|
|
for r in self.results:
|
|
lines.append(f"[{r.status.upper()}] {r.suite}::{r.name} ({r.duration_seconds:.2f}s)")
|
|
lines.append(f" {r.message}")
|
|
if r.agent_errors:
|
|
lines.append(f" Agent errors: {len(r.agent_errors)}")
|
|
lines.append("")
|
|
p.write_text("\n".join(lines), encoding="utf-8")
|
|
return p
|