1+ import os
2+ import shutil
3+
14from invoke import Context , task
25
6+ from inv .config import OUTPUT_DIR
37from inv .params import override_params_defaults
4- from inv .params .build import with_build_params
8+ from inv .params .build import build_opts , with_build_params
59from inv .params .test import test_opts , with_test_params
610
711from . import build
812
13+ COVERAGE_DIR = OUTPUT_DIR / "coverage"
14+
915
1016@task (default = True )
1117@override_params_defaults (sanitizers = True )
@@ -31,9 +37,39 @@ def test(c: Context, label: str):
3137 args .append (test_opts (c ).ctest_args )
3238
3339 c .run (
34- f"ctest -L '{ label } ' --output-on-failure --test-dir '{ str (build_dir )} ' { ' ' .join (args )} "
40+ f"ctest"
41+ f" -L '{ label } '"
42+ f" --output-on-failure"
43+ f" --test-dir '{ str (build_dir )} '"
44+ f" { ' ' .join (args )} "
3545 )
3646
47+ if test_opts (c ).report_coverage :
48+ if COVERAGE_DIR .exists ():
49+ old_coverage_dir = COVERAGE_DIR .with_suffix (".old" )
50+ if old_coverage_dir .exists ():
51+ shutil .rmtree (old_coverage_dir )
52+ os .rename (COVERAGE_DIR , old_coverage_dir )
53+ COVERAGE_DIR .mkdir ()
54+
55+ excluded_src_dirs = {
56+ build_dir / "_deps" ,
57+ }
58+ excluded_src_dirs_args = " " .join (f"--exclude '{ dir } '" for dir in excluded_src_dirs )
59+
60+ gcov_exec = "llvm-cov gcov" if build_opts (c ).toolchain == "clang" else "gcov"
61+ c .run (
62+ f"gcovr"
63+ f" --root .."
64+ f" --object-directory '{ build_dir } '"
65+ f" --gcov-executable '{ gcov_exec } '"
66+ f" { excluded_src_dirs_args } "
67+ f" --print-summary"
68+ f" --html --html-details -o '{ COVERAGE_DIR } /index.html'"
69+ f" -j { test_opts (c ).jobs } "
70+ )
71+ print (f"Coverage report is available at '{ COVERAGE_DIR } '" )
72+
3773
3874@task
3975@override_params_defaults (sanitizers = True )
@@ -52,3 +88,13 @@ def e2e(
5288 overwrite_snapshots : bool = False ,
5389):
5490 test (c , label = "e2e" )
91+
92+
93+ @task
94+ def serve_coverage (c : Context ):
95+ if not COVERAGE_DIR .exists ():
96+ print (f"Coverage report not found at '{ COVERAGE_DIR } '" )
97+ exit (1 ) # TODO(inv): add something like failure(err_msg) that exits
98+ return
99+
100+ c .run (f"python3 -m http.server -d '{ COVERAGE_DIR } '" )
0 commit comments