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) }