| ... | ... | @@ -0,0 +1,95 @@ |
| 1 | const std = @import("std"); |
| 2 | |
| 3 | pub fn build(b: *std.Build) void { |
| 4 | const test_step = b.step("test", "Test"); |
| 5 | b.default_step = test_step; |
| 6 | |
| 7 | // Most targets handle color the same way, regardless of whether libc is linked. |
| 8 | const native_target = b.graph.host; |
| 9 | addTestCases(test_step, native_target, false); |
| 10 | addTestCases(test_step, native_target, true); |
| 11 | |
| 12 | // WASI behaves differently depending on whether libc is linked. |
| 13 | if (b.enable_wasmtime) { |
| 14 | const wasi_target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }); |
| 15 | addTestCases(test_step, wasi_target, false); |
| 16 | addTestCases(test_step, wasi_target, true); |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | fn addTestCases( |
| 21 | test_step: *std.Build.Step, |
| 22 | target: std.Build.ResolvedTarget, |
| 23 | link_libc: bool, |
| 24 | ) void { |
| 25 | const b = test_step.owner; |
| 26 | const exe = b.addExecutable(.{ |
| 27 | .name = b.fmt("{s}{s}", .{ @tagName(target.result.os.tag), if (link_libc) "-libc" else "" }), |
| 28 | .root_module = b.createModule(.{ |
| 29 | .root_source_file = b.path("main.zig"), |
| 30 | .target = target, |
| 31 | .link_libc = link_libc, |
| 32 | }), |
| 33 | }); |
| 34 | |
| 35 | // Should reflect 'std.process.Environ.Block' and 'std.Io.Threaded.init_single_threaded'. |
| 36 | const debug_io_can_read_environ = switch (target.result.os.tag) { |
| 37 | .windows => true, |
| 38 | .wasi, .emscripten => link_libc, |
| 39 | .freestanding, .other => false, |
| 40 | else => true, |
| 41 | }; |
| 42 | |
| 43 | // Don't forget to account for whether the build process's stderr supports color. |
| 44 | const parent_stderr_color_enabled = (std.Io.Terminal.Mode.detect(b.graph.io, .stderr(), false, false) catch unreachable) != .no_color; |
| 45 | |
| 46 | _ = addTestCase(test_step, exe, "neither", .inherit, .manual, parent_stderr_color_enabled); |
| 47 | _ = addTestCase(test_step, exe, "neither", .redirect, .manual, false); |
| 48 | _ = addTestCase(test_step, exe, "no_color", .inherit, .disable, if (debug_io_can_read_environ) false else parent_stderr_color_enabled); |
| 49 | _ = addTestCase(test_step, exe, "no_color", .redirect, .disable, false); |
| 50 | _ = addTestCase(test_step, exe, "clicolor_force", .inherit, .enable, if (debug_io_can_read_environ) true else parent_stderr_color_enabled); |
| 51 | _ = addTestCase(test_step, exe, "clicolor_force", .redirect, .enable, debug_io_can_read_environ); |
| 52 | |
| 53 | const both = addTestCase(test_step, exe, "both", .inherit, .manual, if (debug_io_can_read_environ) false else parent_stderr_color_enabled); |
| 54 | both.setEnvironmentVariable("NO_COLOR", "1"); |
| 55 | both.setEnvironmentVariable("CLICOLOR_FORCE", "1"); |
| 56 | |
| 57 | const both_redirected = addTestCase(test_step, exe, "both", .redirect, .manual, false); |
| 58 | both_redirected.setEnvironmentVariable("NO_COLOR", "1"); |
| 59 | both_redirected.setEnvironmentVariable("CLICOLOR_FORCE", "1"); |
| 60 | } |
| 61 | |
| 62 | fn addTestCase( |
| 63 | test_step: *std.Build.Step, |
| 64 | exe: *std.Build.Step.Compile, |
| 65 | test_case_name: []const u8, |
| 66 | stderr: enum { inherit, redirect }, |
| 67 | run_step_color: std.Build.Step.Run.Color, |
| 68 | expected_color_enabled: bool, |
| 69 | ) *std.Build.Step.Run { |
| 70 | const b = test_step.owner; |
| 71 | const step_name = b.fmt("{s} {s}{s}", .{ |
| 72 | exe.name, |
| 73 | test_case_name, |
| 74 | if (stderr == .redirect) "-redirect" else "", |
| 75 | }); |
| 76 | const run_exe = b.addRunArtifact(exe); |
| 77 | run_exe.setName(b.fmt("run {s}", .{step_name})); |
| 78 | |
| 79 | run_exe.failing_to_execute_foreign_is_an_error = false; |
| 80 | if (stderr == .redirect) run_exe.expectStdErrMatch(""); |
| 81 | |
| 82 | run_exe.clearEnvironment(); |
| 83 | run_exe.color = run_step_color; |
| 84 | |
| 85 | // Build system quirk: Currently, Run step stdout checks will also redirect stderr, so as a |
| 86 | // workaround we use a CheckFile step instead. We must also mark the Run step as having side |
| 87 | // effects, to ensure the parent stderr is inherited when not explicitly redirected. |
| 88 | run_exe.has_side_effects = true; |
| 89 | const stdout = run_exe.captureStdOut(.{}); |
| 90 | const check_file = b.addCheckFile(stdout, .{ .expected_exact = if (expected_color_enabled) "true" else "false" }); |
| 91 | check_file.setName(b.fmt("check {s}", .{step_name})); |
| 92 | test_step.dependOn(&check_file.step); |
| 93 | |
| 94 | return run_exe; |
| 95 | } |