authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2022-11-30 18:06:02-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-01 02:18:51-05:00
logc37afa2811677b7602cdde8120049358c0d8c467
tree816dd0512b72cb0b7a9806dd4cda242efe776292
parenta943422672a9f456a74c20b4c167107ccbadfb1a

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 files changed, 46 insertions(+), 10 deletions(-)

lib/std/testing.zig+46-10
......@@ -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`).
285286pub 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()`.
558562pub 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
581617const BytesDiffer = struct {