mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
test-assert-typedarray-deepequal (#19285)
This commit is contained in:
@@ -3361,6 +3361,8 @@ pub const Formatter = struct {
|
||||
if (arrayBuffer.typed_array_type == .Uint8Array and
|
||||
arrayBuffer.value.isBuffer(this.globalThis))
|
||||
"Buffer"
|
||||
else if (arrayBuffer.typed_array_type == .ArrayBuffer and arrayBuffer.shared)
|
||||
"SharedArrayBuffer"
|
||||
else
|
||||
bun.asByteSlice(@tagName(arrayBuffer.typed_array_type)),
|
||||
);
|
||||
|
||||
@@ -1085,6 +1085,10 @@ std::optional<bool> specialObjectsDequal(JSC__JSGlobalObject* globalObject, Mark
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UNLIKELY(left->isShared() != right->isShared())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (byteLength == 0)
|
||||
return true;
|
||||
|
||||
@@ -1292,6 +1296,45 @@ std::optional<bool> specialObjectsDequal(JSC__JSGlobalObject* globalObject, Mark
|
||||
if (UNLIKELY(vector == rightVector))
|
||||
return true;
|
||||
|
||||
// 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.
|
||||
if (!isStrict && (c1Type == Float16ArrayType || c1Type == Float32ArrayType || c1Type == Float64ArrayType)) {
|
||||
if (c1Type == Float16ArrayType) {
|
||||
auto* leftFloat = static_cast<const WTF::Float16*>(vector);
|
||||
auto* rightFloat = static_cast<const WTF::Float16*>(rightVector);
|
||||
size_t numElements = byteLength / sizeof(WTF::Float16);
|
||||
|
||||
for (size_t i = 0; i < numElements; i++) {
|
||||
if (leftFloat[i] != rightFloat[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (c1Type == Float32ArrayType) {
|
||||
auto* leftFloat = static_cast<const float*>(vector);
|
||||
auto* rightFloat = static_cast<const float*>(rightVector);
|
||||
size_t numElements = byteLength / sizeof(float);
|
||||
|
||||
for (size_t i = 0; i < numElements; i++) {
|
||||
if (leftFloat[i] != rightFloat[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else { // Float64Array
|
||||
auto* leftDouble = static_cast<const double*>(vector);
|
||||
auto* rightDouble = static_cast<const double*>(rightVector);
|
||||
size_t numElements = byteLength / sizeof(double);
|
||||
|
||||
for (size_t i = 0; i < numElements; i++) {
|
||||
if (leftDouble[i] != rightDouble[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (memcmp(vector, rightVector, byteLength) == 0);
|
||||
}
|
||||
case StringObjectType: {
|
||||
|
||||
@@ -23,7 +23,17 @@
|
||||
|
||||
const { SafeMap, SafeSet, SafeWeakSet } = require("internal/primordials");
|
||||
const { Buffer } = require("node:buffer");
|
||||
const { isKeyObject, isPromise, isRegExp, isMap, isSet, isDate, isWeakSet, isWeakMap } = require("node:util/types");
|
||||
const {
|
||||
isKeyObject,
|
||||
isPromise,
|
||||
isRegExp,
|
||||
isMap,
|
||||
isSet,
|
||||
isDate,
|
||||
isWeakSet,
|
||||
isWeakMap,
|
||||
isAnyArrayBuffer,
|
||||
} = require("node:util/types");
|
||||
const { innerOk } = require("internal/assert/utils");
|
||||
const { validateFunction } = require("internal/validators");
|
||||
|
||||
@@ -32,6 +42,7 @@ const ArrayPrototypeIndexOf = Array.prototype.indexOf;
|
||||
const ArrayPrototypeJoin = Array.prototype.join;
|
||||
const ArrayPrototypePush = Array.prototype.push;
|
||||
const ArrayPrototypeSlice = Array.prototype.slice;
|
||||
const ArrayBufferIsView = ArrayBuffer.isView;
|
||||
const NumberIsNaN = Number.isNaN;
|
||||
const ObjectAssign = Object.assign;
|
||||
const ObjectIs = Object.is;
|
||||
@@ -383,6 +394,16 @@ function compareBranch(actual, expected, comparedObjects?) {
|
||||
return Bun.deepEquals(actual, expected, true);
|
||||
}
|
||||
|
||||
// Check for ArrayBuffer object equality
|
||||
if (
|
||||
ArrayBufferIsView(actual) ||
|
||||
isAnyArrayBuffer(actual) ||
|
||||
ArrayBufferIsView(expected) ||
|
||||
isAnyArrayBuffer(expected)
|
||||
) {
|
||||
return Bun.deepEquals(actual, expected, true);
|
||||
}
|
||||
|
||||
for (const type of typesToCallDeepStrictEqualWith) {
|
||||
if (type(actual) || type(expected)) {
|
||||
return isDeepStrictEqual(actual, expected);
|
||||
@@ -693,7 +714,7 @@ async function waitForActual(promiseFn) {
|
||||
} else if (checkIsPromise(promiseFn)) {
|
||||
resultPromise = promiseFn;
|
||||
} else {
|
||||
throw $ERR_INVALID_ARG_TYPE("promiseFn", ["Function", "Promise"], promiseFn);
|
||||
throw $ERR_INVALID_ARG_TYPE("promiseFn", ["function", "an instance of Promise"], promiseFn);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1706,6 +1706,12 @@ describe("expect()", () => {
|
||||
expect(array2).not.toEqual(expect.arrayContaining([{ a: 2, b: 3 }]));
|
||||
});
|
||||
|
||||
test("toEqual ArrayBuffer with SharedArrayBuffer", () => {
|
||||
const ab1 = new SharedArrayBuffer(1);
|
||||
expect(ab1).toEqual(new SharedArrayBuffer(1));
|
||||
expect(ab1).not.toEqual(new ArrayBuffer(1));
|
||||
});
|
||||
|
||||
test("symbol based keys in arrays are processed correctly", () => {
|
||||
const mySymbol = Symbol("test");
|
||||
|
||||
|
||||
107
test/js/node/assert/assert-typedarray-deepequal.test.ts
Normal file
107
test/js/node/assert/assert-typedarray-deepequal.test.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import assert from "assert";
|
||||
import { test, describe, expect } from "bun:test";
|
||||
|
||||
function makeBlock(f: Function, ...args: any[]) {
|
||||
return function () {
|
||||
return f.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
describe("TypedArray deepEqual", () => {
|
||||
describe("equalArrayPairs", () => {
|
||||
const equalArrayPairs = [
|
||||
[new Uint8Array(1e5), new Uint8Array(1e5)],
|
||||
[new Uint16Array(1e5), new Uint16Array(1e5)],
|
||||
[new Uint32Array(1e5), new Uint32Array(1e5)],
|
||||
[new Uint8ClampedArray(1e5), new Uint8ClampedArray(1e5)],
|
||||
[new Int8Array(1e5), new Int8Array(1e5)],
|
||||
[new Int16Array(1e5), new Int16Array(1e5)],
|
||||
[new Int32Array(1e5), new Int32Array(1e5)],
|
||||
[new Float32Array(1e5), new Float32Array(1e5)],
|
||||
[new Float64Array(1e5), new Float64Array(1e5)],
|
||||
[new Float32Array([+0.0]), new Float32Array([+0.0])],
|
||||
[new Uint8Array([1, 2, 3, 4]).subarray(1), new Uint8Array([2, 3, 4])],
|
||||
[new Uint16Array([1, 2, 3, 4]).subarray(1), new Uint16Array([2, 3, 4])],
|
||||
[new Uint32Array([1, 2, 3, 4]).subarray(1, 3), new Uint32Array([2, 3])],
|
||||
[new ArrayBuffer(3), new ArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
];
|
||||
|
||||
for (const arrayPair of equalArrayPairs) {
|
||||
test(`${arrayPair[0].constructor.name} should equal`, () => {
|
||||
assert.deepEqual(arrayPair[0], arrayPair[1]);
|
||||
assert.deepStrictEqual(arrayPair[0], arrayPair[1]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("looseEqualArrayPairs", () => {
|
||||
const looseEqualArrayPairs = [
|
||||
// @ts-ignore
|
||||
[new Float16Array([+0.0]), new Float16Array([-0.0])],
|
||||
[new Float32Array([+0.0]), new Float32Array([-0.0])],
|
||||
[new Float64Array([+0.0]), new Float64Array([-0.0])],
|
||||
];
|
||||
|
||||
for (const arrayPair of looseEqualArrayPairs) {
|
||||
test(`${arrayPair[0].constructor.name} should be loosely equal but not strictly equal`, () => {
|
||||
assert.deepEqual(arrayPair[0], arrayPair[1]);
|
||||
expect(() => assert.deepStrictEqual(arrayPair[0], arrayPair[1])).toThrow(assert.AssertionError);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("looseNotEqualArrayPairs", () => {
|
||||
const looseNotEqualArrayPairs = [
|
||||
// @ts-ignore
|
||||
[new Float16Array([NaN]), new Float16Array([NaN])],
|
||||
[new Float32Array([NaN]), new Float32Array([NaN])],
|
||||
[new Float64Array([NaN]), new Float64Array([NaN])],
|
||||
];
|
||||
|
||||
for (const arrayPair of looseNotEqualArrayPairs) {
|
||||
test(`${arrayPair[0].constructor.name} should be strictly equal but not loosely equal`, () => {
|
||||
expect(() => assert.deepEqual(arrayPair[0], arrayPair[1])).toThrow(assert.AssertionError);
|
||||
assert.deepStrictEqual(arrayPair[0], arrayPair[1]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("notEqualArrayPairs", () => {
|
||||
const notEqualArrayPairs = [
|
||||
[new ArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
[new Int16Array(256), new Uint16Array(256)],
|
||||
[new Int16Array([256]), new Uint16Array([256])],
|
||||
[new Float64Array([+0.0]), new Float32Array([-0.0])],
|
||||
[new Uint8Array(2), new Uint8Array(3)],
|
||||
[new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])],
|
||||
[new Uint8ClampedArray([300, 2, 3]), new Uint8Array([300, 2, 3])],
|
||||
[new Uint16Array([2]), new Uint16Array([3])],
|
||||
[new Uint16Array([0]), new Uint16Array([256])],
|
||||
[new Int16Array([0]), new Uint16Array([256])],
|
||||
[new Int16Array([-256]), new Uint16Array([0xff00])], // same bits
|
||||
[new Int32Array([-256]), new Uint32Array([0xffffff00])], // ditto
|
||||
[new Float32Array([0.1]), new Float32Array([0.0])],
|
||||
[new Float32Array([0.1]), new Float32Array([0.1, 0.2])],
|
||||
[new Float64Array([0.1]), new Float64Array([0.0])],
|
||||
[new Uint8Array([1, 2, 3]).buffer, new Uint8Array([4, 5, 6]).buffer],
|
||||
[
|
||||
new Uint8Array(new SharedArrayBuffer(3)).fill(1).buffer,
|
||||
new Uint8Array(new SharedArrayBuffer(3)).fill(2).buffer,
|
||||
],
|
||||
[new ArrayBuffer(2), new ArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(2), new SharedArrayBuffer(3)],
|
||||
[new ArrayBuffer(2), new SharedArrayBuffer(3)],
|
||||
[new Uint8Array(new ArrayBuffer(3)).fill(1).buffer, new Uint8Array(new SharedArrayBuffer(3)).fill(2).buffer],
|
||||
[new ArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(2), new ArrayBuffer(2)],
|
||||
];
|
||||
|
||||
for (const arrayPair of notEqualArrayPairs) {
|
||||
test(`${arrayPair[0].constructor.name} should not equal ${arrayPair[1].constructor.name}`, () => {
|
||||
expect(() => assert.deepEqual(arrayPair[0], arrayPair[1])).toThrow(assert.AssertionError);
|
||||
expect(() => assert.deepStrictEqual(arrayPair[0], arrayPair[1])).toThrow(assert.AssertionError);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
110
test/js/node/test/parallel/test-assert-typedarray-deepequal.js
Normal file
110
test/js/node/test/parallel/test-assert-typedarray-deepequal.js
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const { test, suite } = require('node:test');
|
||||
|
||||
function makeBlock(f) {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
return function() {
|
||||
return f.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
suite('equalArrayPairs', () => {
|
||||
const equalArrayPairs = [
|
||||
[new Uint8Array(1e5), new Uint8Array(1e5)],
|
||||
[new Uint16Array(1e5), new Uint16Array(1e5)],
|
||||
[new Uint32Array(1e5), new Uint32Array(1e5)],
|
||||
[new Uint8ClampedArray(1e5), new Uint8ClampedArray(1e5)],
|
||||
[new Int8Array(1e5), new Int8Array(1e5)],
|
||||
[new Int16Array(1e5), new Int16Array(1e5)],
|
||||
[new Int32Array(1e5), new Int32Array(1e5)],
|
||||
[new Float32Array(1e5), new Float32Array(1e5)],
|
||||
[new Float64Array(1e5), new Float64Array(1e5)],
|
||||
[new Float32Array([+0.0]), new Float32Array([+0.0])],
|
||||
[new Uint8Array([1, 2, 3, 4]).subarray(1), new Uint8Array([2, 3, 4])],
|
||||
[new Uint16Array([1, 2, 3, 4]).subarray(1), new Uint16Array([2, 3, 4])],
|
||||
[new Uint32Array([1, 2, 3, 4]).subarray(1, 3), new Uint32Array([2, 3])],
|
||||
[new ArrayBuffer(3), new ArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
];
|
||||
|
||||
for (const arrayPair of equalArrayPairs) {
|
||||
test('', () => {
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
assert.deepEqual(arrayPair[0], arrayPair[1]);
|
||||
assert.deepStrictEqual(arrayPair[0], arrayPair[1]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
suite('looseEqualArrayPairs', () => {
|
||||
const looseEqualArrayPairs = [
|
||||
[new Float32Array([+0.0]), new Float32Array([-0.0])],
|
||||
[new Float64Array([+0.0]), new Float64Array([-0.0])],
|
||||
];
|
||||
|
||||
for (const arrayPair of looseEqualArrayPairs) {
|
||||
test('', () => {
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
assert.deepEqual(arrayPair[0], arrayPair[1]);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepStrictEqual, arrayPair[0], arrayPair[1]),
|
||||
assert.AssertionError
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
suite('notEqualArrayPairs', () => {
|
||||
const notEqualArrayPairs = [
|
||||
[new ArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
[new Int16Array(256), new Uint16Array(256)],
|
||||
[new Int16Array([256]), new Uint16Array([256])],
|
||||
[new Float64Array([+0.0]), new Float32Array([-0.0])],
|
||||
[new Uint8Array(2), new Uint8Array(3)],
|
||||
[new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])],
|
||||
[new Uint8ClampedArray([300, 2, 3]), new Uint8Array([300, 2, 3])],
|
||||
[new Uint16Array([2]), new Uint16Array([3])],
|
||||
[new Uint16Array([0]), new Uint16Array([256])],
|
||||
[new Int16Array([0]), new Uint16Array([256])],
|
||||
[new Int16Array([-256]), new Uint16Array([0xff00])], // same bits
|
||||
[new Int32Array([-256]), new Uint32Array([0xffffff00])], // ditto
|
||||
[new Float32Array([0.1]), new Float32Array([0.0])],
|
||||
[new Float32Array([0.1]), new Float32Array([0.1, 0.2])],
|
||||
[new Float64Array([0.1]), new Float64Array([0.0])],
|
||||
[new Uint8Array([1, 2, 3]).buffer, new Uint8Array([4, 5, 6]).buffer],
|
||||
[
|
||||
new Uint8Array(new SharedArrayBuffer(3)).fill(1).buffer,
|
||||
new Uint8Array(new SharedArrayBuffer(3)).fill(2).buffer,
|
||||
],
|
||||
[new ArrayBuffer(2), new ArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(2), new SharedArrayBuffer(3)],
|
||||
[new ArrayBuffer(2), new SharedArrayBuffer(3)],
|
||||
[
|
||||
new Uint8Array(new ArrayBuffer(3)).fill(1).buffer,
|
||||
new Uint8Array(new SharedArrayBuffer(3)).fill(2).buffer,
|
||||
],
|
||||
[new ArrayBuffer(3), new SharedArrayBuffer(3)],
|
||||
[new SharedArrayBuffer(2), new ArrayBuffer(2)],
|
||||
];
|
||||
|
||||
for (const arrayPair of notEqualArrayPairs) {
|
||||
test('', () => {
|
||||
assert.throws(
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
makeBlock(assert.deepEqual, arrayPair[0], arrayPair[1]),
|
||||
assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepStrictEqual, arrayPair[0], arrayPair[1]),
|
||||
assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.partialDeepStrictEqual, arrayPair[0], arrayPair[1]),
|
||||
assert.AssertionError
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -152,3 +152,29 @@ NamedError: console.error a named error
|
||||
Error log"
|
||||
`);
|
||||
});
|
||||
|
||||
it("console.log with SharedArrayBuffer", () => {
|
||||
const proc = Bun.spawnSync({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`
|
||||
console.log(new ArrayBuffer(0));
|
||||
console.log(new SharedArrayBuffer(0));
|
||||
console.log(new ArrayBuffer(3));
|
||||
console.log(new SharedArrayBuffer(3));
|
||||
`,
|
||||
],
|
||||
env: bunEnv,
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
});
|
||||
expect(proc.stderr.toString("utf8")).toBeEmpty();
|
||||
expect(proc.exitCode).toBe(0);
|
||||
expect(proc.stdout.toString("utf8")).toMatchInlineSnapshot(`
|
||||
"ArrayBuffer(0) []
|
||||
SharedArrayBuffer(0) []
|
||||
ArrayBuffer(3) [ 0, 0, 0 ]
|
||||
SharedArrayBuffer(3) [ 0, 0, 0 ]
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -660,8 +660,11 @@ for (const { body, fn } of bodyTypes) {
|
||||
}
|
||||
|
||||
function arrayBuffer(buffer: BufferSource) {
|
||||
if (buffer instanceof ArrayBuffer || buffer instanceof SharedArrayBuffer) {
|
||||
if (buffer instanceof ArrayBuffer) {
|
||||
return buffer;
|
||||
}
|
||||
if (buffer instanceof SharedArrayBuffer) {
|
||||
return new Uint8Array(new Uint8Array(buffer)).buffer;
|
||||
}
|
||||
return buffer.buffer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user