authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-18 14:47:21+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-18 14:47:21+02:00
log8082323dfd65c20328991d9a0d6740b779b26670
treee689d430ba34ad788499fa85dff7ad4552dcc77e
parent5f6f38ff3160c75c03ce0477904051e6d8af0c80
parenta1b123bccbc2ae50442fcc1544b0da0595401038
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13411 from dweiller/custom-test-runner

Custom test runner

7 files changed, 100 insertions(+), 6 deletions(-)

lib/std/build.zig+12
...@@ -1509,6 +1509,7 @@ pub const LibExeObjStep = struct {...@@ -1509,6 +1509,7 @@ pub const LibExeObjStep = struct {
1509 name_prefix: []const u8,1509 name_prefix: []const u8,
1510 filter: ?[]const u8,1510 filter: ?[]const u8,
1511 test_evented_io: bool = false,1511 test_evented_io: bool = false,
1512 test_runner: ?[]const u8,
1512 code_model: std.builtin.CodeModel = .default,1513 code_model: std.builtin.CodeModel = .default,
1513 wasi_exec_model: ?std.builtin.WasiExecModel = null,1514 wasi_exec_model: ?std.builtin.WasiExecModel = null,
1514 /// Symbols to be exported when compiling to wasm1515 /// Symbols to be exported when compiling to wasm
...@@ -1771,6 +1772,7 @@ pub const LibExeObjStep = struct {...@@ -1771,6 +1772,7 @@ pub const LibExeObjStep = struct {
1771 .exec_cmd_args = null,1772 .exec_cmd_args = null,
1772 .name_prefix = "",1773 .name_prefix = "",
1773 .filter = null,1774 .filter = null,
1775 .test_runner = null,
1774 .disable_stack_probing = false,1776 .disable_stack_probing = false,
1775 .disable_sanitize_c = false,1777 .disable_sanitize_c = false,
1776 .sanitize_thread = false,1778 .sanitize_thread = false,
...@@ -2204,6 +2206,11 @@ pub const LibExeObjStep = struct {...@@ -2204,6 +2206,11 @@ pub const LibExeObjStep = struct {
2204 self.filter = if (text) |t| self.builder.dupe(t) else null;2206 self.filter = if (text) |t| self.builder.dupe(t) else null;
2205 }2207 }
22062208
2209 pub fn setTestRunner(self: *LibExeObjStep, path: ?[]const u8) void {
2210 assert(self.kind == .@"test" or self.kind == .test_exe);
2211 self.test_runner = if (path) |p| self.builder.dupePath(p) else null;
2212 }
2213
2207 /// Handy when you have many C/C++ source files and want them all to have the same flags.2214 /// Handy when you have many C/C++ source files and want them all to have the same flags.
2208 pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: []const []const u8) void {2215 pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: []const []const u8) void {
2209 const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable;2216 const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable;
...@@ -2669,6 +2676,11 @@ pub const LibExeObjStep = struct {...@@ -2669,6 +2676,11 @@ pub const LibExeObjStep = struct {
2669 try zig_args.append(self.name_prefix);2676 try zig_args.append(self.name_prefix);
2670 }2677 }
26712678
2679 if (self.test_runner) |test_runner| {
2680 try zig_args.append("--test-runner");
2681 try zig_args.append(builder.pathFromRoot(test_runner));
2682 }
2683
2672 for (builder.debug_log_scopes) |log_scope| {2684 for (builder.debug_log_scopes) |log_scope| {
2673 try zig_args.append("--debug-log");2685 try zig_args.append("--debug-log");
2674 try zig_args.append(log_scope);2686 try zig_args.append(log_scope);
src/Compilation.zig+10-6
...@@ -994,6 +994,7 @@ pub const InitOptions = struct {...@@ -994,6 +994,7 @@ pub const InitOptions = struct {
994 reference_trace: ?u32 = null,994 reference_trace: ?u32 = null,
995 test_filter: ?[]const u8 = null,995 test_filter: ?[]const u8 = null,
996 test_name_prefix: ?[]const u8 = null,996 test_name_prefix: ?[]const u8 = null,
997 test_runner_path: ?[]const u8 = null,
997 subsystem: ?std.Target.SubSystem = null,998 subsystem: ?std.Target.SubSystem = null,
998 /// WASI-only. Type of WASI execution model ("command" or "reactor").999 /// WASI-only. Type of WASI execution model ("command" or "reactor").
999 wasi_exec_model: ?std.builtin.WasiExecModel = null,1000 wasi_exec_model: ?std.builtin.WasiExecModel = null,
...@@ -1581,12 +1582,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1581,12 +1582,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1581 errdefer std_pkg.destroy(gpa);1582 errdefer std_pkg.destroy(gpa);
15821583
1583 const root_pkg = if (options.is_test) root_pkg: {1584 const root_pkg = if (options.is_test) root_pkg: {
1584 const test_pkg = try Package.createWithDir(1585 const test_pkg = if (options.test_runner_path) |test_runner|
1585 gpa,1586 try Package.create(gpa, null, test_runner)
1586 options.zig_lib_directory,1587 else
1587 null,1588 try Package.createWithDir(
1588 "test_runner.zig",1589 gpa,
1589 );1590 options.zig_lib_directory,
1591 null,
1592 "test_runner.zig",
1593 );
1590 errdefer test_pkg.destroy(gpa);1594 errdefer test_pkg.destroy(gpa);
15911595
1592 break :root_pkg test_pkg;1596 break :root_pkg test_pkg;
src/main.zig+5
...@@ -503,6 +503,7 @@ const usage_build_generic =...@@ -503,6 +503,7 @@ const usage_build_generic =
503 \\ --test-cmd-bin Appends test binary path to test cmd args503 \\ --test-cmd-bin Appends test binary path to test cmd args
504 \\ --test-evented-io Runs the test in evented I/O mode504 \\ --test-evented-io Runs the test in evented I/O mode
505 \\ --test-no-exec Compiles test binary without running it505 \\ --test-no-exec Compiles test binary without running it
506 \\ --test-runner [path] Specify a custom test runner
506 \\507 \\
507 \\Debug Options (Zig Compiler Development):508 \\Debug Options (Zig Compiler Development):
508 \\ -ftime-report Print timing diagnostics509 \\ -ftime-report Print timing diagnostics
...@@ -726,6 +727,7 @@ fn buildOutputType(...@@ -726,6 +727,7 @@ fn buildOutputType(
726 var runtime_args_start: ?usize = null;727 var runtime_args_start: ?usize = null;
727 var test_filter: ?[]const u8 = null;728 var test_filter: ?[]const u8 = null;
728 var test_name_prefix: ?[]const u8 = null;729 var test_name_prefix: ?[]const u8 = null;
730 var test_runner_path: ?[]const u8 = null;
729 var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR");731 var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR");
730 var override_global_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_GLOBAL_CACHE_DIR");732 var override_global_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_GLOBAL_CACHE_DIR");
731 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");733 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");
...@@ -1043,6 +1045,8 @@ fn buildOutputType(...@@ -1043,6 +1045,8 @@ fn buildOutputType(
1043 test_filter = args_iter.nextOrFatal();1045 test_filter = args_iter.nextOrFatal();
1044 } else if (mem.eql(u8, arg, "--test-name-prefix")) {1046 } else if (mem.eql(u8, arg, "--test-name-prefix")) {
1045 test_name_prefix = args_iter.nextOrFatal();1047 test_name_prefix = args_iter.nextOrFatal();
1048 } else if (mem.eql(u8, arg, "--test-runner")) {
1049 test_runner_path = args_iter.nextOrFatal();
1046 } else if (mem.eql(u8, arg, "--test-cmd")) {1050 } else if (mem.eql(u8, arg, "--test-cmd")) {
1047 try test_exec_args.append(args_iter.nextOrFatal());1051 try test_exec_args.append(args_iter.nextOrFatal());
1048 } else if (mem.eql(u8, arg, "--cache-dir")) {1052 } else if (mem.eql(u8, arg, "--cache-dir")) {
...@@ -2943,6 +2947,7 @@ fn buildOutputType(...@@ -2943,6 +2947,7 @@ fn buildOutputType(
2943 .test_evented_io = test_evented_io,2947 .test_evented_io = test_evented_io,
2944 .test_filter = test_filter,2948 .test_filter = test_filter,
2945 .test_name_prefix = test_name_prefix,2949 .test_name_prefix = test_name_prefix,
2950 .test_runner_path = test_runner_path,
2946 .disable_lld_caching = !have_enable_cache,2951 .disable_lld_caching = !have_enable_cache,
2947 .subsystem = subsystem,2952 .subsystem = subsystem,
2948 .wasi_exec_model = wasi_exec_model,2953 .wasi_exec_model = wasi_exec_model,
test/standalone.zig+1
...@@ -15,6 +15,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -15,6 +15,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
15 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");15 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
16 cases.add("test/standalone/noreturn_call/inline.zig");16 cases.add("test/standalone/noreturn_call/inline.zig");
17 cases.add("test/standalone/noreturn_call/as_arg.zig");17 cases.add("test/standalone/noreturn_call/as_arg.zig");
18 cases.addBuildFile("test/standalone/test_runner_path/build.zig", .{ .requires_stage2 = true });
18 cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{});19 cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{});
19 cases.addBuildFile("test/standalone/shared_library/build.zig", .{});20 cases.addBuildFile("test/standalone/shared_library/build.zig", .{});
20 cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{});21 cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{});
test/standalone/test_runner_path/build.zig created+11
...@@ -0,0 +1,11 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const test_exe = b.addTestExe("test", "test.zig");
5 test_exe.test_runner = "test_runner.zig";
6
7 const test_run = test_exe.run();
8
9 const test_step = b.step("test", "Test the program");
10 test_step.dependOn(&test_run.step);
11}
test/standalone/test_runner_path/test.zig created+9
...@@ -0,0 +1,9 @@
1test "test runner path pass" {}
2
3test "test runner path fail" {
4 return error.Fail;
5}
6
7test "test runner path skip" {
8 return error.SkipZigTest;
9}
test/standalone/test_runner_path/test_runner.zig created+52
...@@ -0,0 +1,52 @@
1const std = @import("std");
2const io = std.io;
3const builtin = @import("builtin");
4
5pub const io_mode: io.Mode = builtin.test_io_mode;
6
7pub fn main() void {
8 const test_fn_list = builtin.test_functions;
9 var ok_count: usize = 0;
10 var skip_count: usize = 0;
11 var fail_count: usize = 0;
12
13 var async_frame_buffer: []align(std.Target.stack_align) u8 = undefined;
14 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
15 // ignores the alignment of the slice.
16 async_frame_buffer = &[_]u8{};
17
18 for (test_fn_list) |test_fn| {
19 const result = if (test_fn.async_frame_size) |size| switch (io_mode) {
20 .evented => blk: {
21 if (async_frame_buffer.len < size) {
22 std.heap.page_allocator.free(async_frame_buffer);
23 async_frame_buffer = std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size) catch @panic("out of memory");
24 }
25 const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func);
26 break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{});
27 },
28 .blocking => {
29 skip_count += 1;
30 continue;
31 },
32 } else test_fn.func();
33 if (result) |_| {
34 ok_count += 1;
35 } else |err| switch (err) {
36 error.SkipZigTest => {
37 skip_count += 1;
38 },
39 else => {
40 fail_count += 1;
41 },
42 }
43 }
44 if (ok_count == test_fn_list.len) {
45 std.debug.print("All {d} tests passed.\n", .{ok_count});
46 } else {
47 std.debug.print("{d} passed; {d} skipped; {d} failed.\n", .{ ok_count, skip_count, fail_count });
48 }
49 if (ok_count != 1 or skip_count != 1 or fail_count != 1) {
50 std.process.exit(1);
51 }
52}