Skip to content

Commit d786dd6

Browse files
authored
Update test runner output with colors and diffs (#2122)
* add zig-diff * move diff functions * toHaveProperty diff for objects * use formatter * format labels * move work to format, diff when it makes sense * remove comptime, dim equal slices * order before diff * line diffs * add diffz * switch to diffz * add `diffLines()` function * small `prettyFmt()` bug fix * test runner color output * update `toBe()` error output * fix test * diff method, fix crash * fix link test * remove `isRegex`
1 parent e21796a commit d786dd6

File tree

11 files changed

+3224
-173
lines changed

11 files changed

+3224
-173
lines changed

src/bun.js/api/bun.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ pub fn inspect(
246246
false,
247247
false,
248248
false,
249+
false,
250+
false,
249251
);
250252
buffered_writer.flush() catch {
251253
return JSC.C.JSValueMakeUndefined(ctx);

src/bun.js/bindings/bindings.cpp

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,23 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
9797
auto& internalHeaders = headers->internalHeaders();
9898

9999
for (auto& value : internalHeaders.getSetCookieHeaders()) {
100-
res->writeHeader(std::string_view("set-cookie", 10), std::string_view(
101-
value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()
102-
));
100+
res->writeHeader(std::string_view("set-cookie", 10), std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
103101
}
104102

105103
for (auto& header : internalHeaders.commonHeaders()) {
106104
const auto& name = WebCore::httpHeaderNameString(header.key);
107105
auto& value = header.value;
108106
res->writeHeader(
109107
std::string_view(name.is8Bit() ? reinterpret_cast<const char*>(name.characters8()) : name.utf8().data(), name.length()),
110-
std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length())
111-
);
108+
std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
112109
}
113110

114111
for (auto& header : internalHeaders.uncommonHeaders()) {
115112
auto& name = header.key;
116113
auto& value = header.value;
117114
res->writeHeader(
118115
std::string_view(name.is8Bit() ? reinterpret_cast<const char*>(name.characters8()) : name.utf8().data(), name.length()),
119-
std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length())
120-
);
116+
std::string_view(value.is8Bit() ? reinterpret_cast<const char*>(value.characters8()) : value.utf8().data(), value.length()));
121117
}
122118
}
123119

@@ -718,12 +714,11 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__createEmpty()
718714
return new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
719715
}
720716
void WebCore__FetchHeaders__append(WebCore__FetchHeaders* headers, const ZigString* arg1, const ZigString* arg2,
721-
JSC__JSGlobalObject* lexicalGlobalObject)
717+
JSC__JSGlobalObject* lexicalGlobalObject)
722718
{
723719
auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
724720
WebCore::propagateException(*lexicalGlobalObject, throwScope,
725-
headers->append(Zig::toString(*arg1), Zig::toString(*arg2))
726-
);
721+
headers->append(Zig::toString(*arg1), Zig::toString(*arg2)));
727722
}
728723
WebCore__FetchHeaders* WebCore__FetchHeaders__cast_(JSC__JSValue JSValue0, JSC__VM* vm)
729724
{
@@ -752,8 +747,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__createFromJS(JSC__JSGlobalObject*
752747
// ExceptionOr<void>. So we need to check for the exception and, if set,
753748
// translate it to JSValue and throw it.
754749
WebCore::propagateException(*lexicalGlobalObject, throwScope,
755-
headers->fill(WTFMove(init.value()))
756-
);
750+
headers->fill(WTFMove(init.value())));
757751
}
758752
return headers;
759753
}
@@ -770,8 +764,7 @@ JSC__JSValue WebCore__FetchHeaders__clone(WebCore__FetchHeaders* headers, JSC__J
770764
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg1);
771765
auto* clone = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
772766
WebCore::propagateException(*arg1, throwScope,
773-
clone->fill(*headers)
774-
);
767+
clone->fill(*headers));
775768
return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg1, globalObject, WTFMove(clone)));
776769
}
777770

@@ -780,8 +773,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__cloneThis(WebCore__FetchHeaders* h
780773
auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
781774
auto* clone = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} });
782775
WebCore::propagateException(*lexicalGlobalObject, throwScope,
783-
clone->fill(*headers)
784-
);
776+
clone->fill(*headers));
785777
return clone;
786778
}
787779

@@ -936,9 +928,8 @@ JSC__JSValue WebCore__FetchHeaders__createValue(JSC__JSGlobalObject* arg0, Strin
936928
}
937929

938930
Ref<WebCore::FetchHeaders> headers = WebCore::FetchHeaders::create();
939-
WebCore::propagateException(*arg0, throwScope,
940-
headers->fill(WebCore::FetchHeaders::Init(WTFMove(pairs)))
941-
);
931+
WebCore::propagateException(*arg0, throwScope,
932+
headers->fill(WebCore::FetchHeaders::Init(WTFMove(pairs))));
942933
pairs.releaseBuffer();
943934
return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg0, reinterpret_cast<Zig::GlobalObject*>(arg0), WTFMove(headers)));
944935
}
@@ -965,15 +956,13 @@ void WebCore__FetchHeaders__put_(WebCore__FetchHeaders* headers, const ZigString
965956
{
966957
auto throwScope = DECLARE_THROW_SCOPE(global->vm());
967958
WebCore::propagateException(*global, throwScope,
968-
headers->set(Zig::toString(*arg1), Zig::toString(*arg2))
969-
);
959+
headers->set(Zig::toString(*arg1), Zig::toString(*arg2)));
970960
}
971961
void WebCore__FetchHeaders__remove(WebCore__FetchHeaders* headers, const ZigString* arg1, JSC__JSGlobalObject* global)
972962
{
973963
auto throwScope = DECLARE_THROW_SCOPE(global->vm());
974964
WebCore::propagateException(*global, throwScope,
975-
headers->remove(Zig::toString(*arg1))
976-
);
965+
headers->remove(Zig::toString(*arg1)));
977966
}
978967

979968
void WebCore__FetchHeaders__fastRemove_(WebCore__FetchHeaders* headers, unsigned char headerName)
@@ -3762,6 +3751,40 @@ void JSC__JSValue__forEachProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* g
37623751
}
37633752
}
37643753

3754+
inline bool propertyCompare(const std::pair<String, JSValue>& a, const std::pair<String, JSValue>& b)
3755+
{
3756+
return codePointCompare(a.first.impl(), b.first.impl()) < 0;
3757+
}
3758+
3759+
void JSC__JSValue__forEachPropertyOrdered(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, void* arg2, void (*iter)(JSC__JSGlobalObject* arg0, void* ctx, ZigString* arg2, JSC__JSValue JSValue3, bool isSymbol))
3760+
{
3761+
JSC::JSValue value = JSC::JSValue::decode(JSValue0);
3762+
JSC::JSObject* object = value.getObject();
3763+
if (!object)
3764+
return;
3765+
3766+
JSC::VM& vm = globalObject->vm();
3767+
auto scope = DECLARE_CATCH_SCOPE(vm);
3768+
3769+
JSC::PropertyNameArray properties(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
3770+
JSC::JSObject::getOwnPropertyNames(object, globalObject, properties, DontEnumPropertiesMode::Include);
3771+
3772+
Vector<std::pair<String, JSValue>> ordered_properties;
3773+
for (auto property : properties) {
3774+
JSValue propertyValue = object->getDirect(vm, property);
3775+
ordered_properties.append(std::pair<String, JSValue>(property.isSymbol() && !property.isPrivateName() ? property.impl() : property.string(), propertyValue));
3776+
}
3777+
3778+
std::sort(ordered_properties.begin(), ordered_properties.end(), propertyCompare);
3779+
3780+
for (auto item : ordered_properties) {
3781+
ZigString key = toZigString(item.first);
3782+
JSValue propertyValue = item.second;
3783+
JSC::EnsureStillAliveScope ensureStillAliveScope(propertyValue);
3784+
iter(globalObject, arg2, &key, JSC::JSValue::encode(propertyValue), propertyValue.isSymbol());
3785+
}
3786+
}
3787+
37653788
extern "C" JSC__JSValue JSC__JSValue__createRopeString(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
37663789
{
37673790
return JSValue::encode(JSC::jsString(globalObject, JSC::JSValue::decode(JSValue0).toString(globalObject), JSC::JSValue::decode(JSValue1).toString(globalObject)));
@@ -3796,39 +3819,44 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject* arg0
37963819
JSC::JSValue::decode(JSValue4));
37973820
}
37983821

3799-
extern "C" JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1) {
3822+
extern "C" JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1)
3823+
{
38003824
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
38013825
abortSignal->signalAbort(JSC::JSValue::decode(JSValue1));
38023826
return arg0;
38033827
}
38043828

3805-
extern "C" bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0) {
3829+
extern "C" bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0)
3830+
{
38063831
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
38073832
return abortSignal->aborted();
38083833
}
38093834

3810-
extern "C" JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0) {
3835+
extern "C" JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0)
3836+
{
38113837
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
38123838
return JSC::JSValue::encode(abortSignal->reason().getValue());
38133839
}
38143840

3815-
3816-
extern "C" JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0) {
3841+
extern "C" JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0)
3842+
{
38173843
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
38183844
abortSignal->ref();
38193845
return arg0;
38203846
}
38213847

3822-
extern "C" JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0) {
3848+
extern "C" JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0)
3849+
{
38233850
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
38243851
abortSignal->deref();
38253852
return arg0;
38263853
}
38273854

3828-
extern "C" JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* ctx, void (*callback)(void* ctx, JSC__JSValue reason)) {
3855+
extern "C" JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* ctx, void (*callback)(void* ctx, JSC__JSValue reason))
3856+
{
38293857
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
3830-
3831-
if(abortSignal->aborted()){
3858+
3859+
if (abortSignal->aborted()) {
38323860
callback(ctx, JSC::JSValue::encode(abortSignal->reason().getValue()));
38333861
return arg0;
38343862
}
@@ -3859,7 +3887,7 @@ extern "C" JSC__JSValue JSC__AbortSignal__createAbortError(const ZigString* mess
38593887
error->putDirect(
38603888
vm, vm.propertyNames->name,
38613889
JSC::JSValue(JSC::jsOwnedString(vm, ABORT_ERROR_NAME)),
3862-
0);
3890+
0);
38633891

38643892
if (code.len > 0) {
38653893
auto clientData = WebCore::clientData(vm);
@@ -3881,7 +3909,7 @@ extern "C" JSC__JSValue JSC__AbortSignal__createTimeoutError(const ZigString* me
38813909
error->putDirect(
38823910
vm, vm.propertyNames->name,
38833911
JSC::JSValue(JSC::jsOwnedString(vm, TIMEOUT_ERROR_NAME)),
3884-
0);
3912+
0);
38853913

38863914
if (code.len > 0) {
38873915
auto clientData = WebCore::clientData(vm);

src/bun.js/bindings/bindings.zig

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ pub const ZigString = extern struct {
211211

212212
pub fn substring(this: ZigString, offset: usize, maxlen: usize) ZigString {
213213
var len: usize = undefined;
214-
if(maxlen == 0){
214+
if (maxlen == 0) {
215215
len = this.len;
216-
}else {
216+
} else {
217217
len = @max(this.len, maxlen);
218218
}
219-
219+
220220
if (this.is16Bit()) {
221221
return ZigString.from16Slice(this.utf16SliceAligned()[@min(this.len, offset)..len]);
222222
}
@@ -2911,6 +2911,15 @@ pub const JSValue = enum(JSValueReprInt) {
29112911
cppFn("forEachProperty", .{ this, globalThis, ctx, callback });
29122912
}
29132913

2914+
pub fn forEachPropertyOrdered(
2915+
this: JSValue,
2916+
globalObject: *JSC.JSGlobalObject,
2917+
ctx: ?*anyopaque,
2918+
callback: PropertyIteratorFn,
2919+
) void {
2920+
cppFn("forEachPropertyOrdered", .{ this, globalObject, ctx, callback });
2921+
}
2922+
29142923
pub fn coerce(this: JSValue, comptime T: type, globalThis: *JSC.JSGlobalObject) T {
29152924
return switch (T) {
29162925
ZigString => this.getZigString(globalThis),
@@ -3638,6 +3647,19 @@ pub const JSValue = enum(JSValueReprInt) {
36383647
return cppFn("strictDeepEquals", .{ this, other, global });
36393648
}
36403649

3650+
pub const DiffMethod = enum(u8) {
3651+
none,
3652+
character,
3653+
word,
3654+
line,
3655+
};
3656+
3657+
pub fn determineDiffMethod(this: JSValue, other: JSValue, global: *JSGlobalObject) DiffMethod {
3658+
if ((this.isString() and other.isString()) or (this.jsType() == .RegExpObject and other.jsType() == .RegExpObject) or (this.isBuffer(global) and other.isBuffer(global))) return .character;
3659+
if (this.isObject() and other.isObject()) return .line;
3660+
return .none;
3661+
}
3662+
36413663
pub fn asString(this: JSValue) *JSString {
36423664
return cppFn("asString", .{
36433665
this,
@@ -3852,6 +3874,7 @@ pub const JSValue = enum(JSValueReprInt) {
38523874
"fastGet_",
38533875
"forEach",
38543876
"forEachProperty",
3877+
"forEachPropertyOrdered",
38553878
"fromEntries",
38563879
"fromInt64NoTruncate",
38573880
"fromUInt64NoTruncate",

src/bun.js/bindings/exports.zig

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,8 @@ pub const ZigConsoleClient = struct {
967967
enable_colors,
968968
true,
969969
true,
970+
false,
971+
false,
970972
)
971973
else if (message_type == .Log) {
972974
_ = console.writer.write("\n") catch 0;
@@ -1015,6 +1017,8 @@ pub const ZigConsoleClient = struct {
10151017
enable_colors: bool,
10161018
add_newline: bool,
10171019
flush: bool,
1020+
order_properties: bool,
1021+
quote_strings: bool,
10181022
) void {
10191023
var fmt: ZigConsoleClient.Formatter = undefined;
10201024
defer {
@@ -1026,7 +1030,12 @@ pub const ZigConsoleClient = struct {
10261030
}
10271031

10281032
if (len == 1) {
1029-
fmt = ZigConsoleClient.Formatter{ .remaining_values = &[_]JSValue{}, .globalThis = global };
1033+
fmt = ZigConsoleClient.Formatter{
1034+
.remaining_values = &[_]JSValue{},
1035+
.globalThis = global,
1036+
.ordered_properties = order_properties,
1037+
.quote_strings = quote_strings,
1038+
};
10301039
const tag = ZigConsoleClient.Formatter.Tag.get(vals[0], global);
10311040

10321041
var unbuffered_writer = if (comptime Writer != RawWriter)
@@ -1099,7 +1108,12 @@ pub const ZigConsoleClient = struct {
10991108
}
11001109

11011110
var this_value: JSValue = vals[0];
1102-
fmt = ZigConsoleClient.Formatter{ .remaining_values = vals[0..len][1..], .globalThis = global };
1111+
fmt = ZigConsoleClient.Formatter{
1112+
.remaining_values = vals[0..len][1..],
1113+
.globalThis = global,
1114+
.ordered_properties = order_properties,
1115+
.quote_strings = quote_strings,
1116+
};
11031117
var tag: ZigConsoleClient.Formatter.Tag.Result = undefined;
11041118

11051119
var any = false;
@@ -1163,6 +1177,7 @@ pub const ZigConsoleClient = struct {
11631177
failed: bool = false,
11641178
estimated_line_length: usize = 0,
11651179
always_newline_scope: bool = false,
1180+
ordered_properties: bool = false,
11661181

11671182
pub fn goodTimeForANewLine(this: *@This()) bool {
11681183
if (this.estimated_line_length > 80) {
@@ -2541,7 +2556,11 @@ pub const ZigConsoleClient = struct {
25412556
.parent = value,
25422557
};
25432558

2544-
value.forEachProperty(this.globalThis, &iter, Iterator.forEach);
2559+
if (this.ordered_properties) {
2560+
value.forEachPropertyOrdered(this.globalThis, &iter, Iterator.forEach);
2561+
} else {
2562+
value.forEachProperty(this.globalThis, &iter, Iterator.forEach);
2563+
}
25452564

25462565
if (iter.i == 0) {
25472566
if (value.isClass(this.globalThis) and !value.isCallable(this.globalThis.vm()))

src/bun.js/bindings/headers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// clang-format off
2-
//-- AUTOGENERATED FILE -- 1676656020
2+
//-- AUTOGENERATED FILE -- 1676945760
33
#pragma once
44

55
#include <stddef.h>
@@ -296,6 +296,7 @@ CPP_DECL bool JSC__JSValue__eqlValue(JSC__JSValue JSValue0, JSC__JSValue JSValue
296296
CPP_DECL JSC__JSValue JSC__JSValue__fastGet_(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, unsigned char arg2);
297297
CPP_DECL void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__VM* arg0, JSC__JSGlobalObject* arg1, void* arg2, JSC__JSValue JSValue3)) __attribute__((nonnull (3)));
298298
CPP_DECL void JSC__JSValue__forEachProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
299+
CPP_DECL void JSC__JSValue__forEachPropertyOrdered(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
299300
CPP_DECL JSC__JSValue JSC__JSValue__fromEntries(JSC__JSGlobalObject* arg0, ZigString* arg1, ZigString* arg2, size_t arg3, bool arg4);
300301
CPP_DECL JSC__JSValue JSC__JSValue__fromInt64NoTruncate(JSC__JSGlobalObject* arg0, int64_t arg1);
301302
CPP_DECL JSC__JSValue JSC__JSValue__fromUInt64NoTruncate(JSC__JSGlobalObject* arg0, uint64_t arg1);

src/bun.js/bindings/headers.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSVa
209209
pub extern fn JSC__JSValue__fastGet_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue;
210210
pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.VM, *bindings.JSGlobalObject, ?*anyopaque, JSC__JSValue) callconv(.C) void) void;
211211
pub extern fn JSC__JSValue__forEachProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
212+
pub extern fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
212213
pub extern fn JSC__JSValue__fromEntries(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString, arg2: [*c]ZigString, arg3: usize, arg4: bool) JSC__JSValue;
213214
pub extern fn JSC__JSValue__fromInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: i64) JSC__JSValue;
214215
pub extern fn JSC__JSValue__fromUInt64NoTruncate(arg0: *bindings.JSGlobalObject, arg1: u64) JSC__JSValue;

0 commit comments

Comments
 (0)