test/Runner: support more syntax for command contents

This commit is contained in:
Jacob Young authored and Andrew Kelley committed 2026-10-21 10:05:29 -07:00
1 parent 203bbaee07
commit 809fcd4910
63 files changed
+606 -730

No files matched your search

+8 -10
View File
@@ -793,7 +793,7 @@ pub fn build(b: *std.Build) !void {
const runner = b.addExecutable(.{
.name = "runner",
.root_module = b.createModule(.{
.root_source_file = b.path("test/src/Runner.zig"),
.root_source_file = b.path("test/Runner.zig"),
.target = b.graph.host,
}),
});
@@ -813,17 +813,15 @@ pub fn build(b: *std.Build) !void {
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
};
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests");
try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", tests.incremental_matrix, runner_opts);
test_step.dependOn(test_incremental_step);
const test_debugger_step = b.step("test-debugger", "Run the debugger tests");
if (runner_opts.gdb == null and runner_opts.lldb == null) {
test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);
} else {
try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", tests.debugger_matrix, runner_opts);
if (runner_opts.gdb != null or runner_opts.lldb != null) {
try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", @import("test/debugger/matrix.zon"), runner_opts);
test_step.dependOn(test_debugger_step);
}
} else test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests");
try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts);
test_step.dependOn(test_incremental_step);
}
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
+3 -89
View File
@@ -494,95 +494,9 @@ const Parse = struct {
};
switch (result) {
.success => {},
.failure => |err| try p.appendStrLitError(err, token, bytes, offset),
}
}
/// TODO: try to DRY this with AstGen.failWithStrLitError
fn appendStrLitError(
p: *Parse,
err: std.zig.string_literal.Error,
token: Ast.TokenIndex,
bytes: []const u8,
offset: u32,
) Allocator.Error!void {
const raw_string = bytes[offset..];
switch (err) {
.invalid_escape_character => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"invalid escape character: '{c}'",
.{raw_string[bad_index]},
);
},
.expected_hex_digit => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"expected hex digit, found '{c}'",
.{raw_string[bad_index]},
);
},
.empty_unicode_escape_sequence => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"empty unicode escape sequence",
.{},
);
},
.expected_hex_digit_or_rbrace => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"expected hex digit or '}}', found '{c}'",
.{raw_string[bad_index]},
);
},
.invalid_unicode_codepoint => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"unicode escape does not correspond to a unicode code point",
.{},
);
},
.expected_lbrace => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"expected '{{', found '{c}",
.{raw_string[bad_index]},
);
},
.expected_rbrace => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"expected '}}', found '{c}",
.{raw_string[bad_index]},
);
},
.expected_single_quote => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"expected single quote ('), found '{c}",
.{raw_string[bad_index]},
);
},
.invalid_character => |bad_index| {
try p.appendErrorOff(
token,
offset + @as(u32, @intCast(bad_index)),
"invalid byte in string or character literal: '{c}'",
.{raw_string[bad_index]},
);
},
.empty_char_literal => {
try p.appendErrorOff(token, offset, "empty character literal", .{});
},
.failure => |err| try p.appendErrorOff(token, @intCast(offset + err.offset()), "{f}", .{
err.fmt(bytes[offset..]),
}),
}
}
+17 -1
View File
@@ -38,6 +38,11 @@ pub const Error = union(enum) {
invalid_character: usize,
/// `''`. Not returned for string literals.
empty_char_literal,
/// The input ended before the end of the literal.
end_of_input: usize,
/// The literal ended before the end of the input. There was an otherwise successful
/// parse of a prefix of the input of length given by this payload written to the writer.
end_of_literal: usize,
const FormatMessage = struct {
err: Error,
@@ -83,6 +88,12 @@ pub const Error = union(enum) {
.empty_char_literal => try writer.writeAll(
"empty character literal",
),
.end_of_input => try writer.writeAll(
"expected end of string literal",
),
.end_of_literal => try writer.writeAll(
"unexpected end of string literal",
),
}
}
@@ -104,6 +115,8 @@ pub const Error = union(enum) {
.expected_rbrace,
.expected_single_quote,
.invalid_character,
.end_of_input,
.end_of_literal,
=> |n| n,
.empty_char_literal => 0,
};
@@ -339,13 +352,16 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result {
try writer.writeAll(buf[0..len]);
} else {
try writer.writeByte(@as(u8, @intCast(codepoint)));
if (index == bytes.len) return .{ .failure = .{ .end_of_input = index } };
}
},
.failure => |err| return .{ .failure = err },
}
},
'\n' => return .{ .failure = .{ .invalid_character = index } },
'"' => return .success,
'"' => return if (index < bytes.len - 1) .{
.failure = .{ .end_of_literal = index },
} else .success,
else => {
try writer.writeByte(b);
index += 1;
+258 -159
View File
@@ -64,9 +64,7 @@ fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError {
return runner.failString(try runner.eb_wip.printString(fmt, args));
}
fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError {
try runner.eb_wip.addRootErrorMessage(.{
.msg = msg,
});
try runner.eb_wip.addRootErrorMessage(.{ .msg = msg });
return error.AlreadyReported;
}
@@ -505,33 +503,34 @@ pub const SourceReader = struct {
src_loc: []const u8,
msg: std.zig.ErrorBundle.String,
) FailError {
try s.eb_wip.addRootErrorMessage(.{ .msg = msg, .src_loc = try s.srcLoc(src_loc) });
return error.AlreadyReported;
}
fn srcLoc(
s: *SourceReader,
src_loc: []const u8,
) std.mem.Allocator.Error!std.zig.ErrorBundle.SourceLocationIndex {
const line: u32, const column: u32, const source_line = src_loc: {
const pos = src_loc.ptr - s.interface.buffer.ptr;
const end = std.mem.findScalarPos(u8, s.interface.buffer, pos, '\n') orelse
s.interface.buffer.len;
const start = if (std.mem.findScalarLast(u8, s.interface.buffer[0..end], '\n')) |newline|
newline + 1
else
0;
const buffer = s.interface.buffer[0..s.interface.end];
const pos = src_loc.ptr - buffer.ptr;
const end = std.mem.findScalarPos(u8, buffer, pos, '\n') orelse buffer.len;
const start =
if (std.mem.findScalarLast(u8, buffer[0..end], '\n')) |newline| newline + 1 else 0;
break :src_loc .{
@intCast(s.line + std.mem.countScalar(u8, s.interface.buffer[0..start], '\n')),
@intCast(s.line + std.mem.countScalar(u8, buffer[0..start], '\n')),
@intCast(pos - start),
s.interface.buffer[start..end],
buffer[start..end],
};
};
try s.eb_wip.addRootErrorMessage(.{
.msg = msg,
.src_loc = try s.eb_wip.addSourceLocation(.{
.src_path = s.src_path,
.line = line,
.column = column,
.span_start = column,
.span_main = column,
.span_end = @intCast(column + src_loc.len),
.source_line = try s.eb_wip.addString(source_line),
}),
return s.eb_wip.addSourceLocation(.{
.src_path = s.src_path,
.line = line,
.column = column,
.span_start = column,
.span_main = column,
.span_end = @intCast(column + src_loc.len),
.source_line = try s.eb_wip.addString(source_line),
});
return error.AlreadyReported;
}
};
pub const DelimitedReader = struct {
@@ -585,10 +584,66 @@ const Update = struct {
manifest_sr: SourceReader,
compiler: ?Compiler,
src_dir: std.Io.Dir,
eb_wip: *std.zig.ErrorBundle.Wip,
cmd_src_loc: std.zig.ErrorBundle.SourceLocationIndex,
src_loc: ?std.zig.ErrorBundle.SourceLocationIndex,
num: usize,
name: []const u8,
prog_node: std.Progress.Node,
mtime: std.Io.Timestamp,
num: usize,
allow_skip: bool,
fn checkMatches(
update: *const Update,
what: []const u8,
expected: []const u8,
actual: []const u8,
) FailError!void {
var expected_match_it = std.mem.splitSequence(u8, expected, "#...");
var pos: usize = 0;
while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) {
var context_len: usize = expected_match.len;
pos = while (true) : (context_len -= 1) break std.mem.findPos(
u8,
actual,
pos,
expected_match[0..context_len],
) orelse continue;
const actual_match = actual[pos..];
std.testing.expectEqualStrings(
expected_match,
actual_match[0..@min(actual_match.len, expected_match.len)],
) catch |err| switch (err) {
error.TestExpectedEqual => {
std.testing.failPrint("\n=============== full output: =========\n", .{});
std.testing.failPrintWithVisibleNewlines(actual_match);
std.testing.failPrint("\n======================================\n", .{});
return update.fail("{s} did not match expected", .{what});
},
};
}
}
fn fail(update: *const Update, comptime fmt: []const u8, args: anytype) FailError {
return update.failString(try update.eb_wip.printString(fmt, args));
}
fn failString(update: *const Update, msg: std.zig.ErrorBundle.String) FailError {
var notes_buffer: [1]std.zig.ErrorBundle.ErrorMessage = undefined;
var notes_len: u32 = 0;
if (update.src_loc) |src_loc| {
notes_buffer[notes_len] = .{
.msg = try update.eb_wip.addString("after this update"),
.src_loc = src_loc,
};
notes_len += 1;
}
try update.eb_wip.addRootErrorMessageWithNotes(.{
.msg = msg,
.src_loc = update.cmd_src_loc,
.notes_len = 1,
}, notes_buffer[0..notes_len]);
return error.AlreadyReported;
}
};
const TestError = error{
@@ -626,9 +681,13 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to create {q}: {t}", .{ target_query, e }),
},
.eb_wip = &runner.eb_wip,
.cmd_src_loc = undefined,
.src_loc = null,
.num = 0,
.name = undefined,
.prog_node = .none,
.mtime = .now(runner.io, .real),
.num = 0,
.allow_skip = true,
};
defer {
@@ -654,6 +713,7 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr
return update.manifest_sr.fail(unexpected, "unexpected argument {q}", .{unexpected});
continue;
}
update.cmd_src_loc = try update.manifest_sr.srcLoc(cmd_src_loc);
const cmd = std.meta.stringToEnum(Command, std.mem.cutPrefix(u8, cmd_src_loc, "#") orelse
return update.manifest_sr.fail(cmd_src_loc, "expected command", .{})) orelse
return update.manifest_sr.fail(cmd_src_loc, "unknown command", .{});
@@ -666,7 +726,7 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr
defer if (contents_file) |file| file.close(runner.io);
var contents_buffer: [512]u8 = undefined;
var contents_impl: union(enum) {
ending: std.Io.Reader,
r: std.Io.Reader,
dr: DelimitedReader,
fr: std.Io.File.Reader,
} = undefined;
@@ -678,42 +738,75 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr
"unexpected argument {q}",
.{unexpected},
);
contents_impl = .{ .ending = .ending_instance };
break :contents_r &contents_impl.ending;
contents_impl = .{ .r = .ending_instance };
break :contents_r &contents_impl.r;
},
else => {
const contents_path = line_it.rest();
if (contents_path.len == 0) {
contents_impl = .{ .ending = .ending_instance };
break :contents_r &contents_impl.ending;
const contents = line_it.rest();
if (contents.len == 0) {
contents_impl = .{ .r = .ending_instance };
break :contents_r &contents_impl.r;
}
contents: switch (contents[0]) {
else => return update.manifest_sr.fail(contents, "invalid contents syntax", .{}),
'"' => {
if (contents.len < 2 or contents[contents.len - 1] != '"') continue :contents 0;
var contents_fw: std.Io.Writer = .fixed(&contents_buffer);
switch (std.zig.string_literal.parseWrite(
&contents_fw,
contents,
) catch |err| switch (err) {
error.WriteFailed => return update.manifest_sr.fail(
contents,
"contents string too long, use inline or file syntax instead",
.{},
),
}) {
.success => {
contents_impl = .{ .r = .fixed(contents_fw.buffered()) };
break :contents_r &contents_impl.r;
},
.failure => |err| return update.manifest_sr.fail(
contents[err.offset()..][0..0],
"{f}",
.{err.fmt(contents)},
),
}
},
'{' => {
if (contents.len != 1) continue :contents 0;
if (std.mem.eql(u8, contents_path, "{")) {
contents_impl = .{
.dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer),
};
skip_delimiter = true;
break :contents_r &contents_impl.dr.interface;
}
contents_impl = .{
.dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer),
};
skip_delimiter = true;
break :contents_r &contents_impl.dr.interface;
},
'@' => {
const args_test = runner.args.@"test" orelse return update.manifest_sr.fail(
contents,
"contents file requires directory test",
.{},
);
const contents_path = contents[1..];
try runner.discoverInput(args_test.input_dir, contents_path);
const args_test = runner.args.@"test" orelse return update.manifest_sr.fail(
contents_path,
"contents file requires directory test",
.{},
);
try runner.discoverInput(args_test.input_dir, contents_path);
contents_file =
args_test.dir.openFile(runner.io, contents_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return update.manifest_sr.fail(
contents_file = args_test.dir.openFile(
runner.io,
contents_path,
"unable to open contents file: {t}",
.{e},
),
};
contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) };
break :contents_r &contents_impl.fr.interface;
.{},
) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return update.manifest_sr.fail(
contents_path,
"unable to open contents file: {t}",
.{e},
),
};
contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) };
break :contents_r &contents_impl.fr.interface;
},
}
},
};
@@ -724,28 +817,41 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr
error.SkipTest,
=> |e| return e,
error.ContentsReadFailed => switch (contents_impl) {
.ending => unreachable,
.r => unreachable,
.dr => switch (manifest_fr.err orelse return error.OutOfMemory) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
else => |e| return update.fail("unable to read manifest: {t}", .{e}),
},
.fr => |fr| switch (fr.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to read contents file: {t}", .{e}),
else => |e| return update.fail("unable to read contents file: {t}", .{e}),
},
},
};
} else |err| switch (err) {
error.ReadFailed => switch (manifest_fr.err orelse return error.OutOfMemory) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
else => |e| return update.fail("unable to read manifest: {t}", .{e}),
},
error.StreamTooLong => unreachable,
error.EndOfStream => if (skip_delimiter)
return runner.fail("manifest missing \"#}}\" delimiter", .{}),
error.EndOfStream => {
const final_line = update.manifest_sr.interface.buffered();
switch (final_line.len) {
0 => if (skip_delimiter) return update.manifest_sr.fail(
final_line[0..0],
"missing \"#}}\" delimiter",
.{},
),
else => return update.manifest_sr.fail(
final_line[final_line.len..],
"missing trailing newline",
.{},
),
}
},
}
if (update.compiler) |*comp| {
if (comp.state != .idle) return runner.fail("missing \"#check\"", .{});
if (comp.state != .idle) return update.fail("missing \"#check\"", .{});
try comp.exit();
}
}
@@ -781,21 +887,27 @@ fn handleCommand(
}, contents_r, target: {
var component_it = std.mem.splitBackwardsScalar(u8, update.target_query, '-');
const pic_str = component_it.next() orelse
return runner.fail("target {q} missing pic", .{update.target_query});
return update.fail("target {q} missing pic", .{update.target_query});
const pic = std.meta.stringToEnum(Compiler.Target.Pic, pic_str) orelse
return runner.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str });
return update.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str });
const linker_str = component_it.next() orelse
return runner.fail("target {q} missing linker", .{update.target_query});
return update.fail("target {q} missing linker", .{update.target_query});
const linker = std.meta.stringToEnum(Compiler.Target.Linker, linker_str) orelse
return runner.fail("target {q} unknown linker {q}", .{ update.target_query, linker_str });
return update.fail("target {q} unknown linker {q}", .{
update.target_query, linker_str,
});
const backend_str = component_it.next() orelse
return runner.fail("target {q} missing backend", .{update.target_query});
return update.fail("target {q} missing backend", .{update.target_query});
const backend = std.meta.stringToEnum(Compiler.Target.Backend, backend_str) orelse
return runner.fail("target {q} unknown backend {q}", .{ update.target_query, backend_str });
return update.fail("target {q} unknown backend {q}", .{
update.target_query, backend_str,
});
const cache_mode_str = component_it.next() orelse
return runner.fail("target {q} missing cache mode", .{update.target_query});
return update.fail("target {q} missing cache mode", .{update.target_query});
const cache_mode = std.meta.stringToEnum(Compiler.Target.CacheMode, cache_mode_str) orelse
return runner.fail("target {q} unknown cache mode {q}", .{ update.target_query, cache_mode_str });
return update.fail("target {q} unknown cache mode {q}", .{
update.target_query, cache_mode_str,
});
const triple = component_it.rest();
break :target .{
.triple = triple,
@@ -808,13 +920,13 @@ fn handleCommand(
.cbe => "c",
},
}) catch |err| switch (err) {
error.ParseFailed => return runner.fail("unable to parse triple {q}", .{
error.ParseFailed => return update.fail("unable to parse triple {q}", .{
triple,
}),
},
) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to resolve target {q}: {t}", .{ triple, e }),
else => |e| return update.fail("unable to resolve target {q}: {t}", .{ triple, e }),
},
.cache_mode = cache_mode,
.backend = backend,
@@ -868,25 +980,24 @@ fn handleCommand(
else => |e| return update.manifest_sr.fail(arg.?, "unable to delete file: {t}", .{e}),
},
.update => {
update.src_loc = update.cmd_src_loc;
const comp = &(update.compiler orelse return update.manifest_sr.fail(
cmd_src_loc,
"missing \"#exe\", \"#lib\", or \"#obj\"",
.{},
));
update.prog_node.end();
update.prog_node = runner.prog_node.start(
switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) {
error.ReadFailed => return error.ContentsReadFailed,
}) {
0 => switch (update.num) {
0 => "initial update",
else => |num| std.mem.print(&name_buffer, "update {d}", .{num}) catch
&name_buffer,
},
else => |name_len| name_buffer[0..name_len],
const arena = runner.arena.allocator();
update.name = switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) {
error.ReadFailed => return error.ContentsReadFailed,
}) {
0 => switch (update.num) {
0 => "initial update",
else => |num| try arena.print("update {d}", .{num}),
},
0,
);
else => |name_len| try arena.dupe(u8, name_buffer[0..name_len]),
};
update.prog_node = runner.prog_node.start(update.name, 0);
_ = contents_r.discardRemaining() catch |err| switch (err) {
error.ReadFailed => return error.ContentsReadFailed,
};
@@ -895,7 +1006,7 @@ fn handleCommand(
comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
error.WriteFailed => switch (comp.fw.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to send message to compiler: {t}", .{e}),
else => |e| return update.fail("unable to send message to compiler: {t}", .{e}),
},
};
comp.state = .update;
@@ -934,7 +1045,7 @@ fn handleCommand(
unreachable;
const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch
unreachable;
try comp.checkSuccess(check, expected, update.src_dir, digest);
try comp.checkSuccess(update, check, expected, digest);
},
.error_bundle => {
const eb = std.zig.Server.allocErrorBundle(
@@ -942,7 +1053,7 @@ fn handleCommand(
message.body,
) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
error.EndOfStream => return runner.fail("error bundle truncated", .{}),
error.EndOfStream => return update.fail("error bundle truncated", .{}),
};
switch (check) {
.errors => {
@@ -958,7 +1069,7 @@ fn handleCommand(
const actual = error_aw.written();
std.mem.replaceScalar(u8, actual, '\\', '/');
std.testing.expectEqualStrings(expected, actual) catch |err| switch (err) {
error.TestExpectedEqual => return runner.fail(
error.TestExpectedEqual => return update.fail(
"errors did not match expected",
.{},
),
@@ -969,7 +1080,7 @@ fn handleCommand(
error.Canceled => {},
else => {},
};
return runner.fail("unexpected compile errors", .{});
return update.fail("unexpected compile errors", .{});
},
}
comp.state = .idle;
@@ -977,17 +1088,15 @@ fn handleCommand(
},
};
const buffered_stderr = stderr.buffered();
if (buffered_stderr.len > 0) {
const stderr_buffered = stderr.buffered();
if (stderr_buffered.len > 0) {
if (comp.allow_compiler_stderr) {
std.log.info("stderr:\n{s}", .{buffered_stderr});
} else {
return runner.fail("unexpected stderr:\n{s}", .{buffered_stderr});
}
std.log.info("#update {q} stderr:\n{s}", .{ update.name, stderr_buffered });
} else return update.fail("unexpected stderr:\n{s}", .{stderr_buffered});
}
try comp.exit();
return runner.fail("compiler failed to send terminating error_bundle", .{});
return update.fail("compiler failed to send terminating error_bundle", .{});
},
}
assert(contents_r.discardRemaining() catch |err| switch (err) {
@@ -1219,9 +1328,9 @@ const Compiler = struct {
const Check = enum { errors, stdout, exit, gdb, lldb };
fn checkSuccess(
comp: *Compiler,
update: *const Update,
check: Check,
expected: []const u8,
src_dir: std.Io.Dir,
digest: *const std.Build.Cache.BinDigest,
) TestError!void {
const runner = comp.runner;
@@ -1238,9 +1347,9 @@ const Compiler = struct {
const debug_success = 99;
const tmp_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "tmp";
src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) {
update.src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to create dir path {q}: {t}", .{
else => |e| return update.fail("unable to create dir path {q}: {t}", .{
tmp_dir_path, e,
}),
};
@@ -1256,12 +1365,13 @@ const Compiler = struct {
.gdb => {
const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb";
argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" });
const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{
script_path, e,
}),
};
const script_file =
update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return update.fail("unable to create debugger script {q}: {t}", .{
script_path, e,
}),
};
errdefer script_file.close(io);
var script_fw = script_file.writer(io, &script_buffer);
script_fw.interface.writeAll(
@@ -1271,7 +1381,9 @@ const Compiler = struct {
) catch |err| switch (err) {
error.WriteFailed => switch (script_fw.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }),
else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
script_path, e,
}),
},
};
break :script .{ script_path, script_file, script_fw };
@@ -1280,13 +1392,13 @@ const Compiler = struct {
const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "lldb";
argv.appendSliceAssumeCapacity(&.{ "lldb", "--batch", "--source", script_path, "--" });
try environ_map.put("LANG", "C.UTF-8"); // affects output formatting
const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{
script_path,
e,
}),
};
const script_file =
update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return update.fail("unable to create debugger script {q}: {t}", .{
script_path, e,
}),
};
errdefer script_file.close(io);
var script_fw = script_file.writer(io, &script_buffer);
script_fw.interface.writeAll(
@@ -1298,7 +1410,9 @@ const Compiler = struct {
) catch |err| switch (err) {
error.WriteFailed => switch (script_fw.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }),
else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
script_path, e,
}),
},
};
break :script .{ script_path, script_file, script_fw };
@@ -1312,7 +1426,7 @@ const Compiler = struct {
const bin_path = switch (comp.target.backend.?) {
.sema => return,
.selfhosted, .llvm => out_path,
.cbe => try comp.compileC(src_dir, out_path),
.cbe => try comp.compileC(update.src_dir, out_path),
};
const need_cross_libc =
@@ -1347,7 +1461,7 @@ const Compiler = struct {
&path_buffer,
) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to get libc runtimes path: {t}", .{e}),
else => |e| return update.fail("unable to get libc runtimes path: {t}", .{e}),
}];
argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{
libc_runtimes_path,
@@ -1386,7 +1500,10 @@ const Compiler = struct {
if (!runner.args.quiet) std.log.info("{f}", .{std.zig.SubprocessCommand{
.argv = argv.items,
.cwd = cwd_path: {
break :cwd_path path_buffer[0 .. src_dir.realPath(io, &path_buffer) catch |err| switch (err) {
break :cwd_path path_buffer[0 .. update.src_dir.realPath(
io,
&path_buffer,
) catch |err| switch (err) {
error.Canceled => |e| return e,
else => break :cwd_path null,
}];
@@ -1401,9 +1518,9 @@ const Compiler = struct {
}) catch &name_buffer, 0);
defer run_prog_node.end();
const bin_file = src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) {
const bin_file = update.src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to open {q}: {t}", .{ bin_path, e }),
else => |e| return update.fail("unable to open {q}: {t}", .{ bin_path, e }),
};
defer bin_file.close(io);
const result = std.process.run(gpa, io, .{
@@ -1430,7 +1547,7 @@ const Compiler = struct {
, .{cmd}) catch |err| switch (err) {
error.WriteFailed => switch (script_fw.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
script_path, e,
}),
},
@@ -1442,14 +1559,14 @@ const Compiler = struct {
, .{debug_success}) catch |err| switch (err) {
error.WriteFailed => switch (script_fw.err.?) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
script_path, e,
}),
},
};
script_fw.flush() catch |err| switch (err) {
error.Canceled => |e| return e,
else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
script_path, e,
}),
};
@@ -1467,7 +1584,7 @@ const Compiler = struct {
},
},
.argv = argv.items,
.cwd = .{ .dir = src_dir },
.cwd = .{ .dir = update.src_dir },
.environ_map = &environ_map,
.progress_node = run_prog_node,
}) catch |err| if (use_executor) {
@@ -1477,7 +1594,7 @@ const Compiler = struct {
.{ bin_path, comp.target.triple, err },
);
return;
} else return runner.fail("unable to run the generated executable {q}: {t}", .{
} else return update.fail("unable to run the generated executable {q}: {t}", .{
bin_path, err,
});
defer {
@@ -1488,7 +1605,7 @@ const Compiler = struct {
.exited => |code| switch (check) {
.errors => unreachable,
.stdout => {
if (code != 0) return runner.fail(
if (code != 0) return update.fail(
"generated executable {q} failed with code {d}",
.{ bin_path, code },
);
@@ -1496,67 +1613,49 @@ const Compiler = struct {
expected,
result.stdout,
) catch |err| switch (err) {
error.TestExpectedEqual => return runner.fail("stdout did not match expected", .{}),
error.TestExpectedEqual => return update.fail(
"stdout did not match expected",
.{},
),
};
},
.exit => {
var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 = undefined;
var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 =
undefined;
std.testing.expectEqualStrings(
expected,
std.mem.print(&actual_code_buffer, "{d}", .{code}) catch unreachable,
) catch |err| switch (err) {
error.TestExpectedEqual => return runner.fail(
error.TestExpectedEqual => return update.fail(
"exit code did not match expected",
.{},
),
};
},
.gdb, .lldb => {
if (code != debug_success) return runner.fail(
if (code != debug_success) return update.fail(
"debugging {q} failed with code {d}",
.{ bin_path, code },
);
var expected_match_it = std.mem.splitSequence(u8, expected, "#...");
var pos: usize = 0;
while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) {
var context_len: usize = expected_match.len;
pos = while (true) : (context_len -= 1) break std.mem.findPos(
u8,
result.stdout,
pos,
expected_match[0..context_len],
) orelse continue;
const actual_match = result.stdout[pos..];
std.testing.expectEqualStrings(
expected_match,
actual_match[0..@min(actual_match.len, expected_match.len)],
) catch |err| switch (err) {
error.TestExpectedEqual => {
std.testing.failPrint("\n=============== full output: =========\n", .{});
std.testing.failPrintWithVisibleNewlines(actual_match);
std.testing.failPrint("\n======================================\n", .{});
return runner.fail("stdout did not match expected", .{});
},
};
}
try update.checkMatches("stdout", expected, result.stdout);
},
},
.signal => |sig| return runner.fail(
.signal => |sig| return update.fail(
"generated executable {q} terminated with signal {t}",
.{ bin_path, sig },
),
.stopped => |sig| return runner.fail(
.stopped => |sig| return update.fail(
"generated executable {q} stopped with signal {t}",
.{ bin_path, sig },
),
.unknown => return runner.fail(
.unknown => return update.fail(
"generated executable {q} terminated unexpectedly",
.{bin_path},
),
}
if (!use_executor and result.stderr.len > 0) {
std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{
bin_path, result.stderr,
std.log.err("#update {q} generated executable {q} had unexpected stderr:\n{s}", .{
update.name, bin_path, result.stderr,
});
}
}
+2 -2
View File
@@ -3,6 +3,6 @@
-Mroot=basic.zig
#}
#write basic.zig basic.zig
#write basic.zig @basic.zig
#update
#check lldb lldb
#check lldb @lldb
+1 -3
View File
@@ -1,6 +1,4 @@
#todo {
passes, but prints errors
#}
#todo "passes, but prints errors"
#skip x86_64-linux-none-whole-selfhosted-new-nopic
#skip x86_64-linux-none-whole-selfhosted-new-pic
#skip x86_64-linux-none-incremental-selfhosted-new-nopic
+1 -3
View File
@@ -1,6 +1,4 @@
#todo {
passes, but prints errors
#}
#todo "passes, but prints errors"
#skip x86_64-linux-none-whole-selfhosted-new-nopic
#skip x86_64-linux-none-whole-selfhosted-new-pic
#skip x86_64-linux-none-incremental-selfhosted-new-nopic
+6 -8
View File
@@ -1,6 +1,4 @@
#todo {
implement inline line info in lldb
#}
#todo "implement inline line info in lldb"
#skip x86_64-linux-none-incremental-selfhosted-new-nopic
#skip x86_64-linux-none-incremental-selfhosted-new-pic
@@ -10,9 +8,9 @@ implement inline line info in lldb
-Mmodule=mod0.zig
#}
#write root0.zig root0.zig
#write root1.zig root1.zig
#write mod0.zig mod0.zig
#write mod1.zig mod1.zig
#write root0.zig @root0.zig
#write root1.zig @root1.zig
#write mod0.zig @mod0.zig
#write mod1.zig @mod1.zig
#update
#check lldb lldb
#check lldb @lldb
+68
View File
@@ -0,0 +1,68 @@
.{
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .old,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .old,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .new,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .pic,
},
}
+2 -2
View File
@@ -3,6 +3,6 @@
-Mroot=main.zig
#}
#write main.zig main.zig
#write main.zig @main.zig
#update
#check lldb lldb
#check lldb @lldb
@@ -3,6 +3,6 @@
-Mroot=step_single_stmt_loops.zig
#}
#write step_single_stmt_loops.zig step_single_stmt_loops.zig
#write step_single_stmt_loops.zig @step_single_stmt_loops.zig
#update
#check lldb lldb
#check lldb @lldb
+1 -3
View File
@@ -1,6 +1,4 @@
#todo {
passes, but prints errors
#}
#todo "passes, but prints errors"
#skip x86_64-linux-none-whole-selfhosted-new-nopic
#skip x86_64-linux-none-whole-selfhosted-new-pic
#skip x86_64-linux-none-incremental-selfhosted-new-nopic
+5 -10
View File
@@ -24,8 +24,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add new declaration#}
#update "add new declaration"
#check stdout {
good morning
#}
@@ -39,8 +38,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
reference new declaration#}
#update "reference new declaration"
#check stdout {
good evening
#}
@@ -54,8 +52,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
reference missing declaration#}
#update "reference missing declaration"
#check errors {
main.zig:3:52: error: use of undeclared identifier 'qux'
#}
@@ -70,8 +67,7 @@ const bar = "good evening\n";
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add missing declaration#}
#update "add missing declaration"
#check stdout {
good night
#}
@@ -84,8 +80,7 @@ pub fn main() !void {
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove unused declarations#}
#update "remove unused declarations"
#check stdout {
good night
#}
+5 -10
View File
@@ -24,8 +24,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add new declaration#}
#update "add new declaration"
#check stdout {
good morning
#}
@@ -39,8 +38,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
reference new declaration#}
#update "reference new declaration"
#check stdout {
good evening
#}
@@ -54,8 +52,7 @@ const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
reference missing declaration#}
#update "reference missing declaration"
#check errors {
main.zig:3:59: error: root source file struct 'main' has no member named 'qux'
main.zig:1:1: note: struct declared here
@@ -71,8 +68,7 @@ const bar = "good evening\n";
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add missing declaration#}
#update "add missing declaration"
#check stdout {
good night
#}
@@ -85,8 +81,7 @@ pub fn main() !void {
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove unused declarations#}
#update "remove unused declarations"
#check stdout {
good night
#}
@@ -32,8 +32,7 @@ pub fn main() void {
_ = @as(@This(), undefined);
}
#}
#update {
add more decls around error#}
#update "add more decls around error"
#check errors {
main.zig:4:15: error: root source file struct 'main' has no member named 'does_not_exist'
main.zig:1:1: note: struct declared here
@@ -14,8 +14,7 @@ const S = struct {
};
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
pub fn main() void {
@@ -29,7 +28,5 @@ const S = struct {
bar: u32,
};
#}
#update {
add field to outer struct, change decl used by inner struct#}
#check stdout {
#}
#update "add field to outer struct, change decl used by inner struct"
#check stdout
@@ -2,30 +2,27 @@
-Mroot=main.zig
#}
#write main.zig 0/main.zig
#write main.zig @0/main.zig
#update
#check stdout {
1 100
#}
#write main.zig 1/main.zig
#update {
add a field#}
#write main.zig @1/main.zig
#update "add a field"
#check stdout {
2 100
#}
#write main.zig 2/main.zig
#update {
remove all fields#}
#write main.zig @2/main.zig
#update "remove all fields"
#check errors {
main.zig:15:24: error: no field named 'x' in struct 'main.S'
main.zig:1:11: note: struct declared here
#}
#write main.zig 3/main.zig
#update {
remove reference to non-existent field#}
#write main.zig @3/main.zig
#update "remove reference to non-existent field"
#check stdout {
0 <no fields>
#}
@@ -2,30 +2,27 @@
-Mroot=main.zig
#}
#write main.zig 0/main.zig
#write main.zig @0/main.zig
#update
#check stdout {
1 100
#}
#write main.zig 1/main.zig
#update {
add a field#}
#write main.zig @1/main.zig
#update "add a field"
#check stdout {
2 100
#}
#write main.zig 2/main.zig
#update {
remove all fields#}
#write main.zig @2/main.zig
#update "remove all fields"
#check errors {
main.zig:15:24: error: no field named 'x' in struct 'main'
main.zig:1:1: note: struct declared here
#}
#write main.zig 3/main.zig
#update {
remove reference to non-existent field#}
#write main.zig @3/main.zig
#update "remove reference to non-existent field"
#check stdout {
0 <no fields>
#}
@@ -16,8 +16,7 @@ main.zig:2:5: error: uh oh
pub fn main() !void {
@compileError("uh oh");
#}
#update {
add parse error#}
#update "add parse error"
#check errors {
main.zig:3:1: error: expected statement, found 'EOF'
#}
@@ -27,8 +26,7 @@ pub fn main() !void {
@compileError("uh oh");
}
#}
#update {
fix parse error#}
#update "fix parse error"
#check errors {
main.zig:2:5: error: uh oh
#}
@@ -37,8 +35,7 @@ main.zig:2:5: error: uh oh
pub fn main() !void {
@compileError("uh oh");
#}
#update {
add parse error again#}
#update "add parse error again"
#check errors {
main.zig:3:1: error: expected statement, found 'EOF'
#}
@@ -47,8 +44,7 @@ main.zig:3:1: error: expected statement, found 'EOF'
pub fn main() !void {
//@compileError("uh oh");
#}
#update {
comment @compileError call#}
#update "comment @compileError call"
#check errors {
main.zig:3:1: error: expected statement, found 'EOF'
#}
@@ -58,7 +54,5 @@ pub fn main() !void {
//@compileError("uh oh");
}
#}
#update {
fix parse error again#}
#check stdout {
#}
#update "fix parse error again"
#check stdout
+2 -4
View File
@@ -26,8 +26,7 @@ comptime {
_ = @import("this_is/not_real.zig");
}
#}
#update {
change bad import#}
#update "change bad import"
#check errors {
this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
foo.zig:2:17: note: file imported here
@@ -41,8 +40,7 @@ pub fn main() !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove import of 'foo.zig'#}
#update "remove import of 'foo.zig'"
#check stdout {
success
#}
+3 -6
View File
@@ -38,8 +38,7 @@ comptime {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
make backing types signed#}
#update "make backing types signed"
#check errors {
main.zig:5:5: error: found compile log statement
main.zig:8:5: note: also here
@@ -62,8 +61,7 @@ comptime {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
make backing types too small#}
#update "make backing types too small"
#check errors {
main.zig:1:20: error: backing integer bit width does not match total bit width of fields
main.zig:1:27: note: backing integer 'i5' has bit width '5'
@@ -87,8 +85,7 @@ comptime {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
make backing types too big#}
#update "make backing types too big"
#check errors {
main.zig:1:20: error: backing integer bit width does not match total bit width of fields
main.zig:1:27: note: backing integer 'u10' has bit width '10'
+8 -16
View File
@@ -12,8 +12,7 @@ pub fn main() void {
#write foo.zig {
pub const T = struct { x: u8 };
#}
#update {
T is struct#}
#update "T is struct"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -25,8 +24,7 @@ Compile Log Output:
#write foo.zig {
pub const T = union {};
#}
#update {
T is union#}
#update "T is union"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -38,8 +36,7 @@ Compile Log Output:
#write foo.zig {
pub const T = enum {};
#}
#update {
T is enum#}
#update "T is enum"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -51,8 +48,7 @@ Compile Log Output:
#write foo.zig {
pub const T = opaque {};
#}
#update {
T is opaque#}
#update "T is opaque"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -64,8 +60,7 @@ Compile Log Output:
#write foo.zig {
pub const T = packed struct {};
#}
#update {
T is packed struct#}
#update "T is packed struct"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -77,8 +72,7 @@ Compile Log Output:
#write foo.zig {
pub const T = packed union { x: void }; // packed unions need at least 1 field
#}
#update {
T is packed union#}
#update "T is packed union"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -90,8 +84,7 @@ Compile Log Output:
#write foo.zig {
pub const T = extern struct {};
#}
#update {
T is extern struct#}
#update "T is extern struct"
#check errors {
main.zig:3:5: error: found compile log statement
@@ -103,8 +96,7 @@ Compile Log Output:
#write foo.zig {
pub const T = extern union { x: void }; // extern unions need at least 1 field
#}
#update {
T is extern union#}
#update "T is extern union"
#check errors {
main.zig:3:5: error: found compile log statement
+5 -10
View File
@@ -21,15 +21,13 @@ Hello, World!
#write string.txt {
Hello again, World!
#}
#update {
change file contents#}
#update "change file contents"
#check stdout {
Hello again, World!
#}
#delete string.txt
#update {
delete file#}
#update "delete file"
#check errors {
main.zig:2:27: error: failed opening "string.txt": FileNotFound
#}
@@ -42,8 +40,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove reference to file#}
#update "remove reference to file"
#check stdout {
a hardcoded string
#}
@@ -56,8 +53,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
re-introduce reference to file#}
#update "re-introduce reference to file"
#check errors {
main.zig:2:27: error: failed opening "string.txt": FileNotFound
#}
@@ -65,8 +61,7 @@ main.zig:2:27: error: failed opening "string.txt": FileNotFound
#write string.txt {
We're back, World!
#}
#update {
recreate file#}
#update "recreate file"
#check stdout {
We're back, World!
#}
+9 -13
View File
@@ -2,29 +2,26 @@
-Mroot=main.zig
#}
#write main.zig 0/main.zig
#write main.zig @0/main.zig
#update
#check stdout {
a
#}
#write main.zig 1/main.zig
#update {
too many enum fields#}
#write main.zig @1/main.zig
#update "too many enum fields"
#check errors {
main.zig:7:5: error: enum tag value '4' too large for type 'u2'
#}
#write main.zig 2/main.zig
#update {
increase tag size#}
#write main.zig @2/main.zig
#update "increase tag size"
#check stdout {
a
#}
#write main.zig 3/main.zig
#update {
specify tag directly#}
#write main.zig @3/main.zig
#update "specify tag directly"
#check errors {
main.zig:9:5: error: found compile log statement
@@ -32,9 +29,8 @@ Compile Log Output:
@as(type, u3)
#}
#write main.zig 4/main.zig
#update {
change directly-specified tag type#}
#write main.zig @4/main.zig
#update "change directly-specified tag type"
#check errors {
main.zig:9:5: error: found compile log statement
+14 -21
View File
@@ -2,50 +2,43 @@
-Mroot=main.zig
#}
#write main.zig 0/main.zig
#write main.zig @0/main.zig
#update
#check stdout {
123
#}
#write main.zig 1/main.zig
#update {
add conflict#}
#write main.zig @1/main.zig
#update "add conflict"
#check errors {
main.zig:6:5: error: exported symbol collision: foo
main.zig:1:1: note: other symbol here
#}
#write main.zig 2/main.zig
#update {
resolve conflict#}
#write main.zig @2/main.zig
#update "resolve conflict"
#check stdout {
123 456
#}
#write main.zig 3/main.zig
#update {
put exports in decl#}
#write main.zig @3/main.zig
#update "put exports in decl"
#check stdout {
123 456
#}
#write main.zig 4/main.zig
#update {
remove reference to exporting decl#}
#check stdout {
#}
#write main.zig @4/main.zig
#update "remove reference to exporting decl"
#check stdout
#write main.zig 5/main.zig
#update {
mark consts as export#}
#write main.zig @5/main.zig
#update "mark consts as export"
#check stdout {
123 456
#}
#write main.zig 6/main.zig
#update {
reintroduce reference to exporting decl, introducing conflict#}
#write main.zig @6/main.zig
#update "reintroduce reference to exporting decl, introducing conflict"
#check errors {
main.zig:5:5: error: exported symbol collision: bar
main.zig:2:1: note: other symbol here
+2 -4
View File
@@ -29,8 +29,7 @@ fn foo(x: i64) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change function type#}
#update "change function type"
#check stdout {
123
#}
@@ -46,8 +45,7 @@ fn foo(x: i64) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change function argument#}
#update "change function argument"
#check stdout {
-42
#}
+1 -2
View File
@@ -39,8 +39,7 @@ pub fn main() !void {
try Printer("bar\n").print();
}
#}
#update {
change line number#}
#update "change line number"
#check stdout {
foo
bar
+1 -2
View File
@@ -22,8 +22,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change line number#}
#update "change line number"
#check stdout {
foo
#}
+4 -8
View File
@@ -41,8 +41,7 @@ comptime {
//_ = @import("other.zig");
}
#}
#update {
change module of other.zig#}
#update "change module of other.zig"
#check errors {
other.zig:2:5: error: found compile log statement
@@ -61,8 +60,7 @@ comptime {
_ = @import("other.zig");
}
#}
#update {
put other.zig in both modules#}
#update "put other.zig in both modules"
#check errors {
other.zig:1:1: error: file exists in modules 'root' and 'foo'
other.zig:1:1: note: files must belong to only one module
@@ -81,7 +79,5 @@ comptime {
//_ = @import("other.zig");
}
#}
#update {
put other.zig in no modules#}
#check stdout {
#}
#update "put other.zig in no modules"
#check stdout
+2 -4
View File
@@ -39,8 +39,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change the panic handler body#}
#update "change the panic handler body"
#check stdout {
new panic message: integer overflow
#}
@@ -61,8 +60,7 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change the panic handler function value#}
#update "change the panic handler function value"
#check stdout {
third panic message: integer overflow
#}
@@ -2,22 +2,20 @@
-Mroot=main.zig
#}
#write main.zig 0/main.zig
#write main.zig @0/main.zig
#update
#check stdout {
panic message: integer overflow
#}
#write main.zig 1/main.zig
#update {
change the panic handler body#}
#write main.zig @1/main.zig
#update "change the panic handler body"
#check stdout {
new panic message: integer overflow
#}
#write main.zig 2/main.zig
#update {
change the panic handler function value#}
#write main.zig @2/main.zig
#update "change the panic handler function value"
#check stdout {
third panic message: integer overflow
#}
@@ -13,8 +13,7 @@ const Enum = enum { foo, bar };
const std = @import("std");
#}
#update
#check stdout {
foo#}
#check stdout "foo"
#write main.zig {
fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {
@@ -26,7 +25,5 @@ pub fn main(init: std.process.Init) !void {
const Enum = enum { foo, bar };
const std = @import("std");
#}
#update {
change field type#}
#check stdout {
bar#}
#update "change field type"
#check stdout "bar"
+1 -2
View File
@@ -29,8 +29,7 @@ fn foo(x: u16) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change to right shift#}
#update "change to right shift"
#check stdout {
0x130
#}
+2 -4
View File
@@ -39,8 +39,7 @@ fn foo(val: *const S) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change struct layout#}
#update "change struct layout"
#check stdout {
100 200
#}
@@ -61,8 +60,7 @@ fn foo(val: *const S) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change values#}
#update "change values"
#check stdout {
1234 5678
#}
+2 -4
View File
@@ -29,8 +29,7 @@ pub fn main(init: std.process.Init) !void {
}
const std = @import("std");
#}
#update {
change tag type#}
#update "change tag type"
#check errors {
main.zig:3:24: error: no field named 'a' in enum 'main.B'
main.zig:2:11: note: enum declared here
@@ -47,8 +46,7 @@ pub fn main(init: std.process.Init) !void {
}
const std = @import("std");
#}
#update {
change field name to match new tag type#}
#update "change field name to match new tag type"
#check stdout {
b
#}
+5 -10
View File
@@ -21,15 +21,13 @@ Hello, World!
#write message.zon {
"Hello again, World!\n"
#}
#update {
change ZON file contents#}
#update "change ZON file contents"
#check stdout {
Hello again, World!
#}
#delete message.zon
#update {
delete file#}
#update "delete file"
#check errors {
message.zon:1:1: error: unable to load "message.zon": FileNotFound
main.zig:2:37: note: file imported here
@@ -43,8 +41,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove reference to ZON file#}
#update "remove reference to ZON file"
#check errors {
message.zon:1:1: error: unable to load "message.zon": FileNotFound
main.zig:2:37: note: file imported here
@@ -53,8 +50,7 @@ main.zig:2:37: note: file imported here
#write message.zon {
"We're back, World!\n"
#}
#update {
recreate ZON file#}
#update "recreate ZON file"
#check stdout {
a hardcoded string
#}
@@ -67,8 +63,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
re-introduce reference to ZON file#}
#update "re-introduce reference to ZON file"
#check stdout {
We're back, World!
#}
@@ -26,8 +26,7 @@ Hello, World!
.b_number = 0,
}
#}
#update {
change ZON file#}
#update "change ZON file"
#check stdout {
Hello again, World!
#}
+2 -4
View File
@@ -11,8 +11,7 @@ comptime {
@compileLog("this is a log");
}
#}
#update {
compile error#}
#update "compile error"
#check errors {
main.zig:3:5: error: this is an error
@@ -29,8 +28,7 @@ comptime {
@compileLog("this is a log");
}
#}
#update {
remove the compile error#}
#update "remove the compile error"
#check errors {
main.zig:6:5: error: found compile log statement
+3 -6
View File
@@ -9,8 +9,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
no compile log#}
#update "no compile log"
#check stdout {
Hello, World!
#}
@@ -23,8 +22,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add compile log#}
#update "add compile log"
#check errors {
main.zig:4:5: error: found compile log statement
@@ -39,8 +37,7 @@ pub fn main() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove compile log#}
#update "remove compile log"
#check stdout {
Hello, World!
#}
+1 -2
View File
@@ -44,8 +44,7 @@ comptime {
_ = y;
}
#}
#update {
delete and modify comptime decls#}
#update "delete and modify comptime decls"
#check errors {
main.zig:6:16: error: slice of null pointer
#}
@@ -15,8 +15,7 @@ comptime {
pub fn main() void {}
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
const foo = @as(u16, 123);
@@ -30,8 +29,7 @@ comptime {
}
pub fn main() void {}
#}
#update {
change the type#}
#update "change the type"
#check errors {
main.zig:8:37: error: reached unreachable code
#}
+4 -9
View File
@@ -1,6 +1,4 @@
#todo {
it'd be great if we could actually check that no analysis happened!
#}
#todo "it'd be great if we could actually check that no analysis happened!"
#exe {
-Mroot=main.zig
#}
@@ -25,8 +23,7 @@ const O = opaque {
};
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
pub fn main() void {
@@ -47,7 +44,5 @@ const O = opaque {
}
};
#}
#update {
do literally nothing#}
#check stdout {
#}
#update "do literally nothing"
#check stdout
+4 -8
View File
@@ -12,8 +12,7 @@ pub fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
#}
#update {
error#}
#update "error"
#check errors {
foo.zig:2:9: error: use of undeclared identifier 'std'
#}
@@ -25,8 +24,7 @@ pub fn hello() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
fix the error#}
#update "fix the error"
#check stdout {
Hello, World!
#}
@@ -38,8 +36,7 @@ pub fn hello() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add new error#}
#update "add new error"
#check errors {
foo.zig:3:52: error: use of undeclared identifier 'hello_str'
#}
@@ -52,8 +49,7 @@ pub fn hello() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
fix the new error#}
#update "fix the new error"
#check stdout {
Hello, World! Again!
#}
+3 -6
View File
@@ -12,8 +12,7 @@ fn foo() !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
non-inline version#}
#update "non-inline version"
#check stdout {
Hello, World!
#}
@@ -28,8 +27,7 @@ inline fn foo() !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
make function inline#}
#update "make function inline"
#check stdout {
Hello, World!
#}
@@ -44,8 +42,7 @@ inline fn foo() !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change string#}
#update "change string"
#check stdout {
Hello, `inline` World!
#}
+1 -2
View File
@@ -21,8 +21,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
}
#}
#update {
change the string#}
#update "change the string"
#check stdout {
おはようございます
#}
+1 -2
View File
@@ -35,8 +35,7 @@ pub fn main(init: std.process.Init) !void {
}
const std = @import("std");
#}
#update {
increase array length#}
#update "increase array length"
#check stdout {
arr[999] = 234
#}
+1 -2
View File
@@ -28,8 +28,7 @@ pub fn hello() !void {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
make hello pub#}
#update "make hello pub"
#check stdout {
Hello, World!
#}
+61
View File
@@ -0,0 +1,61 @@
.{
// Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others
// to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang
// or LLVM). We just have a couple here to make sure that it works.
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .musl,
},
.cache_mode = .incremental,
.backend = .cbe,
.linker = .old,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .llvm,
.linker = .lld,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .windows,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .old,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .wasm32,
.os_tag = .wasi,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .old,
.pic = .nopic,
},
}
+1 -2
View File
@@ -29,8 +29,7 @@ inline fn getStr() []const u8 {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
change the string#}
#update "change the string"
#check stdout {
bar
#}
+1 -2
View File
@@ -36,8 +36,7 @@ fn bar() u32 {
}
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
add newline#}
#update "add newline"
#check stdout {
8 123
#}
@@ -9,8 +9,7 @@ pub fn main() void {
}
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
const foo = something;
@@ -18,8 +17,7 @@ pub fn main() void {
_ = &foo;
}
#}
#update {
introduce use of undeclared identifier#}
#update "introduce use of undeclared identifier"
#check errors {
main.zig:1:13: error: use of undeclared identifier 'something'
#}
@@ -30,7 +28,5 @@ pub fn main() void {
_ = &foo;
}
#}
#update {
revert use of undeclared identifier#}
#check stdout {
#}
#update "revert use of undeclared identifier"
#check stdout
@@ -31,8 +31,7 @@ fn foo(recurse: bool) !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
eliminate recursion and change argument#}
#update "eliminate recursion and change argument"
#check stdout {
x==1
#}
+1 -2
View File
@@ -31,8 +31,7 @@ pub fn main() !void {
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove enum field#}
#update "remove enum field"
#check errors {
main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo'
main.zig:1:16: note: enum declared here
@@ -28,8 +28,7 @@ pub fn main() !void {
}
#}
#update
#check stdout {
0#}
#check stdout "0"
#write main.zig {
//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.
@@ -54,7 +53,5 @@ pub fn main() !void {
try bar(.one);
}
#}
#update {
remove foo and change bar wasm function type#}
#check stdout {
1#}
#update "remove foo and change bar wasm function type"
#check stdout "1"
@@ -33,7 +33,5 @@ pub fn main() void {
_ = u;
}
#}
#update {
remove invalid backing enum#}
#check stdout {
#}
#update "remove invalid backing enum"
#check stdout
@@ -23,8 +23,7 @@ pub fn main(init: std.process.Init) !void {
}
const std = @import("std");
#}
#update {
change to `@TypeOf` anonymous init#}
#update "change to `@TypeOf` anonymous init"
#check stdout {
anon_field
#}
+5 -10
View File
@@ -11,8 +11,7 @@ pub fn main() !void {
}
#}
#update
#check stdout {
first#}
#check stdout "first"
#write main.zig {
const std = @import("std");
@@ -22,10 +21,8 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
}
#}
#update {
no change#}
#check stdout {
first#}
#update "no change"
#check stdout "first"
#write main.zig {
const std = @import("std");
@@ -35,7 +32,5 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
}
#}
#update {
swap fields#}
#check stdout {
first#}
#update "swap fields"
#check stdout "first"
@@ -33,8 +33,7 @@ fn bar(comptime x: u8) @This().FooAlias {
}
const std = @import("std");
#}
#update {
change generic signature to use non-existent member#}
#update "change generic signature to use non-existent member"
#check errors {
main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'
main.zig:1:1: note: struct declared here
@@ -54,8 +53,7 @@ fn bar(comptime x: u8) @This().FooAlias {
}
const std = @import("std");
#}
#update {
add that member, fixing the error#}
#update "add that member, fixing the error"
#check stdout {
Z
#}
+4 -8
View File
@@ -7,14 +7,12 @@ const std = @import("std");
pub fn main() !void {}
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
pub fn main() !void {
#}
#update {
introduce parse error#}
#update "introduce parse error"
#check errors {
main.zig:2:1: error: expected statement, found 'EOF'
#}
@@ -22,7 +20,5 @@ main.zig:2:1: error: expected statement, found 'EOF'
#write main.zig {
pub fn main() !void {}
#}
#update {
fix parse error#}
#check stdout {
#}
#update "fix parse error"
#check stdout
+5 -10
View File
@@ -14,8 +14,7 @@ pub fn main() void {
}
#}
#update
#check stdout {
#}
#check stdout
#write main.zig {
const SomeType = comptime_int;
@@ -28,10 +27,8 @@ pub fn main() void {
s.foo();
}
#}
#update {
make S comptime-only#}
#check stdout {
#}
#update "make S comptime-only"
#check stdout
#write main.zig {
const SomeType = u16;
@@ -44,7 +41,5 @@ pub fn main() void {
s.foo();
}
#}
#update {
make S runtime again#}
#check stdout {
#}
#update "make S runtime again"
#check stdout
+7 -14
View File
@@ -24,10 +24,8 @@ pub fn main() void {
_ = B;
}
#}
#update {
remove reference to dependency loop#}
#check stdout {
#}
#update "remove reference to dependency loop"
#check stdout
#write main.zig {
pub const A = struct { b: B };
@@ -36,10 +34,8 @@ pub fn main() void {
_ = B;
}
#}
#update {
change dependency loop without fixing it#}
#check stdout {
#}
#update "change dependency loop without fixing it"
#check stdout
#write main.zig {
pub const A = struct { b: B };
@@ -48,8 +44,7 @@ pub fn main() void {
_ = @as(B, undefined);
}
#}
#update {
reference dependency loop again#}
#update "reference dependency loop again"
#check errors {
error: dependency loop with length 2
main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here
@@ -64,7 +59,5 @@ pub fn main() void {
_ = @as(B, undefined);
}
#}
#update {
fix dependency loop#}
#check stdout {
#}
#update "fix dependency loop"
#check stdout
+3 -6
View File
@@ -23,8 +23,7 @@ pub fn main() !void {
const a = @compileError("bad a");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
introduce compile error#}
#update "introduce compile error"
#check errors {
main.zig:5:11: error: bad a
#}
@@ -38,8 +37,7 @@ const a = @compileError("bad a");
const b = "Hi there!\n";
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
remove error reference#}
#update "remove error reference"
#check stdout {
Hi there!
#}
@@ -53,8 +51,7 @@ const a = "Back to a\n";
const b = @compileError("bad b");
const io = std.Io.Threaded.global_single_threaded.io();
#}
#update {
introduce and remove reference to error#}
#update "introduce and remove reference to error"
#check stdout {
Back to a
#}
+10 -138
View File
@@ -2201,137 +2201,6 @@ const RunnerTarget = struct {
pic: enum { nopic, pic, pie },
};
pub const incremental_matrix: []const RunnerTarget = &.{
// Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others
// to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang
// or LLVM). We just have a couple here to make sure that it works.
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .musl,
},
.cache_mode = .incremental,
.backend = .cbe,
.linker = .old,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .llvm,
.linker = .lld,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .windows,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .old,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .wasm32,
.os_tag = .wasi,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .old,
.pic = .nopic,
},
};
pub const debugger_matrix: []const RunnerTarget = &.{
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .old,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .old,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .whole,
.backend = .selfhosted,
.linker = .new,
.pic = .pic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .nopic,
},
.{
.target = .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
},
.cache_mode = .incremental,
.backend = .selfhosted,
.linker = .new,
.pic = .pic,
},
};
pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step {
const step = b.step("test-stack-traces", "Run the stack trace tests");
@@ -3224,21 +3093,24 @@ pub fn addRunnerTests(
defer tests_dir.close(b.graph.io);
var test_it = tests_dir.iterate();
while (try test_it.next(b.graph.io)) |@"test"| {
switch (@"test".kind) {
else => continue,
.file => {
if (std.mem.eql(u8, @"test".name, "matrix.zon")) continue;
if (isEditorFileName(@"test".name)) continue;
},
.directory => {},
}
for (options.test_filters) |filter| {
if (std.mem.find(u8, @"test".name, filter) != null) break;
} else if (options.test_filters.len > 0) continue;
const test_path = tests_path.path(b, @"test".name);
switch (@"test".kind) {
else => continue,
.file => if (isEditorFileName(@"test".name)) continue,
.directory => {},
}
const run = b.addRunArtifact(runner);
run.setName(@"test".name);
run.enableProtocolMode();
const test_path = tests_path.path(b, @"test".name);
switch (@"test".kind) {
else => continue,
.file => run.addFileArg(test_path),