From 258da539bcf0d8c0cb9f7bde97c0eada283166ba Mon Sep 17 00:00:00 2001 From: Leo Balter <leonardo.balter@gmail.com> Date: Tue, 18 Dec 2018 18:33:56 -0200 Subject: [PATCH] refactor coverage for flatMap --- .../flatMap/array-like-objects-nested.js | 68 +++++++++ .../array-like-objects-poisoned-length.js | 60 ++++++++ .../flatMap/array-like-objects-typedarrays.js | 50 +++++++ .../prototype/flatMap/array-like-objects.js | 82 ++++++++-- .../flatMap/non-callable-argument-throws.js | 42 +++++- .../flatMap/non-object-ctor-throws.js | 35 ----- .../flatMap/this-value-ctor-non-object.js | 74 +++++++++ ...is-value-ctor-object-species-bad-throws.js | 129 ++++++++++++++++ ...ect-species-custom-ctor-poisoned-throws.js | 58 +++++++ ...s-value-ctor-object-species-custom-ctor.js | 94 ++++++++++++ .../flatMap/this-value-ctor-object-species.js | 141 ++++++++++++++++++ ...js => this-value-null-undefined-throws.js} | 17 ++- .../prototype/flatMap/thisArg-argument.js | 39 +++-- 13 files changed, 815 insertions(+), 74 deletions(-) create mode 100644 test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js create mode 100644 test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js create mode 100644 test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js delete mode 100644 test/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js create mode 100644 test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js create mode 100644 test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js create mode 100644 test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js create mode 100644 test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js create mode 100644 test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js rename test/built-ins/Array/prototype/flatMap/{null-undefined-input-throws.js => this-value-null-undefined-throws.js} (60%) diff --git a/test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js b/test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js new file mode 100644 index 0000000000..82f5a2dc4a --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js @@ -0,0 +1,68 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-array.prototype.flatMap +description: > + Does not flatten array-like objects nested into the main array +info: | + FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ]) + + 1. Let targetIndex be start. + 2. Let sourceIndex be 0. + 3. Repeat, while sourceIndex < sourceLen + a. Let P be ! ToString(sourceIndex). + b. Let exists be ? HasProperty(source, P). + c. If exists is true, then + i. Let element be ? Get(source, P). + ii. If mapperFunction is present, then + 1. Assert: thisArg is present. + 2. Set element to ? Call(mapperFunction, thisArg , « element, sourceIndex, source »). + iii. Let shouldFlatten be false. + iv. If depth > 0, then + 1. Set shouldFlatten to ? IsArray(element). + v. If shouldFlatten is true, then + 1. Let elementLen be ? ToLength(? Get(element, "length")). + 2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1). + vi. Else, + 1. If targetIndex ≥ 253-1, throw a TypeError exception. + 2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element). + 3. Increase targetIndex by 1. +includes: [compareArray.js] +features: [Array.prototype.flatMap, Int32Array] +---*/ + +function fn(e) { + return e; +} + +var obj1 = { + length: 1, + 0: 'a', + toString() { return 'obj1'; } +}; + +var obj2 = new Int32Array(2); + +var obj3 = { + get length() { throw "should not even consider the length property" }, + toString() { return 'obj3'; } +}; + +var arr = [obj1, obj2, obj3]; +var actual = arr.flatMap(fn); +assert.compareArray(actual, arr, 'returns a similar array'); +assert.notSameValue(actual, arr, 'not the same array'); + +var arrLike = { + length: 4, + 0: obj1, + 1: obj2, + 2: obj3, + get 3() { return arrLike }, + toString() { return 'obj4'; } +}; + +actual = [].flatMap.call(arrLike, fn); +assert.compareArray(actual, [obj1, obj2, obj3, arrLike], 'returns a similar array'); +assert.notSameValue(actual, arrLike, 'not the same object'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); diff --git a/test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js b/test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js new file mode 100644 index 0000000000..a4e8e8684f --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js @@ -0,0 +1,60 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-array.prototype.flatMap +description: > + Observe abrupt completion in poisoned lengths of array-like objects +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). +features: [Array.prototype.flatMap, Symbol.toPrimitive] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +function fn(e) { + return e; +} + +var arr = { + length: Symbol(), +}; +assert.throws(TypeError, function() { + [].flatMap.call(arr, fn); +}, 'length is a symbol'); + +arr = { + get length() { throw new Test262Error() } +}; +assert.throws(Test262Error, function() { + [].flatMap.call(arr, fn); +}, 'custom get error'); + +arr = { + length: { + valueOf() { throw new Test262Error() } + } +}; +assert.throws(Test262Error, function() { + [].flatMap.call(arr, fn); +}, 'custom valueOf error'); + +arr = { + length: { + toString() { throw new Test262Error() } + } +}; +assert.throws(Test262Error, function() { + [].flatMap.call(arr, fn); +}, 'custom toString error'); + +arr = { + length: { + [Symbol.toPrimitive]() { throw new Test262Error() } + } +}; +assert.throws(Test262Error, function() { + [].flatMap.call(arr, fn); +}, 'custom Symbol.toPrimitive error'); diff --git a/test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js b/test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js new file mode 100644 index 0000000000..fd0dd5a192 --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js @@ -0,0 +1,50 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-array.prototype.flatMap +description: > + array-like objects can be flattened (typedArrays) +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + ... + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). +includes: [compareArray.js] +features: [Array.prototype.flatMap, Int32Array] +---*/ + +function same(e) { + return e; +} + +var ta; +var actual; + +ta = new Int32Array([1, 0, 42]); + +Object.defineProperty(ta, 'constructor', { + get() { throw "it should not object the typedarray ctor"; } +}); +actual = [].flatMap.call(ta, same); +assert.compareArray(actual, [1, 0, 42], 'compare returned array'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #1'); +assert.sameValue(actual instanceof Int32Array, false, 'returned object is not an instance of Int32Array #1'); + +ta = new Int32Array(0); + +Object.defineProperty(ta, 'constructor', { + get() { throw "it should not object the typedarray ctor"; } +}); +actual = [].flatMap.call(ta, same); +assert.compareArray(actual, [], 'compare returned empty array'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #2'); +assert.sameValue(actual instanceof Int32Array, false, 'returned object is not an instance of Int32Array #2'); diff --git a/test/built-ins/Array/prototype/flatMap/array-like-objects.js b/test/built-ins/Array/prototype/flatMap/array-like-objects.js index 8b2c597a84..5a8a2fca33 100644 --- a/test/built-ins/Array/prototype/flatMap/array-like-objects.js +++ b/test/built-ins/Array/prototype/flatMap/array-like-objects.js @@ -3,33 +3,83 @@ /*--- esid: sec-array.prototype.flatMap description: > - array-like objects can be flattened + array-like objects can be flattened +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + ... + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + + FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ]) + + 1. Let targetIndex be start. + 2. Let sourceIndex be 0. + 3. Repeat, while sourceIndex < sourceLen + a. Let P be ! ToString(sourceIndex). + b. Let exists be ? HasProperty(source, P). + c. If exists is true, then + ... + ** Skip if property does not exist ** includes: [compareArray.js] features: [Array.prototype.flatMap] ---*/ -function getArgumentsObject() { - return arguments; -} - -function double(e) { - return [e * 2]; +function fn(e) { + return [39, e * 2]; // returns an array to observe it being flattened after } -var a = getArgumentsObject(1, 2); -var actual = [].flatMap.call(a, double); -assert.compareArray(actual, [2, 4], 'arguments objects'); +var a; +var actual; a = { - length: 1, + length: 3, 0: 1, + // property 1 will be fully skipped + 2: 21, + get 3() { throw 'it should not get this property'; } }; -actual = [].flatMap.call(a, double); -assert.compareArray(actual, [2], 'array-like objects'); +actual = [].flatMap.call(a, fn); +assert.compareArray(actual, [39, 2, 39, 42], 'array-like flattened object, number length'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #1'); a = { - length: void 0, - 0: 1, + length: undefined, + get 0() { throw 'it should not get this property'; }, }; -actual = [].flatMap.call(a, double); +actual = [].flatMap.call(a, fn); assert.compareArray(actual, [], 'array-like objects; undefined length'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #2'); + +var called = false; +a = { + get length() { + if (!called) { + called = true; + return 2; + } else { + throw 'is should get the length only once'; + } + }, + 0: 21, + 1: 19.5, + get 2() { throw 'it should not get this property'; }, +}; +actual = [].flatMap.call(a, fn); +assert.compareArray(actual, [39, 42, 39, 39], 'array-like flattened objects; custom get length'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #3'); + +a = { + length: 10001, + [10000]: 7, +}; +actual = [].flatMap.call(a, fn); +assert.compareArray(actual, [39, 14], 'array-like flattened object, long length simulating shallow array'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #4'); diff --git a/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js b/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js index c9b7144135..a094feb5b4 100644 --- a/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js +++ b/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js @@ -3,12 +3,48 @@ /*--- esid: sec-array.prototype.flatMap description: > - non callable argument should throw TypeError Exception -features: [Array.prototype.flatMap] + non callable argument should throw TypeError Exception +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + 3. If IsCallable(mapperFunction) is false, throw a TypeError exception. + ... +features: [Array.prototype.flatMap, Symbol] ---*/ assert.sameValue(typeof Array.prototype.flatMap, "function"); assert.throws(TypeError, function() { [].flatMap({}); -}, 'non callable argument'); +}, 'non callable argument, object'); + +assert.throws(TypeError, function() { + [].flatMap(0); +}, 'non callable argument, number'); + +assert.throws(TypeError, function() { + [].flatMap(); +}, 'non callable argument, implict undefined'); + +assert.throws(TypeError, function() { + [].flatMap(undefined); +}, 'non callable argument, undefined'); + +assert.throws(TypeError, function() { + [].flatMap(null); +}, 'non callable argument, null'); + +assert.throws(TypeError, function() { + [].flatMap(false); +}, 'non callable argument, boolean'); + +assert.throws(TypeError, function() { + [].flatMap(''); +}, 'non callable argument, string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + [].flatMap(s); +}, 'non callable argument, symbol'); diff --git a/test/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js b/test/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js deleted file mode 100644 index 39cc66e97d..0000000000 --- a/test/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. -/*--- -esid: sec-array.prototype.flatMap -description: > - Behavior when `constructor` property is neither an Object nor undefined - - if IsConstructor(C) is false, throw a TypeError exception. -features: [Array.prototype.flatMap] ----*/ - -assert.sameValue(typeof Array.prototype.flatMap, 'function'); - -var a = []; -a.constructor = null; -assert.throws(TypeError, function() { - a.flatMap(); -}, 'null value'); - -a = []; -a.constructor = 1; -assert.throws(TypeError, function() { - a.flatMap(); -}, 'number value'); - -a = []; -a.constructor = 'string'; -assert.throws(TypeError, function() { - a.flatMap(); -}, 'string value'); - -a = []; -a.constructor = true; -assert.throws(TypeError, function() { - a.flatMap(); -}, 'boolean value'); diff --git a/test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js b/test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js new file mode 100644 index 0000000000..a71ad5a4ed --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js @@ -0,0 +1,74 @@ +// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-array.prototype.flatMap +description: > + Assert behavior if this value has a custom non-object constructor property +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + ... + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). + 6. If IsConstructor(C) is true, then + a. Let thisRealm be the current Realm Record. + b. Let realmC be ? GetFunctionRealm(C). + c. If thisRealm and realmC are not the same Realm Record, then + i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined. + 7. If Type(C) is Object, then + a. Set C to ? Get(C, @@species). + b. If C is null, set C to undefined. + 8. If C is undefined, return ? ArrayCreate(length). + 9. If IsConstructor(C) is false, throw a TypeError exception. +features: [Array.prototype.flatMap, Symbol] +includes: [compareArray.js] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +var a = []; +var mapperFn = function() {}; + +a.constructor = null; +assert.throws(TypeError, function() { + a.flatMap(mapperFn); +}, 'null value'); + +a = []; +a.constructor = 1; +assert.throws(TypeError, function() { + a.flatMap(mapperFn); +}, 'number value'); + +a = []; +a.constructor = 'string'; +assert.throws(TypeError, function() { + a.flatMap(mapperFn); +}, 'string value'); + +a = []; +a.constructor = true; +assert.throws(TypeError, function() { + a.flatMap(mapperFn); +}, 'boolean value'); + +a = []; +a.constructor = Symbol(); +assert.throws(TypeError, function() { + a.flatMap(mapperFn); +}, 'symbol value'); + +a = []; +a.constructor = undefined; +var actual = a.flatMap(mapperFn); +assert.compareArray(actual, [], 'undefined value does not throw'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); +assert.notSameValue(actual, a, 'returns a new array'); diff --git a/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js new file mode 100644 index 0000000000..64fdb6ea10 --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js @@ -0,0 +1,129 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.flatMap +description: > + Assert behavior if this value has a custom object constructor property species +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + ... + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). + 6. If IsConstructor(C) is true, then + a. Let thisRealm be the current Realm Record. + b. Let realmC be ? GetFunctionRealm(C). + c. If thisRealm and realmC are not the same Realm Record, then + i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined. + 7. If Type(C) is Object, then + a. Set C to ? Get(C, @@species). + b. If C is null, set C to undefined. + 8. If C is undefined, return ? ArrayCreate(length). + 9. If IsConstructor(C) is false, throw a TypeError exception. + 10. Return ? Construct(C, « length »). +features: [Array.prototype.flatMap, Symbol, Symbol.species] +includes: [compareArray.js] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +var arr = [[42, 1], [42, 2]]; +var mapperFn = function(e) { return e; }; + +arr.constructor = {}; +var actual = arr.flatMap(mapperFn); +assert.compareArray(actual, [42, 1, 42, 2], 'undefined species does not throw'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); + +var called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return 0; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a number'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return ''; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a string'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return false; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a boolean'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return {}; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is an object'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return []; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is an array'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return Symbol(); + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a symbol'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + throw new Test262Error + } +}; +assert.throws(Test262Error, function() { + arr.flatMap(mapperFn); +}, 'Return abrupt completion from getting the @@species'); +assert.sameValue(called, 1, 'got species once'); \ No newline at end of file diff --git a/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js new file mode 100644 index 0000000000..3ecf17e32a --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js @@ -0,0 +1,58 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.flatMap +description: > + Assert behavior if this value has a poisoned custom species constructor +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T). + 7. Return A. + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). + 6. If IsConstructor(C) is true, then + ... + 7. If Type(C) is Object, then + a. Set C to ? Get(C, @@species). + b. If C is null, set C to undefined. + 8. If C is undefined, return ? ArrayCreate(length). + 9. If IsConstructor(C) is false, throw a TypeError exception. + 10. Return ? Construct(C, « length »). +features: [Array.prototype.flatMap, Symbol, Symbol.species] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +var arr = []; +var mapperFn = function(e) { return e; }; + +var called = 0; +var ctorCalled = 0; +function ctor(len) { + assert.sameValue(new.target, ctor, 'new target is defined'); + assert.sameValue(len, 0, 'first argument is always 0'); + ctorCalled++; + throw new Test262Error(); +} + +arr.constructor = { + get [Symbol.species]() { + called++; + return ctor; + } +}; +assert.throws(Test262Error, function() { + arr.flatMap(mapperFn); +}, 'Return abrupt completion from species custom ctor'); +assert.sameValue(called, 1, 'got species once'); +assert.sameValue(ctorCalled, 1, 'called custom ctor once'); diff --git a/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js new file mode 100644 index 0000000000..c23c605f63 --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js @@ -0,0 +1,94 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.flatMap +description: > + Assert behavior if this value has a custom species constructor +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T). + 7. Return A. + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). + 6. If IsConstructor(C) is true, then + ... + 7. If Type(C) is Object, then + a. Set C to ? Get(C, @@species). + b. If C is null, set C to undefined. + 8. If C is undefined, return ? ArrayCreate(length). + 9. If IsConstructor(C) is false, throw a TypeError exception. + 10. Return ? Construct(C, « length »). + + FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ]) + + 3. Repeat, while sourceIndex < sourceLen + a. Let P be ! ToString(sourceIndex). + b. Let exists be ? HasProperty(source, P). + c. If exists is true, then + ... + vi. Else, + ... + 2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element). +features: [Array.prototype.flatMap, Symbol, Symbol.species] +includes: [propertyHelper.js] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +var arr = [[42, 1], [42, 2]]; +var mapperFn = function(e) { return e; }; + +var called = 0; +var ctorCalled = 0; +function ctor(len) { + assert.sameValue(new.target, ctor, 'new target is defined'); + assert.sameValue(len, 0, 'first argument is always 0'); + ctorCalled++; +} + +arr.constructor = { + get [Symbol.species]() { + called++; + return ctor; + } +}; +var actual = arr.flatMap(mapperFn); +assert(actual instanceof ctor, 'returned value is an instance of custom ctor'); +assert.sameValue(called, 1, 'got species once'); +assert.sameValue(ctorCalled, 1, 'called custom ctor once'); + +assert.sameValue(Object.prototype.hasOwnProperty.call(actual, 'length'), false, 'it does not define an own length property'); +verifyProperty(actual, '0', { + configurable: true, + writable: true, + enumerable: true, + value: 42 +}); +verifyProperty(actual, '1', { + configurable: true, + writable: true, + enumerable: true, + value: 1 +}); +verifyProperty(actual, '2', { + configurable: true, + writable: true, + enumerable: true, + value: 42 +}); +verifyProperty(actual, '3', { + configurable: true, + writable: true, + enumerable: true, + value: 2 +}); diff --git a/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js new file mode 100644 index 0000000000..a8d560bff2 --- /dev/null +++ b/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js @@ -0,0 +1,141 @@ +// Copyright (C) 2018 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-array.prototype.flatMap +description: > + Assert behavior if this value has a custom object constructor property +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + 2. Let sourceLen be ? ToLength(? Get(O, "length")). + ... + 5. Let A be ? ArraySpeciesCreate(O, 0). + ... + + ArraySpeciesCreate ( originalArray, length ) + + 3. Let isArray be ? IsArray(originalArray). + 4. If isArray is false, return ? ArrayCreate(length). + 5. Let C be ? Get(originalArray, "constructor"). + 6. If IsConstructor(C) is true, then + a. Let thisRealm be the current Realm Record. + b. Let realmC be ? GetFunctionRealm(C). + c. If thisRealm and realmC are not the same Realm Record, then + i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined. + 7. If Type(C) is Object, then + a. Set C to ? Get(C, @@species). + b. If C is null, set C to undefined. + 8. If C is undefined, return ? ArrayCreate(length). + 9. If IsConstructor(C) is false, throw a TypeError exception. + 10. Return ? Construct(C, « length »). +features: [Array.prototype.flatMap, Symbol, Symbol.species] +includes: [compareArray.js] +---*/ + +assert.sameValue(typeof Array.prototype.flatMap, 'function'); + +var arr = [[42, 1], [42, 2]]; +var mapperFn = function(e) { return e; }; + +arr.constructor = {}; +var actual = arr.flatMap(mapperFn); +assert.compareArray(actual, [42, 1, 42, 2], 'undefined species does not throw'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); + +var called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return null; + } +}; +actual = arr.flatMap(mapperFn); +assert.compareArray(actual, [42, 1, 42, 2], 'null species value does not throw'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return undefined; + } +}; +actual = arr.flatMap(mapperFn); +assert.compareArray(actual, [42, 1, 42, 2], 'undefined species value does not throw'); +assert.sameValue(Object.getPrototypeOf(actual), Array.prototype); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return 0; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a number'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return ''; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a string'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return false; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a boolean'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return {}; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is an object'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return []; + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is an array'); +assert.sameValue(called, 1, 'got species once'); + +called = 0; +arr.constructor = { + get [Symbol.species]() { + called++; + return Symbol(); + } +}; +assert.throws(TypeError, function() { + arr.flatMap(mapperFn); +}, 'throw TypeError if @@species is a symbol'); +assert.sameValue(called, 1, 'got species once'); diff --git a/test/built-ins/Array/prototype/flatMap/null-undefined-input-throws.js b/test/built-ins/Array/prototype/flatMap/this-value-null-undefined-throws.js similarity index 60% rename from test/built-ins/Array/prototype/flatMap/null-undefined-input-throws.js rename to test/built-ins/Array/prototype/flatMap/this-value-null-undefined-throws.js index 44630d9644..b7b9845603 100644 --- a/test/built-ins/Array/prototype/flatMap/null-undefined-input-throws.js +++ b/test/built-ins/Array/prototype/flatMap/this-value-null-undefined-throws.js @@ -3,20 +3,23 @@ /*--- esid: sec-array.prototype.flatMap description: > - null or undefined should throw TypeError Exception + Throw a TypeError if this value is null or undefined +info: | + Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) + + 1. Let O be ? ToObject(this value). + ... features: [Array.prototype.flatMap] ---*/ assert.sameValue(typeof Array.prototype.flatMap, 'function'); -assert.throws(TypeError, function() { - [].flatMap.call(null); -}, 'null value'); +var mapperFn = function() {}; assert.throws(TypeError, function() { - [].flatMap.call(); -}, 'missing'); + [].flatMap.call(null, mapperFn); +}, 'null value'); assert.throws(TypeError, function() { - [].flatMap.call(void 0); + [].flatMap.call(undefined, mapperFn); }, 'undefined'); diff --git a/test/built-ins/Array/prototype/flatMap/thisArg-argument.js b/test/built-ins/Array/prototype/flatMap/thisArg-argument.js index 34db60abdc..24b52af747 100644 --- a/test/built-ins/Array/prototype/flatMap/thisArg-argument.js +++ b/test/built-ins/Array/prototype/flatMap/thisArg-argument.js @@ -5,28 +5,41 @@ esid: sec-array.prototype.flatMap description: > Behavior when thisArg is provided Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) -includes: [compareArray.js] flags: [onlyStrict] +includes: [compareArray.js] features: [Array.prototype.flatMap] ---*/ var a = {}; +var actual; -assert(compareArray([1].flatMap(function() { +actual = [1].flatMap(function() { return [this]; -}, "TestString"), ["TestString"])); -assert(compareArray([1].flatMap(function() { +}, "TestString"); +assert.compareArray(actual, ["TestString"]); + +actual = [1].flatMap(function() { return [this]; -}, 1), [1])); -assert(compareArray([1].flatMap(function() { +}, 1); +assert.compareArray(actual, [1]); + +actual = [1].flatMap(function() { return [this]; -}, null), [null])); -assert(compareArray([1].flatMap(function() { +}, null); +assert.compareArray(actual, [null]); + +actual = [1].flatMap(function() { return [this]; -}, true), [true])); -assert(compareArray([1].flatMap(function() { +}, true); +assert.compareArray(actual, [true]); + +actual = [1].flatMap(function() { return [this]; -}, a), [a])); -assert(compareArray([1].flatMap(function() { +}, a); +assert.compareArray(actual, [a]); + +actual = [1].flatMap(function() { return [this]; -}, void 0), [undefined])); +}, void 0); +assert.compareArray(actual, [undefined]); + -- GitLab