Skip to content

Commit

Permalink
build: convert zig build coverage into -Dcoverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Techatrix committed Feb 15, 2025
1 parent c5f2544 commit 188a4c0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Run Tests with kcov
run: |
kcov --version
zig build coverage --summary all
zig build test -Dcoverage --summary all
- name: Upload to Codecov
uses: codecov/codecov-action@v5
Expand Down
51 changes: 27 additions & 24 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub fn build(b: *Build) !void {
const enable_tracy_callstack = b.option(bool, "enable-tracy-callstack", "Enable callstack graphs.") orelse enable_tracy;
const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match filter") orelse &.{};
const use_llvm = b.option(bool, "use-llvm", "Use Zig's llvm code backend");
const coverage = b.option(bool, "coverage", "Generate a coverage report with kcov") orelse false;

const resolved_zls_version = getVersion(b);

Expand Down Expand Up @@ -243,42 +244,45 @@ pub fn build(b: *Build) !void {
.use_lld = use_llvm,
});

var coverage_test_analysis_steps: std.ArrayListUnmanaged(*std.Build.Step.Run) = .empty;

{ // zig build test, zig build test-build-runner, zig build test-analysis
blk: { // zig build test, zig build test-build-runner, zig build test-analysis
const test_step = b.step("test", "Run all the tests");
const test_build_runner_step = b.step("test-build-runner", "Run all the build runner tests");
const test_analysis_step = b.step("test-analysis", "Run all the analysis tests");

// Create run steps
@import("tests/add_build_runner_cases.zig").addCases(b, test_build_runner_step, test_filters);
@import("tests/add_analysis_cases.zig").addCases(b, test_analysis_step, test_filters);

const test_analysis_step = b.step("test-analysis", "Run all the analysis tests");
var test_analysis_steps: std.ArrayListUnmanaged(*std.Build.Step.Run) = .empty;
@import("tests/add_analysis_cases.zig").addCases(b, test_filters, &test_analysis_steps, &coverage_test_analysis_steps);
for (test_analysis_steps.items) |run| test_analysis_step.dependOn(&run.step);
const run_tests = b.addRunArtifact(tests);
const run_src_tests = b.addRunArtifact(src_tests);

const test_step = b.step("test", "Run all the tests");
// Setup dependencies of `zig build test`
test_step.dependOn(&run_tests.step);
test_step.dependOn(&run_src_tests.step);
test_step.dependOn(test_build_runner_step);
test_step.dependOn(test_analysis_step);
test_step.dependOn(&b.addRunArtifact(tests).step);
test_step.dependOn(&b.addRunArtifact(src_tests).step);
}

{ // zig build coverage
if (!coverage) break :blk;

// Collect all run steps into one ArrayList
var run_test_steps: std.ArrayListUnmanaged(*std.Build.Step.Run) = .empty;
run_test_steps.append(b.allocator, run_tests) catch @panic("OOM");
run_test_steps.append(b.allocator, run_src_tests) catch @panic("OOM");
for (test_build_runner_step.dependencies.items) |step| {
run_test_steps.append(b.allocator, step.cast(std.Build.Step.Run).?) catch @panic("OOM");
}
for (test_analysis_step.dependencies.items) |step| {
run_test_steps.append(b.allocator, step.cast(std.Build.Step.Run).?) catch @panic("OOM");
}

const kcov_bin = b.findProgram(&.{"kcov"}, &.{}) catch "kcov";

const merge_step = std.Build.Step.Run.create(b, "merge coverage");
merge_step.addArgs(&.{ kcov_bin, "--merge" });
merge_step.rename_step_with_output_arg = false;
const merged_coverage_output = merge_step.addOutputFileArg(".");

for ([_]*std.Build.Step.Compile{ tests, src_tests }) |test_exe| {
const kcov_collect = std.Build.Step.Run.create(b, b.fmt("run {s} (collect coverage)", .{test_exe.name}));
kcov_collect.addArgs(&.{ kcov_bin, "--collect-only" });
kcov_collect.addPrefixedDirectoryArg("--include-pattern=", b.path("src"));
merge_step.addDirectoryArg(kcov_collect.addOutputFileArg(test_exe.name));
kcov_collect.addArtifactArg(test_exe);
kcov_collect.enableTestRunnerMode();
}

for (coverage_test_analysis_steps.items) |run_step| {
for (run_test_steps.items) |run_step| {
run_step.setName(b.fmt("{s} (collect coverage)", .{run_step.step.name}));

// prepend the kcov exec args
Expand All @@ -294,8 +298,7 @@ pub fn build(b: *Build) !void {
.install_dir = .{ .custom = "coverage" },
.install_subdir = "",
});
const coverage_step = b.step("coverage", "Generate a coverage report with kcov");
coverage_step.dependOn(&install_coverage.step);
test_step.dependOn(&install_coverage.step);
}
}

Expand Down
26 changes: 11 additions & 15 deletions tests/add_analysis_cases.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ const std = @import("std");

pub fn addCases(
b: *std.Build,
test_step: *std.Build.Step,
test_filters: []const []const u8,
steps1: *std.ArrayListUnmanaged(*std.Build.Step.Run),
steps2: *std.ArrayListUnmanaged(*std.Build.Step.Run),
) void {
const cases_dir = b.path("tests/analysis");
const cases_path_from_root = b.pathFromRoot("tests/analysis");
Expand Down Expand Up @@ -34,18 +33,15 @@ pub fn addCases(
if (std.mem.indexOf(u8, entry.name, test_filter) != null) break;
} else if (test_filters.len > 0) continue;

// We create two runs steps, one for `zig build test` and another for `zig build coverage`
for ([_]*std.ArrayListUnmanaged(*std.Build.Step.Run){ steps1, steps2 }) |steps| {
const run_check = std.Build.Step.Run.create(b, b.fmt("run analysis on {s}", .{entry.name}));
run_check.producer = check_exe;
run_check.addArtifactArg(check_exe);
run_check.addArg("--zig-exe-path");
run_check.addFileArg(.{ .cwd_relative = b.graph.zig_exe });
run_check.addArg("--zig-lib-path");
run_check.addDirectoryArg(.{ .cwd_relative = b.fmt("{}", .{b.graph.zig_lib_directory}) });
run_check.addFileArg(cases_dir.path(b, entry.name));

steps.append(b.allocator, run_check) catch @panic("OOM");
}
const run_check = std.Build.Step.Run.create(b, b.fmt("run analysis on {s}", .{entry.name}));
run_check.producer = check_exe;
run_check.addArtifactArg(check_exe);
run_check.addArg("--zig-exe-path");
run_check.addFileArg(.{ .cwd_relative = b.graph.zig_exe });
run_check.addArg("--zig-lib-path");
run_check.addDirectoryArg(.{ .cwd_relative = b.fmt("{}", .{b.graph.zig_lib_directory}) });
run_check.addFileArg(cases_dir.path(b, entry.name));

test_step.dependOn(&run_check.step);
}
}

0 comments on commit 188a4c0

Please sign in to comment.