aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Dylan Conway <35280289+dylan-conway@users.noreply.github.com> 2022-12-01 19:36:47 -0800
committerGravatar GitHub <noreply@github.com> 2022-12-01 19:36:47 -0800
commit92da72beb03dd686209428fcd0951b57d41e854c (patch)
tree3173a7671637c45d1456210eae519da8381b59c1 /src
parenta896d6c46c5a2ed6cf28c885d3077df972e7be43 (diff)
downloadbun-92da72beb03dd686209428fcd0951b57d41e854c.tar.gz
bun-92da72beb03dd686209428fcd0951b57d41e854c.tar.zst
bun-92da72beb03dd686209428fcd0951b57d41e854c.zip
bun test `toStrictEqual` (#1568)
* toStrictEqual and bug fix in deepEqual * rebase Remove some dead bindings code * remove debugging test * canGetIndexQuickly for array holes * isStrict template Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp2
-rw-r--r--src/bun.js/bindings/bindings.cpp142
-rw-r--r--src/bun.js/bindings/bindings.zig6
-rw-r--r--src/bun.js/bindings/headers-handwritten.h1
-rw-r--r--src/bun.js/bindings/headers.h3
-rw-r--r--src/bun.js/bindings/headers.zig1
-rw-r--r--src/bun.js/test/jest.zig43
7 files changed, 152 insertions, 46 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index bcb42dc29..50a07f06e 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -1803,7 +1803,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepEquals, (JSGlobalObject * globalObject,
Vector<std::pair<JSValue, JSValue>, 16> stack;
- bool isEqual = Bun__deepEquals(globalObject, arg1, arg2, stack, &scope, true);
+ bool isEqual = Bun__deepEquals<false>(globalObject, arg1, arg2, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
}
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 410855a8c..fe778ce42 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -152,6 +152,7 @@ static bool canPerformFastPropertyEnumerationForIterationBun(Structure* s)
return true;
}
+template<bool isStrict>
bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack)
{
VM& vm = globalObject->vm();
@@ -184,6 +185,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSCell* c1 = v1.asCell();
JSCell* c2 = v2.asCell();
+ JSObject* o1 = v1.getObject();
+ JSObject* o2 = v2.getObject();
JSC::JSType c1Type = c1->type();
JSC::JSType c2Type = c2->type();
@@ -223,7 +226,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
RETURN_IF_EXCEPTION(*scope, false);
// set has unique values, no need to count
- if (Bun__deepEquals(globalObject, nextValue1, nextValue2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
found = true;
if (!nextValue1.isPrimitive()) {
stack.append({ nextValue1, nextValue2 });
@@ -303,8 +306,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSValue value2 = nextValueObject2->getIndex(globalObject, static_cast<unsigned>(1));
RETURN_IF_EXCEPTION(*scope, false);
- if (Bun__deepEquals(globalObject, key1, key2, stack, scope, false)) {
- if (Bun__deepEquals(globalObject, nextValue1, nextValue2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict>(globalObject, key1, key2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
found = true;
if (!nextValue1.isPrimitive()) {
stack.append({ nextValue1, nextValue2 });
@@ -443,7 +446,12 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return (memcmp(vector, rightVector, byteLength) == 0);
}
-
+ case StringObjectType: {
+ if (!equal(JSObject::calculatedClassName(o1), JSObject::calculatedClassName(o2))) {
+ return false;
+ }
+ break;
+ }
case JSFunctionType: {
return false;
}
@@ -457,46 +465,50 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
bool v2Array = isArray(globalObject, v2);
RETURN_IF_EXCEPTION(*scope, false);
- JSObject* o1 = v1.getObject();
- JSObject* o2 = v2.getObject();
-
if (v1Array != v2Array)
return false;
if (v1Array && v2Array) {
JSC::JSArray* array1 = JSC::jsCast<JSC::JSArray*>(v1);
JSC::JSArray* array2 = JSC::jsCast<JSC::JSArray*>(v2);
+
size_t length = array1->length();
if (length != array2->length()) {
return false;
}
- if (array1->canDoFastIndexedAccess() && array2->canDoFastIndexedAccess()) {
- for (size_t i = 0; i < length; i++) {
- JSValue left = o1->getIndexQuickly(i);
- RETURN_IF_EXCEPTION(*scope, false);
- JSValue right = o2->getIndexQuickly(i);
- RETURN_IF_EXCEPTION(*scope, false);
- if (!Bun__deepEquals(globalObject, left, right, stack, scope, true)) {
+ for (uint64_t i = 0; i < length; i++) {
+ // array holes come back as empty values with tryGetIndexQuickly()
+ JSValue left = o1->canGetIndexQuickly(i)
+ ? o1->getIndexQuickly(i)
+ : o1->tryGetIndexQuickly(i);
+ RETURN_IF_EXCEPTION(*scope, false);
+
+ JSValue right = o2->canGetIndexQuickly(i)
+ ? o2->getIndexQuickly(i)
+ : o2->tryGetIndexQuickly(i);
+ RETURN_IF_EXCEPTION(*scope, false);
+
+ if constexpr (isStrict) {
+ if (left.isEmpty() && right.isEmpty()) {
+ continue;
+ }
+ if (left.isEmpty() || right.isEmpty()) {
return false;
}
-
- RETURN_IF_EXCEPTION(*scope, false);
}
- } else {
- for (size_t i = 0; i < length; i++) {
- JSValue left = o1->getIndex(globalObject, i);
- RETURN_IF_EXCEPTION(*scope, false);
- JSValue right = o2->getIndex(globalObject, i);
- RETURN_IF_EXCEPTION(*scope, false);
-
- if (!Bun__deepEquals(globalObject, left, right, stack, scope, true)) {
- return false;
+ if constexpr (!isStrict) {
+ if (((left.isEmpty() || right.isEmpty()) && (left.isUndefined() || right.isUndefined()))) {
+ continue;
}
+ }
- RETURN_IF_EXCEPTION(*scope, false);
+ if (!Bun__deepEquals<isStrict>(globalObject, left, right, stack, scope, true)) {
+ return false;
}
+
+ RETURN_IF_EXCEPTION(*scope, false);
}
JSC::PropertyNameArray a1(vm, PropertyNameMode::Symbols, PrivateSymbolMode::Include);
@@ -505,8 +517,10 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSObject::getOwnPropertyNames(o2, globalObject, a2, DontEnumPropertiesMode::Exclude);
size_t propertyLength = a1.size();
- if (propertyLength != a2.size()) {
- return false;
+ if constexpr (isStrict) {
+ if (propertyLength != a2.size()) {
+ return false;
+ }
}
// take a property name from one, try to get it from both
@@ -524,11 +538,17 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSValue prop2 = o2->getIfPropertyExists(globalObject, propertyName1);
RETURN_IF_EXCEPTION(*scope, false);
+ if constexpr (!isStrict) {
+ if (prop1.isUndefined() && prop2.isEmpty()) {
+ continue;
+ }
+ }
+
if (!prop2) {
return false;
}
- if (!Bun__deepEquals(globalObject, prop1, prop2, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict>(globalObject, prop1, prop2, stack, scope, true)) {
return false;
}
@@ -544,6 +564,12 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return true;
}
+ if constexpr (isStrict) {
+ if (!equal(JSObject::calculatedClassName(o1), JSObject::calculatedClassName(o2))) {
+ return false;
+ }
+ }
+
JSC::Structure* o1Structure = o1->structure();
if (canPerformFastPropertyEnumerationForIterationBun(o1Structure)) {
JSC::Structure* o2Structure = o2->structure();
@@ -552,8 +578,10 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
size_t count1 = 0;
bool result = true;
- if (o2Structure->inlineSize() + o2Structure->outOfLineSize() != o1Structure->inlineSize() + o1Structure->outOfLineSize()) {
- return false;
+ if constexpr (isStrict) {
+ if (o2Structure->inlineSize() + o2Structure->outOfLineSize() != o1Structure->inlineSize() + o1Structure->outOfLineSize()) {
+ return false;
+ }
}
o1Structure->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool {
@@ -562,19 +590,25 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
}
count1++;
+ JSValue left = o1->getDirect(entry.offset());
JSValue right = o2->getDirect(vm, JSC::PropertyName(entry.key()));
+ if constexpr (!isStrict) {
+ if (left.isUndefined() && right.isEmpty()) {
+ return true;
+ }
+ }
+
if (!right) {
result = false;
return false;
}
- JSValue left = o1->getDirect(entry.offset());
if (left == right || JSC::sameValue(globalObject, left, right)) {
return true;
}
- if (!Bun__deepEquals(globalObject, left, right, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict>(globalObject, left, right, stack, scope, true)) {
result = false;
return false;
}
@@ -589,6 +623,12 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return true;
}
+ if constexpr (!isStrict) {
+ if (o2->getDirect(entry.offset()).isUndefined()) {
+ return true;
+ }
+ }
+
if (remain == 0) {
result = false;
return false;
@@ -612,13 +652,15 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
o1->getPropertyNames(globalObject, a1, DontEnumPropertiesMode::Exclude);
o2->getPropertyNames(globalObject, a2, DontEnumPropertiesMode::Exclude);
- size_t propertyLength = a1.size();
- if (propertyLength != a2.size()) {
- return false;
+ const size_t propertyArrayLength = a1.size();
+ if constexpr (isStrict) {
+ if (propertyArrayLength != a2.size()) {
+ return false;
+ }
}
// take a property name from one, try to get it from both
- for (size_t i = 0; i < propertyLength; i++) {
+ for (size_t i = 0; i < propertyArrayLength; i++) {
Identifier i1 = a1[i];
PropertyName propertyName1 = PropertyName(i1);
@@ -632,11 +674,17 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSValue prop2 = o2->getIfPropertyExists(globalObject, propertyName1);
RETURN_IF_EXCEPTION(*scope, false);
+ if constexpr (!isStrict) {
+ if (prop1.isUndefined() && prop2.isEmpty()) {
+ continue;
+ }
+ }
+
if (!prop2) {
return false;
}
- if (!Bun__deepEquals(globalObject, prop1, prop2, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict>(globalObject, prop1, prop2, stack, scope, true)) {
return false;
}
@@ -1236,12 +1284,22 @@ bool JSC__JSValue__isSameValue(JSC__JSValue JSValue0, JSC__JSValue JSValue1,
bool JSC__JSValue__deepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
{
- JSC::JSValue v1 = JSC::JSValue::decode(JSValue0);
- JSC::JSValue v2 = JSC::JSValue::decode(JSValue1);
+ JSValue v1 = JSValue::decode(JSValue0);
+ JSValue v2 = JSValue::decode(JSValue1);
+
+ ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
+ Vector<std::pair<JSValue, JSValue>, 16> stack;
+ return Bun__deepEquals<false>(globalObject, v1, v2, stack, &scope, true);
+}
+
+bool JSC__JSValue__strictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
+{
+ JSValue v1 = JSValue::decode(JSValue0);
+ JSValue v2 = JSValue::decode(JSValue1);
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
- Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16> stack;
- return Bun__deepEquals(globalObject, v1, v2, stack, &scope, true);
+ Vector<std::pair<JSValue, JSValue>, 16> stack;
+ return Bun__deepEquals<true>(globalObject, v1, v2, stack, &scope, true);
}
// This is the same as the C API version, except it returns a JSValue which may be a *Exception
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index d17cc5382..3b933f976 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2977,6 +2977,10 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("deepEquals", .{ this, other, global });
}
+ pub fn strictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
+ return cppFn("strictDeepEquals", .{ this, other, global });
+ }
+
pub fn asString(this: JSValue) *JSString {
return cppFn("asString", .{
this,
@@ -3165,7 +3169,7 @@ pub const JSValue = enum(JSValueReprInt) {
return this.asNullableVoid().?;
}
- pub const Extern = [_][]const u8{ "forEachProperty", "coerceToInt32", "fastGet_", "getStaticProperty", "createUninitializedUint8Array", "fromInt64NoTruncate", "fromUInt64NoTruncate", "toUInt64NoTruncate", "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable", "toBooleanSlow", "deepEquals", "getIfPropertyExistsFromPath" };
+ pub const Extern = [_][]const u8{ "forEachProperty", "coerceToInt32", "fastGet_", "getStaticProperty", "createUninitializedUint8Array", "fromInt64NoTruncate", "fromUInt64NoTruncate", "toUInt64NoTruncate", "asPromise", "toInt64", "_then", "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable", "toBooleanSlow", "deepEquals", "strictDeepEquals", "getIfPropertyExistsFromPath" };
};
extern "c" fn Microtask__run(*Microtask, *JSGlobalObject) void;
diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h
index 9018615fc..5ce164a69 100644
--- a/src/bun.js/bindings/headers-handwritten.h
+++ b/src/bun.js/bindings/headers-handwritten.h
@@ -271,6 +271,7 @@ extern "C" size_t Bun__encoding__byteLengthUTF16(const UChar* ptr, size_t len, E
extern "C" int64_t Bun__encoding__constructFromLatin1(void*, const unsigned char* ptr, size_t len, Encoding encoding);
extern "C" int64_t Bun__encoding__constructFromUTF16(void*, const UChar* ptr, size_t len, Encoding encoding);
+template<bool isStrict>
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, JSC::ThrowScope* scope, bool addToStack);
namespace Inspector {
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 75701502d..675d6df44 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1669880224
+//-- AUTOGENERATED FILE -- 1669793662
#pragma once
#include <stddef.h>
@@ -314,6 +314,7 @@ CPP_DECL JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObject
CPP_DECL JSC__JSValue JSC__JSValue__parseJSON(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
CPP_DECL void JSC__JSValue__put(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, const ZigString* arg2, JSC__JSValue JSValue3);
CPP_DECL void JSC__JSValue__putRecord(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4);
+CPP_DECL bool JSC__JSValue__strictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2);
CPP_DECL JSC__JSValue JSC__JSValue__symbolFor(JSC__JSGlobalObject* arg0, ZigString* arg1);
CPP_DECL bool JSC__JSValue__symbolKeyFor(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2);
CPP_DECL bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0);
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index b0bfadae9..808fa4fbc 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -238,6 +238,7 @@ pub extern fn JSC__JSValue__makeWithNameAndPrototype(arg0: ?*JSC__JSGlobalObject
pub extern fn JSC__JSValue__parseJSON(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSValue__put(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]const ZigString, JSValue3: JSC__JSValue) void;
pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void;
+pub extern fn JSC__JSValue__strictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: ?*JSC__JSGlobalObject) bool;
pub extern fn JSC__JSValue__symbolFor(arg0: ?*JSC__JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue;
pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) bool;
pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool;
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index abde377db..351049f65 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -717,6 +717,48 @@ pub const Expect = struct {
return .zero;
}
+ pub fn toStrictEqual(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
+
+ const thisValue = callFrame.this();
+ const _arguments = callFrame.arguments(1);
+ const arguments: []const JSValue = _arguments.ptr[0.._arguments.len];
+
+ if (arguments.len < 1) {
+ globalObject.throwInvalidArguments("toStrictEqual() requires 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.scope.tests.items.len <= this.test_id) {
+ globalObject.throw("toStrictEqual() must be called in a test", .{});
+ return .zero;
+ }
+
+ active_test_expectation_counter.actual += 1;
+
+ const expected = arguments[0];
+ const value = Expect.capturedValueGetCached(thisValue) orelse {
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ return .zero;
+ };
+ value.ensureStillAlive();
+
+ const not = this.op.contains(.not);
+ var pass = value.strictDeepEquals(expected, globalObject);
+
+ if (not) pass = !pass;
+ if (pass) return thisValue;
+
+ // handle failure
+ var fmt = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject };
+ if (not) {
+ globalObject.throw("Expected values to not be strictly equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
+ } else {
+ globalObject.throw("Expected values to be strictly equal:\n\tExpected: {any}\n\tReceived: {any}", .{ expected.toFmt(globalObject, &fmt), value.toFmt(globalObject, &fmt) });
+ }
+ return .zero;
+ }
+
pub fn toHaveProperty(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
defer this.postMatch(globalObject);
@@ -805,7 +847,6 @@ pub const Expect = struct {
pub const toMatchObject = notImplementedJSCFn;
pub const toMatchSnapshot = notImplementedJSCFn;
pub const toMatchInlineSnapshot = notImplementedJSCFn;
- pub const toStrictEqual = notImplementedJSCFn;
pub const toThrow = notImplementedJSCFn;
pub const toThrowErrorMatchingSnapshot = notImplementedJSCFn;
pub const toThrowErrorMatchingInlineSnapshot = notImplementedJSCFn;