diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 9d8f26559cf5..f9ab232da577 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -1112,6 +1112,7 @@ fn evalZigTest( const md = metadata.?; const TrHdr = std.zig.Server.Message.TestResults; + const tr_hdr = @as(*align(1) const TrHdr, @ptrCast(body)); fail_count +|= @intFromBool(tr_hdr.flags.fail); skip_count +|= @intFromBool(tr_hdr.flags.skip); @@ -1120,20 +1121,32 @@ fn evalZigTest( if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) { const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0); + const err = body[@sizeOf(TrHdr)..][0..tr_hdr.err_len]; const msg = std.mem.trim(u8, stderr.readableSlice(0), "\n"); - const label = if (tr_hdr.flags.fail) - "failed" + + const label = if (tr_hdr.flags.fail and tr_hdr.flags.leak) + "leaked and failed" else if (tr_hdr.flags.leak) "leaked" + else if (tr_hdr.flags.fail) + "failed" else if (tr_hdr.flags.log_err_count > 0) "logged errors" else unreachable; + if (msg.len > 0) { - try self.step.addError("'{s}' {s}: {s}", .{ name, label, msg }); + if (err.len > 0) + try self.step.addError("'{s}' {s} with error {s}:\n{s}", .{ name, label, err, msg }) + else + try self.step.addError("'{s}' {s}:\n{s}", .{ name, label, msg }); } else { - try self.step.addError("'{s}' {s}", .{ name, label }); + if (err.len > 0) + try self.step.addError("'{s}' {s} with error {s}", .{ name, label, err }) + else + try self.step.addError("'{s}' {s}", .{ name, label }); } + stderr.discard(msg.len); } diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index 15795176a00f..c2df42fef702 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -42,16 +42,20 @@ pub const Message = struct { /// - 0 means not async /// * expected_panic_msg: [tests_len]u32, /// - null-terminated string_bytes index - /// - 0 means does not expect pani + /// - 0 means does not expect panic /// * string_bytes: [string_bytes_len]u8, pub const TestMetadata = extern struct { string_bytes_len: u32, tests_len: u32, }; + /// Trailing: + /// * error_name: [err_len]u8 + /// - err_len == 0 means there was no error pub const TestResults = extern struct { index: u32, flags: Flags, + err_len: usize, pub const Flags = packed struct(u32) { fail: bool, @@ -179,14 +183,19 @@ pub fn serveEmitBinPath( pub fn serveTestResults( s: *Server, - msg: OutMessage.TestResults, + error_name: []const u8, + results: OutMessage.TestResults, ) !void { - const msg_le = bswap(msg); + assert(results.err_len == error_name.len); + const result_le = bswap(results); + const bytes_len = @sizeOf(OutMessage.TestResults) + error_name.len; + try s.serveMessage(.{ .tag = .test_results, - .bytes_len = @as(u32, @intCast(@sizeOf(OutMessage.TestResults))), + .bytes_len = @intCast(bytes_len), }, &.{ - std.mem.asBytes(&msg_le), + std.mem.asBytes(&result_le), + error_name, }); } diff --git a/lib/test_runner.zig b/lib/test_runner.zig index 18608d298afe..bf715a8ac5bc 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -98,28 +98,36 @@ fn mainServer() !void { var fail = false; var skip = false; var leak = false; - test_fn.func() catch |err| switch (err) { + var err_name: []const u8 = ""; + + test_fn.func() catch |e| switch (e) { error.SkipZigTest => skip = true, else => { fail = true; + err_name = @errorName(e); if (@errorReturnTrace()) |trace| { std.debug.dumpStackTrace(trace.*); } }, }; + leak = std.testing.allocator_instance.deinit() == .leak; - try server.serveTestResults(.{ - .index = index, - .flags = .{ - .fail = fail, - .skip = skip, - .leak = leak, - .log_err_count = std.math.lossyCast(std.meta.FieldType( - std.zig.Server.Message.TestResults.Flags, - .log_err_count, - ), log_err_count), + try server.serveTestResults( + err_name, + .{ + .index = index, + .flags = .{ + .fail = fail, + .skip = skip, + .leak = leak, + .log_err_count = std.math.lossyCast(std.meta.FieldType( + std.zig.Server.Message.TestResults.Flags, + .log_err_count, + ), log_err_count), + }, + .err_len = err_name.len, }, - }); + ); }, else => {