diff --git a/tests/gen-ut-summary.py b/tests/gen-ut-summary.py new file mode 100755 index 00000000..6ccee178 --- /dev/null +++ b/tests/gen-ut-summary.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +"""Generate ut-summary.json from gtest XML reports and lcov coverage data. + +Usage: + Called from shell test scripts. Reads environment variables: + - projectdir: project root directory + - builddir: build directory name (relative to projectdir) + - reportdir: report output directory name (relative to projectdir) + + Optional overrides (take precedence over defaults): + - GTEST_XML_DIR: directory containing gtest XML reports + - COVERAGE_INFO: path to lcov .info file for coverage parsing + + Output: {projectdir}/{reportdir}/ut-summary.json +""" + +import json +import xml.etree.ElementTree as ET +import glob +import os +import subprocess +import re +import sys + + +def parse_gtest_xml(xml_dir): + """Parse Google Test / JUnit XML output and return (total, passed, failed).""" + total = passed = failed = 0 + for xml_file in sorted(glob.glob(os.path.join(xml_dir, "*.xml"))): + try: + root = ET.parse(xml_file).getroot() + # JUnit format uses as root with aggregated counts + # gtest XML uses or as root + t = int(root.get("tests", 0)) + f_count = int(root.get("failures", 0)) + err_count = int(root.get("errors", 0)) + total += t + failed += f_count + err_count + passed += t - f_count - err_count + except Exception as e: + print(f"Warning: failed to parse {xml_file}: {e}", file=sys.stderr) + return total, passed, failed + + +def parse_lcov_summary(coverage_info): + """Parse lcov --summary output and return coverage dict.""" + result = {} + if not os.path.exists(coverage_info): + print(f"Warning: coverage info file not found: {coverage_info}", file=sys.stderr) + return result + + lcov_out = subprocess.run( + ["lcov", "--summary", coverage_info, "--rc", "lcov_branch_coverage=1"], + capture_output=True, text=True + ) + summary_text = lcov_out.stdout + lcov_out.stderr + + # Parse lines: "lines......: XX.X% (NNN of MMMM lines)" + m_lines = re.search(r'lines.*?:\s*([\d.]+)%\s*\((\d+)\s+of\s+(\d+)\s+\w+\)', summary_text) + if m_lines: + pct, hit, total = m_lines.groups() + result["line_coverage"] = { + "total": int(total), + "passed": int(hit), + "failed": int(total) - int(hit), + "coverage": f"{float(pct):.2f}%" + } + + # Parse functions: "functions..: XX.X% (NNN of MMMM functions)" + m_func = re.search(r'functions.*?:\s*([\d.]+)%\s*\((\d+)\s+of\s+(\d+)\s+\w+\)', summary_text) + if m_func: + pct, hit, total = m_func.groups() + result["function_coverage"] = { + "total": int(total), + "passed": int(hit), + "failed": int(total) - int(hit), + "coverage": f"{float(pct):.2f}%" + } + + return result + + +def main(): + projectdir = os.environ.get("projectdir") + builddir = os.environ.get("builddir") + reportdir = os.environ.get("reportdir") + + if not all([projectdir, builddir, reportdir]): + print("Error: environment variables projectdir, builddir, reportdir are required", file=sys.stderr) + sys.exit(1) + + # Resolve paths (env overrides take precedence) + gtest_dir = os.environ.get("GTEST_XML_DIR", + os.path.join(projectdir, builddir, "report")) + coverage_info = os.environ.get("COVERAGE_INFO", + os.path.join(projectdir, builddir, "coverage.info")) + + # --- Test case counts from gtest XML --- + total, passed, failed = parse_gtest_xml(gtest_dir) + + result = { + "test_cases": { + "total": total, + "passed": passed, + "failed": failed + } + } + + # --- Coverage from lcov --summary --- + coverage_data = parse_lcov_summary(coverage_info) + result.update(coverage_data) + + # --- Write output --- + output_path = os.path.join(projectdir, reportdir, "ut-summary.json") + os.makedirs(os.path.dirname(output_path), exist_ok=True) + with open(output_path, "w") as f: + json.dump(result, f, indent=2) + + print(json.dumps(result, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/tests/test-prj-running.sh b/tests/test-prj-running.sh old mode 100644 new mode 100755 index ce79da3c..98bd477c --- a/tests/test-prj-running.sh +++ b/tests/test-prj-running.sh @@ -1,6 +1,13 @@ #!/bin/bash -builddir=build -reportdir=build-ut +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +export builddir=build +export reportdir=build-ut +scriptdir=$(cd $(dirname $0); pwd) +export projectdir=$(cd "$scriptdir/.."; pwd) + rm -r $builddir rm -r ../$builddir rm -r $reportdir @@ -10,11 +17,18 @@ mkdir ../$reportdir cd ../$builddir #编译 cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_SAFETYTEST_ARG="CMAKE_SAFETYTEST_ARG_ON" .. -make -j8 +make -j$(nproc) #生成asan日志和ut测试xml结果 export ASAN_OPTIONS=abort_on_error=0:detect_leaks=0 export UBSAN_OPTIONS=halt_on_error=0 -./tests/deepin-editor-test --gtest_output=xml:./report/report_deepin-editor.xml + +# 运行测试并生成 gtest XML 报告 +GTEST_XML_DIR="$projectdir/$builddir/report" +mkdir -p "$GTEST_XML_DIR" +set +e +./tests/deepin-editor-test --gtest_output="xml:$GTEST_XML_DIR/report_deepin-editor.xml" +test_exit_code=$? +set -e workdir=$(cd ../$(dirname $0)/$builddir; pwd) @@ -34,4 +48,9 @@ cp -r html ../$reportdir/ cp -r report ../$reportdir/ cp asan*.log* ../$reportdir/asan_deepin-editor.log 2>/dev/null || true -exit 0 +# 生成摘要 JSON +echo "==> Generating summary JSON: $projectdir/$reportdir/ut-summary.json" + +python3 "$scriptdir/gen-ut-summary.py" + +exit $test_exit_code