368 lines
9.1 KiB
Go
368 lines
9.1 KiB
Go
package goja
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestArrayProtoProp(t *testing.T) {
|
|
const SCRIPT = `
|
|
Object.defineProperty(Array.prototype, '0', {value: 42, configurable: true, writable: false})
|
|
var a = []
|
|
a[0] = 1
|
|
a[0]
|
|
`
|
|
|
|
testScript(SCRIPT, valueInt(42), t)
|
|
}
|
|
|
|
func TestArrayDelete(t *testing.T) {
|
|
const SCRIPT = `
|
|
var a = [1, 2];
|
|
var deleted = delete a[0];
|
|
var undef = a[0] === undefined;
|
|
var len = a.length;
|
|
|
|
deleted && undef && len === 2;
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArrayDeleteNonexisting(t *testing.T) {
|
|
const SCRIPT = `
|
|
Array.prototype[0] = 42;
|
|
var a = [];
|
|
delete a[0] && a[0] === 42;
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArraySetLength(t *testing.T) {
|
|
const SCRIPT = `
|
|
var a = [1, 2];
|
|
var assert0 = a.length == 2;
|
|
a.length = "1";
|
|
a.length = 1.0;
|
|
a.length = 1;
|
|
var assert1 = a.length == 1;
|
|
a.length = 2;
|
|
var assert2 = a.length == 2;
|
|
assert0 && assert1 && assert2 && a[1] === undefined;
|
|
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArrayReverseNonOptimisable(t *testing.T) {
|
|
const SCRIPT = `
|
|
var a = [];
|
|
Object.defineProperty(a, "0", {get: function() {return 42}, set: function(v) {Object.defineProperty(a, "0", {value: v + 1, writable: true, configurable: true})}, configurable: true})
|
|
a[1] = 43;
|
|
a.reverse();
|
|
|
|
a.length === 2 && a[0] === 44 && a[1] === 42;
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArrayPushNonOptimisable(t *testing.T) {
|
|
const SCRIPT = `
|
|
Object.defineProperty(Object.prototype, "0", {value: 42});
|
|
var a = [];
|
|
var thrown = false;
|
|
try {
|
|
a.push(1);
|
|
} catch (e) {
|
|
thrown = e instanceof TypeError;
|
|
}
|
|
thrown;
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArraySetLengthWithPropItems(t *testing.T) {
|
|
const SCRIPT = `
|
|
var a = [1,2,3,4];
|
|
var thrown = false;
|
|
|
|
Object.defineProperty(a, "2", {value: 42, configurable: false, writable: false});
|
|
try {
|
|
Object.defineProperty(a, "length", {value: 0, writable: false});
|
|
} catch (e) {
|
|
thrown = e instanceof TypeError;
|
|
}
|
|
thrown && a.length === 3;
|
|
`
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArrayFrom(t *testing.T) {
|
|
const SCRIPT = `
|
|
function checkDestHoles(dest, prefix) {
|
|
assert(dest !== source, prefix + ": dest !== source");
|
|
assert.sameValue(dest.length, 3, prefix + ": dest.length");
|
|
assert.sameValue(dest[0], 1, prefix + ": [0]");
|
|
assert.sameValue(dest[1], undefined, prefix + ": [1]");
|
|
assert(dest.hasOwnProperty("1"), prefix + ': hasOwnProperty("1")');
|
|
assert.sameValue(dest[2], 3, prefix + ": [2]");
|
|
}
|
|
|
|
function checkDest(dest, prefix) {
|
|
assert(dest !== source, prefix + ": dest !== source");
|
|
assert.sameValue(dest.length, 3, prefix + ": dest.length");
|
|
assert.sameValue(dest[0], 1, prefix + ": [0]");
|
|
assert.sameValue(dest[1], 2, prefix + ": [1]");
|
|
assert.sameValue(dest[2], 3, prefix + ": [2]");
|
|
}
|
|
|
|
var source = [1,2,3];
|
|
var srcHoles = [1,,3];
|
|
|
|
checkDest(Array.from(source), "std source/std dest");
|
|
checkDestHoles(Array.from(srcHoles), "std source (holes)/std dest");
|
|
|
|
function Iter() {
|
|
this.idx = 0;
|
|
}
|
|
Iter.prototype.next = function() {
|
|
if (this.idx < source.length) {
|
|
return {value: source[this.idx++]};
|
|
} else {
|
|
return {done: true};
|
|
}
|
|
}
|
|
|
|
var src = {};
|
|
src[Symbol.iterator] = function() {
|
|
return new Iter();
|
|
}
|
|
checkDest(Array.from(src), "iter src/std dest");
|
|
|
|
src = {0: 1, 2: 3, length: 3};
|
|
checkDestHoles(Array.from(src), "arrayLike src/std dest");
|
|
|
|
function A() {}
|
|
A.from = Array.from;
|
|
|
|
checkDest(A.from(source), "std src/cust dest");
|
|
checkDestHoles(A.from(srcHoles), "std src (holes)/cust dest");
|
|
checkDestHoles(A.from(src), "arrayLike src/cust dest");
|
|
|
|
function T2() {
|
|
Object.defineProperty(this, 0, {
|
|
configurable: false,
|
|
writable: true,
|
|
enumerable: true
|
|
});
|
|
}
|
|
|
|
assert.throws(TypeError, function() {
|
|
Array.from.call(T2, source);
|
|
});
|
|
|
|
`
|
|
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayOf(t *testing.T) {
|
|
const SCRIPT = `
|
|
function T1() {
|
|
Object.preventExtensions(this);
|
|
}
|
|
|
|
assert.throws(TypeError, function() {
|
|
Array.of.call(T1, 'Bob');
|
|
});
|
|
|
|
function T2() {
|
|
Object.defineProperty(this, 0, {
|
|
configurable: false,
|
|
writable: true,
|
|
enumerable: true
|
|
});
|
|
}
|
|
|
|
assert.throws(TypeError, function() {
|
|
Array.of.call(T2, 'Bob');
|
|
})
|
|
|
|
result = Array.of.call(undefined);
|
|
assert(
|
|
result instanceof Array,
|
|
'this is not a constructor'
|
|
);
|
|
|
|
result = Array.of.call(Math.cos);
|
|
assert(
|
|
result instanceof Array,
|
|
'this is a builtin function with no [[Construct]] slot'
|
|
);
|
|
|
|
`
|
|
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestUnscopables(t *testing.T) {
|
|
const SCRIPT = `
|
|
var keys = [];
|
|
var _length;
|
|
with (Array.prototype) {
|
|
_length = length;
|
|
keys.push('something');
|
|
}
|
|
_length === 0 && keys.length === 1 && keys[0] === "something";
|
|
`
|
|
testScript(SCRIPT, valueTrue, t)
|
|
}
|
|
|
|
func TestArraySort(t *testing.T) {
|
|
const SCRIPT = `
|
|
assert.throws(TypeError, function() {
|
|
[1,2].sort(null);
|
|
}, "null compare function");
|
|
assert.throws(TypeError, function() {
|
|
[1,2].sort({});
|
|
}, "non-callable compare function");
|
|
`
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArraySortNonStdArray(t *testing.T) {
|
|
const SCRIPT = `
|
|
const array = [undefined, 'c', /*hole*/, 'b', undefined, /*hole*/, 'a', 'd'];
|
|
|
|
Object.defineProperty(array, '2', {
|
|
get() {
|
|
array.pop();
|
|
array.pop();
|
|
return this.foo;
|
|
},
|
|
set(v) {
|
|
this.foo = v;
|
|
}
|
|
});
|
|
|
|
array.sort();
|
|
|
|
assert.sameValue(array[0], 'b');
|
|
assert.sameValue(array[1], 'c');
|
|
assert.sameValue(array[3], undefined);
|
|
assert.sameValue(array[4], undefined);
|
|
assert.sameValue('5' in array, false);
|
|
assert.sameValue(array.hasOwnProperty('5'), false);
|
|
assert.sameValue(array.length, 6);
|
|
assert.sameValue(array.foo, undefined);
|
|
|
|
assert.sameValue(array[2], undefined);
|
|
assert.sameValue(array.length, 4);
|
|
`
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayConcat(t *testing.T) {
|
|
const SCRIPT = `
|
|
var concat = Array.prototype.concat;
|
|
var array = [1, 2];
|
|
var sparseArray = [1, , 2];
|
|
var nonSpreadableArray = [1, 2];
|
|
nonSpreadableArray[Symbol.isConcatSpreadable] = false;
|
|
var arrayLike = { 0: 1, 1: 2, length: 2 };
|
|
var spreadableArrayLike = { 0: 1, 1: 2, length: 2 };
|
|
spreadableArrayLike[Symbol.isConcatSpreadable] = true;
|
|
assert(looksNative(concat));
|
|
assert(deepEqual(array.concat(), [1, 2]), '#1');
|
|
assert(deepEqual(sparseArray.concat(), [1, , 2]), '#2');
|
|
assert(deepEqual(nonSpreadableArray.concat(), [[1, 2]]), '#3');
|
|
assert(deepEqual(concat.call(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#4');
|
|
assert(deepEqual(concat.call(spreadableArrayLike), [1, 2]), '#5');
|
|
assert(deepEqual([].concat(array), [1, 2]), '#6');
|
|
assert(deepEqual([].concat(sparseArray), [1, , 2]), '#7');
|
|
assert(deepEqual([].concat(nonSpreadableArray), [[1, 2]]), '#8');
|
|
assert(deepEqual([].concat(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#9');
|
|
assert(deepEqual([].concat(spreadableArrayLike), [1, 2]), '#10');
|
|
assert(deepEqual(array.concat(sparseArray, nonSpreadableArray, arrayLike, spreadableArrayLike), [
|
|
1, 2, 1, , 2, [1, 2], { 0: 1, 1: 2, length: 2 }, 1, 2,
|
|
]), '#11');
|
|
array = [];
|
|
array.constructor = {};
|
|
array.constructor[Symbol.species] = function () {
|
|
return { foo: 1 };
|
|
}
|
|
assert.sameValue(array.concat().foo, 1, '@@species');
|
|
`
|
|
testScriptWithTestLibX(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayFlat(t *testing.T) {
|
|
const SCRIPT = `
|
|
var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
|
|
assert(deepEqual(array.flat(), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
|
|
assert(deepEqual(array.flat(1), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#2');
|
|
assert(deepEqual(array.flat(3), [1,2,3,4,5,6,[7,8,9]]), '#3');
|
|
assert(deepEqual(array.flat(4), [1,2,3,4,5,6,7,8,9]), '#4');
|
|
assert(deepEqual(array.flat(10), [1,2,3,4,5,6,7,8,9]), '#5');
|
|
`
|
|
testScriptWithTestLibX(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayFlatMap(t *testing.T) {
|
|
const SCRIPT = `
|
|
var double = function(x) {
|
|
if (isNaN(x)) {
|
|
return x
|
|
}
|
|
return x * 2
|
|
}
|
|
var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
|
|
assert(deepEqual(array.flatMap(double), [2,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
|
|
`
|
|
testScriptWithTestLibX(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayProto(t *testing.T) {
|
|
const SCRIPT = `
|
|
const a = Array.prototype;
|
|
a.push(1, 2, 3, 4, 5);
|
|
assert.sameValue(a.length, 5);
|
|
assert.sameValue(a[0], 1);
|
|
a.length = 3;
|
|
assert.sameValue(a.length, 3);
|
|
assert(compareArray(a, [1, 2, 3]));
|
|
a.shift();
|
|
assert.sameValue(a.length, 2);
|
|
assert(compareArray(a, [2, 3]));
|
|
`
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|
|
|
|
func TestArrayToSpliced(t *testing.T) {
|
|
const SCRIPT = `
|
|
const a = [1, 2, 3];
|
|
a.push(4)
|
|
assert(compareArray(a, [1, 2, 3, 4]));
|
|
const b = a.toSpliced(2)
|
|
assert(compareArray(a, [1, 2, 3, 4]));
|
|
assert(compareArray(b, [1, 2]));
|
|
a.push(5)
|
|
const c = a.toSpliced(1, 2);
|
|
assert(compareArray(a, [1, 2, 3, 4, 5]));
|
|
assert(compareArray(c, [1, 4, 5]));
|
|
assert(compareArray(a.toSpliced(4, 2, 'a', 'b'), [1, 2, 3, 4, 'a', 'b']));
|
|
assert(compareArray(a, [1, 2, 3, 4, 5]));
|
|
assert(compareArray(a.toSpliced(-2, 2), [1, 2, 3]));
|
|
assert(compareArray(a, [1, 2, 3, 4, 5]));
|
|
assert(compareArray(a.toSpliced(2, 10), [1, 2]));
|
|
assert(compareArray(a, [1, 2, 3, 4, 5]));
|
|
assert(compareArray(a.toSpliced(1, 0, 'a'), [1, 'a', 2, 3, 4, 5]));
|
|
assert(compareArray(a, [1, 2, 3, 4, 5]));
|
|
`
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
}
|