File size: 4,969 Bytes
395651c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import json
import os
import sys
import xml.etree.ElementTree as ET
from datetime import datetime


def _parse_junit_xml(path: str) -> dict:
    """Summarize pytest junitxml (JUnit) file."""
    out = {"tests": 0, "failures": 0, "errors": 0, "skipped": 0, "time": 0.0}
    try:
        tree = ET.parse(path)
        root = tree.getroot()
        nodes = [root] if root.tag == "testsuite" else list(root.iter("testsuite"))
        for ts in nodes:
            if ts.tag != "testsuite":
                continue
            out["tests"] += int(ts.attrib.get("tests", 0) or 0)
            out["failures"] += int(ts.attrib.get("failures", 0) or 0)
            out["errors"] += int(ts.attrib.get("errors", 0) or 0)
            out["skipped"] += int(ts.attrib.get("skipped", 0) or 0)
            out["time"] += float(ts.attrib.get("time", 0) or 0)
    except Exception as e:
        out["parse_error"] = str(e)
    return out


def generate_report(json_path: str, report_path: str, junit_path: str | None = None) -> None:
    try:
        with open(json_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        junit_summary = None
        if junit_path and os.path.isfile(junit_path):
            junit_summary = _parse_junit_xml(junit_path)

        with open(report_path, "w", encoding="utf-8") as f:
            f.write("# Báo cáo Kiểm thử tích hợp Backend (Integration Report)\n\n")
            f.write(f"**Thời gian chạy:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            suite_ok = all(r.get("success", False) for r in data) if isinstance(data, list) else False
            f.write(f"**API suite (JSON):** {'PASS' if suite_ok else 'FAIL'}\n")

            if junit_summary and "parse_error" not in junit_summary:
                j_ok = junit_summary["failures"] == 0 and junit_summary["errors"] == 0
                f.write(
                    f"**Pytest (JUnit):** {'PASS' if j_ok else 'FAIL'} — "
                    f"tests={junit_summary['tests']}, failures={junit_summary['failures']}, "
                    f"errors={junit_summary['errors']}, skipped={junit_summary['skipped']}, "
                    f"time_s={junit_summary['time']:.2f}\n"
                )
            elif junit_summary and "parse_error" in junit_summary:
                f.write(f"**Pytest (JUnit):** (could not parse: {junit_summary['parse_error']})\n")

            f.write("\n")

            f.write("| ID | Câu hỏi (Query) | Trạng thái | Thời gian (s) | Kết quả / Lỗi |\n")
            f.write("| :--- | :--- | :--- | :--- | :--- |\n")
            for r in data:
                status = "PASS" if r.get("success") else "FAIL"
                elapsed = f"{float(r.get('elapsed', 0) or 0):.2f}"
                query = r.get("query", "-")

                res = r.get("result", {})
                if not isinstance(res, dict):
                    res = {}

                analysis = res.get("semantic_analysis", "-")
                if not r.get("success"):
                    analysis = f"**Lỗi:** {r.get('error', '-')}"

                short_analysis = (analysis[:100] + "...") if len(str(analysis)) > 100 else analysis

                f.write(f"| {r['id']} | {query} | {status} | {elapsed} | {short_analysis} |\n")

            f.write("\n---\n**Chi tiết Output (DSL & Analysis):**\n")
            for r in data:
                if not r.get("success"):
                    continue
                res = r.get("result", {})
                if not isinstance(res, dict):
                    continue

                f.write(f"\n### Case {r['id']}: {r.get('query')}\n")
                f.write(f"**Semantic Analysis:**\n{res.get('semantic_analysis', '-')}\n\n")
                f.write(f"**Geometry DSL:**\n```\n{res.get('geometry_dsl', '-')}\n```\n")

                sol = res.get("solution")
                if sol and isinstance(sol, dict):
                    f.write("**Solution (v5.1):**\n")
                    f.write(f"- **Answer:** {sol.get('answer', 'N/A')}\n")
                    f.write("- **Steps:**\n")
                    steps = sol.get("steps", [])
                    if steps:
                        for step in steps:
                            f.write(f"  - {step}\n")
                    else:
                        f.write("  - (Không có bước giải cụ thể)\n")

                    if sol.get("symbolic_expression"):
                        f.write(f"- **Symbolic:** `{sol.get('symbolic_expression')}`\n")
                    f.write("\n")

        print(f"Report generated: {report_path}")
    except Exception as e:
        print(f"Error generating report: {e}")


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(
            "Usage: python generate_report.py <json_results> <report_output> [junit_xml_optional]"
        )
        sys.exit(1)
    junit = sys.argv[3] if len(sys.argv) > 3 else None
    generate_report(sys.argv[1], sys.argv[2], junit)