diff options
author | 2023-05-31 23:12:04 -0700 | |
---|---|---|
committer | 2023-05-31 23:12:04 -0700 | |
commit | e632941c520e9346fc706bb12d0434974c3f5a98 (patch) | |
tree | d80b1895cd920d45d0e74bff11ca90fc4ff2dfcd /src/bun.js/test/diff_format.zig | |
parent | 176fade220ccc254e5ad822c3bd211023e961074 (diff) | |
download | bun-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.zig | 293 |
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; + } +}; |