diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index acba93209..acb1db154 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -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 diff --git a/build.zig b/build.zig index 0bfb64c49..ecae50edc 100644 --- a/build.zig +++ b/build.zig @@ -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); @@ -243,25 +244,37 @@ 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"); @@ -269,16 +282,7 @@ pub fn build(b: *Build) !void { 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 @@ -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); } } diff --git a/tests/add_analysis_cases.zig b/tests/add_analysis_cases.zig index d747ea2d5..aca73e0d0 100644 --- a/tests/add_analysis_cases.zig +++ b/tests/add_analysis_cases.zig @@ -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"); @@ -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); } }