44const std = @import ("std" );
55
66pub fn build (b : * std.Build ) void {
7+ const coverage = b .option (bool , "coverage" , "Generate a coverage report with kcov" ) orelse false ;
8+
79 const target = b .standardTargetOptions (.{});
810 const optimize = b .standardOptimizeOption (.{});
911
@@ -30,4 +32,38 @@ pub fn build(b: *std.Build) void {
3032 const run_lib_unit_tests = b .addRunArtifact (lib_unit_tests );
3133 const test_step = b .step ("test" , "Run unit tests" );
3234 test_step .dependOn (& run_lib_unit_tests .step );
35+
36+ if (coverage ) {
37+ try addCoverageReporting ();
38+
39+ var run_test_steps : std .ArrayListUnmanaged (* std .Build .Step .Run ) = .empty ;
40+ run_test_steps .append (b .allocator , run_lib_unit_tests ) catch @panic ("OOM" );
41+
42+ const kcov_bin = b .findProgram (&.{"kcov" }, &.{}) catch "kcov" ;
43+
44+ const merge_step = std .Build .Step .Run .create (b , "merge coverage" );
45+ merge_step .addArgs (&.{ kcov_bin , "--merge" });
46+ merge_step .rename_step_with_output_arg = false ;
47+ const merged_coverage_output = merge_step .addOutputFileArg ("." );
48+
49+ for (run_test_steps .items ) | run_step | {
50+ run_step .setName (b .fmt ("{s} (collect coverage)" , .{run_step .step .name }));
51+
52+ // prepend the kcov exec args
53+ const argv = run_step .argv .toOwnedSlice (b .allocator ) catch @panic ("OOM" );
54+ run_step .addArgs (&.{ kcov_bin , "--collect-only" });
55+ run_step .addPrefixedDirectoryArg ("--include-pattern=" , b .path ("src" ));
56+ merge_step .addDirectoryArg (run_step .addOutputFileArg (run_step .producer .? .name ));
57+ run_step .argv .appendSlice (b .allocator , argv ) catch @panic ("OOM" );
58+ }
59+
60+ const install_coverage = b .addInstallDirectory (.{
61+ .source_dir = merged_coverage_output ,
62+ .install_dir = .{ .custom = "coverage" },
63+ .install_subdir = "" ,
64+ });
65+ test_step .dependOn (& install_coverage .step );
66+ }
3367}
68+
69+ fn addCoverageReporting () ! void {}
0 commit comments