aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/test/diff_format.zig
diff options
context:
space:
mode:
authorGravatar Ashcon Partovi <ashcon@partovi.net> 2023-05-31 23:12:04 -0700
committerGravatar GitHub <noreply@github.com> 2023-05-31 23:12:04 -0700
commite632941c520e9346fc706bb12d0434974c3f5a98 (patch)
treed80b1895cd920d45d0e74bff11ca90fc4ff2dfcd /src/bun.js/test/diff_format.zig
parent176fade220ccc254e5ad822c3bd211023e961074 (diff)
downloadbun-e632941c520e9346fc706bb12d0434974c3f5a98.tar.gz
bun-e632941c520e9346fc706bb12d0434974c3f5a98.tar.zst
bun-e632941c520e9346fc706bb12d0434974c3f5a98.zip
Small improvements to `bun test` (#3071)
* Change status icon for skipped tests from "-" to "ยป" * Show file path instead of filename in `bun test` * Emit collapsable logs when running `bun test` in Github Actions https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines * Add fallback for test icons when emojis are not available * Only check for GITHUB_ACTIONS when running `bun test` * Emit error annotations when running `bun test` in Github Actions https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message * Remove ANSI output from Github annotation, it doesn't work * Remove outdated code from internal test runner * Add GithubActionFormatter to handle cases where error name or message is already ANSI * Fix formatting of test * Fix #3070 * Implement `bun test --run-todo` By default, `test.todo()` is no longer run, unless `--run-todo` is specified. * Fix test that relies on test.todo() being run * Support vitest-style test options * Disable GITHUB_ACTION in test harness * Add types for TestOptions * Fix bug where test.skip() actually ran * Implement `test.skipIf()` and `describe.skipIf()` * Implement `test.runIf()` * Move DiffFormatter to its own file * Fix bug where Bun.inspect() would emit a Github annotation * Introduce `bun test --only`, rename `--run-todo` to `--todo` * Implement `test.if()`, `describe.if()`, and other test fixes * Remove unwanted files from last commit * Fix last reference to --run-todo * Fix memory issues with printing github actions text * Update bindings.zig * Fix bug with `test.only()` * Remove debug test * Make the github annotations better * Improve .vscode/launch.json * Implement `expect().toBeNil()` * Remove .only() from test * Implement toBeBoolean(), toBeTrue(), toBeFalse() * Add lots of matchers * toBeNil() * toBeBoolean() * toBeTrue() * toBeFalse() * toBeNumber() * toBeInteger() * toBeFinite() * toBePositive() * toBeNegative() * toBeWithin() * toBeSymbol() * toBeFunction() * toBeDate() * toBeString() * toInclude() * toStartWith() * toEndWith() * Fix #3135 * Reduce verbosity of test * Fix snapshot bug --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/test/diff_format.zig')
-rw-r--r--src/bun.js/test/diff_format.zig293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/bun.js/test/diff_format.zig b/src/bun.js/test/diff_format.zig
new file mode 100644
index 000000000..4558a5f39
--- /dev/null
+++ b/src/bun.js/test/diff_format.zig
@@ -0,0 +1,293 @@
+const std = @import("std");
+const bun = @import("root").bun;
+const MutableString = bun.MutableString;
+const Output = bun.Output;
+const default_allocator = bun.default_allocator;
+const string = bun.string;
+const JSC = bun.JSC;
+const JSValue = JSC.JSValue;
+const JSGlobalObject = JSC.JSGlobalObject;
+const ZigConsoleClient = JSC.ZigConsoleClient;
+const DiffMatchPatch = @import("../../deps/diffz/DiffMatchPatch.zig");
+
+pub const DiffFormatter = struct {
+ received_string: ?string = null,
+ expected_string: ?string = null,
+ received: ?JSValue = null,
+ expected: ?JSValue = null,
+ globalObject: *JSGlobalObject,
+ not: bool = false,
+
+ pub fn format(this: DiffFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
+ if (this.expected_string != null and this.received_string != null) {
+ const received = this.received_string.?;
+ const expected = this.expected_string.?;
+
+ var dmp = DiffMatchPatch.default;
+ dmp.diff_timeout = 200;
+ var diffs = try dmp.diff(default_allocator, received, expected, false);
+ defer diffs.deinit(default_allocator);
+
+ const equal_fmt = "<d>{s}<r>";
+ const delete_fmt = "<red>{s}<r>";
+ const insert_fmt = "<green>{s}<r>";
+
+ try writer.writeAll("Expected: ");
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .delete => continue,
+ .insert => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(insert_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(insert_fmt, false), .{df.text});
+ }
+ },
+ .equal => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(equal_fmt, false), .{df.text});
+ }
+ },
+ }
+ }
+
+ try writer.writeAll("\nReceived: ");
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .insert => continue,
+ .delete => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(delete_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(delete_fmt, false), .{df.text});
+ }
+ },
+ .equal => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(equal_fmt, false), .{df.text});
+ }
+ },
+ }
+ }
+ return;
+ }
+
+ if (this.received == null or this.expected == null) return;
+
+ const received = this.received.?;
+ const expected = this.expected.?;
+ var received_buf = MutableString.init(default_allocator, 0) catch unreachable;
+ var expected_buf = MutableString.init(default_allocator, 0) catch unreachable;
+ defer {
+ received_buf.deinit();
+ expected_buf.deinit();
+ }
+
+ {
+ var buffered_writer_ = MutableString.BufferedWriter{ .context = &received_buf };
+ var buffered_writer = &buffered_writer_;
+
+ var buf_writer = buffered_writer.writer();
+ const Writer = @TypeOf(buf_writer);
+
+ const fmt_options = ZigConsoleClient.FormatOptions{
+ .enable_colors = false,
+ .add_newline = false,
+ .flush = false,
+ .ordered_properties = true,
+ .quote_strings = true,
+ };
+ ZigConsoleClient.format(
+ .Debug,
+ this.globalObject,
+ @ptrCast([*]const JSValue, &received),
+ 1,
+ Writer,
+ Writer,
+ buf_writer,
+ fmt_options,
+ );
+ buffered_writer.flush() catch unreachable;
+
+ buffered_writer_.context = &expected_buf;
+
+ ZigConsoleClient.format(
+ .Debug,
+ this.globalObject,
+ @ptrCast([*]const JSValue, &this.expected),
+ 1,
+ Writer,
+ Writer,
+ buf_writer,
+ fmt_options,
+ );
+ buffered_writer.flush() catch unreachable;
+ }
+
+ const received_slice = received_buf.toOwnedSliceLeaky();
+ const expected_slice = expected_buf.toOwnedSliceLeaky();
+
+ if (this.not) {
+ const not_fmt = "Expected: not <green>{s}<r>";
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(not_fmt, true), .{expected_slice});
+ } else {
+ try writer.print(Output.prettyFmt(not_fmt, false), .{expected_slice});
+ }
+ return;
+ }
+
+ switch (received.determineDiffMethod(expected, this.globalObject)) {
+ .none => {
+ const fmt = "Expected: <green>{any}<r>\nReceived: <red>{any}<r>";
+ var formatter = ZigConsoleClient.Formatter{ .globalThis = this.globalObject, .quote_strings = true };
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(fmt, true), .{
+ expected.toFmt(this.globalObject, &formatter),
+ received.toFmt(this.globalObject, &formatter),
+ });
+ return;
+ }
+
+ try writer.print(Output.prettyFmt(fmt, true), .{
+ expected.toFmt(this.globalObject, &formatter),
+ received.toFmt(this.globalObject, &formatter),
+ });
+ return;
+ },
+ .character => {
+ var dmp = DiffMatchPatch.default;
+ dmp.diff_timeout = 200;
+ var diffs = try dmp.diff(default_allocator, received_slice, expected_slice, false);
+ defer diffs.deinit(default_allocator);
+
+ const equal_fmt = "<d>{s}<r>";
+ const delete_fmt = "<red>{s}<r>";
+ const insert_fmt = "<green>{s}<r>";
+
+ try writer.writeAll("Expected: ");
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .delete => continue,
+ .insert => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(insert_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(insert_fmt, false), .{df.text});
+ }
+ },
+ .equal => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(equal_fmt, false), .{df.text});
+ }
+ },
+ }
+ }
+
+ try writer.writeAll("\nReceived: ");
+ for (diffs.items) |df| {
+ switch (df.operation) {
+ .insert => continue,
+ .delete => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(delete_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(delete_fmt, false), .{df.text});
+ }
+ },
+ .equal => {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text});
+ } else {
+ try writer.print(Output.prettyFmt(equal_fmt, false), .{df.text});
+ }
+ },
+ }
+ }
+ return;
+ },
+ .line => {
+ var dmp = DiffMatchPatch.default;
+ dmp.diff_timeout = 200;
+ var diffs = try dmp.diffLines(default_allocator, received_slice, expected_slice);
+ defer diffs.deinit(default_allocator);
+
+ const equal_fmt = "<d> {s}<r>";
+ const delete_fmt = "<red>+ {s}<r>";
+ const insert_fmt = "<green>- {s}<r>";
+
+ var insert_count: usize = 0;
+ var delete_count: usize = 0;
+
+ for (diffs.items) |df| {
+ var prev: usize = 0;
+ var curr: usize = 0;
+ switch (df.operation) {
+ .equal => {
+ while (curr < df.text.len) {
+ if (curr == df.text.len - 1 or df.text[curr] == '\n' and curr != 0) {
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(equal_fmt, true), .{df.text[prev .. curr + 1]});
+ } else {
+ try writer.print(Output.prettyFmt(equal_fmt, false), .{df.text[prev .. curr + 1]});
+ }
+ prev = curr + 1;
+ }
+ curr += 1;
+ }
+ },
+ .insert => {
+ while (curr < df.text.len) {
+ if (curr == df.text.len - 1 or df.text[curr] == '\n' and curr != 0) {
+ insert_count += 1;
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(insert_fmt, true), .{df.text[prev .. curr + 1]});
+ } else {
+ try writer.print(Output.prettyFmt(insert_fmt, false), .{df.text[prev .. curr + 1]});
+ }
+ prev = curr + 1;
+ }
+ curr += 1;
+ }
+ },
+ .delete => {
+ while (curr < df.text.len) {
+ if (curr == df.text.len - 1 or df.text[curr] == '\n' and curr != 0) {
+ delete_count += 1;
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt(delete_fmt, true), .{df.text[prev .. curr + 1]});
+ } else {
+ try writer.print(Output.prettyFmt(delete_fmt, false), .{df.text[prev .. curr + 1]});
+ }
+ prev = curr + 1;
+ }
+ curr += 1;
+ }
+ },
+ }
+ if (df.text[df.text.len - 1] != '\n') try writer.writeAll("\n");
+ }
+
+ if (Output.enable_ansi_colors) {
+ try writer.print(Output.prettyFmt("\n<green>- Expected - {d}<r>\n", true), .{insert_count});
+ try writer.print(Output.prettyFmt("<red>+ Received + {d}<r>", true), .{delete_count});
+ return;
+ }
+ try writer.print("\n- Expected - {d}\n", .{insert_count});
+ try writer.print("+ Received + {d}", .{delete_count});
+ return;
+ },
+ .word => {
+ // not implemented
+ // https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs#word-mode
+ },
+ }
+ return;
+ }
+};