blob: 53f527418f96fa4cd0951aca8aded44d3d81dbc0 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
// Verifies TypedArray builtin properties
if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
}
function mangle(u8) {
u8.length = -2;
u8.byteLength = 2000;
u8.byteOffset = 45;
u8.buffer = 25;
u8.BYTES_PER_ELEMENT = 4;
}
var tests = [
{
name: "TypedArray builtin properties can't be overwritten, but writing to them does not throw an error",
body: function () {
var arr = new ArrayBuffer(100);
var u8 = new Uint8Array(arr, 90);
for (var i = 0; i < u8.length; i++) {
u8[i] = i;
}
mangle(u8);
assert.areEqual(10, u8.length, "Writing to length has no effect");
assert.areEqual(10, u8.byteLength, "Writing to byteLength has no effect");
assert.areEqual(90, u8.byteOffset, "Writing to byteOffset has no effect");
assert.areEqual(1, u8.BYTES_PER_ELEMENT, "Writing to BYTES_PER_ELEMENT has no effect");
assert.isTrue(arr === u8.buffer, "Writing to buffer has no effect");
assert.throws(function() { Array.prototype.splice.call(u8, 4, 3, 1, 2, 3, 4, 5); }, TypeError, "Array.prototype.splice tries to set the length property of the TypedArray object which will throw", "Cannot define property: object is not extensible");
assert.areEqual(10, u8.length, "Array.prototype.splice throws when it tries to set the length property");
assert.areEqual(10, u8.byteLength, "The byteLength property should not be changed");
assert.areEqual([0,1,2,3,1,2,3,4,5,7], u8, "After splice, array has correct values - NOTE: last two values are gone from the array");
assert.throws(function() { Array.prototype.push.call(u8, 100); }, TypeError, "Array.prototype.push tries to set the length property of the TypedArray object which will throw", "Cannot define property: object is not extensible");
assert.areEqual([0,1,2,3,1,2,3,4,5,7], u8, "Array.prototype.push doesn't modify the TypedArray");
}
},
{
name: "TypedArray constructed out of an iterable object",
body: function () {
function getIterableObj (array)
{
return {
[Symbol.iterator]: ()=> {
return {
next: () => {
return {
value: array.shift(),
done: array.length == 0
};
}
};
}
};
}
function getIterableObjNextDesc (array)
{
return {
get: function () {
array.shift(); // side effect
return function () {
return {
value: array.shift(),
done: array.length == 0
};
};
}
};
}
var TypedArray = [
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
];
for(var t of TypedArray) {
var arr = new this[t](getIterableObj([1,2,3,4]));
assert.areEqual(3, arr.length, "TypedArray " + t + " created from iterable has length == 3");
assert.areEqual(1, arr[0], "TypedArray " + t + " created from iterable has element #0 == 1");
assert.areEqual(2, arr[1], "TypedArray " + t + " created from iterable has element #1 == 2");
assert.areEqual(3, arr[2], "TypedArray " + t + " created from iterable has element #2 == 3");
}
// change array's iterator
(function() {
for(var t of TypedArray) {
var a = [1,2,3,4];
a[Symbol.iterator] = getIterableObj([99,0])[Symbol.iterator];
var arr = new this[t](a);
assert.areEqual(1, arr.length, "TypedArray " + t + " created from array with user-defined iterator has length == 1");
assert.areEqual(99, arr[0], "TypedArray " + t + " created from array with user-defined iterator has element #0 == 99");
}
})();
// helpers for testing all typed arrays when built-in array iterator is changed
function testTypedArrayConstructorWithIterableArray(inputarray, t, func, text) {
func();
var arr = new this[t](inputarray);
assert.areEqual(1, arr.length, "TypedArray " + t + " created from array with " + text + " has length == 1");
assert.areEqual(99, arr[0], "TypedArray " + t + " created from array with "+ text + " has element #0 == 99");
}
function testAllTypedArrayConstructorsWithIterableArray(inputarray, func, text) {
testTypedArrayConstructorWithIterableArray(inputarray, 'Int8Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Uint8Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Uint8ClampedArray', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Int16Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Uint16Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Int32Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Uint32Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Float32Array', func, text);
testTypedArrayConstructorWithIterableArray(inputarray, 'Float64Array', func, text);
}
// change built-in Array prototype's iterator
(function() {
var builtinArrayPrototypeIteratorDesc = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
var a = [1,2,3,4];
Object.defineProperty(Array.prototype, Symbol.iterator, {enumerable: false, configurable: true, writable: true});
var overrideBuiltinArrayPrototypeIterator = function() {
Array.prototype[Symbol.iterator] = getIterableObj([99,0])[Symbol.iterator];
};
testAllTypedArrayConstructorsWithIterableArray(a, overrideBuiltinArrayPrototypeIterator, "Array.prototype overriden");
Object.defineProperty(Array.prototype, Symbol.iterator, builtinArrayPrototypeIteratorDesc);
})();
// change built-in array iterator's next function
(function() {
var arrayIteratorProto = Object.getPrototypeOf([][Symbol.iterator]());
var builtinArrayPrototypeIteratorNext = arrayIteratorProto.next;
var overrideBuiltinArrayIteratorNext = function() {
arrayIteratorProto.next = getIterableObj([99,0])[Symbol.iterator]().next;
}
var a = [1,2,3,4];
testAllTypedArrayConstructorsWithIterableArray(a, overrideBuiltinArrayIteratorNext, "%ArrayIteratorPrototype%.next overriden");
arrayIteratorProto.next = builtinArrayPrototypeIteratorNext;
})();
// change built-in array iterator's next getter function
(function() {
var arrayIteratorProto = Object.getPrototypeOf([][Symbol.iterator]());
var builtinArrayPrototypeIteratorNextDesc = Object.getOwnPropertyDescriptor(arrayIteratorProto, "next");
var overrideBuiltinArrayIteratorNext = function() {
Object.defineProperty(arrayIteratorProto, "next", getIterableObjNextDesc([0,99,0]));
}
var a = [1,2,3,4];
testAllTypedArrayConstructorsWithIterableArray(a, overrideBuiltinArrayIteratorNext, "%ArrayIteratorPrototype%.next overriden by getter");
Object.defineProperty(arrayIteratorProto, "next", builtinArrayPrototypeIteratorNextDesc);
})();
}
},
{
name: "TypedArray constructor and TypedArray.from don't get @@iterator twice",
body: function () {
let count = 0;
new Uint8Array({
get [Symbol.iterator]() {
count++;
return [][Symbol.iterator];
}
});
assert.areEqual(count, 1, "TypedArray constructor calls @@iterator getter once");
count = 0;
new Uint8Array(new Proxy({}, {
get(target, property) {
if (property === Symbol.iterator) {
count++;
return [][Symbol.iterator];
}
return Reflect.get(target, property);
}
}));
assert.areEqual(count, 1, "TypedArray constructor calls proxy's getter with @@iterator as parameter only once");
count = 0;
Uint8Array.from({
get [Symbol.iterator]() {
count++;
return [][Symbol.iterator];
}
});
assert.areEqual(count, 1, "TypedArray.from calls @@iterator getter once");
count = 0;
Uint8Array.from(new Proxy({}, {
get(target, property) {
if (property === Symbol.iterator) {
count++;
return [][Symbol.iterator];
}
return Reflect.get(target, property);
}
}));
assert.areEqual(count, 1, "TypedArray.from calls proxy's getter with @@iterator as parameter only once");
}
}
];
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });