mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
6 Commits
claude/add
...
claude/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5088b0e6f4 | ||
|
|
3652008b0d | ||
|
|
7c65c35f8f | ||
|
|
455f3a65b9 | ||
|
|
4d301cc3c4 | ||
|
|
e9dc25200a |
@@ -568,7 +568,7 @@ function getTestBunStep(platform, options, testOptions = {}) {
|
||||
agents: getTestAgent(platform, options),
|
||||
retry: getRetry(),
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
parallelism: unifiedTests ? undefined : os === "darwin" ? 2 : 10,
|
||||
parallelism: unifiedTests ? undefined : os === "darwin" ? 7 : 10,
|
||||
timeout_in_minutes: profile === "asan" || os === "windows" ? 45 : 30,
|
||||
command:
|
||||
os === "windows"
|
||||
|
||||
@@ -274,6 +274,8 @@ src/bun.js/RuntimeTranspilerCache.zig
|
||||
src/bun.js/SavedSourceMap.zig
|
||||
src/bun.js/Strong.zig
|
||||
src/bun.js/test/diff_format.zig
|
||||
src/bun.js/test/diff/diff_match_patch.zig
|
||||
src/bun.js/test/diff/printDiff.zig
|
||||
src/bun.js/test/expect.zig
|
||||
src/bun.js/test/jest.zig
|
||||
src/bun.js/test/pretty_format.zig
|
||||
@@ -511,7 +513,6 @@ src/defines.zig
|
||||
src/deps/boringssl.translated.zig
|
||||
src/deps/brotli_c.zig
|
||||
src/deps/c_ares.zig
|
||||
src/deps/diffz/DiffMatchPatch.zig
|
||||
src/deps/libdeflate.zig
|
||||
src/deps/libuv.zig
|
||||
src/deps/lol-html.zig
|
||||
|
||||
@@ -64,6 +64,12 @@ if(ENABLE_VALGRIND)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_VALGRIND=ON)
|
||||
endif()
|
||||
|
||||
# Enable SIMD optimizations when not building for baseline (older CPUs)
|
||||
if(NOT ENABLE_BASELINE)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_ARCH=ON)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OPT_SIMD=ON)
|
||||
endif()
|
||||
|
||||
if(DEBUG)
|
||||
if (ENABLE_ASAN)
|
||||
set(MIMALLOC_LIBRARY mimalloc-asan-debug)
|
||||
|
||||
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 642e2252f6298387edb6d2f991a0408fd0320466)
|
||||
set(WEBKIT_VERSION 75f6499360f42d580c406f4969689a1e14b46447)
|
||||
endif()
|
||||
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
||||
|
||||
@@ -82,6 +82,10 @@ function getNodeParallelTestTimeout(testPath) {
|
||||
return 10_000;
|
||||
}
|
||||
|
||||
process.on("SIGTRAP", () => {
|
||||
console.warn("Test runner received SIGTRAP. Doing nothing.");
|
||||
});
|
||||
|
||||
const { values: options, positionals: filters } = parseArgs({
|
||||
allowPositionals: true,
|
||||
options: {
|
||||
|
||||
@@ -1024,6 +1024,10 @@ pub const JSValue = enum(i64) {
|
||||
extern fn JSC__JSValue__getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void;
|
||||
// TODO: absorb this into className()
|
||||
pub fn getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) bun.JSError!void {
|
||||
if (!this.isCell()) {
|
||||
ret.* = ZigString.static("[not a class]").*;
|
||||
return;
|
||||
}
|
||||
return bun.jsc.fromJSHostCallGeneric(global, @src(), JSC__JSValue__getClassName, .{ this, global, ret });
|
||||
}
|
||||
|
||||
|
||||
@@ -1599,6 +1599,104 @@ bool Bun__deepMatch(
|
||||
JSObject* obj = objValue.getObject();
|
||||
JSObject* subsetObj = subsetValue.getObject();
|
||||
|
||||
// Special handling for Maps and Sets
|
||||
JSCell* objCell = objValue.asCell();
|
||||
JSCell* subsetCell = subsetValue.asCell();
|
||||
uint8_t objType = objCell->type();
|
||||
uint8_t subsetType = subsetCell->type();
|
||||
|
||||
if (subsetType == JSSetType) {
|
||||
if (objType != JSSetType) {
|
||||
return false;
|
||||
}
|
||||
JSSet* objSet = jsCast<JSSet*>(objCell);
|
||||
JSSet* subsetSet = jsCast<JSSet*>(subsetCell);
|
||||
|
||||
// For Maps and Sets, require exact equality (same size and contents)
|
||||
// This matches the behavior expected in the issue
|
||||
if (objSet->size() != subsetSet->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All elements in subset should exist in obj
|
||||
auto iter = JSSetIterator::create(globalObject, globalObject->setIteratorStructure(), subsetSet, IterationKind::Keys);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
JSValue key;
|
||||
while (iter->next(globalObject, key)) {
|
||||
bool has = objSet->has(globalObject, key);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
if (has) {
|
||||
continue;
|
||||
}
|
||||
// We couldn't find the key in the target set. This may be a false positive due to how
|
||||
// JSValues are represented in JSC, so we need to fall back to a linear search to be sure.
|
||||
auto objIter = JSSetIterator::create(globalObject, globalObject->setIteratorStructure(), objSet, IterationKind::Keys);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
JSValue objKey;
|
||||
bool foundMatchingKey = false;
|
||||
while (objIter->next(globalObject, objKey)) {
|
||||
bool equal = JSC::sameValue(globalObject, key, objKey);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
if (equal) {
|
||||
foundMatchingKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMatchingKey) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (subsetType == JSMapType) {
|
||||
if (objType != JSMapType) {
|
||||
return false;
|
||||
}
|
||||
JSMap* objMap = jsCast<JSMap*>(objCell);
|
||||
JSMap* subsetMap = jsCast<JSMap*>(subsetCell);
|
||||
|
||||
// For Maps and Sets, require exact equality (same size and contents)
|
||||
// This matches the behavior expected in the issue
|
||||
if (objMap->size() != subsetMap->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All key-value pairs in subset should exist in obj
|
||||
auto iter = JSMapIterator::create(globalObject, globalObject->mapIteratorStructure(), subsetMap, IterationKind::Entries);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
JSValue subsetKey, subsetValue;
|
||||
while (iter->nextKeyValue(globalObject, subsetKey, subsetValue)) {
|
||||
JSValue objValue = objMap->get(globalObject, subsetKey);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
if (objValue.isUndefined()) {
|
||||
// We couldn't find the key in the target map. This may be a false positive due to
|
||||
// how JSValues are represented in JSC, so we need to fall back to a linear search
|
||||
// to be sure.
|
||||
auto objIter = JSMapIterator::create(globalObject, globalObject->mapIteratorStructure(), objMap, IterationKind::Entries);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
JSValue objKey;
|
||||
bool foundMatchingKey = false;
|
||||
while (objIter->nextKeyValue(globalObject, objKey, objValue)) {
|
||||
bool keysEqual = JSC::sameValue(globalObject, subsetKey, objKey);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
if (keysEqual) {
|
||||
foundMatchingKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMatchingKey) {
|
||||
return false;
|
||||
}
|
||||
// Compare both values below.
|
||||
}
|
||||
bool valuesEqual = JSC::sameValue(globalObject, subsetValue, objValue);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
if (!valuesEqual) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyNameArray subsetProps(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Include);
|
||||
subsetObj->getPropertyNames(globalObject, subsetProps, DontEnumPropertiesMode::Exclude);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
|
||||
2994
src/bun.js/test/diff/diff_match_patch.zig
Normal file
2994
src/bun.js/test/diff/diff_match_patch.zig
Normal file
File diff suppressed because it is too large
Load Diff
541
src/bun.js/test/diff/printDiff.zig
Normal file
541
src/bun.js/test/diff/printDiff.zig
Normal file
@@ -0,0 +1,541 @@
|
||||
//! Tested in test/js/bun/test/printing/diffexample.test.ts. If modified, the snapshots will need to be updated.
|
||||
|
||||
const DMP = diff_match_patch.DMP(u8);
|
||||
const DMPUsize = diff_match_patch.DMP(usize);
|
||||
|
||||
const Mode = enum {
|
||||
bg_always,
|
||||
bg_diff_only,
|
||||
fg,
|
||||
fg_diff,
|
||||
};
|
||||
const mode: Mode = .bg_diff_only;
|
||||
|
||||
pub const DiffConfig = struct {
|
||||
min_bytes_before_chunking: usize,
|
||||
chunk_context_lines: usize,
|
||||
enable_ansi_colors: bool,
|
||||
truncate_threshold: usize,
|
||||
truncate_context: usize,
|
||||
|
||||
pub fn default(is_agent: bool, enable_ansi_colors: bool) DiffConfig {
|
||||
return .{
|
||||
.min_bytes_before_chunking = if (is_agent) 0 else 2 * 1024, // 2kb
|
||||
.chunk_context_lines = if (is_agent) 1 else 5,
|
||||
.enable_ansi_colors = enable_ansi_colors,
|
||||
.truncate_threshold = if (is_agent) 1 * 1024 else 2 * 1024, // 2kb
|
||||
.truncate_context = if (is_agent) 50 else 100,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
fn removeTrailingNewline(text: []const u8) []const u8 {
|
||||
if (!std.mem.endsWith(u8, text, "\n")) return text;
|
||||
return text[0 .. text.len - 1];
|
||||
}
|
||||
|
||||
pub fn printDiffMain(arena: std.mem.Allocator, not: bool, received_slice: []const u8, expected_slice: []const u8, writer: anytype, config: DiffConfig) !void {
|
||||
if (not) {
|
||||
switch (config.enable_ansi_colors) {
|
||||
true => try writer.print("Expected: not " ++ colors.red ++ "{s}" ++ colors.reset, .{expected_slice}),
|
||||
false => try writer.print("Expected: not {s}", .{expected_slice}),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the diffs are single-line
|
||||
if (std.mem.indexOfScalar(u8, received_slice, '\n') == null and std.mem.indexOfScalar(u8, expected_slice, '\n') == null) {
|
||||
try printModifiedSegment(.{
|
||||
.removed = expected_slice,
|
||||
.inserted = received_slice,
|
||||
.mode = .modified,
|
||||
}, arena, writer, config, .{ .single_line = true });
|
||||
return;
|
||||
}
|
||||
|
||||
var dmp = DMPUsize.default;
|
||||
dmp.config.diff_timeout = 200;
|
||||
const linesToChars = try DMP.diffLinesToChars(arena, expected_slice, received_slice);
|
||||
const charDiffs = try dmp.diff(arena, linesToChars.chars_1, linesToChars.chars_2, false);
|
||||
const diffs = try DMP.diffCharsToLines(arena, &charDiffs, linesToChars.line_array.items);
|
||||
|
||||
var diff_segments = std.ArrayList(DiffSegment).init(arena);
|
||||
for (diffs.items) |diff| {
|
||||
if (diff.operation == .delete) {
|
||||
try diff_segments.append(DiffSegment{
|
||||
.removed = diff.text,
|
||||
.inserted = "",
|
||||
.mode = .removed,
|
||||
});
|
||||
} else if (diff.operation == .insert) {
|
||||
if (diff_segments.items.len > 0 and diff_segments.items[diff_segments.items.len - 1].mode == .removed) {
|
||||
diff_segments.items[diff_segments.items.len - 1].inserted = diff.text;
|
||||
diff_segments.items[diff_segments.items.len - 1].mode = .modified;
|
||||
} else {
|
||||
try diff_segments.append(DiffSegment{
|
||||
.removed = "",
|
||||
.inserted = diff.text,
|
||||
.mode = .inserted,
|
||||
});
|
||||
}
|
||||
} else if (diff.operation == .equal) {
|
||||
try diff_segments.append(DiffSegment{
|
||||
.removed = diff.text,
|
||||
.inserted = diff.text,
|
||||
.mode = .equal,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// trim all segments except the last one
|
||||
if (diff_segments.items.len > 0) for (diff_segments.items[0 .. diff_segments.items.len - 1]) |*diff_segment| {
|
||||
diff_segment.removed = removeTrailingNewline(diff_segment.removed);
|
||||
diff_segment.inserted = removeTrailingNewline(diff_segment.inserted);
|
||||
};
|
||||
|
||||
// Determine if the diff needs to be chunked
|
||||
if (expected_slice.len > config.min_bytes_before_chunking or received_slice.len > config.min_bytes_before_chunking) {
|
||||
// Split 'equal' segments into lines
|
||||
var new_diff_segments = std.ArrayList(DiffSegment).init(arena);
|
||||
|
||||
for (diff_segments.items) |diff_segment| {
|
||||
if (diff_segment.mode == .equal) {
|
||||
var split = std.mem.splitScalar(u8, diff_segment.removed, '\n');
|
||||
while (split.next()) |line| {
|
||||
try new_diff_segments.append(DiffSegment{
|
||||
.removed = line,
|
||||
.inserted = line,
|
||||
.mode = .equal,
|
||||
.skip = true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
try new_diff_segments.append(diff_segment);
|
||||
}
|
||||
}
|
||||
|
||||
diff_segments = new_diff_segments;
|
||||
|
||||
// Forward pass: unskip segments after non-equal segments
|
||||
for (diff_segments.items, 0..) |segment, i| {
|
||||
if (segment.mode != .equal) {
|
||||
const end = @min(i +| config.chunk_context_lines +| 1, diff_segments.items.len);
|
||||
for (diff_segments.items[i..end]) |*seg| {
|
||||
seg.skip = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Reverse pass: unskip segments before non-equal segments
|
||||
var i = diff_segments.items.len;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const segment = diff_segments.items[i];
|
||||
if (segment.mode != .equal) {
|
||||
const start = i -| config.chunk_context_lines;
|
||||
for (diff_segments.items[start .. i + 1]) |*seg| {
|
||||
seg.skip = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill removed_line_count and inserted_line_count
|
||||
for (diff_segments.items) |*segment| {
|
||||
for (segment.removed) |char| if (char == '\n') {
|
||||
segment.removed_line_count += 1;
|
||||
};
|
||||
segment.removed_line_count += 1;
|
||||
|
||||
for (segment.inserted) |char| if (char == '\n') {
|
||||
segment.inserted_line_count += 1;
|
||||
};
|
||||
segment.inserted_line_count += 1;
|
||||
}
|
||||
try printDiff(arena, writer, diff_segments.items, config);
|
||||
}
|
||||
|
||||
pub const Diff = struct {
|
||||
pub const Operation = enum {
|
||||
insert,
|
||||
delete,
|
||||
equal,
|
||||
};
|
||||
|
||||
operation: Operation,
|
||||
text: []const u8,
|
||||
};
|
||||
const colors = struct {
|
||||
const red = "\x1b[31m";
|
||||
const green = "\x1b[32m";
|
||||
const yellow = "\x1b[33m";
|
||||
const invert = "\x1b[7m";
|
||||
const underline = "\x1b[4m";
|
||||
const dim = "\x1b[2m";
|
||||
const white = "\x1b[97m";
|
||||
const reset = "\x1b[0m";
|
||||
};
|
||||
|
||||
const prefix_styles = struct {
|
||||
const inserted = PrefixStyle{
|
||||
.msg = "+ ",
|
||||
.color = colors.red,
|
||||
};
|
||||
const removed = PrefixStyle{
|
||||
.msg = "- ",
|
||||
.color = colors.green,
|
||||
};
|
||||
const equal = PrefixStyle{
|
||||
.msg = " ",
|
||||
.color = "",
|
||||
};
|
||||
const single_line_inserted = PrefixStyle{
|
||||
.msg = "Received: ",
|
||||
.color = "",
|
||||
};
|
||||
const single_line_removed = PrefixStyle{
|
||||
.msg = "Expected: ",
|
||||
.color = "",
|
||||
};
|
||||
};
|
||||
|
||||
const base_styles = struct {
|
||||
const red_bg_inserted = Style{
|
||||
.prefix = prefix_styles.inserted,
|
||||
.text_color = colors.red ++ colors.invert,
|
||||
};
|
||||
const green_bg_removed = Style{
|
||||
.prefix = prefix_styles.removed,
|
||||
.text_color = colors.green ++ colors.invert,
|
||||
};
|
||||
const dim_equal = Style{
|
||||
.prefix = prefix_styles.equal,
|
||||
.text_color = colors.dim,
|
||||
};
|
||||
const red_fg_inserted = Style{
|
||||
.prefix = prefix_styles.inserted,
|
||||
.text_color = colors.red,
|
||||
};
|
||||
const green_fg_removed = Style{
|
||||
.prefix = prefix_styles.removed,
|
||||
.text_color = colors.green,
|
||||
};
|
||||
const dim_inserted = Style{
|
||||
.prefix = prefix_styles.inserted,
|
||||
.text_color = colors.dim,
|
||||
};
|
||||
const dim_removed = Style{
|
||||
.prefix = prefix_styles.removed,
|
||||
.text_color = colors.dim,
|
||||
};
|
||||
};
|
||||
|
||||
const styles = switch (mode) {
|
||||
.bg_always => struct {
|
||||
const inserted_line = base_styles.red_bg_inserted;
|
||||
const removed_line = base_styles.green_bg_removed;
|
||||
const inserted_diff = base_styles.red_bg_inserted;
|
||||
const removed_diff = base_styles.green_bg_removed;
|
||||
const equal = base_styles.dim_equal;
|
||||
const inserted_equal = base_styles.red_fg_inserted;
|
||||
const removed_equal = base_styles.green_fg_removed;
|
||||
},
|
||||
.bg_diff_only => struct {
|
||||
const inserted_line = base_styles.red_fg_inserted;
|
||||
const removed_line = base_styles.green_fg_removed;
|
||||
const inserted_diff = base_styles.red_bg_inserted;
|
||||
const removed_diff = base_styles.green_bg_removed;
|
||||
const equal = base_styles.dim_equal;
|
||||
const inserted_equal = base_styles.red_fg_inserted;
|
||||
const removed_equal = base_styles.green_fg_removed;
|
||||
},
|
||||
.fg => struct {
|
||||
const inserted_line = base_styles.red_fg_inserted;
|
||||
const removed_line = base_styles.green_fg_removed;
|
||||
const equal = base_styles.dim_equal;
|
||||
const inserted_equal = base_styles.red_fg_inserted;
|
||||
const removed_equal = base_styles.green_fg_removed;
|
||||
},
|
||||
.fg_diff => struct {
|
||||
const inserted_line = base_styles.red_fg_inserted;
|
||||
const removed_line = base_styles.green_fg_removed;
|
||||
const inserted_diff = base_styles.red_fg_inserted;
|
||||
const removed_diff = base_styles.green_fg_removed;
|
||||
const equal = base_styles.dim_equal;
|
||||
const inserted_equal = base_styles.dim_inserted;
|
||||
const removed_equal = base_styles.dim_removed;
|
||||
},
|
||||
};
|
||||
|
||||
pub const DiffSegment = struct {
|
||||
removed: []const u8,
|
||||
inserted: []const u8,
|
||||
mode: enum {
|
||||
equal,
|
||||
removed,
|
||||
inserted,
|
||||
modified,
|
||||
},
|
||||
removed_line_count: usize = 0,
|
||||
inserted_line_count: usize = 0,
|
||||
skip: bool = false,
|
||||
};
|
||||
|
||||
fn printDiffFooter(writer: anytype, config: DiffConfig, removed_diff_lines: usize, inserted_diff_lines: usize) !void {
|
||||
if (config.enable_ansi_colors) try writer.writeAll(styles.removed_line.prefix.color);
|
||||
try writer.writeAll(styles.removed_line.prefix.msg);
|
||||
try writer.writeAll("Expected");
|
||||
try writer.print(" {s}{d}", .{ styles.removed_line.prefix.msg, removed_diff_lines });
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
try writer.writeAll("\n");
|
||||
if (config.enable_ansi_colors) try writer.writeAll(styles.inserted_line.prefix.color);
|
||||
try writer.writeAll(styles.inserted_line.prefix.msg);
|
||||
try writer.writeAll("Received");
|
||||
try writer.print(" {s}{d}", .{ styles.inserted_line.prefix.msg, inserted_diff_lines });
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
}
|
||||
|
||||
const PrefixStyle = struct {
|
||||
msg: []const u8,
|
||||
color: []const u8,
|
||||
};
|
||||
const Style = struct {
|
||||
prefix: PrefixStyle,
|
||||
text_color: []const u8,
|
||||
};
|
||||
|
||||
fn printLinePrefix(
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
prefix: PrefixStyle,
|
||||
) !void {
|
||||
if (config.enable_ansi_colors) try writer.writeAll(prefix.color);
|
||||
try writer.writeAll(prefix.msg);
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
}
|
||||
|
||||
fn printTruncatedLine(
|
||||
line: []const u8,
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
style: Style,
|
||||
) !void {
|
||||
if (line.len <= config.truncate_threshold or line.len <= config.truncate_context * 2) {
|
||||
if (config.enable_ansi_colors) try writer.writeAll(style.text_color);
|
||||
try writer.writeAll(line);
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
return;
|
||||
}
|
||||
|
||||
// Line is too long, truncate it.
|
||||
if (config.enable_ansi_colors) try writer.writeAll(style.text_color);
|
||||
try writer.writeAll(line[0..config.truncate_context]);
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.white);
|
||||
// The context is shown on both sides, so we truncate line.len - 2 * context
|
||||
try writer.print("... ({} bytes truncated) ...", .{line.len - 2 * config.truncate_context});
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
|
||||
if (config.enable_ansi_colors) try writer.writeAll(style.text_color);
|
||||
try writer.writeAll(line[line.len - config.truncate_context ..]);
|
||||
if (config.enable_ansi_colors) try writer.writeAll(colors.reset);
|
||||
}
|
||||
|
||||
fn printSegment(
|
||||
text: []const u8,
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
style: Style,
|
||||
) !void {
|
||||
var lines = std.mem.splitScalar(u8, text, '\n');
|
||||
|
||||
try printTruncatedLine(lines.next().?, writer, config, style);
|
||||
|
||||
while (lines.next()) |line| {
|
||||
try writer.writeAll("\n");
|
||||
try printLinePrefix(writer, config, style.prefix);
|
||||
try printTruncatedLine(line, writer, config, style);
|
||||
}
|
||||
}
|
||||
|
||||
fn printModifiedSegmentWithoutDiffdiff(
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
segment: DiffSegment,
|
||||
modified_style: ModifiedStyle,
|
||||
) !void {
|
||||
const removed_prefix = switch (modified_style.single_line) {
|
||||
true => prefix_styles.single_line_removed,
|
||||
false => prefix_styles.removed,
|
||||
};
|
||||
const inserted_prefix = switch (modified_style.single_line) {
|
||||
true => prefix_styles.single_line_inserted,
|
||||
false => prefix_styles.inserted,
|
||||
};
|
||||
|
||||
try printLinePrefix(writer, config, removed_prefix);
|
||||
try printSegment(segment.removed, writer, config, styles.removed_line);
|
||||
try writer.writeAll("\n");
|
||||
try printLinePrefix(writer, config, inserted_prefix);
|
||||
try printSegment(segment.inserted, writer, config, styles.inserted_line);
|
||||
if (!modified_style.single_line) try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
const ModifiedStyle = struct {
|
||||
single_line: bool,
|
||||
};
|
||||
fn printModifiedSegment(
|
||||
segment: DiffSegment,
|
||||
arena: std.mem.Allocator,
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
modified_style: ModifiedStyle,
|
||||
) !void {
|
||||
const removed_prefix = switch (modified_style.single_line) {
|
||||
true => prefix_styles.single_line_removed,
|
||||
false => prefix_styles.removed,
|
||||
};
|
||||
const inserted_prefix = switch (modified_style.single_line) {
|
||||
true => prefix_styles.single_line_inserted,
|
||||
false => prefix_styles.inserted,
|
||||
};
|
||||
|
||||
if (mode == .fg) {
|
||||
return printModifiedSegmentWithoutDiffdiff(writer, config, segment, modified_style);
|
||||
}
|
||||
|
||||
var char_diff = try DMP.default.diff(arena, segment.removed, segment.inserted, true);
|
||||
try DMP.diffCleanupSemantic(arena, &char_diff);
|
||||
|
||||
var deleted_highlighted_length: usize = 0;
|
||||
var inserted_highlighted_length: usize = 0;
|
||||
var unhighlighted_length: usize = 0;
|
||||
for (char_diff.items) |item| {
|
||||
switch (item.operation) {
|
||||
.delete => deleted_highlighted_length += item.text.len,
|
||||
.insert => inserted_highlighted_length += item.text.len,
|
||||
.equal => unhighlighted_length += item.text.len,
|
||||
}
|
||||
}
|
||||
|
||||
if ((deleted_highlighted_length > 10 and deleted_highlighted_length > segment.removed.len / 3 * 2) or (inserted_highlighted_length > 10 and inserted_highlighted_length > segment.inserted.len / 3 * 2)) {
|
||||
// the diff is too significant (more than 2/3 of the original text on one side is modified), so skip printing the second layer of diffs.
|
||||
return printModifiedSegmentWithoutDiffdiff(writer, config, segment, modified_style);
|
||||
}
|
||||
|
||||
const is_valid_utf_8 = for (char_diff.items) |item| {
|
||||
if (!bun.strings.isValidUTF8(item.text)) {
|
||||
break false;
|
||||
}
|
||||
} else true;
|
||||
|
||||
if (!is_valid_utf_8) {
|
||||
// utf-8 was cut up, so skip printing the second layer of diffs. ideally we would update the diff cleanup to handle this case instead.
|
||||
return printModifiedSegmentWithoutDiffdiff(writer, config, segment, modified_style);
|
||||
}
|
||||
|
||||
try printLinePrefix(writer, config, removed_prefix);
|
||||
for (char_diff.items) |item| {
|
||||
switch (item.operation) {
|
||||
.delete => try printSegment(item.text, writer, config, styles.removed_diff),
|
||||
.insert => {},
|
||||
.equal => try printSegment(item.text, writer, config, styles.removed_equal),
|
||||
}
|
||||
}
|
||||
try writer.writeAll("\n");
|
||||
|
||||
try printLinePrefix(writer, config, inserted_prefix);
|
||||
for (char_diff.items) |item| {
|
||||
switch (item.operation) {
|
||||
.delete => {},
|
||||
.insert => try printSegment(item.text, writer, config, styles.inserted_diff),
|
||||
.equal => try printSegment(item.text, writer, config, styles.inserted_equal),
|
||||
}
|
||||
}
|
||||
if (!modified_style.single_line) try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
pub fn printHunkHeader(writer: anytype, config: DiffConfig, original_line_number: usize, original_line_count: usize, changed_line_number: usize, changed_line_count: usize) !void {
|
||||
if (config.enable_ansi_colors) {
|
||||
try writer.print("{s}@@ -{},{} +{},{} @@{s}\n", .{ colors.yellow, original_line_number, original_line_count, changed_line_number, changed_line_count, colors.reset });
|
||||
} else {
|
||||
try writer.print("@@ -{},{} +{},{} @@\n", .{ original_line_number, original_line_count, changed_line_number, changed_line_count });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn printDiff(
|
||||
arena: std.mem.Allocator,
|
||||
writer: anytype,
|
||||
diff_segments: []const DiffSegment,
|
||||
config: DiffConfig,
|
||||
) !void {
|
||||
var removed_line_number: usize = 1;
|
||||
var inserted_line_number: usize = 1;
|
||||
var removed_diff_lines: usize = 0;
|
||||
var inserted_diff_lines: usize = 0;
|
||||
|
||||
const has_skipped_segments = for (diff_segments) |seg| {
|
||||
if (seg.skip) break true;
|
||||
} else false;
|
||||
|
||||
var was_skipped = false;
|
||||
for (diff_segments, 0..) |segment, i| {
|
||||
defer {
|
||||
removed_line_number += segment.removed_line_count;
|
||||
inserted_line_number += segment.inserted_line_count;
|
||||
}
|
||||
|
||||
if ((was_skipped and !segment.skip) or (has_skipped_segments and i == 0 and !segment.skip)) {
|
||||
// have to calculate the length of the non-skipped segment
|
||||
var original_line_count: usize = 0;
|
||||
var changed_line_count: usize = 0;
|
||||
for (diff_segments[i..]) |seg| {
|
||||
if (seg.skip) break;
|
||||
original_line_count += seg.removed_line_count;
|
||||
changed_line_count += seg.inserted_line_count;
|
||||
}
|
||||
try printHunkHeader(writer, config, removed_line_number, original_line_count, inserted_line_number, changed_line_count);
|
||||
was_skipped = false;
|
||||
}
|
||||
|
||||
switch (segment.mode) {
|
||||
.equal => {
|
||||
if (segment.skip) {
|
||||
was_skipped = true;
|
||||
continue;
|
||||
}
|
||||
try printLinePrefix(writer, config, prefix_styles.equal);
|
||||
try printSegment(segment.removed, writer, config, styles.equal);
|
||||
try writer.writeAll("\n");
|
||||
},
|
||||
.removed => {
|
||||
try printLinePrefix(writer, config, prefix_styles.removed);
|
||||
try printSegment(segment.removed, writer, config, styles.removed_line);
|
||||
try writer.writeAll("\n");
|
||||
removed_diff_lines += segment.removed_line_count;
|
||||
},
|
||||
.inserted => {
|
||||
try printLinePrefix(writer, config, prefix_styles.inserted);
|
||||
try printSegment(segment.inserted, writer, config, styles.inserted_line);
|
||||
try writer.writeAll("\n");
|
||||
inserted_diff_lines += segment.inserted_line_count;
|
||||
},
|
||||
.modified => {
|
||||
try printModifiedSegment(segment, arena, writer, config, .{ .single_line = false });
|
||||
removed_diff_lines += segment.removed_line_count;
|
||||
inserted_diff_lines += segment.inserted_line_count;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
try writer.writeAll("\n");
|
||||
|
||||
try printDiffFooter(writer, config, removed_diff_lines, inserted_diff_lines);
|
||||
}
|
||||
|
||||
const bun = @import("bun");
|
||||
const diff_match_patch = @import("./diff_match_patch.zig");
|
||||
const std = @import("std");
|
||||
@@ -7,69 +7,25 @@ pub const DiffFormatter = struct {
|
||||
not: bool = false,
|
||||
|
||||
pub fn format(this: DiffFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
var scope = bun.AllocationScope.init(default_allocator);
|
||||
// defer scope.deinit(); // TODO: fix leaks
|
||||
const allocator = scope.allocator();
|
||||
|
||||
const diff_config: DiffConfig = .default(Output.isAIAgent(), Output.enable_ansi_colors);
|
||||
|
||||
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});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
try printDiffMain(allocator, this.not, received, expected, writer, diff_config);
|
||||
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;
|
||||
var received_buf = MutableString.init(allocator, 0) catch unreachable;
|
||||
var expected_buf = MutableString.init(allocator, 0) catch unreachable;
|
||||
defer {
|
||||
received_buf.deinit();
|
||||
expected_buf.deinit();
|
||||
@@ -82,15 +38,13 @@ pub const DiffFormatter = struct {
|
||||
const buf_writer = buffered_writer.writer();
|
||||
const Writer = @TypeOf(buf_writer);
|
||||
|
||||
const fmt_options = ConsoleObject.FormatOptions{
|
||||
const fmt_options = JestPrettyFormat.FormatOptions{
|
||||
.enable_colors = false,
|
||||
.add_newline = false,
|
||||
.flush = false,
|
||||
.ordered_properties = true,
|
||||
.quote_strings = true,
|
||||
.max_depth = 100,
|
||||
};
|
||||
ConsoleObject.format2(
|
||||
JestPrettyFormat.format(
|
||||
.Debug,
|
||||
this.globalThis,
|
||||
@as([*]const JSValue, @ptrCast(&received)),
|
||||
@@ -104,7 +58,7 @@ pub const DiffFormatter = struct {
|
||||
|
||||
buffered_writer_.context = &expected_buf;
|
||||
|
||||
ConsoleObject.format2(
|
||||
JestPrettyFormat.format(
|
||||
.Debug,
|
||||
this.globalThis,
|
||||
@as([*]const JSValue, @ptrCast(&this.expected)),
|
||||
@@ -117,175 +71,25 @@ pub const DiffFormatter = struct {
|
||||
buffered_writer.flush() catch unreachable;
|
||||
}
|
||||
|
||||
const received_slice = received_buf.slice();
|
||||
const expected_slice = expected_buf.slice();
|
||||
var received_slice = received_buf.slice();
|
||||
var expected_slice = expected_buf.slice();
|
||||
if (std.mem.startsWith(u8, received_slice, "\n")) received_slice = received_slice[1..];
|
||||
if (std.mem.startsWith(u8, expected_slice, "\n")) expected_slice = expected_slice[1..];
|
||||
if (std.mem.endsWith(u8, received_slice, "\n")) received_slice = received_slice[0 .. received_slice.len - 1];
|
||||
if (std.mem.endsWith(u8, expected_slice, "\n")) expected_slice = expected_slice[0 .. expected_slice.len - 1];
|
||||
|
||||
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.globalThis)) {
|
||||
.none => {
|
||||
const fmt = "Expected: <green>{any}<r>\nReceived: <red>{any}<r>";
|
||||
var formatter = ConsoleObject.Formatter{ .globalThis = this.globalThis, .quote_strings = true };
|
||||
defer formatter.deinit();
|
||||
if (Output.enable_ansi_colors) {
|
||||
try writer.print(Output.prettyFmt(fmt, true), .{
|
||||
expected.toFmt(&formatter),
|
||||
received.toFmt(&formatter),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try writer.print(Output.prettyFmt(fmt, true), .{
|
||||
expected.toFmt(&formatter),
|
||||
received.toFmt(&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;
|
||||
try printDiffMain(allocator, this.not, received_slice, expected_slice, writer, diff_config);
|
||||
}
|
||||
};
|
||||
|
||||
const string = []const u8;
|
||||
|
||||
const DiffMatchPatch = @import("../../deps/diffz/DiffMatchPatch.zig");
|
||||
const std = @import("std");
|
||||
const JestPrettyFormat = @import("./pretty_format.zig").JestPrettyFormat;
|
||||
|
||||
const printDiffFile = @import("./diff/printDiff.zig");
|
||||
const DiffConfig = printDiffFile.DiffConfig;
|
||||
const printDiffMain = printDiffFile.printDiffMain;
|
||||
|
||||
const bun = @import("bun");
|
||||
const MutableString = bun.MutableString;
|
||||
@@ -293,6 +97,5 @@ const Output = bun.Output;
|
||||
const default_allocator = bun.default_allocator;
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const ConsoleObject = jsc.ConsoleObject;
|
||||
const JSGlobalObject = jsc.JSGlobalObject;
|
||||
const JSValue = jsc.JSValue;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,7 +66,6 @@ describe("Bun.deepMatch", () => {
|
||||
new Map([ ["foo", 1] ]),
|
||||
new Map([ ["foo", 1] ]),
|
||||
],
|
||||
|
||||
// Sets
|
||||
[new Set(), new Set()],
|
||||
[
|
||||
@@ -100,39 +99,51 @@ describe("Bun.deepMatch", () => {
|
||||
[[], [undefined]],
|
||||
[["a", "b", "c"], ["a", "b", "d"]],
|
||||
|
||||
// Maps
|
||||
// FIXME: I assume this is incorrect but I need confirmation on expected behavior.
|
||||
// [
|
||||
// new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
// new Map<number, number>([ [1, 2], [2, 3] ]),
|
||||
// ],
|
||||
// [
|
||||
// new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
// new Map<number, number>([ [1, 2], [2, 3], [3, 4], [4, 5] ]),
|
||||
// ],
|
||||
// [
|
||||
// new Map<number, number>([ [1, 2], [2, 3], [3, 4], [4, 5] ]),
|
||||
// new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
// ],
|
||||
// Maps - subset should not be contained in object
|
||||
[
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
new Map<number, number>([ [1, 2], [2, 3] ]),
|
||||
],
|
||||
[
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4], [4, 5] ]),
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
],
|
||||
[
|
||||
new Map([ ["foo", 1] ]),
|
||||
new Map([ ["bar", 1] ]),
|
||||
],
|
||||
[
|
||||
new Map([ ["foo", 1] ]),
|
||||
new Map([ ["foo", 2] ]),
|
||||
],
|
||||
|
||||
// Sets
|
||||
// FIXME: I assume this is incorrect but I need confirmation on expected behavior.
|
||||
// [
|
||||
// new Set([1, 2, 3]),
|
||||
// new Set([4, 5, 6]),
|
||||
// ],
|
||||
// [
|
||||
// new Set([1, 2, 3]),
|
||||
// new Set([1, 2]),
|
||||
// ],
|
||||
// [
|
||||
// new Set([1, 2]),
|
||||
// new Set([1, 2, 3]),
|
||||
// ],
|
||||
// [
|
||||
// new Set(["a", "b", "c"]),
|
||||
// new Set(["a", "b", "d"]),
|
||||
// ],
|
||||
// Maps with different sizes (even if one is subset of another)
|
||||
[
|
||||
new Map([ ["foo", 1] ]),
|
||||
new Map([ ["foo", 1], ["bar", 2] ]),
|
||||
],
|
||||
[
|
||||
new Map<number, number>([ [1, 2], [2, 3] ]),
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
],
|
||||
|
||||
// Sets with different contents or sizes
|
||||
[
|
||||
new Set([1, 2, 3]),
|
||||
new Set([4, 5, 6]),
|
||||
],
|
||||
[
|
||||
new Set([1, 2, 3]),
|
||||
new Set([1, 2]),
|
||||
],
|
||||
[
|
||||
new Set([1, 2]),
|
||||
new Set([1, 2, 3]),
|
||||
],
|
||||
[
|
||||
new Set(["a", "b", "c"]),
|
||||
new Set(["a", "b", "d"]),
|
||||
],
|
||||
])("Bun.deepMatch(%p, %p) === false", (a, b) => {
|
||||
expect(Bun.deepMatch(a, b)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -124,22 +124,6 @@ exports[`expect().toEqual() on objects with property indices doesn't print undef
|
||||
"expect(received).toEqual(expected)
|
||||
|
||||
{
|
||||
+ "0": 0,
|
||||
+ "1": 1,
|
||||
+ "10": 10,
|
||||
+ "11": 11,
|
||||
+ "12": 12,
|
||||
+ "13": 13,
|
||||
+ "14": 14,
|
||||
+ "15": 15,
|
||||
+ "2": 2,
|
||||
+ "3": 3,
|
||||
+ "4": 4,
|
||||
+ "5": 5,
|
||||
+ "6": 6,
|
||||
+ "7": 7,
|
||||
+ "8": 8,
|
||||
+ "9": 9,
|
||||
- "0": 123,
|
||||
- "1": 123,
|
||||
- "10": 123,
|
||||
@@ -156,6 +140,22 @@ exports[`expect().toEqual() on objects with property indices doesn't print undef
|
||||
- "7": 123,
|
||||
- "8": 123,
|
||||
- "9": 123,
|
||||
+ "0": 0,
|
||||
+ "1": 1,
|
||||
+ "10": 10,
|
||||
+ "11": 11,
|
||||
+ "12": 12,
|
||||
+ "13": 13,
|
||||
+ "14": 14,
|
||||
+ "15": 15,
|
||||
+ "2": 2,
|
||||
+ "3": 3,
|
||||
+ "4": 4,
|
||||
+ "5": 5,
|
||||
+ "6": 6,
|
||||
+ "7": 7,
|
||||
+ "8": 8,
|
||||
+ "9": 9,
|
||||
}
|
||||
|
||||
- Expected - 16
|
||||
|
||||
109
test/js/bun/test/printing/diffexample-color.fixture.ts
Normal file
109
test/js/bun/test/printing/diffexample-color.fixture.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { expect } from "bun:test";
|
||||
|
||||
try {
|
||||
expect("a\nb\nc\n d\ne").toEqual("a\nd\nc\nd\ne");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
const a = {
|
||||
age: 25,
|
||||
name: "Alice",
|
||||
logs: [
|
||||
"Entered the building",
|
||||
"Checked in at reception",
|
||||
"Took elevator to floor 3",
|
||||
"Attended morning meeting",
|
||||
"Started working on project",
|
||||
],
|
||||
};
|
||||
|
||||
const b = {
|
||||
age: 30,
|
||||
name: "Bob",
|
||||
logs: [
|
||||
"Logged into system",
|
||||
"Accessed dashboard",
|
||||
"Reviewed daily reports",
|
||||
"Updated project status",
|
||||
"Sent status email to team",
|
||||
"Scheduled follow-up meeting",
|
||||
],
|
||||
};
|
||||
try {
|
||||
expect(a).toEqual(b);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
const longInt32ArrayExpected = new Int32Array(100000);
|
||||
const longInt32ArrayReceived = new Int32Array(100000);
|
||||
for (let i = 0; i < 100000; i++) {
|
||||
longInt32ArrayExpected[i] = i;
|
||||
longInt32ArrayReceived[i] = i + 1;
|
||||
}
|
||||
try {
|
||||
expect(longInt32ArrayReceived).toEqual(longInt32ArrayExpected);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect("Hello 👋 世界 🌍").toEqual("Hello 👋 世界 🌎");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect("Line 1: 你好\nLine 2: مرحبا\nLine 3: Здравствуйте").toEqual("Line 1: 你好\nLine 2: مرحبا\nLine 3: Привет");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect({
|
||||
emoji: "🔥💧🌊",
|
||||
chinese: "测试字符串",
|
||||
arabic: "اختبار",
|
||||
mixed: "Hello 世界 🌍",
|
||||
}).toEqual({
|
||||
emoji: "🔥💧🌊",
|
||||
chinese: "测试文本",
|
||||
arabic: "اختبار",
|
||||
mixed: "Hello 世界 🌎",
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect("café résumé naïve").toEqual("café resumé naive");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect("© ® ™ £ € ¥ § ¶").toEqual("© ® ™ £ € ¥ § ¶");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect("Línea 1: ñoño\nLínea 2: àèìòù\nLínea 3: äëïöü").toEqual("Línea 1: ñoño\nLínea 2: àèìòù\nLínea 3: aeiou");
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
expect({
|
||||
french: "crème brûlée",
|
||||
spanish: "niño español",
|
||||
special: "½ ¼ ¾ ± × ÷",
|
||||
}).toEqual({
|
||||
french: "crème brulée",
|
||||
spanish: "niño español",
|
||||
special: "½ ¼ ¾ ± × ÷",
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
298
test/js/bun/test/printing/diffexample.fixture.ts
Normal file
298
test/js/bun/test/printing/diffexample.fixture.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("example 1", () => {
|
||||
expect("a\nb\nc\n d\ne").toEqual("a\nd\nc\nd\ne");
|
||||
});
|
||||
test("example 2", () => {
|
||||
expect({
|
||||
object1: "a",
|
||||
object2: "b",
|
||||
object3: "c\nd\ne",
|
||||
}).toEqual({
|
||||
object1: "a",
|
||||
object2: " b",
|
||||
object3: "c\nd",
|
||||
});
|
||||
});
|
||||
|
||||
test("example 3 - very long string with few changes", () => {
|
||||
// Create a 1000 line string with only a few differences
|
||||
const lines = Array.from({ length: 1000 }, (_, i) => `line ${i + 1}`);
|
||||
const originalString = lines.join("\n");
|
||||
|
||||
// Create expected string with only a few changes
|
||||
const expectedLines = [...lines];
|
||||
expectedLines[499] = "line 500 - CHANGED"; // Change line 500
|
||||
expectedLines[750] = "line 751 - MODIFIED"; // Change line 751
|
||||
expectedLines[900] = "line 901 - DIFFERENT"; // Change line 901
|
||||
expectedLines.splice(100, 0, "line 101 - INSERTED");
|
||||
const expectedString = expectedLines.join("\n");
|
||||
|
||||
expect(originalString).toEqual(expectedString);
|
||||
});
|
||||
|
||||
test.todo("example 4 - ansi colors don't get printed to console", () => {
|
||||
expect("\x1b[31mhello\x1b[0m").toEqual("\x1b[32mhello\x1b[0m");
|
||||
});
|
||||
|
||||
test("example 12 - large multiline diff", () => {
|
||||
const received = `line one
|
||||
line two
|
||||
line three!
|
||||
line four
|
||||
line five
|
||||
!-!six
|
||||
line seven
|
||||
line eight
|
||||
line ten
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
line 17
|
||||
line 18
|
||||
line 19
|
||||
line 20
|
||||
line 21
|
||||
line 22
|
||||
line 23
|
||||
line 24
|
||||
line 25
|
||||
line 26
|
||||
line 27
|
||||
line 28!
|
||||
line 29
|
||||
line 30
|
||||
line 31
|
||||
line 32
|
||||
line 33
|
||||
line 34
|
||||
line 35
|
||||
line 36
|
||||
line 37
|
||||
line 38
|
||||
line 39`;
|
||||
const expected = `line one
|
||||
line two
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
line eight
|
||||
line nine (inserted only)
|
||||
line ten
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
line 17
|
||||
line 18
|
||||
line 19
|
||||
line 20
|
||||
line 21
|
||||
line 22
|
||||
line 23
|
||||
line 24
|
||||
line 25
|
||||
line 26
|
||||
line 27
|
||||
line 28
|
||||
line 29
|
||||
line 30
|
||||
line 31
|
||||
line 32
|
||||
line 33
|
||||
line 34
|
||||
line 35
|
||||
line 36
|
||||
line 37
|
||||
line 38
|
||||
line 39`;
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("example 13 - simple multiline diff with sections", () => {
|
||||
const received = `=== diffdiff ===
|
||||
line one
|
||||
line two!
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== each line changed ===
|
||||
line one?
|
||||
line two
|
||||
line three?
|
||||
line four?
|
||||
|
||||
=== deleted ===
|
||||
line one
|
||||
line two
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted ===
|
||||
line one
|
||||
line two
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted newline ===
|
||||
line one
|
||||
line two
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== has newline at end vs doesn't ===`;
|
||||
const expected = `=== diffdiff ===
|
||||
line one
|
||||
line two
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== each line changed ===
|
||||
line one
|
||||
line two!
|
||||
line three
|
||||
line four!
|
||||
|
||||
=== deleted ===
|
||||
line one
|
||||
line two
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted ===
|
||||
line one
|
||||
line two
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted newline ===
|
||||
line one
|
||||
line two
|
||||
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== has newline at end vs doesn't ===
|
||||
`;
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("example 14 - single line diff", () => {
|
||||
const received = `"¡hello, world"`;
|
||||
const expected = `"hello, world!"`;
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("example 15 - unicode char diff", () => {
|
||||
const received = `Hello 👋 世界 🌎!`;
|
||||
const expected = `Hello 👋 世界 🌍!`;
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("example 16 - indentation change diff", () => {
|
||||
const received = `function main() {
|
||||
if (true) {
|
||||
print("Hello, world!");
|
||||
print("Goodbye, world!");
|
||||
}
|
||||
}`;
|
||||
const expected = `function main() {
|
||||
print("Hello, world!");
|
||||
print("Goodbye, world!");
|
||||
}`;
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("example 17 - very long string", () => {
|
||||
const receivedLines: string[] = [];
|
||||
const expectedLines: string[] = [];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (i === 100) {
|
||||
receivedLines.push(`line ${i} - inserted`);
|
||||
expectedLines.push(`line ${i}`);
|
||||
continue;
|
||||
}
|
||||
if (i === 200) {
|
||||
receivedLines.push(`line ${i}`);
|
||||
expectedLines.push(`line ${i} - deleted`);
|
||||
continue;
|
||||
}
|
||||
if (i === 300) {
|
||||
receivedLines.push(`line ${i} - modified`);
|
||||
expectedLines.push(`modified - line ${i}`);
|
||||
continue;
|
||||
}
|
||||
if (i === 400) {
|
||||
receivedLines.push(`line ${i}`);
|
||||
receivedLines.push(`extra line!`);
|
||||
expectedLines.push(`line ${i}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
receivedLines.push(`line ${i}`);
|
||||
expectedLines.push(`line ${i}`);
|
||||
}
|
||||
|
||||
// The Zig code adds a trailing newline to each string.
|
||||
const receivedString = receivedLines.join("\n") + "\n";
|
||||
const expectedString = expectedLines.join("\n") + "\n";
|
||||
expect(receivedString).toEqual(expectedString);
|
||||
});
|
||||
|
||||
test("example 18 - very long single line string", () => {
|
||||
const expected = "a".repeat(1000000);
|
||||
const received = "a".repeat(1000001);
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("not", () => {
|
||||
expect("Hello, World!").not.toEqual("Hello, World!");
|
||||
});
|
||||
|
||||
test("has end newline vs doesn't", () => {
|
||||
expect("Hello, World!\n").toEqual("Hello, World!");
|
||||
});
|
||||
|
||||
test("extremely float64array", () => {
|
||||
const length = 10000;
|
||||
const expected = new Float64Array(length);
|
||||
const received = new Float64Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
expected[i] = i;
|
||||
received[i] = i + 1;
|
||||
}
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
|
||||
test("completely different long value does not truncate", () => {
|
||||
const length = 100;
|
||||
const expected = new Int32Array(length);
|
||||
const received = new Int32Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
expected[i] = i;
|
||||
received[i] = length - i - 1;
|
||||
}
|
||||
expect(received).toEqual(expected);
|
||||
});
|
||||
848
test/js/bun/test/printing/diffexample.test.ts
Normal file
848
test/js/bun/test/printing/diffexample.test.ts
Normal file
@@ -0,0 +1,848 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
|
||||
function cleanOutput(output: string) {
|
||||
return output
|
||||
.replaceAll(/ \[[0-9\.]+ms\]/g, "")
|
||||
.replaceAll(/at <anonymous> \(.*\)/g, "at <anonymous> (FILE:LINE)")
|
||||
.replaceAll(
|
||||
"test\\js\\bun\\test\\printing\\diffexample.fixture.ts:",
|
||||
"test/js/bun/test/printing/diffexample.fixture.ts:",
|
||||
);
|
||||
}
|
||||
function cleanAnsiEscapes(output: string) {
|
||||
return output.replaceAll(/\x1B\[[0-9;]*m/g, "");
|
||||
}
|
||||
|
||||
test("no color", async () => {
|
||||
const noColorSpawn = Bun.spawn({
|
||||
cmd: [bunExe(), "test", import.meta.dir + "/diffexample.fixture.ts"],
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
env: {
|
||||
...bunEnv,
|
||||
FORCE_COLOR: "0",
|
||||
},
|
||||
});
|
||||
await noColorSpawn.exited;
|
||||
const noColorStderr = cleanOutput(await noColorSpawn.stderr.text());
|
||||
const noColorStdout = await noColorSpawn.stdout.text();
|
||||
expect(noColorStderr).toMatchInlineSnapshot(`
|
||||
"
|
||||
test/js/bun/test/printing/diffexample.fixture.ts:
|
||||
1 | import { test, expect } from "bun:test";
|
||||
2 |
|
||||
3 | test("example 1", () => {
|
||||
4 | expect("a\\nb\\nc\\n d\\ne").toEqual("a\\nd\\nc\\nd\\ne");
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
"a
|
||||
- d
|
||||
+ b
|
||||
c
|
||||
- d
|
||||
+ d
|
||||
e"
|
||||
|
||||
- Expected - 2
|
||||
+ Received + 2
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 1
|
||||
6 | test("example 2", () => {
|
||||
7 | expect({
|
||||
8 | object1: "a",
|
||||
9 | object2: "b",
|
||||
10 | object3: "c\\nd\\ne",
|
||||
11 | }).toEqual({
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
{
|
||||
"object1": "a",
|
||||
- "object2": " b",
|
||||
+ "object2": "b",
|
||||
"object3":
|
||||
"c
|
||||
- d"
|
||||
+ d
|
||||
+ e"
|
||||
,
|
||||
}
|
||||
|
||||
- Expected - 2
|
||||
+ Received + 3
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 2
|
||||
26 | expectedLines[750] = "line 751 - MODIFIED"; // Change line 751
|
||||
27 | expectedLines[900] = "line 901 - DIFFERENT"; // Change line 901
|
||||
28 | expectedLines.splice(100, 0, "line 101 - INSERTED");
|
||||
29 | const expectedString = expectedLines.join("\\n");
|
||||
30 |
|
||||
31 | expect(originalString).toEqual(expectedString);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
@@ -96,11 +96,11 @@
|
||||
line 96
|
||||
line 97
|
||||
line 98
|
||||
line 99
|
||||
line 100
|
||||
- line 101 - INSERTED
|
||||
line 101
|
||||
line 102
|
||||
line 103
|
||||
line 104
|
||||
line 105
|
||||
@@ -496,11 +496,11 @@
|
||||
line 495
|
||||
line 496
|
||||
line 497
|
||||
line 498
|
||||
line 499
|
||||
- line 500 - CHANGED
|
||||
+ line 500
|
||||
line 501
|
||||
line 502
|
||||
line 503
|
||||
line 504
|
||||
line 505
|
||||
@@ -747,11 +747,11 @@
|
||||
line 746
|
||||
line 747
|
||||
line 748
|
||||
line 749
|
||||
line 750
|
||||
- line 751 - MODIFIED
|
||||
+ line 751
|
||||
line 752
|
||||
line 753
|
||||
line 754
|
||||
line 755
|
||||
line 756
|
||||
@@ -897,11 +897,11 @@
|
||||
line 896
|
||||
line 897
|
||||
line 898
|
||||
line 899
|
||||
line 900
|
||||
- line 901 - DIFFERENT
|
||||
+ line 901
|
||||
line 902
|
||||
line 903
|
||||
line 904
|
||||
line 905
|
||||
line 906
|
||||
|
||||
- Expected - 4
|
||||
+ Received + 3
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 3 - very long string with few changes
|
||||
(todo) example 4 - ansi colors don't get printed to console
|
||||
111 | line 35
|
||||
112 | line 36
|
||||
113 | line 37
|
||||
114 | line 38
|
||||
115 | line 39\`;
|
||||
116 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
"line one
|
||||
line two
|
||||
- line three
|
||||
+ line three!
|
||||
line four
|
||||
line five
|
||||
- line six
|
||||
+ !-!six
|
||||
line seven
|
||||
line eight
|
||||
- line nine (inserted only)
|
||||
line ten
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
line 17
|
||||
line 18
|
||||
line 19
|
||||
line 20
|
||||
line 21
|
||||
line 22
|
||||
line 23
|
||||
line 24
|
||||
line 25
|
||||
line 26
|
||||
line 27
|
||||
- line 28
|
||||
+ line 28!
|
||||
line 29
|
||||
line 30
|
||||
line 31
|
||||
line 32
|
||||
line 33
|
||||
line 34
|
||||
line 35
|
||||
line 36
|
||||
line 37
|
||||
line 38
|
||||
line 39"
|
||||
|
||||
- Expected - 4
|
||||
+ Received + 3
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 12 - large multiline diff
|
||||
194 | line six
|
||||
195 | line seven
|
||||
196 |
|
||||
197 | === has newline at end vs doesn't ===
|
||||
198 | \`;
|
||||
199 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
"=== diffdiff ===
|
||||
line one
|
||||
- line two
|
||||
- line three
|
||||
- line four
|
||||
- line five
|
||||
+ line two!
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== each line changed ===
|
||||
- line one
|
||||
- line two!
|
||||
- line three
|
||||
- line four!
|
||||
+ line one?
|
||||
+ line two
|
||||
+ line three?
|
||||
+ line four?
|
||||
|
||||
=== deleted ===
|
||||
line one
|
||||
line two
|
||||
+ line three
|
||||
+ line four
|
||||
+ line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted ===
|
||||
line one
|
||||
line two
|
||||
- line three
|
||||
- line four
|
||||
- line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
=== inserted newline ===
|
||||
line one
|
||||
line two
|
||||
-
|
||||
line three
|
||||
line four
|
||||
line five
|
||||
line six
|
||||
line seven
|
||||
|
||||
- === has newline at end vs doesn't ===
|
||||
- "
|
||||
+ === has newline at end vs doesn't ==="
|
||||
|
||||
- Expected - 14
|
||||
+ Received + 9
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 13 - simple multiline diff with sections
|
||||
200 | });
|
||||
201 |
|
||||
202 | test("example 14 - single line diff", () => {
|
||||
203 | const received = \`"¡hello, world"\`;
|
||||
204 | const expected = \`"hello, world!"\`;
|
||||
205 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
Expected: ""hello, world!""
|
||||
Received: ""¡hello, world""
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 14 - single line diff
|
||||
206 | });
|
||||
207 |
|
||||
208 | test("example 15 - unicode char diff", () => {
|
||||
209 | const received = \`Hello 👋 世界 🌎!\`;
|
||||
210 | const expected = \`Hello 👋 世界 🌍!\`;
|
||||
211 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
Expected: "Hello 👋 世界 🌍!"
|
||||
Received: "Hello 👋 世界 🌎!"
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 15 - unicode char diff
|
||||
220 | }\`;
|
||||
221 | const expected = \`function main() {
|
||||
222 | print("Hello, world!");
|
||||
223 | print("Goodbye, world!");
|
||||
224 | }\`;
|
||||
225 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
"function main() {
|
||||
- print("Hello, world!");
|
||||
- print("Goodbye, world!");
|
||||
+ if (true) {
|
||||
+ print("Hello, world!");
|
||||
+ print("Goodbye, world!");
|
||||
+ }
|
||||
}"
|
||||
|
||||
- Expected - 2
|
||||
+ Received + 4
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 16 - indentation change diff
|
||||
256 | }
|
||||
257 |
|
||||
258 | // The Zig code adds a trailing newline to each string.
|
||||
259 | const receivedString = receivedLines.join("\\n") + "\\n";
|
||||
260 | const expectedString = expectedLines.join("\\n") + "\\n";
|
||||
261 | expect(receivedString).toEqual(expectedString);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
@@ -96,11 +96,11 @@
|
||||
line 95
|
||||
line 96
|
||||
line 97
|
||||
line 98
|
||||
line 99
|
||||
- line 100
|
||||
+ line 100 - inserted
|
||||
line 101
|
||||
line 102
|
||||
line 103
|
||||
line 104
|
||||
line 105
|
||||
@@ -196,11 +196,11 @@
|
||||
line 195
|
||||
line 196
|
||||
line 197
|
||||
line 198
|
||||
line 199
|
||||
- line 200 - deleted
|
||||
+ line 200
|
||||
line 201
|
||||
line 202
|
||||
line 203
|
||||
line 204
|
||||
line 205
|
||||
@@ -296,11 +296,11 @@
|
||||
line 295
|
||||
line 296
|
||||
line 297
|
||||
line 298
|
||||
line 299
|
||||
- modified - line 300
|
||||
+ line 300 - modified
|
||||
line 301
|
||||
line 302
|
||||
line 303
|
||||
line 304
|
||||
line 305
|
||||
@@ -397,11 +397,11 @@
|
||||
line 396
|
||||
line 397
|
||||
line 398
|
||||
line 399
|
||||
line 400
|
||||
+ extra line!
|
||||
line 401
|
||||
line 402
|
||||
line 403
|
||||
line 404
|
||||
line 405
|
||||
|
||||
- Expected - 3
|
||||
+ Received + 4
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 17 - very long string
|
||||
262 | });
|
||||
263 |
|
||||
264 | test("example 18 - very long single line string", () => {
|
||||
265 | const expected = "a".repeat(1000000);
|
||||
266 | const received = "a".repeat(1000001);
|
||||
267 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
Expected: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... (999801 bytes truncated) ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
Received: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... (999801 bytes truncated) ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) example 18 - very long single line string
|
||||
266 | const received = "a".repeat(1000001);
|
||||
267 | expect(received).toEqual(expected);
|
||||
268 | });
|
||||
269 |
|
||||
270 | test("not", () => {
|
||||
271 | expect("Hello, World!").not.toEqual("Hello, World!");
|
||||
^
|
||||
error: expect(received).not.toEqual(expected)
|
||||
|
||||
Expected: not "Hello, World!"
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) not
|
||||
270 | test("not", () => {
|
||||
271 | expect("Hello, World!").not.toEqual("Hello, World!");
|
||||
272 | });
|
||||
273 |
|
||||
274 | test("has end newline vs doesn't", () => {
|
||||
275 | expect("Hello, World!\\n").toEqual("Hello, World!");
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
- "Hello, World!"
|
||||
+ "Hello, World!
|
||||
+ "
|
||||
|
||||
- Expected - 1
|
||||
+ Received + 2
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) has end newline vs doesn't
|
||||
281 | const received = new Float64Array(length);
|
||||
282 | for (let i = 0; i < length; i++) {
|
||||
283 | expected[i] = i;
|
||||
284 | received[i] = i + 1;
|
||||
285 | }
|
||||
286 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Float64Array [
|
||||
- 0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
@@ -9997,7 +9997,7 @@
|
||||
9995,
|
||||
9996,
|
||||
9997,
|
||||
9998,
|
||||
9999,
|
||||
+ 10000,
|
||||
]
|
||||
|
||||
- Expected - 1
|
||||
+ Received + 1
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) extremely float64array
|
||||
292 | const received = new Int32Array(length);
|
||||
293 | for (let i = 0; i < length; i++) {
|
||||
294 | expected[i] = i;
|
||||
295 | received[i] = length - i - 1;
|
||||
296 | }
|
||||
297 | expect(received).toEqual(expected);
|
||||
^
|
||||
error: expect(received).toEqual(expected)
|
||||
|
||||
Int32Array [
|
||||
- 0,
|
||||
- 1,
|
||||
- 2,
|
||||
- 3,
|
||||
- 4,
|
||||
- 5,
|
||||
- 6,
|
||||
- 7,
|
||||
- 8,
|
||||
- 9,
|
||||
- 10,
|
||||
- 11,
|
||||
- 12,
|
||||
- 13,
|
||||
- 14,
|
||||
- 15,
|
||||
- 16,
|
||||
- 17,
|
||||
- 18,
|
||||
- 19,
|
||||
- 20,
|
||||
- 21,
|
||||
- 22,
|
||||
- 23,
|
||||
- 24,
|
||||
- 25,
|
||||
- 26,
|
||||
- 27,
|
||||
- 28,
|
||||
- 29,
|
||||
- 30,
|
||||
- 31,
|
||||
- 32,
|
||||
- 33,
|
||||
- 34,
|
||||
- 35,
|
||||
- 36,
|
||||
- 37,
|
||||
- 38,
|
||||
- 39,
|
||||
- 40,
|
||||
- 41,
|
||||
- 42,
|
||||
- 43,
|
||||
- 44,
|
||||
- 45,
|
||||
- 46,
|
||||
- 47,
|
||||
- 48,
|
||||
- 49,
|
||||
- 50,
|
||||
- 51,
|
||||
- 52,
|
||||
- 53,
|
||||
- 54,
|
||||
- 55,
|
||||
- 56,
|
||||
- 57,
|
||||
- 58,
|
||||
- 59,
|
||||
- 60,
|
||||
- 61,
|
||||
- 62,
|
||||
- 63,
|
||||
- 64,
|
||||
- 65,
|
||||
- 66,
|
||||
- 67,
|
||||
- 68,
|
||||
- 69,
|
||||
- 70,
|
||||
- 71,
|
||||
- 72,
|
||||
- 73,
|
||||
- 74,
|
||||
- 75,
|
||||
- 76,
|
||||
- 77,
|
||||
- 78,
|
||||
- 79,
|
||||
- 80,
|
||||
- 81,
|
||||
- 82,
|
||||
- 83,
|
||||
- 84,
|
||||
- 85,
|
||||
- 86,
|
||||
- 87,
|
||||
- 88,
|
||||
- 89,
|
||||
- 90,
|
||||
- 91,
|
||||
- 92,
|
||||
- 93,
|
||||
- 94,
|
||||
- 95,
|
||||
- 96,
|
||||
- 97,
|
||||
- 98,
|
||||
99,
|
||||
+ 98,
|
||||
+ 97,
|
||||
+ 96,
|
||||
+ 95,
|
||||
+ 94,
|
||||
+ 93,
|
||||
+ 92,
|
||||
+ 91,
|
||||
+ 90,
|
||||
+ 89,
|
||||
+ 88,
|
||||
+ 87,
|
||||
+ 86,
|
||||
+ 85,
|
||||
+ 84,
|
||||
+ 83,
|
||||
+ 82,
|
||||
+ 81,
|
||||
+ 80,
|
||||
+ 79,
|
||||
+ 78,
|
||||
+ 77,
|
||||
+ 76,
|
||||
+ 75,
|
||||
+ 74,
|
||||
+ 73,
|
||||
+ 72,
|
||||
+ 71,
|
||||
+ 70,
|
||||
+ 69,
|
||||
+ 68,
|
||||
+ 67,
|
||||
+ 66,
|
||||
+ 65,
|
||||
+ 64,
|
||||
+ 63,
|
||||
+ 62,
|
||||
+ 61,
|
||||
+ 60,
|
||||
+ 59,
|
||||
+ 58,
|
||||
+ 57,
|
||||
+ 56,
|
||||
+ 55,
|
||||
+ 54,
|
||||
+ 53,
|
||||
+ 52,
|
||||
+ 51,
|
||||
+ 50,
|
||||
+ 49,
|
||||
+ 48,
|
||||
+ 47,
|
||||
+ 46,
|
||||
+ 45,
|
||||
+ 44,
|
||||
+ 43,
|
||||
+ 42,
|
||||
+ 41,
|
||||
+ 40,
|
||||
+ 39,
|
||||
+ 38,
|
||||
+ 37,
|
||||
+ 36,
|
||||
+ 35,
|
||||
+ 34,
|
||||
+ 33,
|
||||
+ 32,
|
||||
+ 31,
|
||||
+ 30,
|
||||
+ 29,
|
||||
+ 28,
|
||||
+ 27,
|
||||
+ 26,
|
||||
+ 25,
|
||||
+ 24,
|
||||
+ 23,
|
||||
+ 22,
|
||||
+ 21,
|
||||
+ 20,
|
||||
+ 19,
|
||||
+ 18,
|
||||
+ 17,
|
||||
+ 16,
|
||||
+ 15,
|
||||
+ 14,
|
||||
+ 13,
|
||||
+ 12,
|
||||
+ 11,
|
||||
+ 10,
|
||||
+ 9,
|
||||
+ 8,
|
||||
+ 7,
|
||||
+ 6,
|
||||
+ 5,
|
||||
+ 4,
|
||||
+ 3,
|
||||
+ 2,
|
||||
+ 1,
|
||||
+ 0,
|
||||
]
|
||||
|
||||
- Expected - 99
|
||||
+ Received + 99
|
||||
|
||||
at <anonymous> (FILE:LINE)
|
||||
(fail) completely different long value does not truncate
|
||||
|
||||
0 pass
|
||||
1 todo
|
||||
14 fail
|
||||
14 expect() calls
|
||||
Ran 15 tests across 1 file.
|
||||
"
|
||||
`);
|
||||
expect(noColorSpawn.exitCode).toBe(1);
|
||||
|
||||
const colorSpawn = Bun.spawn({
|
||||
cmd: [bunExe(), "test", import.meta.dir + "/diffexample.fixture.ts"],
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
env: {
|
||||
...bunEnv,
|
||||
FORCE_COLOR: "0",
|
||||
},
|
||||
});
|
||||
await colorSpawn.exited;
|
||||
const colorStderr = cleanOutput(cleanAnsiEscapes(await colorSpawn.stderr.text()));
|
||||
const colorStdout = cleanAnsiEscapes(await colorSpawn.stdout.text());
|
||||
expect(colorStderr).toEqual(noColorStderr);
|
||||
expect(colorStdout).toEqual(noColorStdout);
|
||||
});
|
||||
|
||||
function getDiffPart(stderr: string): string {
|
||||
stderr = stderr.split("a\\nd\\nc\\nd\\ne")[1];
|
||||
const split = stderr.split("\n\n");
|
||||
split.pop();
|
||||
stderr = split.join("\n\n");
|
||||
return stderr;
|
||||
}
|
||||
|
||||
test("color", async () => {
|
||||
const spawn = Bun.spawn({
|
||||
cmd: [bunExe(), import.meta.dir + "/diffexample-color.fixture.ts"],
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
env: {
|
||||
...bunEnv,
|
||||
FORCE_COLOR: "1",
|
||||
},
|
||||
});
|
||||
await spawn.exited;
|
||||
const stderr = await spawn.stderr.text();
|
||||
|
||||
expect(stderr).toMatchInlineSnapshot(`""`);
|
||||
expect(await spawn.stdout.text()).toMatchInlineSnapshot(`
|
||||
"\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m"a\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7md\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7mb\x1B[0m
|
||||
\x1B[0m\x1B[2mc\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32md\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7m \x1B[0m\x1B[31md\x1B[0m
|
||||
\x1B[0m\x1B[2me"\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 2\x1B[0m
|
||||
\x1B[31m+ Received + 2\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m{\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "age": \x1B[0m\x1B[32m\x1B[7m30\x1B[0m\x1B[32m,\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "age": \x1B[0m\x1B[31m\x1B[7m25\x1B[0m\x1B[31m,\x1B[0m
|
||||
\x1B[0m\x1B[2m "logs": [\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Logged into system",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Accessed dashboard",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Reviewed daily reports",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Updated project status",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Sent status email to team",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "Scheduled follow-up meeting",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "Entered the building",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "Checked in at reception",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "Took elevator to floor 3",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "Attended morning meeting",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "Started working on project",\x1B[0m
|
||||
\x1B[0m\x1B[2m ],\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "name": "\x1B[0m\x1B[32m\x1B[7mBob\x1B[0m\x1B[32m",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "name": "\x1B[0m\x1B[31m\x1B[7mAlice\x1B[0m\x1B[31m",\x1B[0m
|
||||
\x1B[0m\x1B[2m}\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 8\x1B[0m
|
||||
\x1B[31m+ Received + 7\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[33m@@ -1,7 +1,7 @@\x1B[0m
|
||||
\x1B[0m\x1B[2mInt32Array [\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m 0,\x1B[0m
|
||||
\x1B[0m\x1B[2m 1,\x1B[0m
|
||||
\x1B[0m\x1B[2m 2,\x1B[0m
|
||||
\x1B[0m\x1B[2m 3,\x1B[0m
|
||||
\x1B[0m\x1B[2m 4,\x1B[0m
|
||||
\x1B[0m\x1B[2m 5,\x1B[0m
|
||||
\x1B[33m@@ -99997,7 +99997,7 @@\x1B[0m
|
||||
\x1B[0m\x1B[2m 99995,\x1B[0m
|
||||
\x1B[0m\x1B[2m 99996,\x1B[0m
|
||||
\x1B[0m\x1B[2m 99997,\x1B[0m
|
||||
\x1B[0m\x1B[2m 99998,\x1B[0m
|
||||
\x1B[0m\x1B[2m 99999,\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m 100000,\x1B[0m
|
||||
\x1B[0m\x1B[2m]\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 1\x1B[0m
|
||||
\x1B[31m+ Received + 1\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
Expected: \x1B[0m\x1B[32m"Hello 👋 世界 🌎"\x1B[0m
|
||||
Received: \x1B[0m\x1B[31m"Hello 👋 世界 🌍"\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m"Line 1: 你好\x1B[0m
|
||||
\x1B[0m\x1B[2mLine 2: مرحبا\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32mLine 3: Привет"\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31mLine 3: Здравствуйте"\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 1\x1B[0m
|
||||
\x1B[31m+ Received + 1\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m{\x1B[0m
|
||||
\x1B[0m\x1B[2m "arabic": "اختبار",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "chinese": "测试\x1B[0m\x1B[32m\x1B[7m文本\x1B[0m\x1B[32m",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "chinese": "测试\x1B[0m\x1B[31m\x1B[7m字符串\x1B[0m\x1B[31m",\x1B[0m
|
||||
\x1B[0m\x1B[2m "emoji": "🔥💧🌊",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "mixed": "Hello 世界 🌎",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "mixed": "Hello 世界 🌍",\x1B[0m
|
||||
\x1B[0m\x1B[2m}\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 2\x1B[0m
|
||||
\x1B[31m+ Received + 2\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
Expected: \x1B[0m\x1B[32m"café r\x1B[0m\x1B[32m\x1B[7me\x1B[0m\x1B[32msumé na\x1B[0m\x1B[32m\x1B[7mi\x1B[0m\x1B[32mve"\x1B[0m
|
||||
Received: \x1B[0m\x1B[31m"café r\x1B[0m\x1B[31m\x1B[7mé\x1B[0m\x1B[31msumé na\x1B[0m\x1B[31m\x1B[7mï\x1B[0m\x1B[31mve"\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m"Línea 1: ñoño\x1B[0m
|
||||
\x1B[0m\x1B[2mLínea 2: àèìòù\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32mLínea 3: \x1B[0m\x1B[32m\x1B[7maeiou\x1B[0m\x1B[32m"\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31mLínea 3: \x1B[0m\x1B[31m\x1B[7mäëïöü\x1B[0m\x1B[31m"\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 1\x1B[0m
|
||||
\x1B[31m+ Received + 1\x1B[0m
|
||||
|
||||
\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoEqual\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
\x1B[0m\x1B[2m{\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m "french": "crème br\x1B[0m\x1B[32m\x1B[7mu\x1B[0m\x1B[32mlée",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "french": "crème br\x1B[0m\x1B[31m\x1B[7mû\x1B[0m\x1B[31mlée",\x1B[0m
|
||||
\x1B[0m\x1B[2m "spanish": "niño español",\x1B[0m
|
||||
\x1B[0m\x1B[2m "special": "½ ¼ ¾ ± × ÷",\x1B[0m
|
||||
\x1B[0m\x1B[2m}\x1B[0m
|
||||
|
||||
\x1B[32m- Expected - 1\x1B[0m
|
||||
\x1B[31m+ Received + 1\x1B[0m
|
||||
|
||||
"
|
||||
`);
|
||||
expect(spawn.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
/*
|
||||
issue:
|
||||
in inline snapshot diffing, it is printing the color codes
|
||||
*/
|
||||
@@ -607,19 +607,3 @@ exports[`snapshot numbering 4`] = `"snap"`;
|
||||
exports[`snapshot numbering 6`] = `"hello"`;
|
||||
|
||||
exports[`snapshot numbering: hinted 1`] = `"hello"`;
|
||||
|
||||
exports[`indented inline snapshots 4`] = `
|
||||
"\x1B[2mexpect(\x1B[0m\x1B[31mreceived\x1B[0m\x1B[2m).\x1B[0mtoMatchInlineSnapshot\x1B[2m(\x1B[0m\x1B[32mexpected\x1B[0m\x1B[2m)\x1B[0m
|
||||
|
||||
Expected: \x1B[2m
|
||||
\x1B[0m\x1B[32m \x1B[0m\x1B[2m{
|
||||
\x1B[0m\x1B[32m \x1B[0m\x1B[2m"a": 2,
|
||||
\x1B[0m\x1B[32m \x1B[0m\x1B[2m}
|
||||
\x1B[0m
|
||||
Received: \x1B[2m
|
||||
\x1B[0m\x1B[2m{
|
||||
\x1B[0m\x1B[2m"a": 2,
|
||||
\x1B[0m\x1B[2m}
|
||||
\x1B[0m
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -879,7 +879,7 @@ test("indented inline snapshots", () => {
|
||||
"a": 2,
|
||||
}
|
||||
`);
|
||||
}).toThrowErrorMatchingSnapshot();
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test("error snapshots", () => {
|
||||
|
||||
@@ -270,22 +270,38 @@ test/napi/node-napi-tests/test/js-native-api/test_conversions/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_dataview/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_date/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_error/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_exception/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_finalizer/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_function/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_general/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_handle_scope/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_instance_data/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_new_target/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_number/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_object/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_promise/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_properties/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_reference/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_reference_double_free/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_string/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_symbol/do.test.ts
|
||||
test/napi/node-napi-tests/test/js-native-api/test_typedarray/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/1_hello_world/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_async/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_buffer/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_callback_scope/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_cleanup_hook/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_exception/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_fatal/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_fatal_exception/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_general/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_init_order/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_instance_data/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_make_callback/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_make_callback_recurse/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_threadsafe_function/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_worker_terminate_finalization/do.test.ts
|
||||
test/napi/node-napi-tests/test/node-api/test_reference_by_node_api_version/do.test.ts
|
||||
|
||||
# normalizeCryptoAlgorithmParameters
|
||||
test/js/node/test/parallel/test-webcrypto-derivekey.js
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { expect, mock, test } from "bun:test";
|
||||
|
||||
const stripAnsi = (str: string) => str.replaceAll(/\x1b\[[0-9;]*m/g, "");
|
||||
|
||||
test("toHaveBeenCalledWith should show diff when assertion fails", () => {
|
||||
const mockedFn = mock(args => args);
|
||||
|
||||
@@ -18,8 +20,8 @@ test("toHaveBeenCalledWith should show diff when assertion fails", () => {
|
||||
expect(error).toBeDefined();
|
||||
expect(error!.message).toContain("- Expected");
|
||||
expect(error!.message).toContain("+ Received");
|
||||
expect(error!.message).toContain("d: 1");
|
||||
expect(error!.message).toContain("d: 2");
|
||||
expect(stripAnsi(error!.message)).toContain('"d": 1');
|
||||
expect(stripAnsi(error!.message)).toContain('"d": 2');
|
||||
});
|
||||
|
||||
test("toHaveBeenNthCalledWith should show diff when assertion fails", () => {
|
||||
@@ -80,8 +82,8 @@ test("toHaveBeenCalledWith should show diff for multiple arguments", () => {
|
||||
expect(error).toBeDefined();
|
||||
expect(error!.message).toContain("- Expected");
|
||||
expect(error!.message).toContain("+ Received");
|
||||
expect(error!.message).toContain("bar");
|
||||
expect(error!.message).toContain("baz");
|
||||
expect(stripAnsi(error!.message)).toContain("bar");
|
||||
expect(stripAnsi(error!.message)).toContain("baz");
|
||||
});
|
||||
|
||||
test("toHaveBeenCalledWith should show diff for complex nested structures", () => {
|
||||
|
||||
43
test/regression/issue/15673.test.ts
Normal file
43
test/regression/issue/15673.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// Test for https://github.com/oven-sh/bun/issues/15673
|
||||
// `Bun.deepMatch` always returns `true` when comparing `Set` and `Map` instances with different number of entries
|
||||
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test.each([
|
||||
// Maps with different number of entries should return false
|
||||
[
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
new Map<number, number>([ [1, 2], [2, 3] ]),
|
||||
],
|
||||
[
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4] ]),
|
||||
new Map<number, number>([ [1, 2], [2, 3], [3, 4], [4, 5] ]),
|
||||
],
|
||||
// Sets with different number of entries should return false
|
||||
[
|
||||
new Set([1, 2, 3]),
|
||||
new Set([1, 2]),
|
||||
],
|
||||
[
|
||||
new Set([1, 2, 3]),
|
||||
new Set([4, 5, 6]),
|
||||
],
|
||||
])("Bun.deepMatch should return false for Maps/Sets with different contents (%p, %p)", (a, b) => {
|
||||
expect(Bun.deepMatch(a, b)).toBe(false);
|
||||
});
|
||||
|
||||
// Additional cases that were not working in the original issue
|
||||
test.each([
|
||||
[new Map([ ["foo", 1] ]), new Map([ [ "bar", 1 ] ])],
|
||||
[new Map([ ["foo", 1] ]), new Map([ [ "foo", 2 ] ])],
|
||||
])("Bun.deepMatch should return false for Maps with different keys/values (%p, %p)", (a, b) => {
|
||||
expect(Bun.deepMatch(a, b)).toBe(false);
|
||||
});
|
||||
|
||||
// These cases should also return false (different sizes, even if subset)
|
||||
test.each([
|
||||
[new Map([ ["foo", 1] ]), new Map([ [ "foo", 1 ], ["bar", 2] ])],
|
||||
[new Set([1, 2]), new Set([1, 2, 3])],
|
||||
])("Bun.deepMatch should return false for Maps/Sets with different sizes (%p, %p)", (a, b) => {
|
||||
expect(Bun.deepMatch(a, b)).toBe(false);
|
||||
});
|
||||
5
test/regression/issue/19107.test.ts
Normal file
5
test/regression/issue/19107.test.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
test.failing("no crash", () => {
|
||||
expect(() => {
|
||||
throw undefined;
|
||||
}).toThrow(TypeError);
|
||||
});
|
||||
Reference in New Issue
Block a user