correct test №1

This commit is contained in:
G0DSEND016 2026-03-23 05:05:16 +01:00
parent 4fb1fe532b
commit 23c0c61c5c
6 changed files with 6 additions and 270 deletions

File diff suppressed because one or more lines are too long

BIN
testing/charts/report.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View File

@ -1,245 +0,0 @@
import json
from pathlib import Path
from collections import Counter, defaultdict
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
matplotlib.use("Agg")
RESULTS_FILE = Path(__file__).parent.parent / "results.json"
CHARTS_DIR = Path(__file__).parent.parent / "charts"
STATUS_COLORS = {
"passed": "#3ddc84",
"failed": "#ff5c5c",
"skipped": "#e0c84a",
"error": "#ff8a8a",
}
BG_COLOR = "#1a1a1a"
PANEL_COLOR = "#242424"
TEXT_COLOR = "#e0e0e0"
GRID_COLOR = "#333333"
FONT_MONO = "monospace"
def _style_ax(ax, title: str):
ax.set_facecolor(PANEL_COLOR)
ax.set_title(title, color=TEXT_COLOR, fontsize=11, fontweight="bold", pad=10)
ax.tick_params(colors=TEXT_COLOR, labelsize=8)
ax.spines[:].set_color(GRID_COLOR)
ax.yaxis.grid(True, color=GRID_COLOR, linewidth=0.5, linestyle="--")
ax.set_axisbelow(True)
for label in ax.get_xticklabels() + ax.get_yticklabels():
label.set_color(TEXT_COLOR)
label.set_fontfamily(FONT_MONO)
def load_data() -> tuple[pd.DataFrame, dict]:
if not RESULTS_FILE.exists():
raise FileNotFoundError(f"results.json not found at {RESULTS_FILE}")
raw = json.loads(RESULTS_FILE.read_text(encoding="utf-8"))
tests = raw.get("tests", [])
rows = []
for t in tests:
node = t["nodeid"]
parts = node.split("::")
module = parts[0].replace("tests/", "").replace("/", ".").replace(".py", "")
cls = parts[1] if len(parts) >= 3 else "unknown"
name = parts[-1]
duration = t.get("call", {}).get("duration", 0.0) if t.get("call") else 0.0
rows.append({
"module": module,
"class": cls,
"name": name,
"outcome": t["outcome"],
"duration": duration,
})
df = pd.DataFrame(rows)
summary = raw.get("summary", {})
return df, summary
def chart_overall_status(df: pd.DataFrame, ax: plt.Axes):
counts = df["outcome"].value_counts()
colors = [STATUS_COLORS.get(k, "#888") for k in counts.index]
wedges, texts, pcts = ax.pie(
counts.values,
labels=counts.index,
colors=colors,
autopct="%1.1f%%",
startangle=90,
pctdistance=0.78,
wedgeprops={"edgecolor": BG_COLOR, "linewidth": 2},
)
for t in texts:
t.set_color(TEXT_COLOR)
t.set_fontsize(9)
t.set_fontfamily(FONT_MONO)
for p in pcts:
p.set_color("#111")
p.set_fontsize(8)
p.set_fontweight("bold")
ax.set_facecolor(PANEL_COLOR)
ax.set_title("Overall Results", color=TEXT_COLOR, fontsize=11, fontweight="bold", pad=10)
def chart_by_module(df: pd.DataFrame, ax: plt.Axes):
pivot = (
df.groupby(["module", "outcome"])
.size()
.unstack(fill_value=0)
.reindex(columns=["passed", "failed", "skipped", "error"], fill_value=0)
)
x = np.arange(len(pivot))
width = 0.2
offset = -(len(pivot.columns) - 1) / 2 * width
for i, col in enumerate(pivot.columns):
bars = ax.bar(
x + offset + i * width,
pivot[col],
width,
label=col,
color=STATUS_COLORS.get(col, "#888"),
edgecolor=BG_COLOR,
linewidth=0.8,
)
ax.set_xticks(x)
ax.set_xticklabels(pivot.index, rotation=25, ha="right", fontsize=7, fontfamily=FONT_MONO)
ax.set_ylabel("Tests", color=TEXT_COLOR, fontsize=9)
ax.legend(
fontsize=7,
labelcolor=TEXT_COLOR,
facecolor=PANEL_COLOR,
edgecolor=GRID_COLOR,
)
_style_ax(ax, "Results by Module")
def chart_duration_histogram(df: pd.DataFrame, ax: plt.Axes):
durations = df.loc[df["outcome"] != "skipped", "duration"].values * 1000
if len(durations) == 0:
ax.text(0.5, 0.5, "No data", ha="center", va="center", color=TEXT_COLOR)
_style_ax(ax, "Test Duration (ms)")
return
mean_ms = float(np.mean(durations))
median_ms = float(np.median(durations))
p95_ms = float(np.percentile(durations, 95))
ax.hist(durations, bins=20, color="#5cb8ff", edgecolor=BG_COLOR, linewidth=0.6, alpha=0.85)
ax.axvline(mean_ms, color="#3ddc84", linewidth=1.5, linestyle="--", label=f"Mean {mean_ms:.1f} ms")
ax.axvline(median_ms, color="#e0c84a", linewidth=1.5, linestyle=":", label=f"Median {median_ms:.1f} ms")
ax.axvline(p95_ms, color="#ff5c5c", linewidth=1.5, linestyle="-.", label=f"P95 {p95_ms:.1f} ms")
ax.set_xlabel("ms", color=TEXT_COLOR, fontsize=9)
ax.set_ylabel("Tests", color=TEXT_COLOR, fontsize=9)
ax.legend(fontsize=7, labelcolor=TEXT_COLOR, facecolor=PANEL_COLOR, edgecolor=GRID_COLOR)
_style_ax(ax, "Test Duration (ms)")
def chart_slowest_tests(df: pd.DataFrame, ax: plt.Axes):
top = (
df[df["outcome"] != "skipped"]
.nlargest(10, "duration")
.copy()
)
top["label"] = top["class"] + "::" + top["name"]
top["duration"] = top["duration"] * 1000
colors = [STATUS_COLORS.get(o, "#888") for o in top["outcome"]]
bars = ax.barh(top["label"], top["duration"], color=colors, edgecolor=BG_COLOR, linewidth=0.6)
ax.set_xlabel("ms", color=TEXT_COLOR, fontsize=9)
ax.tick_params(axis="y", labelsize=7)
ax.invert_yaxis()
_style_ax(ax, "Top 10 Slowest Tests")
def chart_stats_table(df: pd.DataFrame, summary: dict, ax: plt.Axes):
ax.set_facecolor(PANEL_COLOR)
ax.axis("off")
total = len(df)
passed = summary.get("passed", 0)
failed = summary.get("failed", 0)
skipped = summary.get("skipped", 0)
duration = df["duration"].sum() * 1000
durations = df.loc[df["outcome"] != "skipped", "duration"].values * 1000
rows = [
["Total tests", str(total)],
["Passed", str(passed)],
["Failed", str(failed)],
["Skipped", str(skipped)],
["Pass rate", f"{passed / total * 100:.1f}%" if total else ""],
["Total time", f"{duration:.0f} ms"],
["Mean duration", f"{np.mean(durations):.1f} ms" if len(durations) else ""],
["Median", f"{np.median(durations):.1f} ms" if len(durations) else ""],
["P95", f"{np.percentile(durations, 95):.1f} ms" if len(durations) else ""],
]
table = ax.table(
cellText=rows,
colLabels=["Metric", "Value"],
cellLoc="left",
loc="center",
colWidths=[0.6, 0.4],
)
table.auto_set_font_size(False)
table.set_fontsize(9)
for (row, col), cell in table.get_celld().items():
cell.set_facecolor("#2e2e2e" if row % 2 == 0 else PANEL_COLOR)
cell.set_edgecolor(GRID_COLOR)
cell.set_text_props(color=TEXT_COLOR, fontfamily=FONT_MONO)
ax.set_title("Summary", color=TEXT_COLOR, fontsize=11, fontweight="bold", pad=10)
def generate(output_path: Path = None) -> Path:
CHARTS_DIR.mkdir(parents=True, exist_ok=True)
output_path = output_path or CHARTS_DIR / "report.png"
df, summary = load_data()
fig = plt.figure(figsize=(18, 14), facecolor=BG_COLOR)
fig.suptitle(
"Legal AI Assistant — Test Report",
fontsize=16, fontweight="bold", color=TEXT_COLOR,
y=0.98, fontfamily=FONT_MONO,
)
gs = fig.add_gridspec(2, 3, hspace=0.45, wspace=0.35,
top=0.93, bottom=0.05, left=0.06, right=0.97)
chart_overall_status(df, fig.add_subplot(gs[0, 0]))
chart_by_module(df, fig.add_subplot(gs[0, 1:]))
chart_duration_histogram(df, fig.add_subplot(gs[1, 0]))
chart_slowest_tests(df, fig.add_subplot(gs[1, 1]))
chart_stats_table(df, summary, fig.add_subplot(gs[1, 2]))
fig.savefig(output_path, dpi=150, bbox_inches="tight", facecolor=BG_COLOR)
plt.close(fig)
return output_path
if __name__ == "__main__":
out = generate()
print(f"Chart saved: {out}")

File diff suppressed because one or more lines are too long

View File

@ -14,12 +14,8 @@ def run_pytest() -> int:
args = [
sys.executable, "-m", "pytest",
str(TESTS_DIR / "tests"),
"--json-report",
f"--json-report-file={RESULTS_JSON}",
f"--html={REPORT_HTML}",
"--self-contained-html",
@ -29,32 +25,18 @@ def run_pytest() -> int:
f"--cov-report=html:{CHARTS_DIR / 'coverage'}",
"--tb=no",
"-q",
]
return subprocess.run(args, cwd=str(ROOT), check=False).returncode
def run_charts():
from testing.reports.charts import generate
return generate()
if __name__ == "__main__":
print("Start testing")
code = run_pytest()
charts_path = None
if RESULTS_JSON.exists():
charts_path = run_charts()
print()
print(f"pytest-html: {REPORT_HTML}")
print(f"\npytest-html: {REPORT_HTML}")
print(f"pytest-cov: {CHARTS_DIR / 'coverage' / 'index.html'}")
print(f"charts: {charts_path or CHARTS_DIR / 'report.png'}")
print()
print("Stop testing")
print("\nStop testing")
sys.exit(code)