hermes-windows/test/hermes/TypedArray.js

1478 строки
37 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// RUN: %hermes -Xhermes-internal-test-methods -Xes6-proxy -O -gc-sanitize-handles=0 %s | %FileCheck %s
'use strict';
print("START");
//CHECK:START
function isLittleEndian() {
var uint16 = new Uint16Array(1);
uint16[0] = 1;
var uint8 = new Uint8Array(uint16.buffer);
return uint8[0] === 1;
}
function getByteWidth(cons) {
switch (cons) {
case Int8Array:
case Uint8Array:
case Uint8ClampedArray:
return 1;
case Int16Array:
case Uint16Array:
return 2;
case Int32Array:
case Uint32Array:
case Float32Array:
return 4;
case Float64Array:
return 8;
}
}
// This has the same API as the Node.js assert object.
var assert = {
_isEqual: function(a, b) {
// Remember to check for NaN which does not compare as equal with itself.
return a === b || (Number.isNaN(a) && Number.isNaN(b));
},
equal: function(actual, expected, msg) {
if (!assert._isEqual(actual, expected)) {
assert.fail(
(msg ? msg + ' -- ' : '') +
'Not equal: actual <' +
actual +
'>, and expected <' +
expected +
'>',
);
}
},
_isArrayEqual: function(a, b) {
if (a.length !== b.length)
return false;
for (var i = 0; i < a.length; i++) {
if (!assert._isEqual(a[i], b[i]))
return false;
}
return true;
},
arrayEqual: function(actual, expected, msg) {
if (!assert._isArrayEqual(actual, expected)) {
assert.fail(
(msg ? msg + ' -- ' : '') +
'Array not equal: actual <' +
actual +
'>, and expected <' +
expected +
'>',
);
}
},
notEqual: function(actual, expected, msg) {
if (assert._isEqual(actual, expected)) {
assert.fail(
(msg ? msg + ' -- ' : '') +
'Equal: actual <' +
actual +
'>, and expected <' +
expected +
'>',
);
}
},
ok: function(value, msg) {
assert.equal(!!value, true, msg);
},
throws: function(block, error, msg) {
try {
block();
} catch (e) {
assert.equal(e.constructor, error, msg);
return;
}
// Can't put fail inside the try because it will catch the AssertionError.
assert.fail((msg ? msg + ' -- ' : '') + 'Failed to throw');
},
fail: function(msg) {
throw new Error('AssertionError: ' + (msg ? msg : 'Failed'));
},
};
var cons = [
Int8Array,
Int16Array,
Int32Array,
Uint8Array,
Uint8ClampedArray,
Uint16Array,
Uint32Array,
Float32Array,
Float64Array,
];
var LE = isLittleEndian();
// Check length
cons.forEach(function(TypedArray) {
var buf = new ArrayBuffer(32);
var view = new TypedArray(buf);
assert.equal(view.length, buf.byteLength / getByteWidth(TypedArray));
});
// Check byteLength
cons.forEach(function(TypedArray) {
var buf = new ArrayBuffer(32);
var view = new TypedArray(buf);
assert.equal(view.byteLength, buf.byteLength);
});
// Check byteOffset
cons.forEach(function(TypedArray) {
assert.equal(new TypedArray(new ArrayBuffer(32), 8, 1).byteOffset, 8);
});
// Check BYTES_PER_ELEMENT
cons.forEach(function(TypedArray) {
assert.equal(TypedArray.BYTES_PER_ELEMENT, getByteWidth(TypedArray));
assert.equal(new TypedArray().BYTES_PER_ELEMENT, getByteWidth(TypedArray));
// Check flags of the field.
var desc = Object.getOwnPropertyDescriptor(TypedArray, 'BYTES_PER_ELEMENT');
assert.ok(!desc.writable);
assert.ok(!desc.enumerable);
assert.ok(!desc.configurable);
desc = Object.getOwnPropertyDescriptor(
TypedArray.prototype,
'BYTES_PER_ELEMENT',
);
assert.ok(!desc.writable);
assert.ok(!desc.enumerable);
assert.ok(!desc.configurable);
});
// Check the flags for various fields.
cons.forEach(function(TypedArray) {
var proto = Object.getPrototypeOf(TypedArray);
assert.ok(
!Object.getOwnPropertyDescriptor(proto.prototype, 'buffer').enumerable,
);
assert.ok(
!Object.getOwnPropertyDescriptor(proto.prototype, 'byteLength').enumerable,
);
assert.ok(
!Object.getOwnPropertyDescriptor(proto.prototype, 'byteOffset').enumerable,
);
assert.ok(
Object.getOwnPropertyDescriptor(proto.prototype, 'buffer').configurable,
);
assert.ok(
Object.getOwnPropertyDescriptor(proto.prototype, 'byteLength').configurable,
);
assert.ok(
Object.getOwnPropertyDescriptor(proto.prototype, 'byteOffset').configurable,
);
});
// Check length of the constructors.
cons.forEach(function(TypedArray) {
assert.equal(TypedArray.length, 3);
});
// Check initialized to zero
cons.forEach(function(TypedArray) {
var buf = new ArrayBuffer(32);
var view = new TypedArray(buf);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], 0);
}
});
(function checkBufferShared() {
var buf = new ArrayBuffer(32);
var int8view = new Int8Array(buf);
var uint8view = new Uint8Array(buf);
// Check that the buffer is shared
// Ensure they're both zero'd out before writing (in case previous tests left
// data in them)
int8view[0] = 0;
uint8view[0] = 0;
int8view[0] = 5;
assert.equal(uint8view[0], 5);
})();
/// @name Constructors
/// @{
// Check constructor from Array with ints
cons.forEach(function(TypedArray) {
var view = new TypedArray([1, 2, 3]);
assert.equal(view.length, 3);
assert.equal(view[0], 1);
assert.equal(view[1], 2);
assert.equal(view[2], 3);
});
// Check constructor from Array with arbitrary types
cons.forEach(function(TypedArray) {
var view = new TypedArray(['1', {}, false]);
assert.equal(view.length, 3);
assert.equal(view[0], 1);
if (TypedArray == Float32Array || TypedArray == Float64Array) {
assert.equal(view[1], NaN);
} else {
assert.equal(view[1], 0);
}
assert.equal(view[2], 0);
});
// Check constructor from empty Array
cons.forEach(function(TypedArray) {
assert.equal(new TypedArray([]).length, 0);
});
// Constructor from undefined should give an empty TypedArray
cons.forEach(function(TypedArray) {
assert.equal(new TypedArray(undefined).length, 0);
});
// Check constructor from Array-esque object
cons.forEach(function(TypedArray) {
var arrayEsque = {length: 1};
arrayEsque[0] = 1;
var view = new TypedArray(arrayEsque);
assert.equal(view.length, 1);
assert.equal(view[0], 1);
});
// Empty constructor
cons.forEach(function(TypedArray) {
assert.equal(new TypedArray().length, 0);
});
// Constructor with length
cons.forEach(function(TypedArray) {
var view = new TypedArray(16);
assert.equal(view.length, 16);
assert.equal(view[0], 0);
});
// Constructor from buffer but with zero size
cons.forEach(function(TypedArray) {
var buf = new ArrayBuffer(32);
var emptyArrayFromOtherBuffer = new TypedArray(buf, 16, 0);
assert.equal(emptyArrayFromOtherBuffer.length, 0);
});
// Constructor from buffer with length smaller than offset
cons.forEach(function(TypedArray) {
var buf = new ArrayBuffer(32);
var arrayFromBufferWithSmallLength = new TypedArray(buf, 8, 2);
assert.equal(arrayFromBufferWithSmallLength.length, 2);
assert.equal(arrayFromBufferWithSmallLength[0], 0);
assert.equal(arrayFromBufferWithSmallLength[1], 0);
});
// Constructor from another TypedArray of the same type
cons.forEach(function(TypedArray) {
var original = new TypedArray(32);
var sameTypeArray = new TypedArray(original);
assert.equal(sameTypeArray.length, original.length);
// The bytes should have been copied, and reside in a different buffer
assert.notEqual(sameTypeArray.buffer, original.buffer);
});
(function checkLargeValuesInConstructor() {
// Check constructor from Array with huge values
// 256 should wrap around to be 0
var consFromArray = new Uint8Array([256]);
assert.equal(consFromArray.length, 1);
assert.equal(consFromArray[0], 0);
})();
/// @}
// Check for..of loop
cons.forEach(function(TypedArray) {
var arr = [10, 20, 30]
var view = new TypedArray(arr);
var result = [];
for (var i of view)
result.push(i);
assert.arrayEqual(result, arr);
});
// Check for..in loop
cons.forEach(function(TypedArray) {
var view = new TypedArray(5);
var result = [];
for(var i in view)
result.push(i);
assert.arrayEqual(result, ["0", "1", "2", "3", "4"]);
// Detach the buffer. Result should be the same because
// IsDetachedBuffer is not checked in ES6 9.4.5.6 [[OwnPropertyKeys]].
HermesInternal.detachArrayBuffer(view.buffer);
result = [];
for(var i in view)
result.push(i);
assert.arrayEqual(result, ["0", "1", "2", "3", "4"]);
});
// Check basic writability properties
cons.forEach(function(TypedArray) {
var view = new TypedArray(32);
for (var i = 0; i < view.length; i++) {
view[i] = i;
assert.equal(view[i], i);
}
});
// Check uint8clamped is clamped
(function checkClamped() {
var view = new Uint8ClampedArray(1);
// Writing a value > 255 into uint8clampedview should give 255
view[0] = 300;
assert.equal(view[0], 255);
// Also check for round-to-even behavior
view[0] = 1.5;
assert.equal(view[0], 2);
view[0] = 2.5;
assert.equal(view[0], 2);
})();
(function checkFloatMaxValue() {
var view = new Float32Array(1);
view[0] = Number.MAX_VALUE;
assert.equal(view[0], Infinity);
})();
(function checkFloatSanitization() {
// Check float is sanitized
// Basis of this test is that in Hermes, a NaN can have a "payload" which
// could represent a pointer. We must ensure that if such a value is read from,
// the payload is sanitized out
var buf = new ArrayBuffer(8);
var uint8view = new Uint8Array(buf);
var uint32view = new Uint32Array(buf);
var float32view = new Float32Array(buf);
var float64view = new Float64Array(buf);
// all 1's
uint32view[0] = 0xffffffff;
assert.equal(float32view[0], NaN);
// 64-bit version, need to use a uint8 array,
// 0xff ff 00 01 00 e0 00 58
// is an example tagged NaN value to sanitize
if (LE) {
// little-endian order of bytes
uint8view[0] = 0x58;
uint8view[1] = 0x00;
uint8view[2] = 0xe0;
uint8view[3] = 0x00;
uint8view[4] = 0x01;
uint8view[5] = 0x00;
uint8view[6] = 0xff;
uint8view[7] = 0xff;
} else {
// big-endian order of bytes
uint8view[7] = 0xff;
uint8view[6] = 0xff;
uint8view[5] = 0x00;
uint8view[4] = 0x01;
uint8view[3] = 0x00;
uint8view[2] = 0xe0;
uint8view[1] = 0x00;
uint8view[0] = 0x58;
}
assert.equal(float64view[0], NaN);
})();
(function checkConstructorFromDifferentType() {
// Constructor from another TypedArray of a different type
var int32view = new Int32Array([0, 1, 2, 3]);
// This constructor copies the values
var differentTypeArray = new Int16Array(int32view);
assert.equal(differentTypeArray.length, int32view.length);
// The bytes should have been copied
for (var i = 0; i < differentTypeArray.length; i++) {
assert.equal(differentTypeArray[i], i);
}
})();
(function checkSignsInFloat() {
// Signs in float
var a = new Float64Array(4);
a[0] = -0;
assert.equal(1 / a[0], -Infinity);
})();
/// @name %TypedArray% in and delete
/// @{
cons.forEach(function(TA) {
var ta = new TA([1,2,3,4,5]);
assert.equal(false, -1 in ta);
assert.equal(true, 0 in ta);
assert.equal(true, 4 in ta);
assert.equal(false, 5 in ta);
assert.equal(true, delete ta[-1]);
assert.throws(_ => delete ta[0], TypeError);
assert.throws(_ => delete ta[4], TypeError);
assert.equal(true, delete ta[5]);
assert.equal(true, Reflect.deleteProperty(ta, -1));
assert.equal(false, Reflect.deleteProperty(ta, 0));
assert.equal(false, Reflect.deleteProperty(ta, 4));
assert.equal(true, Reflect.deleteProperty(ta, 5));
});
/// @}
/// @name %TypedArray%.prototype.buffer
/// @{
cons.forEach(function(TypedArray) {
assert.throws(function() {
TypedArray.prototype.buffer;
}, TypeError);
});
/// @}
/// @name %TypedArray%.prototype.at
/// @{
cons.forEach(function(TA) {
var ta = new TA([1, 2, 3, 4, 5]);
assert.equal(ta.at(0).toString(), '1');
assert.equal(ta.at(-1).toString(), '5');
assert.equal(ta.at(10), undefined);
assert.throws(function(){TA.prototype.at.call(ta, 1n)}, TypeError);
assert.throws(function(){TA.prototype.at.call("hi", 1)}, TypeError);
assert.throws(function(){TA.prototype.at.call([1, "f", 3], 1)}, TypeError);
});
// @}
/// @name %TypedArray%.prototype.copyWithin
/// @{
cons.forEach(function(TA) {
assert.equal(new TA([1, 2, 3, 4, 5]).copyWithin(-2).toString(), '1,2,3,1,2');
assert.equal(new TA([1, 2, 3, 4, 5]).copyWithin(0).toString(), '1,2,3,4,5');
assert.equal(
new TA([1, 2, 3, 4, 5]).copyWithin(0, 3, 4).toString(),
'4,2,3,4,5',
);
assert.equal(
new TA([1, 2, 3, 4, 5]).copyWithin(-2, -3, -1).toString(),
'1,2,3,3,4',
);
if (HermesInternal.detachArrayBuffer) {
var ta = new TA(1000);
assert.throws(function() {
ta.copyWithin(
{
valueOf: function() {
HermesInternal.detachArrayBuffer(ta.buffer);
return 1;
},
},
4,
256,
);
}, TypeError);
}
});
(function() {
// Ensure bit-level preservation.
var A = new Float32Array(4);
A[0] = 0 / 0;
A[1] = -(0 / 0);
var bytes1 = new Uint8Array(A.buffer, 0, 8);
A.copyWithin(2, 0); // Copy bytes to the second half of A.
var bytes2 = new Uint8Array(A.buffer, 8, 8);
assert.equal(bytes1.length, bytes2.length);
for (var i = 0; i < bytes1.length; ++i) {
assert.equal(bytes1[i], bytes2[i]);
}
})();
/// @}
/// @name %TypedArray%.from
/// @{
cons.forEach(function(c, i) {
// Function exists.
assert.ok('from' in c);
assert.ok(c.from);
// Works on arrays.
var ta = c.from([1, 2, 3]);
assert.equal(ta.length, 3);
assert.equal(ta[0], 1);
assert.equal(ta[1], 2);
assert.equal(ta[2], 3);
// Works on a different typed array.
var otherTA = new cons[i == 0 ? cons.length - 1 : i - 1]([1, 2, 3]);
ta = c.from(otherTA);
assert.equal(ta.length, 3);
assert.equal(ta[0], 1);
assert.equal(ta[1], 2);
assert.equal(ta[2], 3);
// "array-like" object.
var arrayLike = {length: 3};
arrayLike[0] = 1;
arrayLike[1] = 2;
arrayLike[2] = 3;
ta = c.from(arrayLike);
assert.equal(ta.length, 3);
assert.equal(ta[0], 1);
assert.equal(ta[1], 2);
assert.equal(ta[2], 3);
// Array with holes.
ta = c.from([1, 2, , , 3]);
assert.equal(ta.length, 5);
assert.equal(ta[0], 1);
assert.equal(ta[1], 2);
// undefined is coerced to zero, except for floats which are NaN.
if (c === Float32Array || c === Float64Array) {
assert.equal(ta[2], NaN);
assert.equal(ta[3], NaN);
} else {
assert.equal(ta[2], 0);
assert.equal(ta[3], 0);
}
assert.equal(ta[4], 3);
// Test calling without the this argument.
var from = c.from;
assert.throws(function() {
from([]);
}, TypeError);
// Test a TypedArray whose length is greater than 2 ^ 32 - 1
// NOTE: This behavior differs from v8 and JSC, because we use uint32_t as our
// indexing type. They also disagree with each other.
assert.throws(function() {
var ta = new c();
Object.defineProperty(ta, "length", {
get: function() {
// This number is 2 ^ 32 + 1.
return 4294967297;
}
});
return c.from(ta);
}, RangeError);
});
/// @}
/// @name %TypedArray%.of
/// @{
cons.forEach(function(TypedArray) {
// Function exists.
assert.ok('of' in TypedArray);
assert.ok(TypedArray.of);
assert.equal(TypedArray.of.length, 0);
var ta = TypedArray.of(1, 2, 3);
assert.equal(ta.length, 3);
assert.equal(ta[0], 1);
assert.equal(ta[1], 2);
assert.equal(ta[2], 3);
// Works on no arguments.
ta = TypedArray.of();
assert.equal(ta.length, 0);
// Test calling without the this argument.
var of = TypedArray.of;
assert.throws(function() {
of();
}, TypeError);
});
// Returning a smaller array than requested.
cons.forEach(function(TypedArray) {
var thisArg = function() {
return new TypedArray(1);
};
assert.throws(function() {
TypedArray.of.call(thisArg, 1, 2, 3, 4);
}, TypeError);
});
/// @}
/// @name %TypedArray%.prototype.every && .some
/// @{
cons.forEach(function(TypedArray) {
var view = new TypedArray([0, 1, 2, 3, 4]);
// Check that callback function is passed parameters correctly
assert.ok(
view.every(function(elem, i, v) {
return elem === i && v == view;
}),
);
// Check basic properties
assert.ok(
view.every(function() {
return true;
}),
);
assert.ok(
!view.every(function() {
return false;
}),
);
assert.ok(
!view.every(function(elem, i) {
return i !== 0;
}),
);
// Check that callback function is passed parameters correctly
assert.ok(
!view.some(function(elem, i, v) {
return !(elem === i && v == view);
}),
);
// Check basic properties
assert.ok(
!view.some(function() {
return false;
}),
);
assert.ok(
view.some(function() {
return true;
}),
);
assert.ok(
view.some(function(elem, i) {
if (i == 0) {
return true;
}
}),
);
});
/// @}
/// @name %TypedArray%.prototype.fill
/// @{
cons.forEach(function(TypedArray) {
var view = new TypedArray(4);
view.fill(1);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], 1);
}
view.fill(2, 3);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], i < 3 ? 1 : 2);
}
view.fill(0);
view.fill(1, 4, 6);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], i < 4 || i >= 6 ? 0 : 1);
}
view.fill(0);
view.fill(1, 4, 100);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], i < 4 ? 0 : 1);
}
view.fill(0);
view.fill(1, -100, 4);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], i < 4 ? 1 : 0);
}
view.fill(0);
view.fill(1, -2, -1);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], i < view.length - 2 || i >= view.length - 1 ? 0 : 1);
}
view.fill(1);
// This should not fill any elements.
view.fill(0, Infinity);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], 1);
}
// This should fill all elements, Infinity is past the end.
view.fill(2, 0, Infinity);
for (var i = 0; i < view.length; i++) {
assert.equal(view[i], 2);
}
// Calling fill on a detached TypedArray should throw TypeError.
HermesInternal.detachArrayBuffer(view.buffer);
assert.throws(function() {
view.fill(0);
}, TypeError);
// Converting the first argument to a number can detach the TypedArray.
view = new TypedArray(4);
assert.throws(function() {
view.fill({
valueOf: function() {
HermesInternal.detachArrayBuffer(view.buffer);
return 1;
},
});
}, TypeError);
});
cons.forEach(function(TypedArray) {
// Fill with start >= end should remain the same.
var arr = new TypedArray([0, 0, 0, 0]);
arr.fill(8, 3, 1);
assert.equal(arr.length, 4);
assert.equal(arr[0], 0);
assert.equal(arr[1], 0);
assert.equal(arr[2], 0);
assert.equal(arr[3], 0);
arr.fill(8, -1, -3);
assert.equal(arr.length, 4);
assert.equal(arr[0], 0);
assert.equal(arr[1], 0);
assert.equal(arr[2], 0);
assert.equal(arr[3], 0);
});
/// @}
/// @name TypedArray.prototype.filter
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
// Result should be the same length and contain the same elements
var filtered = arr.filter(function(elem, i, view) {
return elem === i && view === arr;
});
// It should be a copy, not the same
assert.notEqual(filtered, arr);
assert.equal(filtered.length, arr.length);
for (var i = 0; i < filtered.length; i++) {
assert.equal(filtered[i], i);
}
filtered = arr.filter(function(_, i) {
return i >= arr.length - 2 && i < arr.length;
});
assert.equal(filtered.length, 2);
assert.equal(filtered[0], arr.length - 2);
assert.equal(filtered[1], arr.length - 1);
assert.throws(function() {
arr.filter(function() {
throw new RangeError();
});
}, RangeError);
});
/// @}
/// @name TypedArray.prototype.findLast/.findLastIndex
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
var cb = function(elem, i, view) {
assert.equal(view, arr);
assert.equal(elem, i);
return i === arr.length - 1;
};
assert.equal(arr.findLast(cb), arr.length - 1);
assert.equal(arr.findLastIndex(cb), arr.length - 1);
var numcalls = 0;
cb = function() {
++numcalls;
return true;
};
assert.equal(arr.findLast(cb), 3);
assert.equal(arr.findLastIndex(cb), 3);
assert.equal(numcalls, 2);
cb = function() {
return false;
};
assert.equal(arr.findLast(cb), undefined);
assert.equal(arr.findLastIndex(cb), -1);
var state = [];
cb = function(elem, i, view) {
state.push(elem);
return elem === 2;
};
assert.equal(arr.findLast(cb), 2);
assert.arrayEqual(state, [3, 2]);
});
/// @}
/// @name TypedArray.prototype.find/.findIndex
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
var cb = function(elem, i, view) {
assert.equal(view, arr);
assert.equal(elem, i);
return i === arr.length - 1;
};
assert.equal(arr.find(cb), arr.length - 1);
assert.equal(arr.findIndex(cb), arr.length - 1);
var numcalls = 0;
cb = function() {
++numcalls;
return true;
};
assert.equal(arr.find(cb), 0);
assert.equal(arr.findIndex(cb), 0);
assert.equal(numcalls, 2);
cb = function() {
return false;
};
assert.equal(arr.find(cb), undefined);
assert.equal(arr.findIndex(cb), -1);
var state = [];
cb = function(elem, i, view) {
state.push(elem);
return elem === 2;
};
assert.equal(arr.find(cb), 2);
assert.arrayEqual(state, [0, 1, 2]);
});
/// @}
/// @name TypedArray.prototype.forEach
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
assert.equal(
arr.forEach(function(elem, i, view) {
assert.equal(elem, i);
assert.equal(view, arr);
}),
undefined,
);
var numcalls = 0;
arr.forEach(function() {
numcalls++;
});
assert.equal(numcalls, arr.length);
});
/// @}
/// @name TypedArray.prototype.includes && .indexOf
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
assert.ok(arr.includes(1));
assert.equal(arr.indexOf(1), 1);
assert.equal(arr.lastIndexOf(1), 1);
assert.ok(!arr.includes(1000));
assert.equal(arr.indexOf(1000), -1);
assert.equal(arr.lastIndexOf(1000), -1);
assert.ok(arr.includes(0, 0));
assert.ok(!arr.includes(0, 1));
assert.ok(!arr.includes(0, 1000));
assert.equal(arr.indexOf(0, 0), 0);
assert.equal(arr.indexOf(0, 1), -1);
assert.equal(arr.indexOf(0, 1000), -1);
assert.equal(arr.lastIndexOf(0, 0), 0);
assert.equal(arr.lastIndexOf(0, 1), 0);
assert.equal(arr.lastIndexOf(0, 1000), 0);
assert.ok(arr.includes(arr.length - 2, -2));
assert.ok(!arr.includes(arr.length - 3, -1));
assert.equal(arr.indexOf(arr.length - 2, -2), arr.length - 2);
assert.equal(arr.indexOf(arr.length - 3, -1), -1);
assert.equal(arr.lastIndexOf(arr.length - 2, -2), arr.length - 2);
assert.equal(arr.lastIndexOf(arr.length - 3, -1), arr.length - 3);
// Set up duplicates to test indexOf vs lastIndexOf
arr[0] = 50;
arr[1] = 50;
assert.equal(arr.indexOf(50), 0);
assert.equal(arr.lastIndexOf(50), 1);
assert.throws(function() {
arr.includes(0, {
valueOf() {
HermesInternal.detachArrayBuffer(arr.buffer);
return 0;
},
});
}, TypeError);
});
/// @}
/// @name TypedArray.prototype.join && .toString (since toString calls join)
/// @{
cons.forEach(function(ta) {
var arr = new ta([1, 2, 3]);
assert.equal(arr.join(), '1,2,3');
assert.equal(arr.join(','), '1,2,3');
assert.equal(arr.join(''), '123');
assert.equal(arr.join('asdf'), '1asdf2asdf3');
// Test empty case.
assert.equal(new ta([]).join(), '');
// Test toString.
assert.equal(ta.prototype.toString, Array.prototype.toString);
assert.equal(arr.toString(), arr.join());
// Test difference between integral and floating toString
if (ta === Float32Array || ta === Float64Array) {
assert.equal(new ta([{}]).toString(), 'NaN');
} else {
assert.equal(new ta([{}]).toString(), '0', ta.toString());
}
});
/// @}
/// @name TypedArray.prototype.reverse
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
arr.reverse();
for (var i = 0; i < arr.length; i++) {
assert.equal(arr[i], arr.length - 1 - i);
}
var emptyReversed = new (Object.getPrototypeOf(arr)).constructor(
[],
).reverse();
assert.equal(emptyReversed.length, 0);
var oddReversed = new (Object.getPrototypeOf(arr)).constructor([
1,
2,
3,
]).reverse();
assert.equal(oddReversed.length, 3);
assert.equal(oddReversed[0], 3);
assert.equal(oddReversed[1], 2);
assert.equal(oddReversed[2], 1);
});
/// @}
/// @name TypedArray.prototype.sort
/// @{
cons.forEach(function(ta) {
var x = new ta([3, 2, 1]);
x.sort();
assert.equal(x[0], 1);
assert.equal(x[1], 2);
assert.equal(x[2], 3);
// Check empty doesn't crash.
x = new ta([]);
x.sort();
assert.equal(x.length, 0);
// Check with comparefn.
x = new ta([3, 2, 1]);
// Use the reverse sorter, normal definition is a - b.
x.sort(function(a, b) {
return b - a;
});
assert.equal(x[0], 3);
assert.equal(x[1], 2);
assert.equal(x[2], 1);
// Check stable.
x = new ta([1, 111, 11, 22, 2, 33, 3]);
x.sort(function(a, b) {
return (a + "").length - (b + "").length;
});
assert.equal(x[0], 1);
assert.equal(x[1], 2);
assert.equal(x[2], 3);
assert.equal(x[3], 11);
assert.equal(x[4], 22);
assert.equal(x[5], 33);
assert.equal(x[6], 111);
assert.throws(function() {
x.sort(null);
}, TypeError);
assert.throws(function() {
x.sort(true);
}, TypeError);
assert.throws(function() {
x.sort(12);
}, TypeError);
assert.throws(function() {
x.sort({});
}, TypeError);
// Sorting a TypedArray allocates handles linearly with respect to the size
// of the buffer. Sorting a larger array will ensure that we clean those up
// periodically.
x = new ta(104);
x.sort(function(unused1, unused2) {
return true;
});
for (var i = 0; i < x.length; i++) {
assert.equal(x[i], 0);
}
// Check that detaching in the middle of sorting will cause a TypeError.
x = new ta([1, 2, 3]);
assert.throws(function() {
x.sort(function f(unused1, unused2) {
var a = {};
a.valueOf = function() {
HermesInternal.detachArrayBuffer(x.buffer);
};
return a;
});
}, TypeError);
});
(function negativeZeroSort() {
var x = new Float64Array([+0, -0]);
x.sort();
assert.equal(1 / x[0], -Infinity);
assert.equal(1 / x[1], +Infinity);
})();
/// @}
/// @name TypedArray.prototype.set
/// @{
(function checkPrototypeSet() {
cons.forEach(function(ta, i) {
var dst = new ta([1, 2, 3]);
// Check setting to Object.
dst.set([5]);
assert.equal(dst[0], 5);
// Check setting at an offset.
dst.set([5], 2);
assert.equal(dst[2], 5);
assert.notEqual(dst[1], 5);
// Check setting to larger object.
dst.set([3, 2, 1]);
assert.equal(dst[0], 3);
assert.equal(dst[1], 2);
assert.equal(dst[2], 1);
// Check exception case of trying to set too large of an object.
assert.throws(function() {
dst.set([1, 2, 3, 4]);
}, RangeError);
assert.throws(function() {
dst.set([1], 10);
}, RangeError);
dst = new ta([4, 5, 6]);
// Check with other TypedArray of the same type.
var other = new ta([1, 2]);
dst.set(other);
assert.equal(dst[0], 1);
assert.equal(dst[1], 2);
assert.equal(dst[2], 6);
// Check with TypedArray of a different type.
var otherCons = cons[i == 0 ? cons.length - 1 : i - 1];
other = new otherCons([1, 2]);
dst.set(other);
assert.equal(dst[0], 1);
assert.equal(dst[1], 2);
assert.equal(dst[2], 6);
// Check with self.
dst = new ta([0, 1, 2]);
dst.set(dst);
for (var j = 0; j < dst.length; j++) {
assert.equal(dst[j], j);
}
// New TypedArray pointing to the same memory location, but at a different
// starting point.
other = new ta(dst.buffer, getByteWidth(ta));
assert.equal(other.length, dst.length - 1);
assert.equal(other[0], 1);
assert.equal(other[1], 2);
// This should move the rest of the array leftwards 1 space.
dst.set(other);
for (var j = 0; j < dst.length - 1; j++) {
assert.equal(dst[j], j + 1);
}
assert.equal(dst[dst.length - 1], dst.length - 1);
// Check with setting to an empty TypedArray
dst = new ta();
dst.set(new ta());
// Set empty to non-empty
dst = new ta([1, 2, 3]);
dst.set(new ta());
// Set non-empty to empty should throw RangeError
dst = new ta();
assert.throws(function() {
dst.set(new ta([1, 2, 3]));
}, RangeError);
});
// Moving from one typed array view to another of the same data.
var dst = new Int8Array([0, 1, 2, 3, 4, 5, 6, 7]);
var src = new Int32Array(dst.buffer);
dst.set(src);
assert.equal(dst[0], 0);
assert.equal(dst[1], 4);
for (var i = 2; i < dst.length; i++) {
assert.equal(dst[i], i);
}
// Check in reverse.
dst = new Int8Array([7, 6, 5, 4, 3, 2, 1, 0]);
src = new Int32Array(dst.buffer);
dst.set(src);
assert.equal(dst[0], 7);
assert.equal(dst[1], 3);
for (var i = 2; i < dst.length; i++) {
assert.equal(dst[i], dst.length - 1 - i);
}
// Check smaller into bigger as well.
dst = new Int32Array([5, 5, 0]);
src = new Int8Array(dst.buffer, 9);
// This should move the rest of the array leftwards 1 space.
dst.set(src);
assert.equal(dst[0], 0);
assert.equal(dst[1], 0);
assert.equal(dst[2], 0);
// Check overlapping and src is before dst
var buf = new Int8Array([1, 2, 3, 4]).buffer;
dst = new Int8Array(buf, 2);
src = new Int8Array(buf, 1, 2);
dst.set(src);
assert.equal(dst[0], 2);
assert.equal(dst[1], 3);
// Check that bitwise equivalence is preserved.
var bytes = new Uint8Array([0xff, 0xff, 0xff, 0xff]);
var flt = new Float32Array([1]);
flt.set(new Float32Array(bytes.buffer));
var chk = new Uint8Array(flt.buffer);
assert.equal(chk[0], 0xff);
assert.equal(chk[1], 0xff);
assert.equal(chk[2], 0xff);
assert.equal(chk[3], 0xff);
// Check that detach check is called after returning to runtime.
var typedarray = new Uint8Array(16);
var evilNumber = {
valueOf: function() {
HermesInternal.detachArrayBuffer(typedarray.buffer);
return 0;
},
};
assert.throws(function() {
typedarray.set([evilNumber, 5, 5], 5);
}, TypeError);
})();
/// @name TypedArray.prototype.slice
/// @{
(function checkPrototypeSlice() {
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
var x = arr.slice(0, 2);
assert.equal(x.length, 2);
assert.equal(x[0], arr[0]);
assert.equal(x[1], arr[1]);
// Check for the case where end is undefined.
x = arr.slice(1);
assert.equal(x.length, arr.length - 1);
for (var i = 0; i < x.length; i++) {
assert.equal(x[i], i + 1);
}
// Check negatives.
x = arr.slice(-2, -1);
assert.equal(x.length, 1);
assert.equal(x[0], arr.length - 2);
x = arr.slice(-2);
assert.equal(x.length, 2);
assert.equal(x[0], arr.length - 2);
assert.equal(x[1], arr.length - 1);
// Check empty.
arr = new (Object.getPrototypeOf(arr)).constructor([]);
x = arr.slice(0);
assert.equal(x.length, 0);
});
// Check that byte-wise equality is maintained.
var bytes = new Uint8Array([0xff, 0xff, 0xff, 0xff]);
var chk = new Uint8Array(new Float32Array(bytes.buffer).slice(0).buffer);
assert.equal(chk[0], 0xff);
assert.equal(chk[1], 0xff);
assert.equal(chk[2], 0xff);
assert.equal(chk[3], 0xff);
})();
/// @}
/// @name TypedArray.prototype.subarray
/// @{
cons.forEach(function(ta) {
var x = new ta([1, 2, 3]);
// Check when it's the full length.
var y = x.subarray(0, x.length);
assert.equal(y.length, x.length);
// They should share a buffer.
assert.equal(y.buffer, x.buffer);
for (var i = 0; i < x.length; i++) {
assert.equal(y[i], x[i]);
}
// Check undefined second parameter.
y = x.subarray(0);
assert.equal(y.length, x.length);
for (var i = 0; i < x.length; i++) {
assert.equal(y[i], x[i]);
}
// Check smaller range.
y = x.subarray(1);
assert.equal(y.length, x.length - 1);
for (var i = 0; i < y.length; i++) {
assert.equal(y[i], x[i + 1]);
}
// Check negative start.
y = x.subarray(-1);
assert.equal(y.length, 1);
assert.equal(y[0], x[x.length - 1]);
// Check negative end.
y = x.subarray(1, -1);
assert.equal(y.length, x.length - 2);
for (var i = 0; i < y.length; i++) {
assert.equal(y[i], x[i + 1]);
}
// Check negative start and end.
y = x.subarray(-2, -1);
assert.equal(y.length, 1);
assert.equal(y[0], x[x.length - 2]);
// Check end < begin (zero length result).
y = x.subarray(2, 0);
assert.equal(y.length, 0);
// Check that zero-sized array yields another zero size array.
y = new ta(0).subarray();
assert.equal(y.length, 0);
// Check that creating a subarray from a subarray works, and doesn't read
// off the end of the original.
y = new ta(10);
var z = y.subarray(5);
z.subarray();
});
/// @name TypedArray.prototype.toLocaleString
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([1, 2, 3]);
assert.equal(arr.toLocaleString(), '1,2,3');
var n = 0;
var oldToLocale = Number.prototype.toLocaleString;
Number.prototype.toLocaleString = function() {
++n;
return this;
};
assert.equal(arr.toLocaleString(), '1,2,3');
assert.equal(n, 3);
Number.prototype.toLocaleString = oldToLocale;
});
/// @name TypedArray.prototype.map
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
var other = arr.map(function(elem) {
return elem + 1;
});
// Should be a copy, not the same.
assert.notEqual(other, arr);
assert.equal(other.length, arr.length);
for (var i = 0; i < arr.length; i++) {
assert.equal(other[i], arr[i] + 1);
}
// Check non-number usages.
other = arr.map(function(elem) {
return {
valueOf: function() {
return 0;
},
};
});
assert.equal(other.length, arr.length);
for (var i = 0; i < other.length; i++) {
assert.equal(other[i], 0);
}
});
/// @}
/// @name TypedArray.prototype.reduce && reduceRight
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([0, 1, 2, 3]);
var count = function(acc) {
return acc + 1;
};
var sum = function(acc, elem) {
return acc + elem;
};
// sum(0, 1, ..., len - 1) == (len - 1) * (len) / 2
var totalsum = (arr.length * (arr.length - 1)) / 2;
assert.equal(arr.reduce(count, 0), arr.length);
assert.equal(arr.reduce(sum), totalsum);
assert.equal(arr.reduce(sum, 0), totalsum);
assert.equal(arr.reduceRight(count, 0), arr.length);
assert.equal(arr.reduceRight(sum), totalsum);
assert.equal(arr.reduceRight(sum, 0), totalsum);
// Check that it properly uses the first element
assert.equal(
arr.reduce(function(acc) {
return acc;
}),
0,
);
assert.equal(
arr.reduce(function(acc) {
return acc;
}, 1),
1,
);
assert.equal(
arr.reduceRight(function(acc) {
return acc;
}),
arr.length - 1,
);
assert.equal(
arr.reduceRight(function(acc) {
return acc;
}, 1),
1,
);
// Check non-objects:
var anEmptyObject = {};
assert.equal(
arr.reduce(function() {
return anEmptyObject;
}),
anEmptyObject,
);
assert.equal(
arr.reduceRight(function() {
return anEmptyObject;
}),
anEmptyObject,
);
// Check empty array.
var empty = new (Object.getPrototypeOf(arr)).constructor([]);
var numcalls = 0;
assert.throws(function() {
empty.reduce(function() {});
}, TypeError);
assert.equal(
empty.reduce(function() {
numcalls++;
}, 0),
0,
);
assert.equal(numcalls, 0);
numcalls = 0;
assert.throws(function() {
empty.reduceRight(function() {});
}, TypeError);
assert.equal(
empty.reduceRight(function() {
numcalls++;
}, 0),
0,
);
assert.equal(numcalls, 0);
// Check reduce and reduceRight are different
assert.equal(
arr.reduce(function(acc, elem) {
return elem;
}),
arr.length - 1,
);
assert.equal(
arr.reduceRight(function(acc, elem) {
return elem;
}),
0,
);
});
/// @}
/// @name Exception cases
/// @{
// Constructor with non-evenly-divisable length
assert.throws(function() {
new Int32Array(new ArrayBuffer(9));
}, RangeError);
// Constructor with negative offset
assert.throws(function() {
new Int8Array(new ArrayBuffer(8), -1);
}, RangeError);
// Constructor with offset not aligned
assert.throws(function() {
new Int32Array(new ArrayBuffer(8), 3);
}, RangeError);
// Constructor with offset out of bounds
assert.throws(function() {
new Int8Array(new ArrayBuffer(8), 9);
}, RangeError);
// Constructor with offset + length out of bounds
assert.throws(function() {
new Int8Array(new ArrayBuffer(8), 5, 5);
}, RangeError);
// TypedArray shouldn't be a symbol.
assert.throws(function() {
print(TypedArray);
}, ReferenceError);
/// @}
print("OK");
//CHECK-NEXT:OK