mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
80 Commits
claude/add
...
pfg/asymme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0722893599 | ||
|
|
448158d41f | ||
|
|
7437f2d72b | ||
|
|
53527c2cca | ||
|
|
f0aacc3ef2 | ||
|
|
379d432af5 | ||
|
|
dfce9da151 | ||
|
|
8e28e14da2 | ||
|
|
7d0a037ff6 | ||
|
|
ae07e46e25 | ||
|
|
d8a2b706f9 | ||
|
|
a443d4553d | ||
|
|
a66b9dd73d | ||
|
|
72d4ff4aa5 | ||
|
|
ddabc333c1 | ||
|
|
50516e6d06 | ||
|
|
2d3737484a | ||
|
|
c932120d25 | ||
|
|
7b40384b32 | ||
|
|
338ede0a38 | ||
|
|
57efa029c2 | ||
|
|
499d219758 | ||
|
|
b974032cc8 | ||
|
|
55efdcf308 | ||
|
|
aeba5c0b01 | ||
|
|
9a55321997 | ||
|
|
f967e3dca3 | ||
|
|
e382b41cbb | ||
|
|
7a45cc1dc4 | ||
|
|
6528bb9166 | ||
|
|
87521761e7 | ||
|
|
4d2873b4d1 | ||
|
|
38e23a48da | ||
|
|
8f0832f084 | ||
|
|
5a36d29b29 | ||
|
|
9b61830918 | ||
|
|
b1a85cbc3f | ||
|
|
6894faff13 | ||
|
|
5a288c9c73 | ||
|
|
e9b868ce73 | ||
|
|
dda5fdd112 | ||
|
|
1df2cff6c0 | ||
|
|
277656141a | ||
|
|
26191c8d80 | ||
|
|
bede794ff5 | ||
|
|
73663151b1 | ||
|
|
4abb5ab957 | ||
|
|
87d4f12d6a | ||
|
|
334b90749f | ||
|
|
f0b11e0594 | ||
|
|
9142897c4b | ||
|
|
6bc080c351 | ||
|
|
e0aeb0c076 | ||
|
|
1dcc97210b | ||
|
|
f88301cda1 | ||
|
|
47b9882340 | ||
|
|
436bd8a9e1 | ||
|
|
b069f71fed | ||
|
|
e9c205d25a | ||
|
|
c647c914af | ||
|
|
e65b9803d7 | ||
|
|
f5265c784e | ||
|
|
d63b83e6e5 | ||
|
|
21a00bd3c6 | ||
|
|
94f46841dc | ||
|
|
ce0d0dbe5b | ||
|
|
1f988b9705 | ||
|
|
8073f7c473 | ||
|
|
c31c507559 | ||
|
|
c84b2f8506 | ||
|
|
d1a58e6ef0 | ||
|
|
5ec8bc9201 | ||
|
|
ae8fa57d65 | ||
|
|
b6896fbd44 | ||
|
|
e520accfd2 | ||
|
|
678bf0c3fb | ||
|
|
f093751e9b | ||
|
|
3956e7ded5 | ||
|
|
4454e0fd45 | ||
|
|
416d159c83 |
@@ -250,6 +250,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
|
||||
@@ -487,7 +489,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
|
||||
|
||||
@@ -544,7 +544,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, J
|
||||
std::set<EncodedJSValue> objVisited;
|
||||
std::set<EncodedJSValue> subsetVisited;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
bool match = Bun__deepMatch</* enableAsymmetricMatchers */ false>(object, &objVisited, subset, &subsetVisited, globalObject, scope, &gcBuffer, false, false);
|
||||
bool match = Bun__deepMatch</* enableAsymmetricMatchers */ false>(object, &objVisited, subset, &subsetVisited, globalObject, scope, &gcBuffer, false);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsBoolean(match));
|
||||
}
|
||||
|
||||
@@ -1855,10 +1855,10 @@ pub const JSValue = enum(i64) {
|
||||
pub fn jestStrictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) JSError!bool {
|
||||
return bun.jsc.fromJSHostCallGeneric(global, @src(), JSC__JSValue__jestStrictDeepEquals, .{ this, other, global });
|
||||
}
|
||||
extern fn JSC__JSValue__jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) bool;
|
||||
extern fn JSC__JSValue__jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject) bool;
|
||||
/// same as `JSValue.deepMatch`, but with jest asymmetric matchers enabled
|
||||
pub fn jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) JSError!bool {
|
||||
return bun.jsc.fromJSHostCallGeneric(global, @src(), JSC__JSValue__jestDeepMatch, .{ this, subset, global, replace_props_with_asymmetric_matchers });
|
||||
pub fn jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject) JSError!bool {
|
||||
return bun.jsc.fromJSHostCallGeneric(global, @src(), JSC__JSValue__jestDeepMatch, .{ this, subset, global });
|
||||
}
|
||||
|
||||
pub const DiffMethod = enum(u8) {
|
||||
|
||||
@@ -199,7 +199,6 @@ template bool Bun__deepMatch<true>(
|
||||
JSGlobalObject* globalObject,
|
||||
ThrowScope& throwScope,
|
||||
MarkedArgumentBuffer* gcBuffer,
|
||||
bool replacePropsWithAsymmetricMatchers,
|
||||
bool isMatchingObjectContaining);
|
||||
|
||||
template bool Bun__deepMatch<false>(
|
||||
@@ -210,7 +209,6 @@ template bool Bun__deepMatch<false>(
|
||||
JSGlobalObject* globalObject,
|
||||
ThrowScope& throwScope,
|
||||
MarkedArgumentBuffer* gcBuffer,
|
||||
bool replacePropsWithAsymmetricMatchers,
|
||||
bool isMatchingObjectContaining);
|
||||
|
||||
extern "C" bool Expect_readFlagsAndProcessPromise(JSC::EncodedJSValue instanceValue, JSC::JSGlobalObject* globalObject, ExpectFlags* flags, JSC::EncodedJSValue* value, AsymmetricMatcherConstructorType* constructorType);
|
||||
@@ -499,7 +497,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
|
||||
// SAFETY: visited property sets are not required when
|
||||
// `enableAsymmetricMatchers` and `isMatchingObjectContaining`
|
||||
// are both true
|
||||
bool match = Bun__deepMatch<true>(otherProp, nullptr, patternObject, nullptr, globalObject, throwScope, nullptr, false, true);
|
||||
bool match = Bun__deepMatch<true>(otherProp, nullptr, patternObject, nullptr, globalObject, throwScope, nullptr, true);
|
||||
RETURN_IF_EXCEPTION(throwScope, AsymmetricMatcherResult::FAIL);
|
||||
if (match) {
|
||||
return AsymmetricMatcherResult::PASS;
|
||||
@@ -1571,7 +1569,6 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
* @param globalObject
|
||||
* @param throwScope
|
||||
* @param gcBuffer
|
||||
* @param replacePropsWithAsymmetricMatchers
|
||||
* @param isMatchingObjectContaining
|
||||
*
|
||||
* @return true
|
||||
@@ -1586,7 +1583,6 @@ bool Bun__deepMatch(
|
||||
JSGlobalObject* globalObject,
|
||||
ThrowScope& throwScope,
|
||||
MarkedArgumentBuffer* gcBuffer,
|
||||
bool replacePropsWithAsymmetricMatchers,
|
||||
bool isMatchingObjectContaining)
|
||||
{
|
||||
|
||||
@@ -1640,10 +1636,6 @@ bool Bun__deepMatch(
|
||||
case AsymmetricMatcherResult::FAIL:
|
||||
return false;
|
||||
case AsymmetricMatcherResult::PASS:
|
||||
if (replacePropsWithAsymmetricMatchers) {
|
||||
obj->putDirectMayBeIndex(globalObject, property, subsetProp);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
}
|
||||
// continue to next subset prop
|
||||
continue;
|
||||
case AsymmetricMatcherResult::NOT_MATCHER:
|
||||
@@ -1654,10 +1646,6 @@ bool Bun__deepMatch(
|
||||
case AsymmetricMatcherResult::FAIL:
|
||||
return false;
|
||||
case AsymmetricMatcherResult::PASS:
|
||||
if (replacePropsWithAsymmetricMatchers) {
|
||||
subsetObj->putDirectMayBeIndex(globalObject, property, prop);
|
||||
RETURN_IF_EXCEPTION(throwScope, false);
|
||||
}
|
||||
// continue to next subset prop
|
||||
continue;
|
||||
case AsymmetricMatcherResult::NOT_MATCHER:
|
||||
@@ -1686,7 +1674,7 @@ bool Bun__deepMatch(
|
||||
gcBuffer->append(subsetProp);
|
||||
// property cycle detected
|
||||
if (!didInsertProp.second || !didInsertSubset.second) continue;
|
||||
if (!Bun__deepMatch<enableAsymmetricMatchers>(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) {
|
||||
if (!Bun__deepMatch<enableAsymmetricMatchers>(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, isMatchingObjectContaining)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2612,7 +2600,7 @@ bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::Encod
|
||||
|
||||
#undef IMPL_DEEP_EQUALS_WRAPPER
|
||||
|
||||
bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers)
|
||||
bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
JSValue obj = JSValue::decode(JSValue0);
|
||||
JSValue subset = JSValue::decode(JSValue1);
|
||||
@@ -2622,7 +2610,7 @@ bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSVal
|
||||
std::set<EncodedJSValue> objVisited;
|
||||
std::set<EncodedJSValue> subsetVisited;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
RELEASE_AND_RETURN(scope, Bun__deepMatch<true>(obj, &objVisited, subset, &subsetVisited, globalObject, scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false));
|
||||
RELEASE_AND_RETURN(scope, Bun__deepMatch<true>(obj, &objVisited, subset, &subsetVisited, globalObject, scope, &gcBuffer, false));
|
||||
}
|
||||
|
||||
extern "C" bool Bun__JSValue__isAsyncContextFrame(JSC::EncodedJSValue value)
|
||||
|
||||
@@ -432,7 +432,6 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JS
|
||||
* @param globalObject
|
||||
* @param Scope
|
||||
* @param gcBuffer
|
||||
* @param replacePropsWithAsymmetricMatchers
|
||||
* @param isMatchingObjectContaining
|
||||
*
|
||||
* @return true
|
||||
@@ -447,7 +446,6 @@ bool Bun__deepMatch(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
JSC::ThrowScope& throwScope,
|
||||
JSC::MarkedArgumentBuffer* gcBuffer,
|
||||
bool replacePropsWithAsymmetricMatchers,
|
||||
bool isMatchingObjectContaining);
|
||||
|
||||
extern "C" void Bun__remapStackFramePositions(void*, ZigStackFrame*, size_t);
|
||||
|
||||
2
src/bun.js/bindings/headers.h
generated
2
src/bun.js/bindings/headers.h
generated
@@ -259,7 +259,7 @@ CPP_DECL bool JSC__JSValue__isSymbol(JSC::EncodedJSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isTerminationException(JSC::EncodedJSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__isUInt32AsAnyInt(JSC::EncodedJSValue JSValue0);
|
||||
CPP_DECL bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2);
|
||||
CPP_DECL bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2, bool arg3);
|
||||
CPP_DECL bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2);
|
||||
CPP_DECL bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2);
|
||||
CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsDoubleNumber(double arg0);
|
||||
CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsNull();
|
||||
|
||||
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
515
src/bun.js/test/diff/printDiff.zig
Normal file
515
src/bun.js/test/diff/printDiff.zig
Normal file
@@ -0,0 +1,515 @@
|
||||
//! 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);
|
||||
try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
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,
|
||||
removed_prefix: PrefixStyle,
|
||||
inserted_prefix: PrefixStyle,
|
||||
) !void {
|
||||
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);
|
||||
try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
fn printModifiedSegment(
|
||||
segment: DiffSegment,
|
||||
arena: std.mem.Allocator,
|
||||
writer: anytype,
|
||||
config: DiffConfig,
|
||||
modified_style: struct { single_line: bool },
|
||||
) !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, removed_prefix, inserted_prefix);
|
||||
}
|
||||
|
||||
var char_diff = try DMP.default.diff(arena, segment.removed, segment.inserted, true);
|
||||
try DMP.diffCleanupSemantic(arena, &char_diff);
|
||||
|
||||
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, removed_prefix, inserted_prefix);
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -2884,7 +2884,7 @@ pub const Expect = struct {
|
||||
|
||||
const prop_matchers = _prop_matchers;
|
||||
|
||||
if (!try value.jestDeepMatch(prop_matchers, globalThis, true)) {
|
||||
if (!try value.jestDeepMatch(prop_matchers, globalThis)) {
|
||||
// TODO: print diff with properties from propertyMatchers
|
||||
const signature = comptime getSignature(fn_name, "<green>propertyMatchers<r>", false);
|
||||
const fmt = signature ++ "\n\nExpected <green>propertyMatchers<r> to match properties from received object" ++
|
||||
@@ -4285,7 +4285,7 @@ pub const Expect = struct {
|
||||
|
||||
const property_matchers = args[0];
|
||||
|
||||
var pass = try received_object.jestDeepMatch(property_matchers, globalThis, true);
|
||||
var pass = try received_object.jestDeepMatch(property_matchers, globalThis);
|
||||
|
||||
if (not) pass = !pass;
|
||||
if (pass) return .js_undefined;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
});
|
||||
870
test/js/bun/test/printing/diffexample.test.ts
Normal file
870
test/js/bun/test/printing/diffexample.test.ts
Normal file
@@ -0,0 +1,870 @@
|
||||
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 "\x1B[0m\x1B[32m\x1B[7mLogged into system",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7m "Accessed dashboard",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7m "Reviewed daily reports",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7m "Updated project status",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7m "Sent status email to team",\x1B[0m
|
||||
\x1B[32m- \x1B[0m\x1B[32m\x1B[7m "Scheduled follow-up meeting\x1B[0m\x1B[32m",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m "\x1B[0m\x1B[31m\x1B[7mEntered the building",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7m "Checked in at reception",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7m "Took elevator to floor 3",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7m "Attended morning meeting",\x1B[0m
|
||||
\x1B[31m+ \x1B[0m\x1B[31m\x1B[7m "Started working on project\x1B[0m\x1B[31m",\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", () => {
|
||||
|
||||
Reference in New Issue
Block a user