mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
15 Commits
jarred/fix
...
pfg/util-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91225b53c1 | ||
|
|
d533b602e5 | ||
|
|
43f780618d | ||
|
|
3fb9ff5b53 | ||
|
|
d2011e4f98 | ||
|
|
344264dbdc | ||
|
|
5e864d6e47 | ||
|
|
5f05a8ba74 | ||
|
|
5354232e77 | ||
|
|
ebbb6b63fa | ||
|
|
94afa51dde | ||
|
|
ecbb0384bc | ||
|
|
16518f54a2 | ||
|
|
1429f68c99 | ||
|
|
3d59e35db2 |
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 017930ebf915121f8f593bef61cbbca82d78132d)
|
||||
set(WEBKIT_VERSION eda8b0fb4fb1aa23db9c2b00933df8b58bcdd289)
|
||||
endif()
|
||||
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
||||
|
||||
6
repro.js
Normal file
6
repro.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const sym = Symbol();
|
||||
const obj1 = { [sym]: 1 };
|
||||
const obj4 = {};
|
||||
Object.defineProperty(obj4, sym, { value: 1 }); // non-enumerable
|
||||
|
||||
console.log(Bun.deepEquals(obj1, obj4)); // should be 'false'
|
||||
@@ -512,16 +512,40 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepEquals, (JSGlobalObject * globalObject,
|
||||
|
||||
if (strict.isBoolean() && strict.asBoolean()) {
|
||||
|
||||
bool isEqual = Bun__deepEquals<true, false>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
|
||||
bool isEqual = Bun__deepEquals<true, BunDeepEqualsMode_Bun>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsBoolean(isEqual));
|
||||
} else {
|
||||
bool isEqual = Bun__deepEquals<false, false>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
|
||||
bool isEqual = Bun__deepEquals<false, BunDeepEqualsMode_Bun>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsBoolean(isEqual));
|
||||
}
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunction_nodeIsDeepStrictEqual, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
auto* global = reinterpret_cast<GlobalObject*>(globalObject);
|
||||
auto& vm = JSC::getVM(global);
|
||||
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
if (callFrame->argumentCount() < 2) {
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
throwTypeError(globalObject, throwScope, "Expected 2 values to compare"_s);
|
||||
return {};
|
||||
}
|
||||
|
||||
JSC::JSValue arg1 = callFrame->uncheckedArgument(0);
|
||||
JSC::JSValue arg2 = callFrame->uncheckedArgument(1);
|
||||
|
||||
Vector<std::pair<JSValue, JSValue>, 16> stack;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
|
||||
bool isEqual = Bun__deepEquals<true, BunDeepEqualsMode_Node>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsBoolean(isEqual));
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
auto* global = reinterpret_cast<GlobalObject*>(globalObject);
|
||||
@@ -547,7 +571,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<BunDeepEqualsMode_Bun>(object, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, false, false);
|
||||
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return JSValue::encode(jsBoolean(match));
|
||||
@@ -898,7 +922,6 @@ static void exportBunObject(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:
|
||||
exportValues.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Zig {
|
||||
|
||||
@@ -11,6 +11,7 @@ JSC_DECLARE_HOST_FUNCTION(functionBunDeepMatch);
|
||||
JSC_DECLARE_HOST_FUNCTION(functionBunNanoseconds);
|
||||
JSC_DECLARE_HOST_FUNCTION(functionPathToFileURL);
|
||||
JSC_DECLARE_HOST_FUNCTION(functionFileURLToPath);
|
||||
JSC_DECLARE_HOST_FUNCTION(jsFunction_nodeIsDeepStrictEqual);
|
||||
|
||||
JSC::JSValue constructBunFetchObject(VM& vm, JSObject* bunObject);
|
||||
JSC::JSObject* createBunObject(VM& vm, JSObject* globalObject);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "JavaScriptCore/JSCast.h"
|
||||
#include "JavaScriptCore/JSType.h"
|
||||
#include "JavaScriptCore/NumberObject.h"
|
||||
#include "JavaScriptCore/BigIntObject.h"
|
||||
#include "JavaScriptCore/SymbolObject.h"
|
||||
#include "JavaScriptCore/JSCJSValue.h"
|
||||
#include "JavaScriptCore/JSGlobalObject.h"
|
||||
#include "JavaScriptCore/JSPromiseConstructor.h"
|
||||
@@ -456,7 +458,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
|
||||
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
|
||||
Vector<std::pair<JSValue, JSValue>, 16> stack;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
if (Bun__deepEquals<false, true>(globalObject, expectedValue, otherValue, gcBuffer, stack, &scope, true)) {
|
||||
if (Bun__deepEquals<false, BunDeepEqualsMode_Jest>(globalObject, expectedValue, otherValue, gcBuffer, stack, &scope, true)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -481,9 +483,9 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
|
||||
if (otherProp.isObject()) {
|
||||
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
|
||||
// SAFETY: visited property sets are not required when
|
||||
// `enableAsymmetricMatchers` and `isMatchingObjectContaining`
|
||||
// `mode == BunDeepEqualsMode_Jest` and `isMatchingObjectContaining`
|
||||
// are both true
|
||||
if (Bun__deepMatch<true>(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) {
|
||||
if (Bun__deepMatch<BunDeepEqualsMode_Jest>(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) {
|
||||
return AsymmetricMatcherResult::PASS;
|
||||
}
|
||||
}
|
||||
@@ -607,10 +609,10 @@ JSValue getIndexWithoutAccessors(JSGlobalObject* globalObject, JSObject* obj, ui
|
||||
return JSValue();
|
||||
}
|
||||
|
||||
template<bool isStrict, bool enableAsymmetricMatchers>
|
||||
template<bool isStrict, BunDeepEqualsMode mode>
|
||||
std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2);
|
||||
|
||||
template<bool isStrict, bool enableAsymmetricMatchers>
|
||||
template<bool isStrict, BunDeepEqualsMode mode>
|
||||
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack)
|
||||
{
|
||||
VM& vm = globalObject->vm();
|
||||
@@ -621,7 +623,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
|
||||
// need to check this before primitives, asymmetric matchers
|
||||
// can match against any type of value.
|
||||
if constexpr (enableAsymmetricMatchers) {
|
||||
if constexpr (mode == BunDeepEqualsMode_Jest) {
|
||||
if (v2.isCell() && !v2.isEmpty() && v2.asCell()->type() == JSC::JSType(JSDOMWrapperType)) {
|
||||
switch (matchAsymmetricMatcher(globalObject, v2, v1, scope)) {
|
||||
case AsymmetricMatcherResult::FAIL:
|
||||
@@ -685,9 +687,9 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
JSCell* c2 = v2.asCell();
|
||||
ASSERT(c1);
|
||||
ASSERT(c2);
|
||||
std::optional<bool> isSpecialEqual = specialObjectsDequal<isStrict, enableAsymmetricMatchers>(globalObject, gcBuffer, stack, scope, c1, c2);
|
||||
std::optional<bool> isSpecialEqual = specialObjectsDequal<isStrict, mode>(globalObject, gcBuffer, stack, scope, c1, c2);
|
||||
if (isSpecialEqual.has_value()) return std::move(*isSpecialEqual);
|
||||
isSpecialEqual = specialObjectsDequal<isStrict, enableAsymmetricMatchers>(globalObject, gcBuffer, stack, scope, c2, c1);
|
||||
isSpecialEqual = specialObjectsDequal<isStrict, mode>(globalObject, gcBuffer, stack, scope, c2, c1);
|
||||
if (isSpecialEqual.has_value()) return std::move(*isSpecialEqual);
|
||||
JSObject* o1 = v1.getObject();
|
||||
JSObject* o2 = v2.getObject();
|
||||
@@ -734,7 +736,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
}
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -789,7 +791,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -801,6 +803,22 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle boxed primitives
|
||||
auto v1IsBoxedPrimitive = v1.inherits<NumberObject>() || v1.inherits<StringObject>() || v1.inherits<BooleanObject>() || v1.inherits<BigIntObject>() || v1.inherits<SymbolObject>();
|
||||
auto v2IsBoxedPrimitive = v2.inherits<NumberObject>() || v2.inherits<StringObject>() || v2.inherits<BooleanObject>() || v2.inherits<BigIntObject>() || v2.inherits<SymbolObject>();
|
||||
if (v1IsBoxedPrimitive != v2IsBoxedPrimitive) {
|
||||
return false; // one is a boxed primitive, the other is not
|
||||
}
|
||||
if (v1IsBoxedPrimitive && v2IsBoxedPrimitive) {
|
||||
auto v1Wrapper = jsCast<JSC::JSWrapperObject*>(v1);
|
||||
auto v2Wrapper = jsCast<JSC::JSWrapperObject*>(v2);
|
||||
auto v1Value = v1Wrapper->internalValue();
|
||||
auto v2Value = v2Wrapper->internalValue();
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, v1Value, v2Value, gcBuffer, stack, scope, addToStack)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (isStrict) {
|
||||
if (!equal(JSObject::calculatedClassName(o1), JSObject::calculatedClassName(o2))) {
|
||||
return false;
|
||||
@@ -838,7 +856,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
@@ -854,7 +872,12 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
count++;
|
||||
|
||||
JSValue left = o1->getDirect(entry.offset());
|
||||
JSValue right = o2->getDirect(vm, JSC::PropertyName(entry.key()));
|
||||
JSValue right;
|
||||
if (o2->hasEnumerableProperty(globalObject, JSC::PropertyName(entry.key()))) {
|
||||
right = o2->getDirect(vm, JSC::PropertyName(entry.key()));
|
||||
} else {
|
||||
right = JSValue();
|
||||
}
|
||||
|
||||
if constexpr (!isStrict) {
|
||||
if (left.isUndefined() && right.isEmpty()) {
|
||||
@@ -871,7 +894,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
@@ -957,7 +980,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -980,11 +1003,18 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool isStrict, bool enableAsymmetricMatchers>
|
||||
template bool Bun__deepEquals<false, BunDeepEqualsMode_Node>(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack);
|
||||
template bool Bun__deepEquals<true, BunDeepEqualsMode_Node>(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack);
|
||||
|
||||
template<bool isStrict, BunDeepEqualsMode mode>
|
||||
std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2)
|
||||
{
|
||||
uint8_t c1Type = c1->type();
|
||||
uint8_t c2Type = c2->type();
|
||||
std::optional<bool> matchMaybeCheckProperties = true;
|
||||
if constexpr (mode == BunDeepEqualsMode_Node) {
|
||||
matchMaybeCheckProperties = std::nullopt;
|
||||
}
|
||||
|
||||
switch (c1Type) {
|
||||
case JSSetType: {
|
||||
@@ -1012,7 +1042,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
JSValue key2;
|
||||
bool foundMatchingKey = false;
|
||||
while (iter2->next(globalObject, key2)) {
|
||||
if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
||||
if (Bun__deepEquals<isStrict, mode>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
||||
foundMatchingKey = true;
|
||||
break;
|
||||
}
|
||||
@@ -1024,7 +1054,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
case JSMapType: {
|
||||
if (c2Type != JSMapType) {
|
||||
@@ -1051,7 +1081,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
JSValue key2;
|
||||
bool foundMatchingKey = false;
|
||||
while (iter2->nextKeyValue(globalObject, key2, value2)) {
|
||||
if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
||||
if (Bun__deepEquals<isStrict, mode>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
||||
foundMatchingKey = true;
|
||||
break;
|
||||
}
|
||||
@@ -1065,12 +1095,12 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
// Compare both values below.
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, value1, value2, gcBuffer, stack, scope, false)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, value1, value2, gcBuffer, stack, scope, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
case ArrayBufferType: {
|
||||
if (c2Type != ArrayBufferType) {
|
||||
@@ -1090,7 +1120,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
|
||||
if (byteLength == 0)
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
|
||||
if (UNLIKELY(right->isDetached() || left->isDetached())) {
|
||||
return false;
|
||||
@@ -1103,7 +1133,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
|
||||
if (UNLIKELY(vector == rightVector))
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
|
||||
return (memcmp(vector, rightVector, byteLength) == 0);
|
||||
}
|
||||
@@ -1176,7 +1206,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
RETURN_IF_EXCEPTION(*scope, false);
|
||||
auto rightCause = right->get(globalObject, cause);
|
||||
RETURN_IF_EXCEPTION(*scope, false);
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) {
|
||||
return false;
|
||||
}
|
||||
RETURN_IF_EXCEPTION(*scope, false);
|
||||
@@ -1226,7 +1256,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1281,7 +1311,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
|
||||
if (byteLength == 0)
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
|
||||
if (UNLIKELY(right->isDetached() || left->isDetached())) {
|
||||
return false;
|
||||
@@ -1294,7 +1324,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
|
||||
if (UNLIKELY(vector == rightVector))
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
|
||||
// For Float32Array and Float64Array, when not in strict mode, we need to
|
||||
// handle +0 and -0 as equal, and NaN as not equal to itself.
|
||||
@@ -1309,7 +1339,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
} else if (c1Type == Float32ArrayType) {
|
||||
auto* leftFloat = static_cast<const float*>(vector);
|
||||
auto* rightFloat = static_cast<const float*>(rightVector);
|
||||
@@ -1320,7 +1350,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
} else { // Float64Array
|
||||
auto* leftDouble = static_cast<const double*>(vector);
|
||||
auto* rightDouble = static_cast<const double*>(rightVector);
|
||||
@@ -1331,11 +1361,15 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
}
|
||||
|
||||
return (memcmp(vector, rightVector, byteLength) == 0);
|
||||
if (memcmp(vector, rightVector, byteLength) == 0) {
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case StringObjectType: {
|
||||
if (c2Type != StringObjectType) {
|
||||
@@ -1349,7 +1383,10 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
JSString* s1 = c1->toStringInline(globalObject);
|
||||
JSString* s2 = c2->toStringInline(globalObject);
|
||||
|
||||
return s1->equal(globalObject, s2);
|
||||
if (s1->equal(globalObject, s2)) {
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case JSFunctionType: {
|
||||
return false;
|
||||
@@ -1371,7 +1408,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
} else {
|
||||
if ((url1 == nullptr) != (url2 == nullptr)) {
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1384,7 +1421,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
|
||||
// TODO: FormData.
|
||||
@@ -1410,7 +1447,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
}
|
||||
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
} else {
|
||||
if constexpr (isStrict) {
|
||||
// if one is a URLSearchParams and the other is not a URLSearchParams, toStrictEqual should return false.
|
||||
@@ -1419,7 +1456,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
} else {
|
||||
if ((urlSearchParams1 == nullptr) != (urlSearchParams2 == nullptr)) {
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1449,7 +1486,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
}
|
||||
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
} else {
|
||||
if constexpr (isStrict) {
|
||||
// if one is a FetchHeaders and the other is not a FetchHeaders, toStrictEqual should return false.
|
||||
@@ -1458,17 +1495,12 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
}
|
||||
} else {
|
||||
if ((headers1 == nullptr) != (headers2 == nullptr)) {
|
||||
goto compareAsNormalValue;
|
||||
return matchMaybeCheckProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto compareAsNormalValue;
|
||||
|
||||
compareAsNormalValue:
|
||||
break;
|
||||
}
|
||||
// globalThis is only equal to globalThis
|
||||
// NOTE: Zig::GlobalObject is tagged as GlobalProxyType
|
||||
@@ -1497,14 +1529,14 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
* @note
|
||||
* The sets recording already visited properties (`seenObjProperties`,
|
||||
* `seenSubsetProperties`, and `gcBuffer`) aren not needed when both
|
||||
* `enableAsymmetricMatchers` and `isMatchingObjectContaining` are true. In
|
||||
* `mode == BunDeepEqualsMode_Jest` and `isMatchingObjectContaining` are true. In
|
||||
* this case, it is safe to pass a `nullptr`.
|
||||
*
|
||||
* `gcBuffer` ensures JSC's stack scan does not come up empty-handed and free
|
||||
* properties currently within those stacks. Likely unnecessary, but better to
|
||||
* be safe tnan sorry
|
||||
*
|
||||
* @tparam enableAsymmetricMatchers
|
||||
* @tparam mode
|
||||
* @param objValue
|
||||
* @param seenObjProperties already visited properties of `objValue`.
|
||||
* @param subsetValue
|
||||
@@ -1518,7 +1550,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
template<bool enableAsymmetricMatchers>
|
||||
template<BunDeepEqualsMode mode>
|
||||
bool Bun__deepMatch(
|
||||
JSValue objValue,
|
||||
std::set<EncodedJSValue>* seenObjProperties,
|
||||
@@ -1574,7 +1606,7 @@ bool Bun__deepMatch(
|
||||
JSCell* subsetPropCell = !subsetProp.isEmpty() && subsetProp.isCell() ? subsetProp.asCell() : nullptr;
|
||||
JSCell* propCell = prop.isCell() ? prop.asCell() : nullptr;
|
||||
|
||||
if constexpr (enableAsymmetricMatchers) {
|
||||
if constexpr (mode == BunDeepEqualsMode_Jest) {
|
||||
if (subsetPropCell && subsetPropCell->type() == JSC::JSType(JSDOMWrapperType)) {
|
||||
switch (matchAsymmetricMatcher(globalObject, subsetProp, prop, throwScope)) {
|
||||
case AsymmetricMatcherResult::FAIL:
|
||||
@@ -1608,10 +1640,10 @@ bool Bun__deepMatch(
|
||||
// if this is called from inside an objectContaining asymmetric matcher, it should behave slightly differently:
|
||||
// in such case, it expects exhaustive matching of any nested object properties, not just a subset,
|
||||
// and the user would need to opt-in to subset matching by using another nested objectContaining matcher
|
||||
if (enableAsymmetricMatchers && isMatchingObjectContaining) {
|
||||
if (mode == BunDeepEqualsMode_Jest && isMatchingObjectContaining) {
|
||||
Vector<std::pair<JSValue, JSValue>, 16> stack;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
if (!Bun__deepEquals<false, true>(globalObject, prop, subsetProp, gcBuffer, stack, throwScope, true)) {
|
||||
if (!Bun__deepEquals<false, BunDeepEqualsMode_Jest>(globalObject, prop, subsetProp, gcBuffer, stack, throwScope, true)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -1624,7 +1656,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<mode>(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1640,14 +1672,14 @@ bool Bun__deepMatch(
|
||||
|
||||
// anonymous namespace to avoid name collision
|
||||
namespace {
|
||||
template<bool isStrict, bool enableAsymmetricMatchers>
|
||||
template<bool isStrict, BunDeepEqualsMode mode>
|
||||
inline bool deepEqualsWrapperImpl(JSC::EncodedJSValue a, JSC::EncodedJSValue b, JSC::JSGlobalObject* global)
|
||||
{
|
||||
auto& vm = global->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16> stack;
|
||||
MarkedArgumentBuffer args;
|
||||
return Bun__deepEquals<isStrict, enableAsymmetricMatchers>(global, JSC::JSValue::decode(a), JSC::JSValue::decode(b), args, stack, &scope, true);
|
||||
return Bun__deepEquals<isStrict, mode>(global, JSC::JSValue::decode(a), JSC::JSValue::decode(b), args, stack, &scope, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2555,22 +2587,22 @@ bool JSC__JSValue__isSameValue(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue
|
||||
|
||||
bool JSC__JSValue__deepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
return deepEqualsWrapperImpl<false, false>(JSValue0, JSValue1, globalObject);
|
||||
return deepEqualsWrapperImpl<false, BunDeepEqualsMode_Bun>(JSValue0, JSValue1, globalObject);
|
||||
}
|
||||
|
||||
bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
return deepEqualsWrapperImpl<false, true>(JSValue0, JSValue1, globalObject);
|
||||
return deepEqualsWrapperImpl<false, BunDeepEqualsMode_Jest>(JSValue0, JSValue1, globalObject);
|
||||
}
|
||||
|
||||
bool JSC__JSValue__strictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
return deepEqualsWrapperImpl<true, false>(JSValue0, JSValue1, globalObject);
|
||||
return deepEqualsWrapperImpl<true, BunDeepEqualsMode_Bun>(JSValue0, JSValue1, globalObject);
|
||||
}
|
||||
|
||||
bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
return deepEqualsWrapperImpl<true, true>(JSValue0, JSValue1, globalObject);
|
||||
return deepEqualsWrapperImpl<true, BunDeepEqualsMode_Jest>(JSValue0, JSValue1, globalObject);
|
||||
}
|
||||
|
||||
#undef IMPL_DEEP_EQUALS_WRAPPER
|
||||
@@ -2585,7 +2617,7 @@ bool JSC__JSValue__deepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue J
|
||||
std::set<EncodedJSValue> objVisited;
|
||||
std::set<EncodedJSValue> subsetVisited;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
return Bun__deepMatch<false>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
||||
return Bun__deepMatch<BunDeepEqualsMode_Bun>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
||||
}
|
||||
|
||||
bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers)
|
||||
@@ -2598,7 +2630,7 @@ bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSVal
|
||||
std::set<EncodedJSValue> objVisited;
|
||||
std::set<EncodedJSValue> subsetVisited;
|
||||
MarkedArgumentBuffer gcBuffer;
|
||||
return Bun__deepMatch<true>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
||||
return Bun__deepMatch<BunDeepEqualsMode_Jest>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
||||
}
|
||||
|
||||
extern "C" bool Bun__JSValue__isAsyncContextFrame(JSC::EncodedJSValue value)
|
||||
|
||||
@@ -276,6 +276,12 @@ typedef struct StringPointer {
|
||||
} StringPointer;
|
||||
#endif
|
||||
|
||||
enum BunDeepEqualsMode {
|
||||
BunDeepEqualsMode_Node,
|
||||
BunDeepEqualsMode_Jest,
|
||||
BunDeepEqualsMode_Bun,
|
||||
};
|
||||
|
||||
typedef void WebSocketHTTPClient;
|
||||
typedef void WebSocketHTTPSClient;
|
||||
typedef void WebSocketClient;
|
||||
@@ -403,7 +409,7 @@ extern "C" void Bun__EventLoop__runCallback2(JSC::JSGlobalObject* global, JSC::E
|
||||
extern "C" void Bun__EventLoop__runCallback3(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3);
|
||||
|
||||
/// @note throws a JS exception and returns false if a stack overflow occurs
|
||||
template<bool isStrict, bool enableAsymmetricMatchers>
|
||||
template<bool isStrict, BunDeepEqualsMode mode>
|
||||
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, JSC::MarkedArgumentBuffer&, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, JSC::ThrowScope* scope, bool addToStack);
|
||||
|
||||
/**
|
||||
@@ -438,7 +444,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JS
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
template<bool enableAsymmetricMatchers>
|
||||
template<BunDeepEqualsMode enableAsymmetricMatchers>
|
||||
bool Bun__deepMatch(
|
||||
JSC::JSValue object,
|
||||
std::set<JSC::EncodedJSValue>* seenObjProperties,
|
||||
|
||||
@@ -21,8 +21,7 @@ function isFunction(value) {
|
||||
return typeof value === "function";
|
||||
}
|
||||
|
||||
const deepEquals = Bun.deepEquals;
|
||||
const isDeepStrictEqual = (a, b) => deepEquals(a, b, true);
|
||||
const isDeepStrictEqual = $newCppFunction("BunObject.cpp", "jsFunction_nodeIsDeepStrictEqual", 2);
|
||||
|
||||
const parseArgs = $newZigFunction("parse_args.zig", "parseArgs", 1);
|
||||
|
||||
|
||||
49
test/js/bun/test/expect-boxed.test.js
Normal file
49
test/js/bun/test/expect-boxed.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as util from "util";
|
||||
|
||||
test("boxed number", () => {
|
||||
expect(new Number(2)).not.toEqual(new Number(1));
|
||||
expect(2).not.toEqual(new Number(2));
|
||||
});
|
||||
test("boxed symbol", () => {
|
||||
expect(Object(Symbol())).not.toEqual(Object(Symbol()));
|
||||
});
|
||||
test("set props on boxed string", () => {
|
||||
const str1 = new String("abc");
|
||||
const str2 = new String("abc");
|
||||
str1.x = 1;
|
||||
expect(str1).toEqual(str2); // jest doesn't care
|
||||
expect(util.isDeepStrictEqual(str1, str2)).toBe(false);
|
||||
expect(Bun.deepEquals(str1, str2)).toBe(true);
|
||||
});
|
||||
for (const key of [Symbol(), "abc"]) {
|
||||
describe(key === "abc" ? "string key" : "symbol key", () => {
|
||||
const util = require("util");
|
||||
const sym = Symbol();
|
||||
const obj1 = {};
|
||||
const obj4 = {};
|
||||
Object.defineProperty(obj1, sym, { value: 1, enumerable: true });
|
||||
Object.defineProperty(obj4, sym, { value: 1, enumerable: false });
|
||||
test("enumerable 1", () => {
|
||||
expect(obj1).not.toEqual(obj4);
|
||||
expect(util.isDeepStrictEqual(obj1, obj4)).toBe(false);
|
||||
expect(Bun.deepEquals(obj1, obj4)).toBe(false);
|
||||
expect(Bun.deepEquals(obj1, obj4, false)).toBe(false);
|
||||
expect(Bun.deepEquals(obj1, obj4, true)).toBe(false);
|
||||
expect(obj4).not.toEqual(obj1);
|
||||
expect(util.isDeepStrictEqual(obj4, obj1)).toBe(false);
|
||||
expect(Bun.deepEquals(obj4, obj1)).toBe(false);
|
||||
expect(Bun.deepEquals(obj4, obj1, false)).toBe(false);
|
||||
expect(Bun.deepEquals(obj4, obj1, true)).toBe(false);
|
||||
});
|
||||
test("enumerable 2", () => {
|
||||
const obj1 = {};
|
||||
const obj2 = {};
|
||||
Object.defineProperty(obj2, sym, { value: 1 });
|
||||
expect(util.isDeepStrictEqual(obj1, obj2)).toBe(true);
|
||||
expect(util.isDeepStrictEqual(obj2, obj1)).toBe(true);
|
||||
obj1[sym] = 1;
|
||||
expect(util.isDeepStrictEqual(obj1, obj2)).toBe(false);
|
||||
expect(util.isDeepStrictEqual(obj2, obj1)).toBe(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
172
test/js/node/test/parallel/test-filehandle-readablestream.js
Normal file
172
test/js/node/test/parallel/test-filehandle-readablestream.js
Normal file
@@ -0,0 +1,172 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const {
|
||||
readFileSync,
|
||||
} = require('fs');
|
||||
|
||||
const {
|
||||
open,
|
||||
} = require('fs/promises');
|
||||
|
||||
const check = readFileSync(__filename, { encoding: 'utf8' });
|
||||
|
||||
// Make sure the ReadableStream works...
|
||||
(async () => {
|
||||
const dec = new TextDecoder();
|
||||
const file = await open(__filename);
|
||||
let data = '';
|
||||
for await (const chunk of file.readableWebStream())
|
||||
data += dec.decode(chunk);
|
||||
|
||||
assert.strictEqual(check, data);
|
||||
|
||||
assert.throws(() => file.readableWebStream(), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
|
||||
await file.close();
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that acquiring a ReadableStream fails if the
|
||||
// FileHandle is already closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
await file.close();
|
||||
|
||||
assert.throws(() => file.readableWebStream(), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that acquiring a ReadableStream fails if the
|
||||
// FileHandle is already closing.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
file.close();
|
||||
|
||||
assert.throws(() => file.readableWebStream(), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure the ReadableStream is closed when the underlying
|
||||
// FileHandle is closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
const readable = file.readableWebStream();
|
||||
const reader = readable.getReader();
|
||||
file.close();
|
||||
await reader.closed;
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure the ReadableStream is closed when the underlying
|
||||
// FileHandle is closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
const readable = file.readableWebStream();
|
||||
file.close();
|
||||
const reader = readable.getReader();
|
||||
await reader.closed;
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that the FileHandle is properly marked "in use"
|
||||
// when a ReadableStream has been acquired for it.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
file.readableWebStream();
|
||||
const mc = new MessageChannel();
|
||||
mc.port1.onmessage = common.mustNotCall();
|
||||
assert.throws(() => mc.port2.postMessage(file, [file]), {
|
||||
code: 25,
|
||||
name: 'DataCloneError',
|
||||
});
|
||||
mc.port1.close();
|
||||
await file.close();
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure 'bytes' stream works
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
const dec = new TextDecoder();
|
||||
const readable = file.readableWebStream({ type: 'bytes' });
|
||||
const reader = readable.getReader({ mode: 'byob' });
|
||||
|
||||
let data = '';
|
||||
let result;
|
||||
do {
|
||||
const buff = new ArrayBuffer(100);
|
||||
result = await reader.read(new DataView(buff));
|
||||
if (result.value !== undefined) {
|
||||
data += dec.decode(result.value);
|
||||
assert.ok(result.value.byteLength <= 100);
|
||||
}
|
||||
} while (!result.done);
|
||||
|
||||
assert.strictEqual(check, data);
|
||||
|
||||
assert.throws(() => file.readableWebStream(), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
|
||||
await file.close();
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that acquiring a ReadableStream 'bytes' stream
|
||||
// fails if the FileHandle is already closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
await file.close();
|
||||
|
||||
assert.throws(() => file.readableWebStream({ type: 'bytes' }), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that acquiring a ReadableStream 'bytes' stream
|
||||
// fails if the FileHandle is already closing.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
file.close();
|
||||
|
||||
assert.throws(() => file.readableWebStream({ type: 'bytes' }), {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure the 'bytes' ReadableStream is closed when the underlying
|
||||
// FileHandle is closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
const readable = file.readableWebStream({ type: 'bytes' });
|
||||
const reader = readable.getReader({ mode: 'byob' });
|
||||
file.close();
|
||||
await reader.closed;
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure the 'bytes' ReadableStream is closed when the underlying
|
||||
// FileHandle is closed.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
const readable = file.readableWebStream({ type: 'bytes' });
|
||||
file.close();
|
||||
const reader = readable.getReader({ mode: 'byob' });
|
||||
await reader.closed;
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Make sure that the FileHandle is properly marked "in use"
|
||||
// when a 'bytes' ReadableStream has been acquired for it.
|
||||
(async () => {
|
||||
const file = await open(__filename);
|
||||
file.readableWebStream({ type: 'bytes' });
|
||||
const mc = new MessageChannel();
|
||||
mc.port1.onmessage = common.mustNotCall();
|
||||
assert.throws(() => mc.port2.postMessage(file, [file]), {
|
||||
code: 25,
|
||||
name: 'DataCloneError',
|
||||
});
|
||||
mc.port1.close();
|
||||
await file.close();
|
||||
})().then(common.mustCall());
|
||||
94
test/js/node/test/parallel/test-util-isDeepStrictEqual.js
Normal file
94
test/js/node/test/parallel/test-util-isDeepStrictEqual.js
Normal file
@@ -0,0 +1,94 @@
|
||||
'use strict';
|
||||
|
||||
// Confirm functionality of `util.isDeepStrictEqual()`.
|
||||
|
||||
require('../common');
|
||||
|
||||
const assert = require('assert');
|
||||
const util = require('util');
|
||||
|
||||
function utilIsDeepStrict(a, b) {
|
||||
assert.strictEqual(util.isDeepStrictEqual(a, b), true);
|
||||
assert.strictEqual(util.isDeepStrictEqual(b, a), true);
|
||||
}
|
||||
|
||||
function notUtilIsDeepStrict(a, b) {
|
||||
assert.strictEqual(util.isDeepStrictEqual(a, b), false);
|
||||
assert.strictEqual(util.isDeepStrictEqual(b, a), false);
|
||||
}
|
||||
|
||||
// Handle boxed primitives
|
||||
{
|
||||
const boxedString = new String('test');
|
||||
const boxedSymbol = Object(Symbol());
|
||||
notUtilIsDeepStrict(new Boolean(true), Object(false));
|
||||
notUtilIsDeepStrict(Object(true), new Number(1));
|
||||
notUtilIsDeepStrict(new Number(2), new Number(1));
|
||||
notUtilIsDeepStrict(boxedSymbol, Object(Symbol()));
|
||||
notUtilIsDeepStrict(boxedSymbol, {});
|
||||
utilIsDeepStrict(boxedSymbol, boxedSymbol);
|
||||
utilIsDeepStrict(Object(true), Object(true));
|
||||
utilIsDeepStrict(Object(2), Object(2));
|
||||
utilIsDeepStrict(boxedString, Object('test'));
|
||||
boxedString.slow = true;
|
||||
notUtilIsDeepStrict(boxedString, Object('test'));
|
||||
boxedSymbol.slow = true;
|
||||
notUtilIsDeepStrict(boxedSymbol, {});
|
||||
utilIsDeepStrict(Object(BigInt(1)), Object(BigInt(1)));
|
||||
notUtilIsDeepStrict(Object(BigInt(1)), Object(BigInt(2)));
|
||||
|
||||
const booleanish = new Boolean(true);
|
||||
Object.defineProperty(booleanish, Symbol.toStringTag, { value: 'String' });
|
||||
Object.setPrototypeOf(booleanish, String.prototype);
|
||||
notUtilIsDeepStrict(booleanish, new String('true'));
|
||||
|
||||
const numberish = new Number(42);
|
||||
Object.defineProperty(numberish, Symbol.toStringTag, { value: 'String' });
|
||||
Object.setPrototypeOf(numberish, String.prototype);
|
||||
notUtilIsDeepStrict(numberish, new String('42'));
|
||||
|
||||
const stringish = new String('0');
|
||||
Object.defineProperty(stringish, Symbol.toStringTag, { value: 'Number' });
|
||||
Object.setPrototypeOf(stringish, Number.prototype);
|
||||
notUtilIsDeepStrict(stringish, new Number(0));
|
||||
|
||||
const bigintish = new Object(BigInt(42));
|
||||
Object.defineProperty(bigintish, Symbol.toStringTag, { value: 'String' });
|
||||
Object.setPrototypeOf(bigintish, String.prototype);
|
||||
notUtilIsDeepStrict(bigintish, new String('42'));
|
||||
|
||||
const symbolish = new Object(Symbol('fhqwhgads'));
|
||||
Object.defineProperty(symbolish, Symbol.toStringTag, { value: 'String' });
|
||||
Object.setPrototypeOf(symbolish, String.prototype);
|
||||
notUtilIsDeepStrict(symbolish, new String('fhqwhgads'));
|
||||
}
|
||||
|
||||
// Handle symbols (enumerable only)
|
||||
{
|
||||
const symbol1 = Symbol();
|
||||
const obj1 = { [symbol1]: 1 };
|
||||
const obj2 = { [symbol1]: 1 };
|
||||
const obj3 = { [Symbol()]: 1 };
|
||||
const obj4 = { };
|
||||
// Add a non enumerable symbol as well. It is going to be ignored!
|
||||
Object.defineProperty(obj2, Symbol(), { value: 1 });
|
||||
Object.defineProperty(obj4, symbol1, { value: 1 });
|
||||
notUtilIsDeepStrict(obj1, obj3);
|
||||
utilIsDeepStrict(obj1, obj2);
|
||||
notUtilIsDeepStrict(obj1, obj4);
|
||||
// TypedArrays have a fast path. Test for this as well.
|
||||
const a = new Uint8Array(4);
|
||||
const b = new Uint8Array(4);
|
||||
a[symbol1] = true;
|
||||
b[symbol1] = false;
|
||||
notUtilIsDeepStrict(a, b);
|
||||
b[symbol1] = true;
|
||||
utilIsDeepStrict(a, b);
|
||||
// The same as TypedArrays is valid for boxed primitives
|
||||
const boxedStringA = new String('test');
|
||||
const boxedStringB = new String('test');
|
||||
boxedStringA[symbol1] = true;
|
||||
notUtilIsDeepStrict(boxedStringA, boxedStringB);
|
||||
boxedStringA[symbol1] = true;
|
||||
utilIsDeepStrict(a, b);
|
||||
}
|
||||
Reference in New Issue
Block a user