mirror of
https://github.com/ziglang/zig.git
synced 2025-12-07 14:53:08 +00:00
* test runner is improved to respect `error.SkipZigTest`
* start code is improved to `@setAlignStack(16)` before calling main()
* the newly passing behavior test has a workaround for the fact that
stage2 cannot yet call `std.Target.x86.featureSetHas()` at comptime.
This is blocking on comptime closures. The workaround is that there
is a new decl `@import("builtin").stage2_x86_cx16` which is a `bool`.
* Implement `@setAlignStack`. This language feature should be re-evaluated
at some point - I'll file an issue for it.
* LLVM backend: apply/remove the cold attribute and noinline attribute
where appropriate.
* LLVM backend: loads and stores are properly annotated with alignment
and volatile attributes.
* LLVM backend: allocas are properly annotated with alignment.
* Type: fix integers reporting wrong alignment for 256-bit integers and
beyond. Once you get to 16 byte aligned, there is no further
alignment for larger integers.
139 lines
4.9 KiB
Zig
139 lines
4.9 KiB
Zig
const std = @import("std");
|
|
const io = std.io;
|
|
const builtin = @import("builtin");
|
|
|
|
pub const io_mode: io.Mode = builtin.test_io_mode;
|
|
|
|
var log_err_count: usize = 0;
|
|
|
|
var args_buffer: [std.fs.MAX_PATH_BYTES + std.mem.page_size]u8 = undefined;
|
|
var args_allocator = std.heap.FixedBufferAllocator.init(&args_buffer);
|
|
|
|
fn processArgs() void {
|
|
const args = std.process.argsAlloc(&args_allocator.allocator) catch {
|
|
@panic("Too many bytes passed over the CLI to the test runner");
|
|
};
|
|
std.testing.zig_exe_path = args[1];
|
|
}
|
|
|
|
pub fn main() void {
|
|
if (builtin.zig_is_stage2) {
|
|
return main2() catch @panic("test failure");
|
|
}
|
|
processArgs();
|
|
const test_fn_list = builtin.test_functions;
|
|
var ok_count: usize = 0;
|
|
var skip_count: usize = 0;
|
|
var fail_count: usize = 0;
|
|
var progress = std.Progress{};
|
|
const root_node = progress.start("Test", test_fn_list.len) catch |err| switch (err) {
|
|
// TODO still run tests in this case
|
|
error.TimerUnsupported => @panic("timer unsupported"),
|
|
};
|
|
|
|
var async_frame_buffer: []align(std.Target.stack_align) u8 = undefined;
|
|
// TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
|
|
// ignores the alignment of the slice.
|
|
async_frame_buffer = &[_]u8{};
|
|
|
|
var leaks: usize = 0;
|
|
for (test_fn_list) |test_fn, i| {
|
|
std.testing.allocator_instance = .{};
|
|
defer {
|
|
if (std.testing.allocator_instance.deinit()) {
|
|
leaks += 1;
|
|
}
|
|
}
|
|
std.testing.log_level = .warn;
|
|
|
|
var test_node = root_node.start(test_fn.name, 0);
|
|
test_node.activate();
|
|
progress.refresh();
|
|
if (progress.terminal == null) {
|
|
std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name });
|
|
}
|
|
const result = if (test_fn.async_frame_size) |size| switch (io_mode) {
|
|
.evented => blk: {
|
|
if (async_frame_buffer.len < size) {
|
|
std.heap.page_allocator.free(async_frame_buffer);
|
|
async_frame_buffer = std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size) catch @panic("out of memory");
|
|
}
|
|
const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func);
|
|
break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{});
|
|
},
|
|
.blocking => {
|
|
skip_count += 1;
|
|
test_node.end();
|
|
progress.log("{s}... SKIP (async test)\n", .{test_fn.name});
|
|
if (progress.terminal == null) std.debug.print("SKIP (async test)\n", .{});
|
|
continue;
|
|
},
|
|
} else test_fn.func();
|
|
if (result) |_| {
|
|
ok_count += 1;
|
|
test_node.end();
|
|
if (progress.terminal == null) std.debug.print("OK\n", .{});
|
|
} else |err| switch (err) {
|
|
error.SkipZigTest => {
|
|
skip_count += 1;
|
|
test_node.end();
|
|
progress.log("{s}... SKIP\n", .{test_fn.name});
|
|
if (progress.terminal == null) std.debug.print("SKIP\n", .{});
|
|
},
|
|
else => {
|
|
fail_count += 1;
|
|
test_node.end();
|
|
progress.log("{s}... FAIL ({s})\n", .{ test_fn.name, @errorName(err) });
|
|
if (progress.terminal == null) std.debug.print("FAIL ({s})\n", .{@errorName(err)});
|
|
if (@errorReturnTrace()) |trace| {
|
|
std.debug.dumpStackTrace(trace.*);
|
|
}
|
|
},
|
|
}
|
|
}
|
|
root_node.end();
|
|
if (ok_count == test_fn_list.len) {
|
|
std.debug.print("All {d} tests passed.\n", .{ok_count});
|
|
} else {
|
|
std.debug.print("{d} passed; {d} skipped; {d} failed.\n", .{ ok_count, skip_count, fail_count });
|
|
}
|
|
if (log_err_count != 0) {
|
|
std.debug.print("{d} errors were logged.\n", .{log_err_count});
|
|
}
|
|
if (leaks != 0) {
|
|
std.debug.print("{d} tests leaked memory.\n", .{leaks});
|
|
}
|
|
if (leaks != 0 or log_err_count != 0 or fail_count != 0) {
|
|
std.process.exit(1);
|
|
}
|
|
}
|
|
|
|
pub fn log(
|
|
comptime message_level: std.log.Level,
|
|
comptime scope: @Type(.EnumLiteral),
|
|
comptime format: []const u8,
|
|
args: anytype,
|
|
) void {
|
|
if (@enumToInt(message_level) <= @enumToInt(std.log.Level.err)) {
|
|
log_err_count += 1;
|
|
}
|
|
if (@enumToInt(message_level) <= @enumToInt(std.testing.log_level)) {
|
|
std.debug.print("[{s}] ({s}): " ++ format ++ "\n", .{ @tagName(scope), @tagName(message_level) } ++ args);
|
|
}
|
|
}
|
|
|
|
pub fn main2() anyerror!void {
|
|
var bad = false;
|
|
// Simpler main(), exercising fewer language features, so that stage2 can handle it.
|
|
for (builtin.test_functions) |test_fn| {
|
|
test_fn.func() catch |err| {
|
|
if (err != error.SkipZigTest) {
|
|
bad = true;
|
|
}
|
|
};
|
|
}
|
|
if (bad) {
|
|
return error.TestsFailed;
|
|
}
|
|
}
|