Skip to content

Commit c37afa2

Browse files
squeek502andrewrk
authored andcommitted
std.testing: Improve expectEqualBytes for large inputs and make expectEqualSlices use it
`expectEqualBytes` will now truncate the hexdump of each input to a maximum window of 256 bytes, which makes it safe to use for arbitrarily large inputs. Therefore, it can be used in `expectEqualSlices` when the type is u8.
1 parent a943422 commit c37afa2

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

lib/std/testing.zig

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,12 @@ test "expectApproxEqRel" {
281281
/// equal, prints diagnostics to stderr to show exactly how they are not equal,
282282
/// then returns a test failure error.
283283
/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
284-
/// If your inputs are slices of bytes, consider calling `expectEqualBytes` instead.
284+
/// If your inputs are slices of bytes, consider calling `expectEqualBytes` instead (this
285+
/// function calls `expectEqualBytes` implicitly when `T` is `u8`).
285286
pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
287+
if (T == u8) {
288+
return expectEqualBytes(expected, actual);
289+
}
286290
// TODO better printing of the difference
287291
// If the arrays are small enough we could print the whole thing
288292
// If the child type is u8 and no weird bytes, we could print it as strings
@@ -556,26 +560,58 @@ test {
556560
/// then returns a test failure error. The colorized output is optional and controlled
557561
/// by the return of `std.debug.detectTTYConfig()`.
558562
pub fn expectEqualBytes(expected: []const u8, actual: []const u8) !void {
559-
std.testing.expectEqualSlices(u8, expected, actual) catch |err| {
563+
if (std.mem.indexOfDiff(u8, actual, expected)) |diff_index| {
564+
std.debug.print("byte slices differ. first difference occurs at offset {d} (0x{X})\n", .{ diff_index, diff_index });
565+
566+
// TODO: Should this be configurable by the caller?
567+
const max_window_size: usize = 256;
568+
569+
// Print a maximum of max_window_size bytes of each input, starting just before the
570+
// first difference.
571+
var window_start: usize = 0;
572+
if (@max(actual.len, expected.len) > max_window_size) {
573+
window_start = std.mem.alignBackward(diff_index - @min(diff_index, 16), 16);
574+
}
575+
const expected_window = expected[window_start..@min(expected.len, window_start + max_window_size)];
576+
const expected_truncated = window_start + expected_window.len < expected.len;
577+
const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
578+
const actual_truncated = window_start + actual_window.len < actual.len;
579+
560580
var differ = BytesDiffer{
561-
.expected = expected,
562-
.actual = actual,
581+
.expected = expected_window,
582+
.actual = actual_window,
563583
.ttyconf = std.debug.detectTTYConfig(),
564584
};
565585
const stderr = std.io.getStdErr();
566586

567-
std.debug.print("\n============ expected this output: =============\n\n", .{});
587+
std.debug.print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
588+
if (window_start > 0) {
589+
std.debug.print("... truncated, start offset: 0x{X} ...\n", .{window_start});
590+
}
568591
differ.write(stderr.writer()) catch {};
592+
if (expected_truncated) {
593+
const end_offset = window_start + expected_window.len;
594+
const num_missing_bytes = expected.len - (window_start + expected_window.len);
595+
std.debug.print("... truncated, end offset: 0x{X}, remaining bytes: 0x{X} ...\n", .{ end_offset, num_missing_bytes });
596+
}
569597

570598
// now reverse expected/actual and print again
571-
differ.expected = actual;
572-
differ.actual = expected;
573-
std.debug.print("\n============= instead found this: ==============\n\n", .{});
599+
differ.expected = actual_window;
600+
differ.actual = expected_window;
601+
std.debug.print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
602+
if (window_start > 0) {
603+
std.debug.print("... truncated, start offset: 0x{X} ...\n", .{window_start});
604+
}
574605
differ.write(stderr.writer()) catch {};
606+
if (actual_truncated) {
607+
const end_offset = window_start + actual_window.len;
608+
const num_missing_bytes = actual.len - (window_start + actual_window.len);
609+
std.debug.print("... truncated, end offset: 0x{X}, remaining bytes: 0x{X} ...\n", .{ end_offset, num_missing_bytes });
610+
}
575611
std.debug.print("\n================================================\n\n", .{});
576612

577-
return err;
578-
};
613+
return error.TestExpectedEqual;
614+
}
579615
}
580616

581617
const BytesDiffer = struct {

0 commit comments

Comments
 (0)