From 7aef9e5fb2cd17859510d80b25a8e9f5374eeadc Mon Sep 17 00:00:00 2001 From: K4 Date: Tue, 28 Jul 2026 17:31:32 +0300 Subject: [PATCH 1/4] std.testing: rename `print*` to `failPrint*` --- lib/std/testing.zig | 134 ++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index eebf3a5195c0d2407c7c51d3b67ef794011f6736..10bf9ab8d7a8a104423d0e20d2f76cb8ab64ba7b 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -41,7 +41,7 @@ pub const backend_can_print = switch (builtin.zig_backend) { else => true, }; -fn print(comptime fmt: []const u8, args: anytype) void { +fn failPrint(comptime fmt: []const u8, args: anytype) void { if (@inComptime()) { @compileError(std.fmt.comptimePrint(fmt, args)); } else if (backend_can_print) { @@ -53,11 +53,11 @@ fn print(comptime fmt: []const u8, args: anytype) void { /// and then returns a test failure error when actual_error_union is not expected_error. pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { if (actual_error_union) |actual_payload| { - print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); + failPrint("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); return error.TestExpectedError; } else |actual_error| { if (expected_error != actual_error) { - print("expected error.{s}, found error.{s}\n", .{ + failPrint("expected error.{s}, found error.{s}\n", .{ @errorName(expected_error), @errorName(actual_error), }); @@ -91,7 +91,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { .type => { if (actual != expected) { - print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); + failPrint("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); return error.TestExpectedEqual; } }, @@ -107,7 +107,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { .error_set, => { if (actual != expected) { - print("expected {any}, found {any}\n", .{ expected, actual }); + failPrint("expected {any}, found {any}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -116,17 +116,17 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { switch (pointer.size) { .one, .many, .c => { if (actual != expected) { - print("expected {*}, found {*}\n", .{ expected, actual }); + failPrint("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, .slice => { if (actual.ptr != expected.ptr) { - print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr }); + failPrint("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr }); return error.TestExpectedEqual; } if (actual.len != expected.len) { - print("expected slice len {}, found {}\n", .{ expected.len, actual.len }); + failPrint("expected slice len {}, found {}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } }, @@ -187,12 +187,12 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { if (actual) |actual_payload| { try expectEqual(expected_payload, actual_payload); } else { - print("expected {any}, found null\n", .{expected_payload}); + failPrint("expected {any}, found null\n", .{expected_payload}); return error.TestExpectedEqual; } } else { if (actual) |actual_payload| { - print("expected null, found {any}\n", .{actual_payload}); + failPrint("expected null, found {any}\n", .{actual_payload}); return error.TestExpectedEqual; } } @@ -203,12 +203,12 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { if (actual) |actual_payload| { try expectEqual(expected_payload, actual_payload); } else |actual_err| { - print("expected {any}, found {}\n", .{ expected_payload, actual_err }); + failPrint("expected {any}, found {}\n", .{ expected_payload, actual_err }); return error.TestExpectedEqual; } } else |expected_err| { if (actual) |actual_payload| { - print("expected {}, found {any}\n", .{ expected_err, actual_payload }); + failPrint("expected {}, found {any}\n", .{ expected_err, actual_payload }); return error.TestExpectedEqual; } else |actual_err| { try expectEqual(expected_err, actual_err); @@ -295,7 +295,7 @@ pub inline fn expectApproxEqAbs(expected: anytype, actual: anytype, tolerance: a fn expectApproxEqAbsInner(comptime T: type, expected: T, actual: T, tolerance: T) !void { switch (@typeInfo(T)) { .float => if (!math.approxEqAbs(T, expected, actual, tolerance)) { - print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected }); + failPrint("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected }); return error.TestExpectedApproxEqAbs; }, @@ -331,7 +331,7 @@ pub inline fn expectApproxEqRel(expected: anytype, actual: anytype, tolerance: a fn expectApproxEqRelInner(comptime T: type, expected: T, actual: T, tolerance: T) !void { switch (@typeInfo(T)) { .float => if (!math.approxEqRel(T, expected, actual, tolerance)) { - print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected }); + failPrint("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected }); return error.TestExpectedApproxEqRel; }, @@ -598,12 +598,12 @@ pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:s }; if (!std.meta.eql(sentinel, expected_value_sentinel)) { - print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel }); + failPrint("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel }); return error.TestExpectedEqual; } if (!std.meta.eql(sentinel, actual_value_sentinel)) { - print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel }); + failPrint("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel }); return error.TestExpectedEqual; } } @@ -660,23 +660,23 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { expected, actual, diff_index, })); } - print("\n====== expected this output: =========\n", .{}); - printWithVisibleNewlines(expected); - print("\n======== instead found this: =========\n", .{}); - printWithVisibleNewlines(actual); - print("\n======================================\n", .{}); + failPrint("\n====== expected this output: =========\n", .{}); + failPrintWithVisibleNewlines(expected); + failPrint("\n======== instead found this: =========\n", .{}); + failPrintWithVisibleNewlines(actual); + failPrint("\n======================================\n", .{}); var diff_line_number: usize = 1; for (expected[0..diff_index]) |value| { if (value == '\n') diff_line_number += 1; } - print("First difference occurs on line {d}:\n", .{diff_line_number}); + failPrint("First difference occurs on line {d}:\n", .{diff_line_number}); - print("expected:\n", .{}); - printIndicatorLine(expected, diff_index); + failPrint("expected:\n", .{}); + failPrintIndicatorLine(expected, diff_index); - print("found:\n", .{}); - printIndicatorLine(actual, diff_index); + failPrint("found:\n", .{}); + failPrintIndicatorLine(actual, diff_index); return error.TestExpectedEqual; } @@ -691,13 +691,13 @@ pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const else actual; - print("\n====== expected to start with: =========\n", .{}); - printWithVisibleNewlines(expected_starts_with); - print("\n====== instead started with: ===========\n", .{}); - printWithVisibleNewlines(shortened_actual); - print("\n========= full output: ==============\n", .{}); - printWithVisibleNewlines(actual); - print("\n======================================\n", .{}); + failPrint("\n====== expected to start with: =========\n", .{}); + failPrintWithVisibleNewlines(expected_starts_with); + failPrint("\n====== instead started with: ===========\n", .{}); + failPrintWithVisibleNewlines(shortened_actual); + failPrint("\n========= full output: ==============\n", .{}); + failPrintWithVisibleNewlines(actual); + failPrint("\n======================================\n", .{}); return error.TestExpectedStartsWith; } @@ -711,13 +711,13 @@ pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) else actual; - print("\n====== expected to end with: =========\n", .{}); - printWithVisibleNewlines(expected_ends_with); - print("\n====== instead ended with: ===========\n", .{}); - printWithVisibleNewlines(shortened_actual); - print("\n========= full output: ==============\n", .{}); - printWithVisibleNewlines(actual); - print("\n======================================\n", .{}); + failPrint("\n====== expected to end with: =========\n", .{}); + failPrintWithVisibleNewlines(expected_ends_with); + failPrint("\n====== instead ended with: ===========\n", .{}); + failPrintWithVisibleNewlines(shortened_actual); + failPrint("\n========= full output: ==============\n", .{}); + failPrintWithVisibleNewlines(actual); + failPrint("\n======================================\n", .{}); return error.TestExpectedEndsWith; } @@ -756,7 +756,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe .type => { if (actual != expected) { - print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); + failPrint("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); return error.TestExpectedEqual; } }, @@ -772,7 +772,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe .error_set, => { if (actual != expected) { - print("expected {any}, found {any}\n", .{ expected, actual }); + failPrint("expected {any}, found {any}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -782,7 +782,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe // We have no idea what is behind those pointers, so the best we can do is `==` check. .c, .many => { if (actual != expected) { - print("expected {*}, found {*}\n", .{ expected, actual }); + failPrint("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -791,7 +791,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe switch (@typeInfo(pointer.child)) { .@"fn", .@"opaque" => { if (actual != expected) { - print("expected {*}, found {*}\n", .{ expected, actual }); + failPrint("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -800,13 +800,13 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe }, .slice => { if (expected.len != actual.len) { - print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + failPrint("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } var i: usize = 0; while (i < expected.len) : (i += 1) { expectEqualDeep(expected[i], actual[i]) catch |e| { - print("index {d} incorrect. expected {any}, found {any}\n", .{ + failPrint("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -818,13 +818,13 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe .array => { if (expected.len != actual.len) { - print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + failPrint("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } var i: usize = 0; while (i < expected.len) : (i += 1) { expectEqualDeep(expected[i], actual[i]) catch |e| { - print("index {d} incorrect. expected {any}, found {any}\n", .{ + failPrint("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -834,12 +834,12 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe .vector => |info| { if (info.len != @typeInfo(@TypeOf(actual)).vector.len) { - print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len }); + failPrint("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len }); return error.TestExpectedEqual; } inline for (0..info.len) |i| { expectEqualDeep(expected[i], actual[i]) catch |e| { - print("index {d} incorrect. expected {any}, found {any}\n", .{ + failPrint("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -850,7 +850,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe .@"struct" => |structType| { inline for (structType.field_names) |field_name| { expectEqualDeep(@field(expected, field_name), @field(actual, field_name)) catch |e| { - print("Field {s} incorrect. expected {any}, found {any}\n", .{ field_name, @field(expected, field_name), @field(actual, field_name) }); + failPrint("Field {s} incorrect. expected {any}, found {any}\n", .{ field_name, @field(expected, field_name), @field(actual, field_name) }); return e; }; } @@ -881,12 +881,12 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe if (actual) |actual_payload| { try expectEqualDeep(expected_payload, actual_payload); } else { - print("expected {any}, found null\n", .{expected_payload}); + failPrint("expected {any}, found null\n", .{expected_payload}); return error.TestExpectedEqual; } } else { if (actual) |actual_payload| { - print("expected null, found {any}\n", .{actual_payload}); + failPrint("expected null, found {any}\n", .{actual_payload}); return error.TestExpectedEqual; } } @@ -897,12 +897,12 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe if (actual) |actual_payload| { try expectEqualDeep(expected_payload, actual_payload); } else |actual_err| { - print("expected {any}, found {any}\n", .{ expected_payload, actual_err }); + failPrint("expected {any}, found {any}\n", .{ expected_payload, actual_err }); return error.TestExpectedEqual; } } else |expected_err| { if (actual) |actual_payload| { - print("expected {any}, found {any}\n", .{ expected_err, actual_payload }); + failPrint("expected {any}, found {any}\n", .{ expected_err, actual_payload }); return error.TestExpectedEqual; } else |actual_err| { try expectEqualDeep(expected_err, actual_err); @@ -998,7 +998,7 @@ test "expectEqualDeep composite type" { ); } -fn printIndicatorLine(source: []const u8, indicator_index: usize) void { +fn failPrintIndicatorLine(source: []const u8, indicator_index: usize) void { const line_begin_index = if (std.mem.findScalarLast(u8, source[0..indicator_index], '\n')) |line_begin| line_begin + 1 else @@ -1008,29 +1008,29 @@ fn printIndicatorLine(source: []const u8, indicator_index: usize) void { else source.len; - printLine(source[line_begin_index..line_end_index]); + failPrintLine(source[line_begin_index..line_end_index]); for (line_begin_index..indicator_index) |_| - print(" ", .{}); + failPrint(" ", .{}); if (indicator_index >= source.len) - print("^ (end of string)\n", .{}) + failPrint("^ (end of string)\n", .{}) else - print("^ ('\\x{x:0>2}')\n", .{source[indicator_index]}); + failPrint("^ ('\\x{x:0>2}')\n", .{source[indicator_index]}); } -fn printWithVisibleNewlines(source: []const u8) void { +fn failPrintWithVisibleNewlines(source: []const u8) void { var i: usize = 0; while (std.mem.findScalar(u8, source[i..], '\n')) |nl| : (i += nl + 1) { - printLine(source[i..][0..nl]); + failPrintLine(source[i..][0..nl]); } - print("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX) + failPrint("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX) } -fn printLine(line: []const u8) void { +fn failPrintLine(line: []const u8) void { if (line.len != 0) switch (line[line.len - 1]) { - ' ', '\t' => return print("{s}⏎\n", .{line}), // Return symbol + ' ', '\t' => return failPrint("{s}⏎\n", .{line}), // Return symbol else => {}, }; - print("{s}\n", .{line}); + failPrint("{s}\n", .{line}); } test { @@ -1139,7 +1139,7 @@ pub fn checkAllAllocationFailures( } else |err| switch (err) { error.OutOfMemory => { if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) { - print( + failPrint( "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}", .{ fail_index, -- 2.54.0 From f7bb482ff38973a94ef693d558993aeac26fc991 Mon Sep 17 00:00:00 2001 From: K4 Date: Tue, 28 Jul 2026 19:10:53 +0300 Subject: [PATCH 2/4] std.testing: make `failPrint*` functions public Also adds this doc comment to each of them: `/// Helper function for printing test failure information.` --- lib/std/testing.zig | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 10bf9ab8d7a8a104423d0e20d2f76cb8ab64ba7b..e3635c09ea0c8a7e965870ee6933fef60fdb2f85 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -41,7 +41,8 @@ pub const backend_can_print = switch (builtin.zig_backend) { else => true, }; -fn failPrint(comptime fmt: []const u8, args: anytype) void { +/// Helper function for printing test failure information. +pub fn failPrint(comptime fmt: []const u8, args: anytype) void { if (@inComptime()) { @compileError(std.fmt.comptimePrint(fmt, args)); } else if (backend_can_print) { @@ -998,7 +999,8 @@ test "expectEqualDeep composite type" { ); } -fn failPrintIndicatorLine(source: []const u8, indicator_index: usize) void { +/// Helper function for printing test failure information. +pub fn failPrintIndicatorLine(source: []const u8, indicator_index: usize) void { const line_begin_index = if (std.mem.findScalarLast(u8, source[0..indicator_index], '\n')) |line_begin| line_begin + 1 else @@ -1017,7 +1019,8 @@ fn failPrintIndicatorLine(source: []const u8, indicator_index: usize) void { failPrint("^ ('\\x{x:0>2}')\n", .{source[indicator_index]}); } -fn failPrintWithVisibleNewlines(source: []const u8) void { +/// Helper function for printing test failure information. +pub fn failPrintWithVisibleNewlines(source: []const u8) void { var i: usize = 0; while (std.mem.findScalar(u8, source[i..], '\n')) |nl| : (i += nl + 1) { failPrintLine(source[i..][0..nl]); @@ -1025,7 +1028,8 @@ fn failPrintWithVisibleNewlines(source: []const u8) void { failPrint("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX) } -fn failPrintLine(line: []const u8) void { +/// Helper function for printing test failure information. +pub fn failPrintLine(line: []const u8) void { if (line.len != 0) switch (line[line.len - 1]) { ' ', '\t' => return failPrint("{s}⏎\n", .{line}), // Return symbol else => {}, -- 2.54.0 From 5ce96175327328f4b039ce44e646653a5b2725ba Mon Sep 17 00:00:00 2001 From: K4 Date: Tue, 28 Jul 2026 23:26:46 +0300 Subject: [PATCH 3/4] std.testing: improve doc comments --- lib/std/testing.zig | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index e3635c09ea0c8a7e965870ee6933fef60fdb2f85..849aa0a289cd07f00af1a1aaba0ad8a033e41c13 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -50,8 +50,8 @@ pub fn failPrint(comptime fmt: []const u8, args: anytype) void { } } -/// This function is intended to be used only in tests. It prints diagnostics to stderr -/// and then returns a test failure error when actual_error_union is not expected_error. +/// This function is intended to be used only in tests. When `actual_error_union` is not +/// `expected_error`, it prints diagnostics to stderr, then returns a test failure error. pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { if (actual_error_union) |actual_payload| { failPrint("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); @@ -358,7 +358,7 @@ test expectApproxEqRel { } /// This function is intended to be used only in tests. When the two slices are -/// not equal, prints diagnostics to stderr to show exactly how they are not +/// not equal, it prints diagnostics to stderr to show exactly how they are not /// equal (with the differences highlighted in red), then returns a test /// failure error. pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void { @@ -567,8 +567,10 @@ test { ); } -/// This function is intended to be used only in tests. Checks that two slices or two arrays are equal, -/// including that their sentinel (if any) are the same. Will error if given another type. +/// This function is intended to be used only in tests. When the two slices or two arrays are not equal, +/// or their sentinel (if any) are not the same, it prints diagnostics to stderr to show exactly how +/// they are not equal (with the differences highlighted in red), then returns a test failure error. +/// It partially depends on `expectEquaSlices` for printing diagnostics. pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:sentinel]const T, actual: [:sentinel]const T) !void { try expectEqualSlices(T, expected, actual); @@ -654,6 +656,8 @@ pub fn tmpDir(opts: Io.Dir.OpenOptions) TmpDir { }; } +/// This function is intended to be used only in test. When the two strings are not equal, +/// it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { if (std.mem.findDiff(u8, actual, expected)) |diff_index| { if (@inComptime()) { @@ -683,6 +687,8 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { } } +/// This function is intended to be used only in test. When the start of `actual` and `expected_starts_with` +/// are not equal, it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const u8) !void { if (std.mem.startsWith(u8, actual, expected_starts_with)) return; @@ -703,6 +709,8 @@ pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const return error.TestExpectedStartsWith; } +/// This function is intended to be used only in test. When the end of `actual` and `expected_ends_with` +/// are not equal, it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void { if (std.mem.endsWith(u8, actual, expected_ends_with)) return; -- 2.54.0 From 960469dc8a3c132c95e51bad304a23811675472f Mon Sep 17 00:00:00 2001 From: K4 Date: Tue, 28 Jul 2026 23:47:54 +0300 Subject: [PATCH 4/4] std.testing: small reorganizing and tests --- lib/std/testing.zig | 98 ++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 849aa0a289cd07f00af1a1aaba0ad8a033e41c13..f053e75b4bbf512b05cf50055de85909ba6a8d90 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -18,10 +18,7 @@ var failing_allocator_instance = FailingAllocator.init(base_allocator_instance.a var base_allocator_instance = std.heap.FixedBufferAllocator.init(""); pub var allocator_instance: std.heap.SafeAllocator = undefined; -pub const allocator = if (builtin.is_test) - allocator_instance.allocator() -else - @compileError("not testing"); +pub const allocator = if (builtin.is_test) allocator_instance.allocator() else @compileError("not testing"); pub var io_instance: Io.Threaded = undefined; pub const io = if (builtin.is_test) io_instance.io() else @compileError("not testing"); @@ -50,23 +47,6 @@ pub fn failPrint(comptime fmt: []const u8, args: anytype) void { } } -/// This function is intended to be used only in tests. When `actual_error_union` is not -/// `expected_error`, it prints diagnostics to stderr, then returns a test failure error. -pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { - if (actual_error_union) |actual_payload| { - failPrint("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); - return error.TestExpectedError; - } else |actual_error| { - if (expected_error != actual_error) { - failPrint("expected error.{s}, found error.{s}\n", .{ - @errorName(expected_error), - @errorName(actual_error), - }); - return error.TestUnexpectedError; - } - } -} - /// This function is intended to be used only in tests. When the two values are not /// equal, prints diagnostics to stderr to show exactly how they are not equal, /// then returns a test failure error. @@ -219,7 +199,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { } } -test "expectEqual.union(enum)" { +test "expectEqual union(enum)" { const T = union(enum) { a: i32, b: f32, @@ -268,20 +248,6 @@ test "expectEqual null" { try expectEqual(a, b); } -/// This function is intended to be used only in tests. When the formatted result of the template -/// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how -/// they are not equal, then returns an error. It depends on `expectEqualStrings` for printing -/// diagnostics. -pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anytype) !void { - if (@inComptime()) { - var buffer: [std.fmt.count(template, args)]u8 = undefined; - return expectEqualStrings(expected, try std.fmt.bufPrint(&buffer, template, args)); - } - const actual = try std.fmt.allocPrint(allocator, template, args); - defer allocator.free(actual); - return expectEqualStrings(expected, actual); -} - /// This function is intended to be used only in tests. When the actual value is /// not approximately equal to the expected value, prints diagnostics to stderr /// to show exactly how they are not equal, then returns a test failure error. @@ -553,7 +519,7 @@ const BytesDiffer = struct { } }; -test { +test expectEqualSlices { try expectEqualSlices(u8, "foo\x00", "foo\x00"); try expectEqualSlices(u16, &[_]u16{ 100, 200, 300, 400 }, &[_]u16{ 100, 200, 300, 400 }); const E = enum { foo, bar }; @@ -656,7 +622,47 @@ pub fn tmpDir(opts: Io.Dir.OpenOptions) TmpDir { }; } -/// This function is intended to be used only in test. When the two strings are not equal, +/// This function is intended to be used only in tests. When `actual_error_union` is not +/// `expected_error`, it prints diagnostics to stderr, then returns a test failure error. +pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { + if (actual_error_union) |actual_payload| { + failPrint("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); + return error.TestExpectedError; + } else |actual_error| { + if (expected_error != actual_error) { + failPrint("expected error.{s}, found error.{s}\n", .{ + @errorName(expected_error), + @errorName(actual_error), + }); + return error.TestUnexpectedError; + } + } +} + +fn returnErrorUnion() !u8 { + return error.Expected; +} + +test expectError { + const actualErrorUnion = returnErrorUnion(); + try expectError(error.Expected, actualErrorUnion); +} + +/// This function is intended to be used only in tests. When the formatted result of the template +/// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how +/// they are not equal, then returns an error. It depends on `expectEqualStrings` for printing +/// diagnostics. +pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anytype) !void { + if (@inComptime()) { + var buffer: [std.fmt.count(template, args)]u8 = undefined; + return expectEqualStrings(expected, try std.fmt.bufPrint(&buffer, template, args)); + } + const actual = try std.fmt.allocPrint(allocator, template, args); + defer allocator.free(actual); + return expectEqualStrings(expected, actual); +} + +// This function is intended to be used only in test. When the two strings are not equal, /// it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { if (std.mem.findDiff(u8, actual, expected)) |diff_index| { @@ -687,6 +693,10 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { } } +test expectEqualStrings { + try expectEqualStrings("foo", "foo"); +} + /// This function is intended to be used only in test. When the start of `actual` and `expected_starts_with` /// are not equal, it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const u8) !void { @@ -709,6 +719,10 @@ pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const return error.TestExpectedStartsWith; } +test expectStringStartsWith { + try expectStringStartsWith("foobar", "foo"); +} + /// This function is intended to be used only in test. When the end of `actual` and `expected_ends_with` /// are not equal, it prints diagnostics to stderr to show how they are not equal, then returns an error. pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void { @@ -731,6 +745,10 @@ pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) return error.TestExpectedEndsWith; } +test expectStringEndsWith { + try expectStringEndsWith("foobar", "bar"); +} + /// This function is intended to be used only in tests. When the two values are not /// deeply equal, prints diagnostics to stderr to show exactly how they are not equal, /// then returns a test failure error. @@ -1045,10 +1063,6 @@ pub fn failPrintLine(line: []const u8) void { failPrint("{s}\n", .{line}); } -test { - try expectEqualStrings("foo", "foo"); -} - /// Exhaustively check that allocation failures within `test_fn` are handled without /// introducing memory leaks. If used with the `testing.allocator` as the `backing_allocator`, /// it will also be able to detect double frees, etc (when runtime safety is enabled). -- 2.54.0