Compare commits

...

80 Commits

Author SHA1 Message Date
pfg
0722893599 remove 'replacePropsWithAsymmetricMatchers' 2025-08-01 12:44:48 -07:00
autofix-ci[bot]
448158d41f [autofix.ci] apply automated fixes 2025-07-31 01:24:08 +00:00
pfg
7437f2d72b add a test case for the utf-8 2025-07-30 18:21:12 -07:00
pfg
53527c2cca workaround invalid utf-8 issue 2025-07-30 18:19:16 -07:00
pfg
f0aacc3ef2 Merge branch 'main' into pfg/bun-test-diff 2025-07-30 15:25:41 -07:00
autofix-ci[bot]
379d432af5 [autofix.ci] apply automated fixes 2025-07-30 03:30:09 +00:00
pfg
dfce9da151 update snapshots 2025-07-29 20:26:53 -07:00
pfg
8e28e14da2 diff update 2025-07-29 20:24:06 -07:00
pfg
7d0a037ff6 windows fix? 2025-07-29 15:24:35 -07:00
pfg
ae07e46e25 Merge remote-tracking branch 'origin/main' into pfg/bun-test-diff 2025-07-29 14:22:59 -07:00
pfg
d8a2b706f9 fix diffexample failure 2025-07-29 14:22:52 -07:00
pfg
a443d4553d update snapshot.test.ts.snap 2025-07-29 14:21:13 -07:00
pfg
a66b9dd73d remove extra padding around jestprettyformatted items 2025-07-29 14:14:30 -07:00
autofix-ci[bot]
72d4ff4aa5 [autofix.ci] apply automated fixes 2025-07-29 05:01:12 +00:00
pfg
ddabc333c1 Merge remote-tracking branch 'origin/main' into pfg/bun-test-diff 2025-07-28 21:57:04 -07:00
pfg
50516e6d06 remove unused 2025-07-28 21:55:24 -07:00
pfg
2d3737484a change hunk headers to yellow 2025-07-28 21:52:15 -07:00
pfg
c932120d25 note 2025-07-28 21:43:16 -07:00
pfg
7b40384b32 add color test for chunking 2025-07-28 21:42:34 -07:00
pfg
338ede0a38 update to use 5 chunk context lines and 100 truncate context 2025-07-28 21:41:03 -07:00
pfg
57efa029c2 diffexample upd 2025-07-28 21:37:43 -07:00
pfg
499d219758 , 2025-07-28 21:29:57 -07:00
pfg
b974032cc8 remove 'zig' 2025-07-28 21:29:53 -07:00
pfg
55efdcf308 mark the diff example as TODO 2025-07-28 21:29:38 -07:00
pfg
aeba5c0b01 ban-words fix 2025-07-28 21:02:30 -07:00
pfg
9a55321997 fix diffexample flaky 2025-07-28 20:51:11 -07:00
pfg
f967e3dca3 Merge remote-tracking branch 'origin/main' into pfg/bun-test-diff 2025-07-24 19:33:26 -07:00
pfg
e382b41cbb fix line counts & print not in red 2025-07-24 19:18:18 -07:00
pfg
7a45cc1dc4 add 2025-07-24 19:15:07 -07:00
pfg
6528bb9166 test case for utf-16 change 2025-07-24 15:05:33 -07:00
pfg
87521761e7 utf-16 change fix 2025-07-24 14:57:28 -07:00
pfg
4d2873b4d1 emojis fix 2025-07-23 21:07:41 -07:00
pfg
38e23a48da keep exact previous behaviour 2025-07-23 20:57:42 -07:00
pfg
8f0832f084 writePreQuotedString fix 2025-07-23 20:45:27 -07:00
pfg
5a36d29b29 js_printer utf16 fix 2025-07-23 20:35:41 -07:00
pfg
9b61830918 add copyright header to diff_match_patch 2025-07-23 19:33:06 -07:00
pfg
b1a85cbc3f update test-test snapshot for new diff format 2025-07-23 19:29:20 -07:00
pfg
6894faff13 consolelogexample fix 2025-07-23 19:27:50 -07:00
pfg
5a288c9c73 ban-words fix 2025-07-23 19:22:25 -07:00
pfg
e9b868ce73 update snapshot snapshot for the new diff format 2025-07-23 19:17:27 -07:00
pfg
dda5fdd112 diff print update (remove extra newline, add single-line display) 2025-07-23 18:53:49 -07:00
pfg
1df2cff6c0 truncate long diff segments 2025-07-23 18:14:15 -07:00
pfg
277656141a switch to x1b[7m 2025-07-22 16:02:40 -07:00
pfg
26191c8d80 fix bad diffs 2025-07-22 14:02:28 -07:00
pfg
bede794ff5 fix 2025-07-22 13:58:57 -07:00
pfg
73663151b1 Merge branch 'main' into pfg/bun-test-diff 2025-07-22 13:36:31 -07:00
autofix-ci[bot]
4abb5ab957 [autofix.ci] apply automated fixes 2025-07-22 04:37:49 +00:00
pfg
87d4f12d6a Merge branch 'main' into pfg/bun-test-diff 2025-07-21 21:34:35 -07:00
pfg
334b90749f use semantic cleanup 2025-07-21 21:08:24 -07:00
pfg
f0b11e0594 heuristic to reduce over-diffs 2025-07-21 20:56:12 -07:00
pfg
9142897c4b Merge remote-tracking branch 'origin/main' into pfg/bun-test-diff 2025-07-21 20:20:04 -07:00
pfg
6bc080c351 multiline_strings only for diff formatting 2025-07-18 16:30:44 -07:00
pfg
e0aeb0c076 update 2025-07-18 16:07:09 -07:00
pfg
1dcc97210b update 2025-07-18 16:07:09 -07:00
pfg
f88301cda1 printDiff update 2025-07-18 16:07:09 -07:00
autofix-ci[bot]
47b9882340 [autofix.ci] apply automated fixes 2025-07-18 04:35:19 +00:00
pfg
436bd8a9e1 upd 2025-07-17 21:20:25 -07:00
pfg
b069f71fed some more examples 2025-07-17 21:16:29 -07:00
pfg
e9c205d25a don't need the whole fixture for consolelogexample there's bun.inspect 2025-07-17 20:50:25 -07:00
pfg
c647c914af what's updiff 2025-07-17 20:48:20 -07:00
pfg
e65b9803d7 test that colored output is the same as no color output but without the color 2025-07-17 20:38:07 -07:00
pfg
f5265c784e latin1 & unicode tests 2025-07-16 17:30:41 -07:00
pfg
d63b83e6e5 test the color codes 2025-07-16 17:11:17 -07:00
pfg
21a00bd3c6 diffexample ansi colors 2025-07-16 17:02:09 -07:00
pfg
94f46841dc oops 2025-07-16 17:01:04 -07:00
pfg
ce0d0dbe5b snapshot the output 2025-07-16 17:00:35 -07:00
pfg
1f988b9705 chunk prints 2025-07-16 16:45:00 -07:00
pfg
8073f7c473 upd 2025-07-16 16:22:27 -07:00
pfg
c31c507559 ,? 2025-07-16 15:52:11 -07:00
pfg
c84b2f8506 wip 2025-07-15 21:29:47 -07:00
pfg
d1a58e6ef0 wip 2025-07-15 21:16:15 -07:00
pfg
5ec8bc9201 wip 2025-07-15 20:51:41 -07:00
pfg
ae8fa57d65 add a long sample 2025-07-15 20:37:41 -07:00
pfg
b6896fbd44 remove the error print. the problem is it calls printErrorlikeObject directly on the writer without indenting. 2025-07-15 20:31:02 -07:00
pfg
e520accfd2 ,, 2025-07-15 20:26:38 -07:00
pfg
678bf0c3fb move & add 2025-07-15 20:19:05 -07:00
pfg
f093751e9b multiline strings?? 2025-07-15 20:13:25 -07:00
pfg
3956e7ded5 sortImports in ConsoleObject 2025-07-15 19:42:52 -07:00
pfg
4454e0fd45 wip2 2025-07-15 19:37:15 -07:00
pfg
416d159c83 wip 2025-07-15 19:26:19 -07:00
17 changed files with 4840 additions and 2533 deletions

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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);

View File

@@ -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();

File diff suppressed because it is too large Load Diff

View 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");

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View 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);
}

View 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);
});

View 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
*/

View File

@@ -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
"
`;

View File

@@ -879,7 +879,7 @@ test("indented inline snapshots", () => {
"a": 2,
}
`);
}).toThrowErrorMatchingSnapshot();
}).toThrow();
});
test("error snapshots", () => {