diff --git a/features.txt b/features.txt index a193406c8d..b4350fea6c 100644 --- a/features.txt +++ b/features.txt @@ -104,6 +104,10 @@ String.prototype.toWellFormed # https://github.com/tc39/proposal-json-parse-with-source json-parse-with-source +# Iterator Helpers +# https://github.com/tc39/proposal-iterator-helpers +iterator-helpers + ## Standard language features # # Language features that have been included in a published version of the diff --git a/test/built-ins/Iterator/constructor.js b/test/built-ins/Iterator/constructor.js new file mode 100644 index 0000000000..9c06d9a964 --- /dev/null +++ b/test/built-ins/Iterator/constructor.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator-constructor +description: > + The Iterator constructor is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator, 'function', 'The value of `typeof Iterator` is "function"'); diff --git a/test/built-ins/Iterator/from/callable.js b/test/built-ins/Iterator/from/callable.js new file mode 100644 index 0000000000..738257dc0c --- /dev/null +++ b/test/built-ins/Iterator/from/callable.js @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from is callable +features: [iterator-helpers] +---*/ +function* g() {} + +Iterator.from(g()); +Iterator.from.call(null, g()); diff --git a/test/built-ins/Iterator/from/get-next-method-only-once.js b/test/built-ins/Iterator/from/get-next-method-only-once.js new file mode 100644 index 0000000000..1c75257f58 --- /dev/null +++ b/test/built-ins/Iterator/from/get-next-method-only-once.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Gets the next method from the underlying iterator only once +info: | + Iterator.from ( O ) + + 2. Let iteratorRecord be ? GetIteratorFlattenable(O). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0, 'The value of `nextGets` is 0'); +assert.sameValue(nextCalls, 0, 'The value of `nextCalls` is 0'); + +iterator = Iterator.from(iterator); + +assert.sameValue(nextGets, 1, 'The value of `nextGets` is 1'); +assert.sameValue(nextCalls, 0, 'The value of `nextCalls` is 0'); + +iterator.toArray(); + +assert.sameValue(nextGets, 1, 'The value of `nextGets` is 1'); +assert.sameValue(nextCalls, 5, 'The value of `nextCalls` is 5'); diff --git a/test/built-ins/Iterator/from/get-next-method-throws.js b/test/built-ins/Iterator/from/get-next-method-throws.js new file mode 100644 index 0000000000..1b1083f2b2 --- /dev/null +++ b/test/built-ins/Iterator/from/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Underlying iterator has throwing next getter +info: | + Iterator.from ( O ) + + 4. Let iterated be ? GetIteratorDirect(O). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + Iterator.from(iterator); +}); diff --git a/test/built-ins/Iterator/from/is-function.js b/test/built-ins/Iterator/from/is-function.js new file mode 100644 index 0000000000..dc8eff9fd5 --- /dev/null +++ b/test/built-ins/Iterator/from/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.from, 'function', 'The value of `typeof Iterator.from` is "function"'); diff --git a/test/built-ins/Iterator/from/iterable-primitives.js b/test/built-ins/Iterator/from/iterable-primitives.js new file mode 100644 index 0000000000..f162ee1cc0 --- /dev/null +++ b/test/built-ins/Iterator/from/iterable-primitives.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from does not respect the iterability of any primitive except Strings +info: | + Iterator.from ( O ) + + 1. If O is a String, set O to ! ToObject(O). + 2. Let iteratorRecord be ? GetIteratorFlattenable(O). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; +} + +Number.prototype[Symbol.iterator] = function* () { + let i = 0; + let target = this >>> 0; + while (i < target) { + yield i; + ++i; + } +}; + +assert.compareArray(Array.from(5), [0, 1, 2, 3, 4]); + +assert.throws(TypeError, function () { + Iterator.from(5); +}); + +assert.compareArray(Array.from(Iterator.from(new Number(5))), [0, 1, 2, 3, 4]); + +assert.compareArray(Array.from(Iterator.from('string')), ['s', 't', 'r', 'i', 'n', 'g']); diff --git a/test/built-ins/Iterator/from/iterable-to-iterator-fallback.js b/test/built-ins/Iterator/from/iterable-to-iterator-fallback.js new file mode 100644 index 0000000000..3228cb47f7 --- /dev/null +++ b/test/built-ins/Iterator/from/iterable-to-iterator-fallback.js @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from falls back to treating its parameter as an iterator if the Symbol.iterator property is null/undefined +info: | + Iterator.from ( O ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; + yield 1; + yield 2; +} + +let iter = (function () { + let n = g(); + return { + [Symbol.iterator]: 0, + next: () => n.next(), + }; +})(); + +assert.throws(TypeError, function () { + Iterator.from(iter); +}); + +iter = (function () { + let n = g(); + return { + [Symbol.iterator]: null, + next: () => n.next(), + }; +})(); + +assert.compareArray(Array.from(Iterator.from(iter)), [0, 1, 2]); + +iter = (function () { + let n = g(); + return { + [Symbol.iterator]: undefined, + next: () => n.next(), + }; +})(); + +assert.compareArray(Array.from(Iterator.from(iter)), [0, 1, 2]); diff --git a/test/built-ins/Iterator/from/length.js b/test/built-ins/Iterator/from/length.js new file mode 100644 index 0000000000..05df92269c --- /dev/null +++ b/test/built-ins/Iterator/from/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.from, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/from/name.js b/test/built-ins/Iterator/from/name.js new file mode 100644 index 0000000000..cff643bd1f --- /dev/null +++ b/test/built-ins/Iterator/from/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + The "name" property of Iterator.from +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.from, 'name', { + value: 'from', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/from/non-constructible.js b/test/built-ins/Iterator/from/non-constructible.js new file mode 100644 index 0000000000..02eae9a510 --- /dev/null +++ b/test/built-ins/Iterator/from/non-constructible.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} + +assert.throws(TypeError, () => { + new Iterator.from(); +}); + +assert.throws(TypeError, () => { + new Iterator.from(g()); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.from(g()); +}); diff --git a/test/built-ins/Iterator/from/primitives.js b/test/built-ins/Iterator/from/primitives.js new file mode 100644 index 0000000000..4c016765c8 --- /dev/null +++ b/test/built-ins/Iterator/from/primitives.js @@ -0,0 +1,38 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from throws on primitives (except Strings) +info: | + Iterator.from ( O ) + +features: [iterator-helpers] +flags: [] +---*/ + +assert.throws(TypeError, function () { + Iterator.from(null); +}); + +assert.throws(TypeError, function () { + Iterator.from(undefined); +}); + +assert.throws(TypeError, function () { + Iterator.from(0); +}); + +assert.throws(TypeError, function () { + Iterator.from(0n); +}); + +assert.throws(TypeError, function () { + Iterator.from(true); +}); + +assert.throws(TypeError, function () { + Iterator.from(Symbol()); +}); + +Iterator.from('string'); diff --git a/test/built-ins/Iterator/from/prop-desc.js b/test/built-ins/Iterator/from/prop-desc.js new file mode 100644 index 0000000000..92fbc25761 --- /dev/null +++ b/test/built-ins/Iterator/from/prop-desc.js @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Property descriptor of Iterator.from +info: | + Iterator.from + + * is the initial value of the Iterator.from property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator, 'from', { + value: Iterator.from, + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/from/proto.js b/test/built-ins/Iterator/from/proto.js new file mode 100644 index 0000000000..b99e04fad2 --- /dev/null +++ b/test/built-ins/Iterator/from/proto.js @@ -0,0 +1,15 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + The value of the [[Prototype]] internal slot of Iterator.from is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue( + Object.getPrototypeOf(Iterator.from), + Function.prototype, + 'Object.getPrototypeOf(Iterator.from) must return the value of Function.prototype' +); diff --git a/test/built-ins/Iterator/from/result-proto.js b/test/built-ins/Iterator/from/result-proto.js new file mode 100644 index 0000000000..0888791d7b --- /dev/null +++ b/test/built-ins/Iterator/from/result-proto.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.from is the + intrinsic object %WrapForValidIteratorPrototype%, whose [[Prototype]] is %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ +let iter = { + next() { + return { + done: true, + value: undefined, + }; + }, +}; + +const WrapForValidIteratorPrototype = Object.getPrototypeOf(Iterator.from(iter)); + +assert.sameValue(Object.getPrototypeOf(WrapForValidIteratorPrototype), Iterator.prototype); + +class SubIterator extends Iterator {} +assert.sameValue(Object.getPrototypeOf(SubIterator.from(iter)), WrapForValidIteratorPrototype); + +function* g() {} +const GeneratorPrototype = Object.getPrototypeOf(g()); + +assert.sameValue(Object.getPrototypeOf(Iterator.from(g())), GeneratorPrototype); diff --git a/test/built-ins/Iterator/from/supports-iterable.js b/test/built-ins/Iterator/from/supports-iterable.js new file mode 100644 index 0000000000..03e26258cb --- /dev/null +++ b/test/built-ins/Iterator/from/supports-iterable.js @@ -0,0 +1,14 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from supports iterables +info: | + Iterator.from ( O ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +assert.compareArray(Array.from(Iterator.from([0, 1, 2, 3])), [0, 1, 2, 3]); diff --git a/test/built-ins/Iterator/from/supports-iterator.js b/test/built-ins/Iterator/from/supports-iterator.js new file mode 100644 index 0000000000..888d8dc916 --- /dev/null +++ b/test/built-ins/Iterator/from/supports-iterator.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iterator.from +description: > + Iterator.from supports non-iterable iterators +info: | + Iterator.from ( O ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; +} + +let n = g(); +let iter = { + next() { + return n.next(); + }, +}; + +assert.compareArray(Array.from(Iterator.from(iter)), [0, 1, 2, 3]); diff --git a/test/built-ins/Iterator/length.js b/test/built-ins/Iterator/length.js new file mode 100644 index 0000000000..78d596a3eb --- /dev/null +++ b/test/built-ins/Iterator/length.js @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator-constructor +description: > + Iterator has a "length" property whose value is 0. +info: | + The Iterator Constructor + + The length property of the Iterator constructor function is 0. + ... + + ES7 section 17: Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator, 'length', { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/name.js b/test/built-ins/Iterator/name.js new file mode 100644 index 0000000000..bb7ada2b6e --- /dev/null +++ b/test/built-ins/Iterator/name.js @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator-constructor +description: > + The "name" property of Iterator +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator, 'name', { + value: 'Iterator', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/newtarget-or-active-function-object.js b/test/built-ins/Iterator/newtarget-or-active-function-object.js new file mode 100644 index 0000000000..de5ad257fc --- /dev/null +++ b/test/built-ins/Iterator/newtarget-or-active-function-object.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator +description: > + Iterator is not callable or constructable +info: | + When the Iterator function is called, the following steps are taken: + + If NewTarget is undefined or the active function object, throw a TypeError exception. + +features: [iterator-helpers] +---*/ + +assert.throws(TypeError, () => { + Iterator(); +}); + +assert.throws(TypeError, () => { + new Iterator(); +}); diff --git a/test/built-ins/Iterator/prop-desc.js b/test/built-ins/Iterator/prop-desc.js new file mode 100644 index 0000000000..e93e9e5136 --- /dev/null +++ b/test/built-ins/Iterator/prop-desc.js @@ -0,0 +1,27 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator-constructor +description: > + Property descriptor of Iterator +info: | + The Iterator Constructor + + * is the initial value of the Iterator property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(globalThis, 'Iterator', { + value: Iterator, + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/proto-from-ctor-realm.js b/test/built-ins/Iterator/proto-from-ctor-realm.js new file mode 100644 index 0000000000..2f2f72b33f --- /dev/null +++ b/test/built-ins/Iterator/proto-from-ctor-realm.js @@ -0,0 +1,36 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator +description: Default [[Prototype]] value derived from realm of the NewTarget. +features: [cross-realm, iterator-helpers, Reflect, Symbol] +---*/ + +let other = $262.createRealm().global; +let newTarget = new other.Function(); +let ai; + +newTarget.prototype = undefined; +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); + +newTarget.prototype = null; +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); + +newTarget.prototype = true; +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); + +newTarget.prototype = ''; +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); + +newTarget.prototype = Symbol(); +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); + +newTarget.prototype = 0; +ai = Reflect.construct(Iterator, [1], newTarget); +assert.sameValue(Object.getPrototypeOf(ai), other.Iterator.prototype); diff --git a/test/built-ins/Iterator/proto.js b/test/built-ins/Iterator/proto.js new file mode 100644 index 0000000000..f71d6eb7cd --- /dev/null +++ b/test/built-ins/Iterator/proto.js @@ -0,0 +1,16 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-iterator-constructor +description: > + The value of the [[Prototype]] internal slot of the Iterator constructor is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue( + Object.getPrototypeOf(Iterator), + Function.prototype, + 'Object.getPrototypeOf(Iterator) must return the value of Function.prototype' +); diff --git a/test/built-ins/Iterator/prototype/Symbol.iterator/is-function.js b/test/built-ins/Iterator/prototype/Symbol.iterator/is-function.js new file mode 100644 index 0000000000..cd6d2d96bf --- /dev/null +++ b/test/built-ins/Iterator/prototype/Symbol.iterator/is-function.js @@ -0,0 +1,13 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some is a built-in function +features: [Symbol.iterator] +---*/ +const IteratorPrototype = Object.getPrototypeOf( + Object.getPrototypeOf([][Symbol.iterator]()) +); + +assert.sameValue(typeof IteratorPrototype[Symbol.iterator], 'function'); diff --git a/test/built-ins/IteratorPrototype/Symbol.iterator/length.js b/test/built-ins/Iterator/prototype/Symbol.iterator/length.js similarity index 68% rename from test/built-ins/IteratorPrototype/Symbol.iterator/length.js rename to test/built-ins/Iterator/prototype/Symbol.iterator/length.js index 7c69aec54a..404b17b1a5 100644 --- a/test/built-ins/IteratorPrototype/Symbol.iterator/length.js +++ b/test/built-ins/Iterator/prototype/Symbol.iterator/length.js @@ -2,7 +2,7 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- es6id: 25.1.2.1 -description: Length of IteratorPrototype[ @@iterator ] +description: Length of %IteratorPrototype%[ @@iterator ] info: | ES6 Section 17: Every built-in Function object, including constructors, has a length @@ -18,13 +18,13 @@ info: | features: [Symbol.iterator] includes: [propertyHelper.js] ---*/ - -var IteratorPrototype = Object.getPrototypeOf( +const IteratorPrototype = Object.getPrototypeOf( Object.getPrototypeOf([][Symbol.iterator]()) ); -assert.sameValue(IteratorPrototype[Symbol.iterator].length, 0); - -verifyNotEnumerable(IteratorPrototype[Symbol.iterator], 'length'); -verifyNotWritable(IteratorPrototype[Symbol.iterator], 'length'); -verifyConfigurable(IteratorPrototype[Symbol.iterator], 'length'); +verifyProperty(IteratorPrototype[Symbol.iterator], 'length', { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/IteratorPrototype/Symbol.iterator/name.js b/test/built-ins/Iterator/prototype/Symbol.iterator/name.js similarity index 74% rename from test/built-ins/IteratorPrototype/Symbol.iterator/name.js rename to test/built-ins/Iterator/prototype/Symbol.iterator/name.js index 06132f5af2..2688c3d4b6 100644 --- a/test/built-ins/IteratorPrototype/Symbol.iterator/name.js +++ b/test/built-ins/Iterator/prototype/Symbol.iterator/name.js @@ -21,13 +21,13 @@ info: | features: [Symbol.iterator] includes: [propertyHelper.js] ---*/ - -var IteratorPrototype = Object.getPrototypeOf( +const IteratorPrototype = Object.getPrototypeOf( Object.getPrototypeOf([][Symbol.iterator]()) ); -assert.sameValue(IteratorPrototype[Symbol.iterator].name, '[Symbol.iterator]'); - -verifyNotEnumerable(IteratorPrototype[Symbol.iterator], 'name'); -verifyNotWritable(IteratorPrototype[Symbol.iterator], 'name'); -verifyConfigurable(IteratorPrototype[Symbol.iterator], 'name'); +verifyProperty(IteratorPrototype[Symbol.iterator], 'name', { + value: '[Symbol.iterator]', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/IteratorPrototype/Symbol.iterator/prop-desc.js b/test/built-ins/Iterator/prototype/Symbol.iterator/prop-desc.js similarity index 65% rename from test/built-ins/IteratorPrototype/Symbol.iterator/prop-desc.js rename to test/built-ins/Iterator/prototype/Symbol.iterator/prop-desc.js index 1395c32d22..29437e8f0f 100644 --- a/test/built-ins/IteratorPrototype/Symbol.iterator/prop-desc.js +++ b/test/built-ins/Iterator/prototype/Symbol.iterator/prop-desc.js @@ -12,12 +12,12 @@ info: | features: [Symbol.iterator] includes: [propertyHelper.js] ---*/ - -var IteratorPrototype = Object.getPrototypeOf( +const IteratorPrototype = Object.getPrototypeOf( Object.getPrototypeOf([][Symbol.iterator]()) ); -assert.sameValue(typeof IteratorPrototype[Symbol.iterator], 'function'); -verifyNotEnumerable(IteratorPrototype, Symbol.iterator); -verifyWritable(IteratorPrototype, Symbol.iterator); -verifyConfigurable(IteratorPrototype, Symbol.iterator); +verifyProperty(IteratorPrototype, Symbol.iterator, { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/IteratorPrototype/Symbol.iterator/return-val.js b/test/built-ins/Iterator/prototype/Symbol.iterator/return-val.js similarity index 67% rename from test/built-ins/IteratorPrototype/Symbol.iterator/return-val.js rename to test/built-ins/Iterator/prototype/Symbol.iterator/return-val.js index d9bc41752f..d7c511149d 100644 --- a/test/built-ins/IteratorPrototype/Symbol.iterator/return-val.js +++ b/test/built-ins/Iterator/prototype/Symbol.iterator/return-val.js @@ -2,31 +2,20 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- esid: sec-%iteratorprototype%-@@iterator -description: Return value of @@iterator on IteratorPrototype +description: Return value of @@iterator on %IteratorPrototype% info: | %IteratorPrototype% [ @@iterator ] ( ) 1. Return the this value. features: [Symbol.iterator] ---*/ - const IteratorPrototype = Object.getPrototypeOf( Object.getPrototypeOf([][Symbol.iterator]()) ); + const getIterator = IteratorPrototype[Symbol.iterator]; -const thisValues = [ - {}, - Symbol(), - 4, - 4n, - true, - undefined, - null, -]; +const thisValues = [{}, Symbol(), 4, 4n, true, undefined, null]; for (const thisValue of thisValues) { - assert.sameValue( - getIterator.call(thisValue), - thisValue - ); + assert.sameValue(getIterator.call(thisValue), thisValue); } diff --git a/test/built-ins/Iterator/prototype/Symbol.toStringTag/prop-desc.js b/test/built-ins/Iterator/prototype/Symbol.toStringTag/prop-desc.js new file mode 100644 index 0000000000..8048fcf5c7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/Symbol.toStringTag/prop-desc.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.1.2.1 +description: Property descriptor +info: | + ES6 Section 17 + + Every other data property described in clauses 18 through 26 and in Annex + B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ +verifyProperty(Iterator.prototype, Symbol.toStringTag, { + value: 'Iterator', + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/drop/argument-effect-order.js b/test/built-ins/Iterator/prototype/drop/argument-effect-order.js new file mode 100644 index 0000000000..0917e8b3d0 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/argument-effect-order.js @@ -0,0 +1,64 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.drop ( limit ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +Iterator.prototype.drop.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + { + valueOf() { + effects.push('ToNumber limit'); + return 0; + }, + } +); + +assert.compareArray(effects, ['ToNumber limit', 'get next']); + +effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.drop.call(null, { + valueOf() { + effects.push('ToNumber limit'); + return 0; + }, + }); +}); + +assert.compareArray(effects, []); + +effects = []; + +assert.throws(RangeError, function () { + Iterator.prototype.drop.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + NaN + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/drop/callable.js b/test/built-ins/Iterator/prototype/drop/callable.js new file mode 100644 index 0000000000..79536d2564 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.drop.call(g(), 0); + +let iter = g(); +iter.drop(0); diff --git a/test/built-ins/Iterator/prototype/drop/exhaustion-does-not-call-return.js b/test/built-ins/Iterator/prototype/drop/exhaustion-does-not-call-return.js new file mode 100644 index 0000000000..744574b6cd --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/exhaustion-does-not-call-return.js @@ -0,0 +1,60 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator return is not called when result iterator is exhausted +info: | + %Iterator.prototype%.drop ( limit ) + + 6.b.ii. Let next be ? IteratorStep(iterated). + 6.b.iii. If next is false, return undefined. + 6.c. Repeat, + 6.c.i. Let next be ? IteratorStep(iterated). + 6.c.ii. If next is false, return undefined. + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +class TestIterator extends Iterator { + get next() { + let n = g(); + return function() { + return n.next(); + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator(); +iterator = iterator.drop(0); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.drop(1); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.drop(1).drop(1).drop(1).drop(1).drop(1); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.drop(10); +iterator.next(); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/drop/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/drop/get-next-method-only-once.js new file mode 100644 index 0000000000..c6d574614c --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/get-next-method-only-once.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Gets the next method from the underlying iterator only once +info: | + %Iterator.prototype%.drop ( limit ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator extends Iterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue(nextCalls, 0); + +for (const value of iterator.drop(2)); + +assert.sameValue(nextGets, 1); +assert.sameValue(nextCalls, 5); diff --git a/test/built-ins/Iterator/prototype/drop/get-next-method-throws.js b/test/built-ins/Iterator/prototype/drop/get-next-method-throws.js new file mode 100644 index 0000000000..20b97d688b --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator has throwing next getter +info: | + %Iterator.prototype%.drop ( limit ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.drop(0); +}); diff --git a/test/built-ins/Iterator/prototype/drop/get-return-method-throws.js b/test/built-ins/Iterator/prototype/drop/get-return-method-throws.js new file mode 100644 index 0000000000..2ecc1a1b1f --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/get-return-method-throws.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator return is throwing getter +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().drop(1); +iterator.next(); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/is-function.js b/test/built-ins/Iterator/prototype/drop/is-function.js new file mode 100644 index 0000000000..9f20d000aa --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.drop, 'function'); diff --git a/test/built-ins/Iterator/prototype/drop/length.js b/test/built-ins/Iterator/prototype/drop/length.js new file mode 100644 index 0000000000..5258228bd5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.drop, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/drop/limit-equals-total.js b/test/built-ins/Iterator/prototype/drop/limit-equals-total.js new file mode 100644 index 0000000000..6dab6111de --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-equals-total.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Removes entries from this iterator, specified by limit argument. +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 1; + yield 2; +} + +let iterator = g().drop(2); +let { value, done } = iterator.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/drop/limit-greater-than-total.js b/test/built-ins/Iterator/prototype/drop/limit-greater-than-total.js new file mode 100644 index 0000000000..97670ad825 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-greater-than-total.js @@ -0,0 +1,37 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Removes entries from this iterator, specified by limit argument. +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 1; + yield 2; +} + +{ + let iterator = g().drop(3); + let { value, done } = iterator.next(); + assert.sameValue(value, undefined); + assert.sameValue(done, true); +} + +{ + let iterator = g().drop(Number.MAX_SAFE_INTEGER); + let { value, done } = iterator.next(); + assert.sameValue(value, undefined); + assert.sameValue(done, true); +} + +{ + let iterator = g().drop(Infinity); + let { value, done } = iterator.next(); + assert.sameValue(value, undefined); + assert.sameValue(done, true); +} diff --git a/test/built-ins/Iterator/prototype/drop/limit-less-than-total.js b/test/built-ins/Iterator/prototype/drop/limit-less-than-total.js new file mode 100644 index 0000000000..a08ede3591 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-less-than-total.js @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Removes entries from this iterator, specified by limit argument. +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 1; + yield 2; +} + +let iterator = g().drop(1); + +{ + let { value, done } = iterator.next(); + assert.sameValue(value, 2); + assert.sameValue(done, false); +} + +{ + let { value, done } = iterator.next(); + assert.sameValue(value, undefined); + assert.sameValue(done, true); +} diff --git a/test/built-ins/Iterator/prototype/drop/limit-rangeerror.js b/test/built-ins/Iterator/prototype/drop/limit-rangeerror.js new file mode 100644 index 0000000000..f30ea6ba87 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-rangeerror.js @@ -0,0 +1,36 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Throws a RangeError exception when limit argument is NaN or less than 0. +info: | + %Iterator.prototype%.drop ( limit ) + + 3. If numLimit is NaN, throw a RangeError exception. + 4. Let integerLimit be ! ToIntegerOrInfinity(numLimit). + 5. If integerLimit < 0, throw a RangeError exception. + +features: [iterator-helpers] +---*/ +let iterator = (function* () {})(); + +iterator.drop(0); +iterator.drop(-0.5); +iterator.drop(null); + +assert.throws(RangeError, () => { + iterator.drop(-1); +}); + +assert.throws(RangeError, () => { + iterator.drop(); +}); + +assert.throws(RangeError, () => { + iterator.drop(undefined); +}); + +assert.throws(RangeError, () => { + iterator.drop(NaN); +}); diff --git a/test/built-ins/Iterator/prototype/drop/limit-tonumber-throws.js b/test/built-ins/Iterator/prototype/drop/limit-tonumber-throws.js new file mode 100644 index 0000000000..44145e530b --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-tonumber-throws.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Throws a RangeError exception when limit argument valueOf throws. +info: | + %Iterator.prototype%.drop ( limit ) + + 2. Let numLimit be ? ToNumber(limit). + +features: [iterator-helpers] +---*/ +let iterator = (function* () {})(); + +assert.throws(Test262Error, () => { + iterator.drop({ + valueOf: function () { + throw new Test262Error(); + }, + }); +}); diff --git a/test/built-ins/Iterator/prototype/drop/limit-tonumber.js b/test/built-ins/Iterator/prototype/drop/limit-tonumber.js new file mode 100644 index 0000000000..80b9bbd483 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/limit-tonumber.js @@ -0,0 +1,37 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Converts the limit argument to a Number using ToNumber and valueOf/toString. +info: | + %Iterator.prototype%.drop ( limit ) + + 2. Let numLimit be ? ToNumber(limit). + +features: [iterator-helpers] +---*/ +function* g() { + yield 1; + yield 2; +} + +{ + let iterator = g(); + let { value, done } = iterator + .drop({ + valueOf: function () { + return 1; + }, + }) + .next(); + assert.sameValue(value, 2); + assert.sameValue(done, false); +} + +{ + let iterator = g(); + let { value, done } = iterator.drop([]).drop([1]).next(); + assert.sameValue(value, 2); + assert.sameValue(done, false); +} diff --git a/test/built-ins/Iterator/prototype/drop/name.js b/test/built-ins/Iterator/prototype/drop/name.js new file mode 100644 index 0000000000..928e376570 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + The "name" property of Iterator.prototype.drop +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.drop, 'name', { + value: 'drop', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/drop/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/drop/next-method-returns-non-object.js new file mode 100644 index 0000000000..028db0226b --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/next-method-returns-non-object.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.drop ( limit ) + + 6.b.ii. Let next be ? IteratorStep(iterated). + + 6.c.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator().drop(0); + +assert.throws(TypeError, function () { + iterator.next(); +}); + +iterator = new NonObjectIterator().drop(2); + +assert.throws(TypeError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..88ef17ea19 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-done.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.drop ( limit ) + + 6.b.ii. Let next be ? IteratorStep(iterated). + + 6.c.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().drop(0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().drop(1); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..06adf97062 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value-done.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.drop ( limit ) + + 6.c.ii. If next is false, return undefined. + +features: [iterator-helpers] +flags: [] +---*/ +class ReturnCalledError extends Error {} +class ValueGetterError extends Error {} + +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new ValueGetterError(); + }, + }; + } + return() { + throw new ReturnCalledError(); + } +} + +let iterator = new ThrowingIterator().drop(0); +iterator.next(); + +iterator = new ThrowingIterator().drop(1); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..da90956616 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.drop ( limit ) + + 6.c.iii. Let completion be Completion(Yield(? IteratorValue(next))). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().drop(0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().drop(1); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/next-method-throws.js b/test/built-ins/Iterator/prototype/drop/next-method-throws.js new file mode 100644 index 0000000000..573294057a --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/next-method-throws.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.drop ( limit ) + + 6.b.ii. Let next be ? IteratorStep(iterated). + + 6.c.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator().drop(0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().drop(1); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/non-constructible.js b/test/built-ins/Iterator/prototype/drop/non-constructible.js new file mode 100644 index 0000000000..391c53d849 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.drop(); +}); + +assert.throws(TypeError, () => { + new iter.drop(0); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.drop(0); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.drop(0); +}); diff --git a/test/built-ins/Iterator/prototype/drop/prop-desc.js b/test/built-ins/Iterator/prototype/drop/prop-desc.js new file mode 100644 index 0000000000..f2018fcc8a --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Property descriptor of Iterator.prototype.drop +info: | + Iterator.prototype.drop + + * is the initial value of the Iterator.prototype.drop property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'drop', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/drop/proto.js b/test/built-ins/Iterator/prototype/drop/proto.js new file mode 100644 index 0000000000..97ee037427 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.drop is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.drop), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/drop/result-is-iterator.js b/test/built-ins/Iterator/prototype/drop/result-is-iterator.js new file mode 100644 index 0000000000..7ccf4aa57f --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/result-is-iterator.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.prototype.drop is the + intrinsic object %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ + +assert((function* () {})().drop(0) instanceof Iterator, 'function*(){}().drop(0) must return an Iterator'); diff --git a/test/built-ins/Iterator/prototype/drop/return-is-forwarded.js b/test/built-ins/Iterator/prototype/drop/return-is-forwarded.js new file mode 100644 index 0000000000..fea82f7ab7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/return-is-forwarded.js @@ -0,0 +1,54 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.drop ( limit ) + + 6.c.iii. Let completion be Completion(Yield(? IteratorValue(next))). + 6.c.iv. IfAbruptCloseIterator(completion, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCount; + return {}; + } +} + +let iterator = new TestIterator().drop(0); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); + +returnCount = 0; + +iterator = new TestIterator().drop(1); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); + +returnCount = 0; + +iterator = new TestIterator().drop(1).drop(1).drop(1).drop(1).drop(1); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/drop/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/prototype/drop/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 0000000000..0917b4a423 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,50 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: true, + value: undefined, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().drop(0); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().drop(1); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().drop(1); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().drop(1).drop(1).drop(1).drop(1).drop(1); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/prototype/drop/this-non-callable-next.js b/test/built-ins/Iterator/prototype/drop/this-non-callable-next.js new file mode 100644 index 0000000000..6fed69ac23 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/this-non-callable-next.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.drop ( limit ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = Iterator.prototype.drop.call({ next: 0 }, 1); + +assert.throws(TypeError, function () { + iter.next(); +}); diff --git a/test/built-ins/Iterator/prototype/drop/this-non-object.js b/test/built-ins/Iterator/prototype/drop/this-non-object.js new file mode 100644 index 0000000000..2e3b2f3f78 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/this-non-object.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.drop ( limit ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.drop.call(null, 1); +}); + +assert.throws(TypeError, function () { + Iterator.prototype.drop.call(null, { + valueOf: function () { + throw new Test262Error(); + }, + }); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.drop.call(0, 1); +}); diff --git a/test/built-ins/Iterator/prototype/drop/this-plain-iterator.js b/test/built-ins/Iterator/prototype/drop/this-plain-iterator.js new file mode 100644 index 0000000000..77071c652f --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/this-plain-iterator.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Iterator.prototype.drop supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.drop ( limit ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let dropIter = Iterator.prototype.drop.call(iter, 1); + +let { done, value } = dropIter.next(); + +assert.sameValue(done, false); +assert.sameValue(value, 1); diff --git a/test/built-ins/Iterator/prototype/drop/underlying-iterator-advanced-in-parallel.js b/test/built-ins/Iterator/prototype/drop/underlying-iterator-advanced-in-parallel.js new file mode 100644 index 0000000000..5040a33d63 --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/underlying-iterator-advanced-in-parallel.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator is advanced after calling drop +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let dropped = iterator.drop(2); + +let { value, done } = iterator.next(); + +assert.sameValue(value, 0); +assert.sameValue(done, false); + +({ value, done } = dropped.next()); + +assert.sameValue(value, 3); +assert.sameValue(done, false); + +({ value, done } = dropped.next()); + +assert.sameValue(value, 4); +assert.sameValue(done, false); + +({ value, done } = dropped.next()); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed-in-parallel.js b/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed-in-parallel.js new file mode 100644 index 0000000000..f8f68198ae --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed-in-parallel.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator is closed after calling drop +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let dropped = iterator.drop(2); + +iterator.return(); + +let { value, done } = dropped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed.js b/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed.js new file mode 100644 index 0000000000..e3cfd1ec4f --- /dev/null +++ b/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.drop +description: > + Underlying iterator is closed before calling drop +info: | + %Iterator.prototype%.drop ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +iterator.return(); + +let dropped = iterator.drop(2); + +let { value, done } = dropped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/every/argument-effect-order.js b/test/built-ins/Iterator/prototype/every/argument-effect-order.js new file mode 100644 index 0000000000..7675398259 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/argument-effect-order.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.every ( predicate ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.every.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + null + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/every/callable.js b/test/built-ins/Iterator/prototype/every/callable.js new file mode 100644 index 0000000000..30bd81e7e7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.every.call(g(), () => {}); + +let iter = g(); +iter.every(() => {}); diff --git a/test/built-ins/Iterator/prototype/every/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/every/get-next-method-only-once.js new file mode 100644 index 0000000000..58baec8714 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/get-next-method-only-once.js @@ -0,0 +1,38 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.every ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter < 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue( + iterator.every(() => true), + true +); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/every/get-next-method-throws.js b/test/built-ins/Iterator/prototype/every/get-next-method-throws.js new file mode 100644 index 0000000000..067167aa9c --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.every ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/get-return-method-throws.js b/test/built-ins/Iterator/prototype/every/get-return-method-throws.js new file mode 100644 index 0000000000..b90f0b103a --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/get-return-method-throws.js @@ -0,0 +1,31 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator has throwing return getter +info: | + %Iterator.prototype%.every ( predicate ) + + 4.f. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)). + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows([1, 2]); + +assert.throws(Test262Error, function () { + iterator.every(() => false); +}); diff --git a/test/built-ins/Iterator/prototype/every/is-function.js b/test/built-ins/Iterator/prototype/every/is-function.js new file mode 100644 index 0000000000..91367c99c0 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.every, 'function'); diff --git a/test/built-ins/Iterator/prototype/every/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/every/iterator-already-exhausted.js new file mode 100644 index 0000000000..43b5bc7216 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/iterator-already-exhausted.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every returns true when the iterator has already been exhausted +info: | + %Iterator.prototype%.every ( predicate ) + + 4.a. Let next be ? IteratorStep(iterated). + 4.b. If next is false, return true. + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +let result = iterator.every(() => true); +assert.sameValue(result, true); + +result = iterator.every(() => false); +assert.sameValue(result, true); diff --git a/test/built-ins/Iterator/prototype/every/iterator-has-no-return.js b/test/built-ins/Iterator/prototype/every/iterator-has-no-return.js new file mode 100644 index 0000000000..d772403ace --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/iterator-has-no-return.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + The underlying iterator is sometimes unable to be closed (has no return method) +info: | + %Iterator.prototype%.every ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = [1, 2, 3, 4, 5][Symbol.iterator](); + +assert.sameValue(iterator.return, undefined); + +let ret = iterator.every(v => v < 4); + +assert.sameValue(ret, false); + +let { done, value } = iterator.next(); +assert.sameValue(done, false); +assert.sameValue(value, 5); + +({ done, value } = iterator.next()); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/every/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/every/iterator-return-method-throws.js new file mode 100644 index 0000000000..b221322e76 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/iterator-return-method-throws.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.every ( predicate ) + + 4.f. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)). + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.every(() => false); +}); diff --git a/test/built-ins/Iterator/prototype/every/length.js b/test/built-ins/Iterator/prototype/every/length.js new file mode 100644 index 0000000000..762f9bdbe1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.every, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/every/name.js b/test/built-ins/Iterator/prototype/every/name.js new file mode 100644 index 0000000000..a0226f8778 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + The "name" property of Iterator.prototype.every +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.every, 'name', { + value: 'every', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/every/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/every/next-method-returns-non-object.js new file mode 100644 index 0000000000..d0ec0e3ee3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/next-method-returns-non-object.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.every ( predicate ) + + 4.a. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..56dc8d62d4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-done.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.every ( predicate ) + + 4.a. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..983a243ab0 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value-done.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.every ( predicate ) + + 4.c. Let value be ? IteratorValue(next). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.every(() => {}); diff --git a/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..b2b5f53558 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/next-method-returns-throwing-value.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.every ( predicate ) + + 4.c. Let value be ? IteratorValue(next). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/next-method-throws.js b/test/built-ins/Iterator/prototype/every/next-method-throws.js new file mode 100644 index 0000000000..91df2bcf65 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.every ( predicate ) + + 4.a. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/non-callable-predicate.js b/test/built-ins/Iterator/prototype/every/non-callable-predicate.js new file mode 100644 index 0000000000..51728975bf --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/non-callable-predicate.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every expects to be called with a callable argument. +info: | + %Iterator.prototype%.every ( predicate ) + + 2. If IsCallable(predicate) is false, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () { + yield 1; +})(); + +assert.throws(TypeError, function () { + iterator.every(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/every/non-constructible.js b/test/built-ins/Iterator/prototype/every/non-constructible.js new file mode 100644 index 0000000000..1b222db1c1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.every(); +}); + +assert.throws(TypeError, () => { + new iter.every(() => {}); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.every(() => {}); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.every(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/predicate-args.js b/test/built-ins/Iterator/prototype/every/predicate-args.js new file mode 100644 index 0000000000..e2f2fb0e61 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-args.js @@ -0,0 +1,43 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every predicate is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.every ( predicate ) + + 4.d. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.every((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; + return true; +}); + +assert.sameValue(result, true); +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/every/predicate-returns-falsey.js b/test/built-ins/Iterator/prototype/every/predicate-returns-falsey.js new file mode 100644 index 0000000000..6e5b973cfb --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-returns-falsey.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every returns false and closes the iterator when the predicate returns falsey immediately +info: | + %Iterator.prototype%.every ( predicate ) + + 4.f. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.every(v => { + ++predicateCalls; + return false; +}); + +assert.sameValue(result, false); +assert.sameValue(predicateCalls, 1); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/every/predicate-returns-non-boolean.js b/test/built-ins/Iterator/prototype/every/predicate-returns-non-boolean.js new file mode 100644 index 0000000000..3c545ed70c --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-returns-non-boolean.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every coerces predicate return value to boolean +info: | + %Iterator.prototype%.every ( predicate ) + + 4.f. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + for (let i = 4; i >= 0; --i) { + yield i; + } +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.every(v => { + ++predicateCalls; + return v; +}); + +assert.sameValue(result, false); +assert.sameValue(predicateCalls, 5); diff --git a/test/built-ins/Iterator/prototype/every/predicate-returns-truthy-then-falsey.js b/test/built-ins/Iterator/prototype/every/predicate-returns-truthy-then-falsey.js new file mode 100644 index 0000000000..28c3bfa43c --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-returns-truthy-then-falsey.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every returns false and closes the iterator when the predicate returns truthy for some iterated values and falsey for others +info: | + %Iterator.prototype%.every ( predicate ) + + 4.f. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + for (let i = 0; i < 5; ++i) { + yield i; + } +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.every(v => { + ++predicateCalls; + return v < 3; +}); + +assert.sameValue(result, false); +assert.sameValue(predicateCalls, 4); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/every/predicate-returns-truthy.js b/test/built-ins/Iterator/prototype/every/predicate-returns-truthy.js new file mode 100644 index 0000000000..3305f926d6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-returns-truthy.js @@ -0,0 +1,24 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every returns true when the predicate returns truthy for all iterated values +info: | + %Iterator.prototype%.every ( predicate ) + + 4.b. If next is false, return true. + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; + yield 4; +} + +let result = g().every(() => true); +assert.sameValue(result, true); diff --git a/test/built-ins/Iterator/prototype/every/predicate-this.js b/test/built-ins/Iterator/prototype/every/predicate-this.js new file mode 100644 index 0000000000..529c809a2c --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-this.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every predicate this value is undefined +info: | + %Iterator.prototype%.every ( predicate ) + + 4.d. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +let result = iter.every(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return true; +}); + +assert.sameValue(result, true); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/every/predicate-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/every/predicate-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..9f149cae37 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Attempts to close iterator when predicate throws, but that throws +info: | + %Iterator.prototype%.every ( predicate ) + + 4.d. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + 4.e. IfAbruptCloseIterator(result, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator(); + +assert.throws(Test262Error, function () { + iterator.every(() => { + throw new Test262Error(); + }); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/every/predicate-throws.js b/test/built-ins/Iterator/prototype/every/predicate-throws.js new file mode 100644 index 0000000000..c99c983314 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/predicate-throws.js @@ -0,0 +1,43 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Closes iterator and throws when predicate throws +info: | + %Iterator.prototype%.every ( predicate ) + + 4.d. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + 4.e. IfAbruptCloseIterator(result, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let iterator = new TestIterator(); + +let callbackCalls = 0; + +assert.throws(Test262Error, function () { + iterator.every(() => { + ++callbackCalls; + throw new Test262Error(); + }); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/every/prop-desc.js b/test/built-ins/Iterator/prototype/every/prop-desc.js new file mode 100644 index 0000000000..fe365a87a2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Property descriptor of Iterator.prototype.every +info: | + Iterator.prototype.every + + * is the initial value of the Iterator.prototype.every property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'every', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/every/proto.js b/test/built-ins/Iterator/prototype/every/proto.js new file mode 100644 index 0000000000..be8c22cb3b --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.every is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.every), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/every/result-is-boolean.js b/test/built-ins/Iterator/prototype/every/result-is-boolean.js new file mode 100644 index 0000000000..9d19ac672d --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/result-is-boolean.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every returns a boolean +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); +assert.sameValue(typeof iter.every(() => {}), 'boolean'); diff --git a/test/built-ins/Iterator/prototype/every/this-non-callable-next.js b/test/built-ins/Iterator/prototype/every/this-non-callable-next.js new file mode 100644 index 0000000000..7c9d792cd3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/this-non-callable-next.js @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.every ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.every.call({ next: 0 }, () => true); +}); diff --git a/test/built-ins/Iterator/prototype/every/this-non-object.js b/test/built-ins/Iterator/prototype/every/this-non-object.js new file mode 100644 index 0000000000..c8d8953071 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/this-non-object.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.every ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.every.call(null, () => {}); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.every.call(0, () => {}); +}); diff --git a/test/built-ins/Iterator/prototype/every/this-plain-iterator.js b/test/built-ins/Iterator/prototype/every/this-plain-iterator.js new file mode 100644 index 0000000000..bf3ba73da6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/every/this-plain-iterator.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.every +description: > + Iterator.prototype.every supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.every ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let predicateCalls = 0; +let result = Iterator.prototype.every.call(iter, function (v) { + ++predicateCalls; + return v; +}); + +assert.sameValue(result, false); +assert.sameValue(predicateCalls, 3); diff --git a/test/built-ins/Iterator/prototype/filter/argument-effect-order.js b/test/built-ins/Iterator/prototype/filter/argument-effect-order.js new file mode 100644 index 0000000000..66b390806b --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/argument-effect-order.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.filter ( predicate ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.filter.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + null + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/filter/callable.js b/test/built-ins/Iterator/prototype/filter/callable.js new file mode 100644 index 0000000000..c27e2fb450 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.filter.call(g(), () => false); + +let iter = g(); +iter.filter(() => false); diff --git a/test/built-ins/Iterator/prototype/filter/exhaustion-does-not-call-return.js b/test/built-ins/Iterator/prototype/filter/exhaustion-does-not-call-return.js new file mode 100644 index 0000000000..7176212a16 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/exhaustion-does-not-call-return.js @@ -0,0 +1,37 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator return is not called when result iterator is exhausted +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.i. Let next be ? IteratorStep(iterated). + 3.b.ii. If next is false, return undefined. + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +class TestIterator extends Iterator { + get next() { + let n = g(); + return function() { + return n.next(); + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().filter(() => false); +iterator.next(); +iterator.next(); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/filter/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/filter/get-next-method-only-once.js new file mode 100644 index 0000000000..fc7a957a41 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/get-next-method-only-once.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Gets the next method from the underlying iterator only once +info: | + %Iterator.prototype%.filter ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator extends Iterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue(nextCalls, 0); + +for (const value of iterator.filter(() => false)); + +assert.sameValue(nextGets, 1); +assert.sameValue(nextCalls, 5); diff --git a/test/built-ins/Iterator/prototype/filter/get-next-method-throws.js b/test/built-ins/Iterator/prototype/filter/get-next-method-throws.js new file mode 100644 index 0000000000..4b411d3239 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator has throwing next getter +info: | + %Iterator.prototype%.filter ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.filter(() => false); +}); diff --git a/test/built-ins/Iterator/prototype/filter/get-return-method-throws.js b/test/built-ins/Iterator/prototype/filter/get-return-method-throws.js new file mode 100644 index 0000000000..30831e5cd1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/get-return-method-throws.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator return is throwing getter +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().filter(() => true); +iterator.next(); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/is-function.js b/test/built-ins/Iterator/prototype/filter/is-function.js new file mode 100644 index 0000000000..f43e683c37 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.filter, 'function'); diff --git a/test/built-ins/Iterator/prototype/filter/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/filter/iterator-already-exhausted.js new file mode 100644 index 0000000000..ddb4ba65f9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/iterator-already-exhausted.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter returns an empty iterator when the iterator has already been exhausted +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.i. Let next be ? IteratorStep(iterated). + 3.b.ii. If next is false, return undefined. + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +iterator = iterator.filter(() => true); +({ value, done } = iterator.next()); +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/filter/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/filter/iterator-return-method-throws.js new file mode 100644 index 0000000000..a1d74c2c1b --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/iterator-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows().filter(() => false); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/length.js b/test/built-ins/Iterator/prototype/filter/length.js new file mode 100644 index 0000000000..7ae2f45278 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.filter, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/filter/name.js b/test/built-ins/Iterator/prototype/filter/name.js new file mode 100644 index 0000000000..3e556d4f76 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + The "name" property of Iterator.prototype.filter +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.filter, 'name', { + value: 'filter', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/filter/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/filter/next-method-returns-non-object.js new file mode 100644 index 0000000000..06e154363a --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/next-method-returns-non-object.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator().filter(() => true); + +assert.throws(TypeError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..e0ea4d820f --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-done.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().filter(() => true); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..1f7c325d77 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value-done.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.ii. If next is false, return undefined. + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().filter(() => true); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..11e67ee5e2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/next-method-returns-throwing-value.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.iii. Let value be ? IteratorValue(next). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().filter(() => true); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/next-method-throws.js b/test/built-ins/Iterator/prototype/filter/next-method-throws.js new file mode 100644 index 0000000000..b114cf1d97 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.i. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator().filter(() => true); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/non-callable-predicate.js b/test/built-ins/Iterator/prototype/filter/non-callable-predicate.js new file mode 100644 index 0000000000..8bf18c5113 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/non-callable-predicate.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter expects to be called with a callable argument. +info: | + %Iterator.prototype%.filter ( predicate ) + + 2. If IsCallable(predicate) is false, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () {})(); + +assert.throws(TypeError, function () { + iterator.filter(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/filter/non-constructible.js b/test/built-ins/Iterator/prototype/filter/non-constructible.js new file mode 100644 index 0000000000..3f63331b4c --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.filter(); +}); + +assert.throws(TypeError, () => { + new iter.filter(() => true); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.filter(() => true); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.filter(() => true); +}); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-args.js b/test/built-ins/Iterator/prototype/filter/predicate-args.js new file mode 100644 index 0000000000..aefcf7c03f --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-args.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter predicate is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.iv. Let selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let assertionCount = 0; +let iter = g().filter((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; + return true; +}); + +assert.sameValue(assertionCount, 0); + +for (let i of iter); + +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-filters.js b/test/built-ins/Iterator/prototype/filter/predicate-filters.js new file mode 100644 index 0000000000..8bef4428a9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-filters.js @@ -0,0 +1,40 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter returns only items for which the predicate returned true. +info: | + %Iterator.prototype%.filter ( filterer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 1; + yield 0; + yield 2; + yield 0; + yield 3; + yield 0; + yield 4; +} + +let iterator = g(); + +let predicateCalls = 0; +iterator = iterator.filter(value => { + ++predicateCalls; + return value !== 0; +}); + +let resultCount = 0; +for (let value of iterator) { + ++resultCount; + assert.sameValue(value, resultCount); +} +assert.sameValue(resultCount, 4); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-returns-non-boolean.js b/test/built-ins/Iterator/prototype/filter/predicate-returns-non-boolean.js new file mode 100644 index 0000000000..7ec64e314f --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-returns-non-boolean.js @@ -0,0 +1,38 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter coerces predicate return value to boolean +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.vi. If ToBoolean(selected) is true, then + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 0; + yield 0; + yield 1; +} + +let iter = g(); + +let predicateCalls = 0; +iter = iter.filter(v => { + ++predicateCalls; + return v; +}); + +assert.sameValue(predicateCalls, 0); + +iter.next(); + +assert.sameValue(predicateCalls, 4); + +iter.next(); + +assert.sameValue(predicateCalls, 4); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-this.js b/test/built-ins/Iterator/prototype/filter/predicate-this.js new file mode 100644 index 0000000000..4d8d8ba014 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-this.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter predicate this value is undefined +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.iv. Let selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +iter = iter.filter(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return true; +}); + +iter.next(); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/filter/predicate-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..ec033aba71 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Attempts to close iterator when predicate throws, but that throws +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.v. IfAbruptCloseIterator(selected, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator().filter(() => { + throw new Test262Error(); +}); + +assert.sameValue(returnCalls, 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/filter/predicate-throws.js b/test/built-ins/Iterator/prototype/filter/predicate-throws.js new file mode 100644 index 0000000000..63bba837eb --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/predicate-throws.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Closes iterator and throws when predicate throws +info: | + %Iterator.prototype%.filter ( predicate ) + + 3.b.v. IfAbruptCloseIterator(selected, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let callbackCalls = 0; +let iterator = new TestIterator().filter(() => { + ++callbackCalls; + throw new Test262Error(); +}); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/filter/prop-desc.js b/test/built-ins/Iterator/prototype/filter/prop-desc.js new file mode 100644 index 0000000000..8f9d9dbab8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Property descriptor of Iterator.prototype.filter +info: | + Iterator.prototype.filter + + * is the initial value of the Iterator.prototype.filter property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'filter', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/filter/proto.js b/test/built-ins/Iterator/prototype/filter/proto.js new file mode 100644 index 0000000000..f496d487bc --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.filter is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.filter), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/filter/result-is-iterator.js b/test/built-ins/Iterator/prototype/filter/result-is-iterator.js new file mode 100644 index 0000000000..462afb585a --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/result-is-iterator.js @@ -0,0 +1,14 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.prototype.filter is the + intrinsic object %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ + +assert( + (function* () {})().filter(() => true) instanceof Iterator, + 'function*(){}().filter(() => true) must return an Iterator' +); diff --git a/test/built-ins/Iterator/prototype/filter/return-is-forwarded.js b/test/built-ins/Iterator/prototype/filter/return-is-forwarded.js new file mode 100644 index 0000000000..0a6efad3c4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/return-is-forwarded.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCount; + return {}; + } +} + +let iterator = new TestIterator().filter(() => false); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/filter/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/prototype/filter/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 0000000000..196f903fa6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: true, + value: undefined, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().filter(() => true); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().filter(() => true); +iterator.next(); +iterator.return(); + +iterator = new TestIterator() + .filter(() => true) + .filter(() => true) + .filter(() => true); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/prototype/filter/this-non-callable-next.js b/test/built-ins/Iterator/prototype/filter/this-non-callable-next.js new file mode 100644 index 0000000000..bd43672c5c --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/this-non-callable-next.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.filter ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = Iterator.prototype.filter.call({ next: 0 }, () => true); + +assert.throws(TypeError, function () { + iter.next(); +}); diff --git a/test/built-ins/Iterator/prototype/filter/this-non-object.js b/test/built-ins/Iterator/prototype/filter/this-non-object.js new file mode 100644 index 0000000000..3a48b97608 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/this-non-object.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.filter ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.filter.call(null, () => true); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.filter.call(0, () => true); +}); diff --git a/test/built-ins/Iterator/prototype/filter/this-plain-iterator.js b/test/built-ins/Iterator/prototype/filter/this-plain-iterator.js new file mode 100644 index 0000000000..2bddfe1b76 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/this-plain-iterator.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Iterator.prototype.filter supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.filter ( predicate ) + + 1. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let predicateCalls = 0; +iter = Iterator.prototype.filter.call(iter, function (v) { + ++predicateCalls; + return v; +}); + +for (let e of iter); + +assert.sameValue(predicateCalls, 3); diff --git a/test/built-ins/Iterator/prototype/filter/underlying-iterator-advanced-in-parallel.js b/test/built-ins/Iterator/prototype/filter/underlying-iterator-advanced-in-parallel.js new file mode 100644 index 0000000000..4ff2b6f623 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/underlying-iterator-advanced-in-parallel.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator is advanced after calling filter +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let filtered = iterator.filter(() => true); + +let { value, done } = iterator.next(); + +assert.sameValue(value, 0); +assert.sameValue(done, false); + +iterator.next(); +iterator.next(); + +({ value, done } = filtered.next()); + +assert.sameValue(value, 3); +assert.sameValue(done, false); + +({ value, done } = filtered.next()); + +assert.sameValue(value, 4); +assert.sameValue(done, false); + +({ value, done } = filtered.next()); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed-in-parallel.js b/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed-in-parallel.js new file mode 100644 index 0000000000..2888553c70 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed-in-parallel.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator is closed after calling filter +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let filtered = iterator.filter(() => true); + +iterator.return(); + +let { value, done } = filtered.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed.js b/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed.js new file mode 100644 index 0000000000..92de4e3d79 --- /dev/null +++ b/test/built-ins/Iterator/prototype/filter/underlying-iterator-closed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.filter +description: > + Underlying iterator is closed before calling filter +info: | + %Iterator.prototype%.filter ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +iterator.return(); + +let filtered = iterator.filter(() => true); + +let { value, done } = filtered.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/find/argument-effect-order.js b/test/built-ins/Iterator/prototype/find/argument-effect-order.js new file mode 100644 index 0000000000..3651081f73 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/argument-effect-order.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.find ( predicate ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.find.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + null + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/find/callable.js b/test/built-ins/Iterator/prototype/find/callable.js new file mode 100644 index 0000000000..a7238402c7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.find.call(g(), () => {}); + +let iter = g(); +iter.find(() => {}); diff --git a/test/built-ins/Iterator/prototype/find/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/find/get-next-method-only-once.js new file mode 100644 index 0000000000..2851c3f563 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/get-next-method-only-once.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter < 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue( + iterator.find(() => true), + 4 +); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/find/get-next-method-throws.js b/test/built-ins/Iterator/prototype/find/get-next-method-throws.js new file mode 100644 index 0000000000..9f74b3135a --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/get-next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/get-return-method-throws.js b/test/built-ins/Iterator/prototype/find/get-return-method-throws.js new file mode 100644 index 0000000000..c50098651c --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/get-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator has throwing return getter +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows([1, 2]); + +assert.throws(Test262Error, function () { + iterator.find(() => true); +}); diff --git a/test/built-ins/Iterator/prototype/find/is-function.js b/test/built-ins/Iterator/prototype/find/is-function.js new file mode 100644 index 0000000000..146bdeec3a --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.find, 'function'); diff --git a/test/built-ins/Iterator/prototype/find/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/find/iterator-already-exhausted.js new file mode 100644 index 0000000000..ca383b24a6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/iterator-already-exhausted.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find returns undefined when the iterator has already been exhausted +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +let result = iterator.find(() => true); +assert.sameValue(result, undefined); + +result = iterator.find(() => false); +assert.sameValue(result, undefined); diff --git a/test/built-ins/Iterator/prototype/find/iterator-has-no-return.js b/test/built-ins/Iterator/prototype/find/iterator-has-no-return.js new file mode 100644 index 0000000000..09862a2009 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/iterator-has-no-return.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + The underlying iterator is sometimes unable to be closed (has no return method) +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = [1, 2, 3, 4, 5][Symbol.iterator](); + +assert.sameValue(iterator.return, undefined); + +let ret = iterator.find(v => v > 3); + +assert.sameValue(ret, 4); + +let { done, value } = iterator.next(); +assert.sameValue(done, false); +assert.sameValue(value, 5); + +({ done, value } = iterator.next()); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/find/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/find/iterator-return-method-throws.js new file mode 100644 index 0000000000..9dc822570a --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/iterator-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.find(() => true); +}); diff --git a/test/built-ins/Iterator/prototype/find/length.js b/test/built-ins/Iterator/prototype/find/length.js new file mode 100644 index 0000000000..e7d50f0637 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.find, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/find/name.js b/test/built-ins/Iterator/prototype/find/name.js new file mode 100644 index 0000000000..4735b28c83 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + The "name" property of Iterator.prototype.find +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.find, 'name', { + value: 'find', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/find/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/find/next-method-returns-non-object.js new file mode 100644 index 0000000000..519c14a962 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..9a3e0a7d85 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..a03849a8e2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.find(() => {}); diff --git a/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..9453b8c08f --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/next-method-throws.js b/test/built-ins/Iterator/prototype/find/next-method-throws.js new file mode 100644 index 0000000000..3a658321fd --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/non-callable-predicate.js b/test/built-ins/Iterator/prototype/find/non-callable-predicate.js new file mode 100644 index 0000000000..a2aa43c147 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/non-callable-predicate.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find expects to be called with a callable argument. +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () { + yield 1; +})(); + +assert.throws(TypeError, function () { + iterator.find(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/find/non-constructible.js b/test/built-ins/Iterator/prototype/find/non-constructible.js new file mode 100644 index 0000000000..df0eef60c9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.find(); +}); + +assert.throws(TypeError, () => { + new iter.find(() => {}); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.find(() => {}); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.find(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/predicate-args.js b/test/built-ins/Iterator/prototype/find/predicate-args.js new file mode 100644 index 0000000000..75a584874c --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-args.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find predicate is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.find((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; + return false; +}); + +assert.sameValue(result, undefined); +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/find/predicate-returns-falsey-then-truthy.js b/test/built-ins/Iterator/prototype/find/predicate-returns-falsey-then-truthy.js new file mode 100644 index 0000000000..2732fba789 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-returns-falsey-then-truthy.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find returns the found value and closes the iterator when the predicate returns falsey for some iterated values and truthy for others +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + for (let i = 0; i < 5; ++i) { + yield i; + } +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.find(v => { + ++predicateCalls; + return v > 2; +}); + +assert.sameValue(result, 3); +assert.sameValue(predicateCalls, 4); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/find/predicate-returns-falsey.js b/test/built-ins/Iterator/prototype/find/predicate-returns-falsey.js new file mode 100644 index 0000000000..11d353b14c --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-returns-falsey.js @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find returns undefined when the predicate returns falsey for all iterated values +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; +} + +let result = g().find(() => false); +assert.sameValue(result, undefined); diff --git a/test/built-ins/Iterator/prototype/find/predicate-returns-non-boolean.js b/test/built-ins/Iterator/prototype/find/predicate-returns-non-boolean.js new file mode 100644 index 0000000000..136fb4e83b --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-returns-non-boolean.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find coerces predicate return value to boolean +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield ''; + yield null; + yield undefined; + yield 0; + yield 1; + yield 2; + yield 3; +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.find(v => { + ++predicateCalls; + return v; +}); + +assert.sameValue(result, 1); +assert.sameValue(predicateCalls, 5); diff --git a/test/built-ins/Iterator/prototype/find/predicate-returns-truthy.js b/test/built-ins/Iterator/prototype/find/predicate-returns-truthy.js new file mode 100644 index 0000000000..a265869f42 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-returns-truthy.js @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find returns the found value and closes the iterator when the predicate returns truthy immediately +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.find(v => { + ++predicateCalls; + return true; +}); + +assert.sameValue(result, 0); +assert.sameValue(predicateCalls, 1); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/find/predicate-this.js b/test/built-ins/Iterator/prototype/find/predicate-this.js new file mode 100644 index 0000000000..84452f5369 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-this.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find predicate this value is undefined +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +let result = iter.find(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return true; +}); + +assert.sameValue(result, 0); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/find/predicate-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/find/predicate-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..f070e00dd7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Attempts to close iterator when predicate throws, but that throws +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator(); + +assert.throws(Test262Error, function () { + iterator.find(() => { + throw new Test262Error(); + }); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/find/predicate-throws.js b/test/built-ins/Iterator/prototype/find/predicate-throws.js new file mode 100644 index 0000000000..c031e43be8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/predicate-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Closes iterator and throws when predicate throws +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let iterator = new TestIterator(); + +let callbackCalls = 0; + +assert.throws(Test262Error, function () { + iterator.find(() => { + ++callbackCalls; + throw new Test262Error(); + }); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/find/prop-desc.js b/test/built-ins/Iterator/prototype/find/prop-desc.js new file mode 100644 index 0000000000..c38c9508ea --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Property descriptor of Iterator.prototype.find +info: | + Iterator.prototype.find + + * is the initial value of the Iterator.prototype.find property of the global object. + + 17 ECMAScript Standard Built-in Objects + + every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'find', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/find/proto.js b/test/built-ins/Iterator/prototype/find/proto.js new file mode 100644 index 0000000000..0d9ca00951 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.find is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.find), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/find/this-non-callable-next.js b/test/built-ins/Iterator/prototype/find/this-non-callable-next.js new file mode 100644 index 0000000000..3168b25b79 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/this-non-callable-next.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.find.call({ next: 0 }, () => true); +}); diff --git a/test/built-ins/Iterator/prototype/find/this-non-object.js b/test/built-ins/Iterator/prototype/find/this-non-object.js new file mode 100644 index 0000000000..05b0c264c5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/this-non-object.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.find.call(null, () => {}); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.find.call(0, () => {}); +}); diff --git a/test/built-ins/Iterator/prototype/find/this-plain-iterator.js b/test/built-ins/Iterator/prototype/find/this-plain-iterator.js new file mode 100644 index 0000000000..4461ad137c --- /dev/null +++ b/test/built-ins/Iterator/prototype/find/this-plain-iterator.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.find +description: > + Iterator.prototype.find supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.find ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let predicateCalls = 0; +let result = Iterator.prototype.find.call(iter, function (v) { + ++predicateCalls; + return v === 0; +}); + +assert.sameValue(result, 0); +assert.sameValue(predicateCalls, 3); diff --git a/test/built-ins/Iterator/prototype/flatMap/argument-effect-order.js b/test/built-ins/Iterator/prototype/flatMap/argument-effect-order.js new file mode 100644 index 0000000000..4683a3024c --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/argument-effect-order.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 1. Let O be the this value. + 2. If O is not an Object, throw a TypeError exception. + 3. If IsCallable(mapper) is false, throw a TypeError exception. + 4. Let iterated be ? GetIteratorDirect(O). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.flatMap.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + { + valueOf() { + effects.push('valueOf mapper'); + return function () { + return []; + }; + }, + } + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/flatMap/callable.js b/test/built-ins/Iterator/prototype/flatMap/callable.js new file mode 100644 index 0000000000..0626011c7d --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.flatMap.call(g(), () => []); + +let iter = g(); +iter.flatMap(() => []); diff --git a/test/built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return.js b/test/built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return.js new file mode 100644 index 0000000000..a33ef7ed16 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator return is not called when result iterator is exhausted +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +class TestIterator extends Iterator { + get next() { + let n = g(); + return function() { + return n.next(); + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().flatMap(() => []); +iterator.next(); +iterator.next(); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/flatMap/flattens-iterable.js b/test/built-ins/Iterator/prototype/flatMap/flattens-iterable.js new file mode 100644 index 0000000000..6668426d51 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/flattens-iterable.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap flattens iterables returned by the mapper +info: | + %Iterator.prototype%.flatMap ( mapper ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; +} + +let iter = g().flatMap((v, count) => { + let result = []; + for (let i = 0; i < v; ++i) { + result.push(v); + } + return result; +}); + +assert.compareArray(Array.from(iter), [1, 2, 2, 3, 3, 3]); diff --git a/test/built-ins/Iterator/prototype/flatMap/flattens-iterator.js b/test/built-ins/Iterator/prototype/flatMap/flattens-iterator.js new file mode 100644 index 0000000000..da236b0fab --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/flattens-iterator.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap flattens non-iterable iterators returned by the mapper +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.vi. Let innerIterator be Completion(GetIteratorFlattenable(mapped)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; +} + +let iter = g().flatMap((v, count) => { + let i = 0; + return { + next: function () { + if (i < v) { + ++i; + return { + value: v, + done: false, + }; + } else { + return { + value: undefined, + done: true, + }; + } + }, + }; +}); + +assert.compareArray(Array.from(iter), [1, 2, 2, 3, 3, 3]); diff --git a/test/built-ins/Iterator/prototype/flatMap/flattens-only-depth-1.js b/test/built-ins/Iterator/prototype/flatMap/flattens-only-depth-1.js new file mode 100644 index 0000000000..1ed5e8b52c --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/flattens-only-depth-1.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap does not flatten recursively +info: | + %Iterator.prototype%.flatMap ( mapper ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +let arr = [ + { + [Symbol.iterator]: function () { + throw new Test262Error(); + }, + }, + { + next: function () { + throw new Test262Error(); + }, + }, +]; + +function* g() { + yield arr; +} + +let iter = g().flatMap(v => v); + +assert.compareArray(Array.from(iter), arr); diff --git a/test/built-ins/Iterator/prototype/flatMap/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/flatMap/get-next-method-only-once.js new file mode 100644 index 0000000000..feb5c7094e --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/get-next-method-only-once.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Gets the next method from the underlying iterator only once +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 4. Let iterated be ? GetIteratorDirect(O). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator extends Iterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue(nextCalls, 0); + +for (const value of iterator.flatMap(() => [])); + +assert.sameValue(nextGets, 1); +assert.sameValue(nextCalls, 5); diff --git a/test/built-ins/Iterator/prototype/flatMap/get-next-method-throws.js b/test/built-ins/Iterator/prototype/flatMap/get-next-method-throws.js new file mode 100644 index 0000000000..a5ae5fabab --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator has throwing next getter +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 4. Let iterated be ? GetIteratorDirect(O). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.flatMap(() => []); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/get-return-method-throws.js b/test/built-ins/Iterator/prototype/flatMap/get-return-method-throws.js new file mode 100644 index 0000000000..e51b9e3336 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/get-return-method-throws.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator return is throwing getter +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().flatMap(x => [x]); +iterator.next(); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/is-function.js b/test/built-ins/Iterator/prototype/flatMap/is-function.js new file mode 100644 index 0000000000..8d2ed6202a --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.flatMap, 'function'); diff --git a/test/built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened.js b/test/built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened.js new file mode 100644 index 0000000000..e3eed45277 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened.js @@ -0,0 +1,37 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap does not respect the iterability of any primitive +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.vi. Let innerIterator be Completion(GetIteratorFlattenable(mapped)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; +} + +Number.prototype[Symbol.iterator] = function* () { + let i = 0; + let target = this >>> 0; + while (i < target) { + yield i; + ++i; + } +}; + +assert.compareArray(Array.from(5), [0, 1, 2, 3, 4]); + +assert.throws(TypeError, function () { + for (let unused of g().flatMap(v => 5)); +}); + +let iter = g().flatMap(v => new Number(5)); +assert.compareArray(Array.from(iter), [0, 1, 2, 3, 4]); diff --git a/test/built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback.js b/test/built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback.js new file mode 100644 index 0000000000..0324025e68 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback.js @@ -0,0 +1,57 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap falls back to treating mapper return values as iterators if the Symbol.iterator property is null/undefined +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.vi. Let innerIterator be Completion(GetIteratorFlattenable(mapped)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; +} + +function* h() { + yield 0; + yield 1; + yield 2; +} + +let iter = g().flatMap(v => { + let n = h(); + return { + [Symbol.iterator]: 0, + next: () => n.next(), + }; +}); + +assert.throws(TypeError, function () { + iter.next(); +}); + +iter = g().flatMap(v => { + let n = h(); + return { + [Symbol.iterator]: null, + next: () => n.next(), + }; +}); + +assert.compareArray(Array.from(iter), [0, 1, 2]); + +iter = g().flatMap(v => { + let n = h(); + return { + [Symbol.iterator]: undefined, + next: () => n.next(), + }; +}); + +assert.compareArray(Array.from(iter), [0, 1, 2]); diff --git a/test/built-ins/Iterator/prototype/flatMap/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/flatMap/iterator-already-exhausted.js new file mode 100644 index 0000000000..ef17517fe9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/iterator-already-exhausted.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap returns an empty iterator when the iterator has already been exhausted +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +iterator = iterator.flatMap(x => [x]); +({ value, done } = iterator.next()); +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/flatMap/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/flatMap/iterator-return-method-throws.js new file mode 100644 index 0000000000..5d8eb46291 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/iterator-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows().flatMap(() => []); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/length.js b/test/built-ins/Iterator/prototype/flatMap/length.js new file mode 100644 index 0000000000..2f61836806 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.flatMap, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-args.js b/test/built-ins/Iterator/prototype/flatMap/mapper-args.js new file mode 100644 index 0000000000..07594d3ca8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-args.js @@ -0,0 +1,55 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap mapper is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.iv. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; + yield 'd'; + yield 'e'; +} + +let assertionCount = 0; +let iter = g().flatMap((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + ++assertionCount; + return [0]; + case 'b': + assert.sameValue(count, 1); + ++assertionCount; + return [0]; + case 'c': + assert.sameValue(count, 2); + ++assertionCount; + return [1, 2]; + case 'd': + assert.sameValue(count, 3); + ++assertionCount; + return [3, 4, 5]; + case 'e': + assert.sameValue(count, 4); + ++assertionCount; + return [6, 7, 8, 9]; + default: + throw new Error(); + } +}); + +assert.sameValue(assertionCount, 0); + +for (let i of iter); + +assert.sameValue(assertionCount, 5); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator.js b/test/built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator.js new file mode 100644 index 0000000000..e44010a733 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap handles closed return values from mapper and does not try to close them again +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; + yield 1; + yield 2; +} + +let closed = g(); +closed.return(); +closed.return = function () { + throw new Test262Error(); +}; + +let iter = g().flatMap(v => closed); +let { value, done } = iter.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-returns-non-object.js b/test/built-ins/Iterator/prototype/flatMap/mapper-returns-non-object.js new file mode 100644 index 0000000000..c40ce55f83 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-returns-non-object.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap mapper return value must be an object +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 0; + yield 0; + yield 1; +} + +let iter = g(); + +let mapperCalls = 0; +iter = iter.flatMap(v => { + ++mapperCalls; + return null; +}); + +assert.sameValue(mapperCalls, 0); + +assert.throws(TypeError, function () { + iter.next(); +}); + +assert.sameValue(mapperCalls, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-this.js b/test/built-ins/Iterator/prototype/flatMap/mapper-this.js new file mode 100644 index 0000000000..dee13a7208 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-this.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap mapper this value is undefined +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.iv. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +iter = iter.flatMap(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return [v]; +}); + +iter.next(); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..41fd2e1204 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Attempts to close iterator when mapper throws, but that throws +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.v. IfAbruptCloseIterator(mapped, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator().flatMap(() => { + throw new Test262Error(); +}); + +assert.sameValue(returnCalls, 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/mapper-throws.js b/test/built-ins/Iterator/prototype/flatMap/mapper-throws.js new file mode 100644 index 0000000000..8e77c245df --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/mapper-throws.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Closes iterator and throws when mapper throws +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.v. IfAbruptCloseIterator(mapped, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let callbackCalls = 0; +let iterator = new TestIterator().flatMap(() => { + ++callbackCalls; + throw new Test262Error(); +}); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/name.js b/test/built-ins/Iterator/prototype/flatMap/name.js new file mode 100644 index 0000000000..d0a24e862f --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + The "name" property of Iterator.prototype.flatMap +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.flatMap, 'name', { + value: 'flatMap', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-non-object.js new file mode 100644 index 0000000000..3a427325cd --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator().flatMap(x => [x]); + +assert.throws(TypeError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..7dac1daa2e --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().flatMap(x => [x]); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..ece5b2d777 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().flatMap(x => [x]); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..c11cfacd6a --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().flatMap(x => [x]); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/next-method-throws.js b/test/built-ins/Iterator/prototype/flatMap/next-method-throws.js new file mode 100644 index 0000000000..aef6861792 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator().flatMap(x => [x]); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/non-callable-mapper.js b/test/built-ins/Iterator/prototype/flatMap/non-callable-mapper.js new file mode 100644 index 0000000000..b596288ec6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/non-callable-mapper.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap expects to be called with a callable argument. +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 3. If IsCallable(mapper) is false, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () {})(); + +assert.throws(TypeError, function () { + iterator.flatMap(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/non-constructible.js b/test/built-ins/Iterator/prototype/flatMap/non-constructible.js new file mode 100644 index 0000000000..e2adfb4241 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.flatMap(); +}); + +assert.throws(TypeError, () => { + new iter.flatMap(() => []); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.flatMap(() => []); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.flatMap(() => []); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/prop-desc.js b/test/built-ins/Iterator/prototype/flatMap/prop-desc.js new file mode 100644 index 0000000000..97266ef53c --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Property descriptor of Iterator.prototype.flatMap +info: | + Iterator.prototype.flatMap + + * is the initial value of the Iterator.prototype.flatMap property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'flatMap', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/proto.js b/test/built-ins/Iterator/prototype/flatMap/proto.js new file mode 100644 index 0000000000..60feb748e4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.flatMap is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.flatMap), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/flatMap/result-is-iterator.js b/test/built-ins/Iterator/prototype/flatMap/result-is-iterator.js new file mode 100644 index 0000000000..e85cf38aba --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/result-is-iterator.js @@ -0,0 +1,14 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.prototype.flatMap is the + intrinsic object %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ + +assert( + (function* () {})().flatMap(() => []) instanceof Iterator, + 'function*(){}().flatMap(() => []) must return an Iterator' +); diff --git a/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result.js b/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result.js new file mode 100644 index 0000000000..004911659a --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result.js @@ -0,0 +1,45 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Mapper returned iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +function* g() { + yield 0; +} + +let iter = g().flatMap(v => ({ + next() { + return { + done: false, + value: 1, + }; + }, + return() { + ++returnCount; + return {}; + }, +})); + +assert.sameValue(returnCount, 0); + +let { done, value } = iter.next(); + +assert.sameValue(done, false); +assert.sameValue(value, 1); + +assert.sameValue(returnCount, 0); + +iter.return(); +assert.sameValue(returnCount, 1); + +iter.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator.js b/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator.js new file mode 100644 index 0000000000..cf2a3a4755 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCount; + return {}; + } +} + +let iterator = new TestIterator().flatMap(() => []); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 0000000000..d970908da3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: true, + value: undefined, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().flatMap(x => [x]); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().flatMap(x => [x]); +iterator.next(); +iterator.return(); + +iterator = new TestIterator() + .flatMap(x => [x]) + .flatMap(x => [x]) + .flatMap(x => [x]); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/prototype/flatMap/strings-are-not-flattened.js b/test/built-ins/Iterator/prototype/flatMap/strings-are-not-flattened.js new file mode 100644 index 0000000000..2584860766 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/strings-are-not-flattened.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap does not respect the iterability of primitive strings +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 5.b.vi. Let innerIterator be Completion(GetIteratorFlattenable(mapped)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ + +function* g() { + yield 0; +} + +assert.throws(TypeError, function () { + for (let unused of g().flatMap(v => 'string')); +}); + +let iter = g().flatMap(v => new String('string')); +assert.compareArray(Array.from(iter), ['s', 't', 'r', 'i', 'n', 'g']); diff --git a/test/built-ins/Iterator/prototype/flatMap/this-non-callable-next.js b/test/built-ins/Iterator/prototype/flatMap/this-non-callable-next.js new file mode 100644 index 0000000000..871f6223f6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/this-non-callable-next.js @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = Iterator.prototype.flatMap.call({ next: 0 }, () => []); + +assert.throws(TypeError, function () { + iter.next(); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/this-non-object.js b/test/built-ins/Iterator/prototype/flatMap/this-non-object.js new file mode 100644 index 0000000000..8893a15046 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/this-non-object.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.flatMap ( mapper ) + + 2. If O is not an Object, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.flatMap.call(null, () => []); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.flatMap.call(0, () => []); +}); diff --git a/test/built-ins/Iterator/prototype/flatMap/this-plain-iterator.js b/test/built-ins/Iterator/prototype/flatMap/this-plain-iterator.js new file mode 100644 index 0000000000..677d6adbcc --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/this-plain-iterator.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Iterator.prototype.flatMap supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let mapperCalls = 0; +iter = Iterator.prototype.flatMap.call(iter, function (v) { + ++mapperCalls; + return [v]; +}); + +for (let e of iter); + +assert.sameValue(mapperCalls, 3); diff --git a/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel.js b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel.js new file mode 100644 index 0000000000..0d2f9f677e --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator is advanced after calling flatMap +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let mapped = iterator.flatMap(x => [x]); + +let { value, done } = iterator.next(); + +assert.sameValue(value, 0); +assert.sameValue(done, false); + +iterator.next(); +iterator.next(); + +({ value, done } = mapped.next()); + +assert.sameValue(value, 3); +assert.sameValue(done, false); + +({ value, done } = mapped.next()); + +assert.sameValue(value, 4); +assert.sameValue(done, false); + +({ value, done } = mapped.next()); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel.js b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel.js new file mode 100644 index 0000000000..be65e4fba8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator is closed after calling flatMap +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let mapped = iterator.flatMap(x => [x]); + +iterator.return(); + +let { value, done } = mapped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed.js b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed.js new file mode 100644 index 0000000000..9f54585ed8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.flatMap +description: > + Underlying iterator is closed before calling flatMap +info: | + %Iterator.prototype%.flatMap ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +iterator.return(); + +let mapped = iterator.flatMap(() => []); + +let { value, done } = mapped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/forEach/argument-effect-order.js b/test/built-ins/Iterator/prototype/forEach/argument-effect-order.js new file mode 100644 index 0000000000..acf139d90c --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/argument-effect-order.js @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.forEach ( fn ) + + 1. Let O be the this value. + 2. If O is not an Object, throw a TypeError exception. + 3. If IsCallable(fn) is false, throw a TypeError exception. + 4. Let iterated be ? GetIteratorDirect(O). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.forEach.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + null + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/forEach/callable.js b/test/built-ins/Iterator/prototype/forEach/callable.js new file mode 100644 index 0000000000..344442e7ec --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.forEach.call(g(), () => {}); + +let iter = g(); +iter.forEach(() => {}); diff --git a/test/built-ins/Iterator/prototype/forEach/fn-args.js b/test/built-ins/Iterator/prototype/forEach/fn-args.js new file mode 100644 index 0000000000..de5d875321 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/fn-args.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach fn is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.forEach((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; +}); + +assert.sameValue(result, undefined); +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/forEach/fn-called-for-each-yielded-value.js b/test/built-ins/Iterator/prototype/forEach/fn-called-for-each-yielded-value.js new file mode 100644 index 0000000000..1df839d6a4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/fn-called-for-each-yielded-value.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach calls fn once for each yielded value, in order +info: | + %Iterator.prototype%.forEach ( fn ) + + 6.d. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +g().forEach((value, count) => { + effects.push(value, count); +}); + +assert.compareArray(effects, ['a', 0, 'b', 1, 'c', 2]); diff --git a/test/built-ins/Iterator/prototype/forEach/fn-this.js b/test/built-ins/Iterator/prototype/forEach/fn-this.js new file mode 100644 index 0000000000..eb0cb574b8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/fn-this.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach fn this value is undefined +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +let result = iter.forEach(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; +}); + +assert.sameValue(result, undefined); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/forEach/fn-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/forEach/fn-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..520f3ab590 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/fn-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Attempts to close iterator when fn throws, but that throws +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator(); + +assert.throws(Test262Error, function () { + iterator.forEach(() => { + throw new Test262Error(); + }); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/forEach/fn-throws.js b/test/built-ins/Iterator/prototype/forEach/fn-throws.js new file mode 100644 index 0000000000..a860244d3a --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/fn-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Closes iterator and throws when fn throws +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let iterator = new TestIterator(); + +let callbackCalls = 0; + +assert.throws(Test262Error, function () { + iterator.forEach(() => { + ++callbackCalls; + throw new Test262Error(); + }); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/forEach/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/forEach/get-next-method-only-once.js new file mode 100644 index 0000000000..ccb0db7da2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/get-next-method-only-once.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter < 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue( + iterator.forEach(() => {}), + undefined +); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/forEach/get-next-method-throws.js b/test/built-ins/Iterator/prototype/forEach/get-next-method-throws.js new file mode 100644 index 0000000000..17464a8457 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/get-next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/is-function.js b/test/built-ins/Iterator/prototype/forEach/is-function.js new file mode 100644 index 0000000000..28e16f80b2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.forEach, 'function'); diff --git a/test/built-ins/Iterator/prototype/forEach/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/forEach/iterator-already-exhausted.js new file mode 100644 index 0000000000..521f120ad5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/iterator-already-exhausted.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach returns immediately when the iterator has already been exhausted +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +let result = iterator.forEach(() => { + throw new Error(); +}); +assert.sameValue(result, undefined); diff --git a/test/built-ins/Iterator/prototype/forEach/length.js b/test/built-ins/Iterator/prototype/forEach/length.js new file mode 100644 index 0000000000..0bfeb8a1c3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.forEach, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/forEach/name.js b/test/built-ins/Iterator/prototype/forEach/name.js new file mode 100644 index 0000000000..780a73855e --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + The "name" property of Iterator.prototype.forEach +info: | + 17 ECMAScript Standard Built-in Objects + + every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.forEach, 'name', { + value: 'forEach', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/forEach/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/forEach/next-method-returns-non-object.js new file mode 100644 index 0000000000..c8de66c3cf --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..906c9d5287 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..e1a586fd3d --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.forEach(() => {}); diff --git a/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..26c3cb04ea --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/next-method-throws.js b/test/built-ins/Iterator/prototype/forEach/next-method-throws.js new file mode 100644 index 0000000000..d6a79e8119 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/non-callable-predicate.js b/test/built-ins/Iterator/prototype/forEach/non-callable-predicate.js new file mode 100644 index 0000000000..abfbfd3639 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/non-callable-predicate.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach expects to be called with a callable argument. +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () { + yield 1; +})(); + +assert.throws(TypeError, function () { + iterator.forEach(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/non-constructible.js b/test/built-ins/Iterator/prototype/forEach/non-constructible.js new file mode 100644 index 0000000000..65156cd462 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.forEach(); +}); + +assert.throws(TypeError, () => { + new iter.forEach(() => {}); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.forEach(() => {}); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.forEach(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/prop-desc.js b/test/built-ins/Iterator/prototype/forEach/prop-desc.js new file mode 100644 index 0000000000..01ce3e9227 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Property descriptor of Iterator.prototype.forEach +info: | + Iterator.prototype.forEach + + * is the initial value of the Iterator.prototype.forEach property of the global object. + + 17 ECMAScript Standard Built-in Objects + + every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'forEach', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/forEach/proto.js b/test/built-ins/Iterator/prototype/forEach/proto.js new file mode 100644 index 0000000000..1b21d92222 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.forEach is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.forEach), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/forEach/result-is-undefined.js b/test/built-ins/Iterator/prototype/forEach/result-is-undefined.js new file mode 100644 index 0000000000..bd7f7975b5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/result-is-undefined.js @@ -0,0 +1,18 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach returns undefined +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); +assert.sameValue( + iter.forEach(() => {}), + undefined +); +assert.sameValue( + iter.forEach(() => 0), + undefined +); diff --git a/test/built-ins/Iterator/prototype/forEach/this-non-callable-next.js b/test/built-ins/Iterator/prototype/forEach/this-non-callable-next.js new file mode 100644 index 0000000000..10a4772e43 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/this-non-callable-next.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.forEach.call({ next: 0 }, () => true); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/this-non-object.js b/test/built-ins/Iterator/prototype/forEach/this-non-object.js new file mode 100644 index 0000000000..6f2058845a --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/this-non-object.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.forEach.call(null, () => {}); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.forEach.call(0, () => {}); +}); diff --git a/test/built-ins/Iterator/prototype/forEach/this-plain-iterator.js b/test/built-ins/Iterator/prototype/forEach/this-plain-iterator.js new file mode 100644 index 0000000000..8ce4235b90 --- /dev/null +++ b/test/built-ins/Iterator/prototype/forEach/this-plain-iterator.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.forEach +description: > + Iterator.prototype.forEach supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.forEach ( fn ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let fnCalls = 0; +let result = Iterator.prototype.forEach.call(iter, function (v) { + ++fnCalls; +}); + +assert.sameValue(result, undefined); +assert.sameValue(fnCalls, 3); diff --git a/test/built-ins/Iterator/prototype/initial-value.js b/test/built-ins/Iterator/prototype/initial-value.js new file mode 100644 index 0000000000..82ab6afe2f --- /dev/null +++ b/test/built-ins/Iterator/prototype/initial-value.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.prototype +description: > + The initial value of Iterator.prototype is %Iterator.prototype%. +info: | + Iterator.prototype + + The initial value of Iterator.prototype is %Iterator.prototype%. + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator, 'prototype', { + value: Iterator.prototype, + writable: false, + enumerable: false, + configurable: false, +}); diff --git a/test/built-ins/Iterator/prototype/map/argument-effect-order.js b/test/built-ins/Iterator/prototype/map/argument-effect-order.js new file mode 100644 index 0000000000..76c6fc55a1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/argument-effect-order.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.map ( mapper ) + + 1. Let O be the this value. + 2. If O is not an Object, throw a TypeError exception. + 3. If IsCallable(mapper) is false, throw a TypeError exception. + 4. Let iterated be ? GetIteratorDirect(O). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.map.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + { + valueOf() { + effects.push('valueOf mapper'); + return function () { + return []; + }; + }, + } + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/map/callable.js b/test/built-ins/Iterator/prototype/map/callable.js new file mode 100644 index 0000000000..fc70927b36 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.map.call(g(), () => 0); + +let iter = g(); +iter.map(() => 0); diff --git a/test/built-ins/Iterator/prototype/map/exhaustion-does-not-call-return.js b/test/built-ins/Iterator/prototype/map/exhaustion-does-not-call-return.js new file mode 100644 index 0000000000..e93c945ebd --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/exhaustion-does-not-call-return.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator return is not called when result iterator is exhausted +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +class TestIterator extends Iterator { + get next() { + let n = g(); + return function() { + return n.next(); + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().map(() => 0); +iterator.next(); +iterator.next(); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/map/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/map/get-next-method-only-once.js new file mode 100644 index 0000000000..4971dfed37 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/get-next-method-only-once.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Gets the next method from the underlying iterator only once +info: | + %Iterator.prototype%.map ( mapper ) + + 4. Let iterated be ? GetIteratorDirect(O). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator extends Iterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue(nextCalls, 0); + +for (const value of iterator.map(() => 0)); + +assert.sameValue(nextGets, 1); +assert.sameValue(nextCalls, 5); diff --git a/test/built-ins/Iterator/prototype/map/get-next-method-throws.js b/test/built-ins/Iterator/prototype/map/get-next-method-throws.js new file mode 100644 index 0000000000..d0884cba5e --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator has throwing next getter +info: | + %Iterator.prototype%.map ( mapper ) + + 4. Let iterated be ? GetIteratorDirect(O). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.map(() => 0); +}); diff --git a/test/built-ins/Iterator/prototype/map/get-return-method-throws.js b/test/built-ins/Iterator/prototype/map/get-return-method-throws.js new file mode 100644 index 0000000000..4fc3299bba --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/get-return-method-throws.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator return is throwing getter +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().map(() => 0); +iterator.next(); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/map/is-function.js b/test/built-ins/Iterator/prototype/map/is-function.js new file mode 100644 index 0000000000..cbc51701ef --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.map, 'function'); diff --git a/test/built-ins/Iterator/prototype/map/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/map/iterator-already-exhausted.js new file mode 100644 index 0000000000..05a0e70653 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/iterator-already-exhausted.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map returns an empty iterator when the iterator has already been exhausted +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +iterator = iterator.map(() => 0); +({ value, done } = iterator.next()); +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/map/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/map/iterator-return-method-throws.js new file mode 100644 index 0000000000..69b67a2794 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/iterator-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows().map(() => 0); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/map/length.js b/test/built-ins/Iterator/prototype/map/length.js new file mode 100644 index 0000000000..b6d4258b1a --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.map, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/map/mapper-args.js b/test/built-ins/Iterator/prototype/map/mapper-args.js new file mode 100644 index 0000000000..25994834a1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/mapper-args.js @@ -0,0 +1,55 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map mapper is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.map ( mapper ) + + 5.b.iv. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; + yield 'd'; + yield 'e'; +} + +let assertionCount = 0; +let iter = g().map((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + ++assertionCount; + return 0; + case 'b': + assert.sameValue(count, 1); + ++assertionCount; + return 1; + case 'c': + assert.sameValue(count, 2); + ++assertionCount; + return 2; + case 'd': + assert.sameValue(count, 3); + ++assertionCount; + return 3; + case 'e': + assert.sameValue(count, 4); + ++assertionCount; + return 4; + default: + throw new Error(); + } +}); + +assert.sameValue(assertionCount, 0); + +for (let i of iter); + +assert.sameValue(assertionCount, 5); diff --git a/test/built-ins/Iterator/prototype/map/mapper-this.js b/test/built-ins/Iterator/prototype/map/mapper-this.js new file mode 100644 index 0000000000..db3a611dea --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/mapper-this.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map mapper this value is undefined +info: | + %Iterator.prototype%.map ( mapper ) + + 5.b.iv. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +iter = iter.map(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return v; +}); + +iter.next(); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/map/mapper-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/map/mapper-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..9b0c772a23 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/mapper-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Attempts to close iterator when mapper throws, but that throws +info: | + %Iterator.prototype%.map ( mapper ) + + 5.b.v. IfAbruptCloseIterator(mapped, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator().map(() => { + throw new Test262Error(); +}); + +assert.sameValue(returnCalls, 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/map/mapper-throws.js b/test/built-ins/Iterator/prototype/map/mapper-throws.js new file mode 100644 index 0000000000..e5142d0be2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/mapper-throws.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Closes iterator and throws when mapper throws +info: | + %Iterator.prototype%.map ( mapper ) + + 5.b.v. IfAbruptCloseIterator(mapped, iterated). + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let callbackCalls = 0; +let iterator = new TestIterator().map(() => { + ++callbackCalls; + throw new Test262Error(); +}); + +assert.throws(Test262Error, function () { + iterator.next(); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/map/name.js b/test/built-ins/Iterator/prototype/map/name.js new file mode 100644 index 0000000000..6815e78998 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + The "name" property of Iterator.prototype.map +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.map, 'name', { + value: 'map', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/map/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/map/next-method-returns-non-object.js new file mode 100644 index 0000000000..21f969105e --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator().map(() => 0); + +assert.throws(TypeError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..c9da2ef6cb --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().map(() => 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..d044cfb516 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().map(() => 0); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..a34de32a03 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator().map(() => 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/map/next-method-throws.js b/test/built-ins/Iterator/prototype/map/next-method-throws.js new file mode 100644 index 0000000000..4a4480273c --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator().map(() => 0); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/map/non-callable-mapper.js b/test/built-ins/Iterator/prototype/map/non-callable-mapper.js new file mode 100644 index 0000000000..dfa0c618f2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/non-callable-mapper.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map expects to be called with a callable argument. +info: | + %Iterator.prototype%.map ( mapper ) + + 3. If IsCallable(mapper) is false, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () {})(); + +assert.throws(TypeError, function () { + iterator.map(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/map/non-constructible.js b/test/built-ins/Iterator/prototype/map/non-constructible.js new file mode 100644 index 0000000000..a6cb476430 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.map(); +}); + +assert.throws(TypeError, () => { + new iter.map(() => 0); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.map(() => 0); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.map(() => 0); +}); diff --git a/test/built-ins/Iterator/prototype/map/prop-desc.js b/test/built-ins/Iterator/prototype/map/prop-desc.js new file mode 100644 index 0000000000..9d58c5fb67 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Property descriptor of Iterator.prototype.map +info: | + Iterator.prototype.map + + * is the initial value of the Iterator.prototype.map property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'map', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/map/proto.js b/test/built-ins/Iterator/prototype/map/proto.js new file mode 100644 index 0000000000..9d1851239c --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.map is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.map), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/map/result-is-iterator.js b/test/built-ins/Iterator/prototype/map/result-is-iterator.js new file mode 100644 index 0000000000..66fa0d10b1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/result-is-iterator.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.prototype.map is the + intrinsic object %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ + +assert((function* () {})().map(() => 0) instanceof Iterator, 'function*(){}().map(() => 0) must return an Iterator'); diff --git a/test/built-ins/Iterator/prototype/map/return-is-forwarded-to-underlying-iterator.js b/test/built-ins/Iterator/prototype/map/return-is-forwarded-to-underlying-iterator.js new file mode 100644 index 0000000000..a51ec50eb3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/return-is-forwarded-to-underlying-iterator.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCount; + return {}; + } +} + +let iterator = new TestIterator().map(() => 0); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/map/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/prototype/map/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 0000000000..f3ca5fece9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: true, + value: undefined, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().map(() => 0); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().map(() => 0); +iterator.next(); +iterator.return(); + +iterator = new TestIterator() + .map(x => x) + .map(x => x) + .map(x => x); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/prototype/map/returned-iterator-yields-mapper-return-values.js b/test/built-ins/Iterator/prototype/map/returned-iterator-yields-mapper-return-values.js new file mode 100644 index 0000000000..5565de995a --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/returned-iterator-yields-mapper-return-values.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + The values returned by the mapper are the values that are yielded by the iterator returned by map +info: | + %Iterator.prototype%.map ( mapper ) + + 5.b.vi. Let completion be Completion(Yield(mapped)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + for (let i = 0; i < 5; ++i) { + yield i; + } +} + +assert.compareArray(Array.from(g()), [0, 1, 2, 3, 4]); +assert.compareArray(Array.from(g().map(x => x)), [0, 1, 2, 3, 4]); +assert.compareArray(Array.from(g().map(() => 0)), [0, 0, 0, 0, 0]); +assert.compareArray( + Array.from( + g() + .map(() => 0) + .map((v, c) => c) + ), + [0, 1, 2, 3, 4] +); +assert.compareArray(Array.from(g().map(x => x * 2)), [0, 2, 4, 6, 8]); + +let obj = {}; +assert.compareArray(Array.from(g().map(() => obj)), [obj, obj, obj, obj, obj]); diff --git a/test/built-ins/Iterator/prototype/map/this-non-callable-next.js b/test/built-ins/Iterator/prototype/map/this-non-callable-next.js new file mode 100644 index 0000000000..db127cb4c3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/this-non-callable-next.js @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = Iterator.prototype.map.call({ next: 0 }, () => 0); + +assert.throws(TypeError, function () { + iter.next(); +}); diff --git a/test/built-ins/Iterator/prototype/map/this-non-object.js b/test/built-ins/Iterator/prototype/map/this-non-object.js new file mode 100644 index 0000000000..e0d4480146 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/this-non-object.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.map ( mapper ) + + 2. If O is not an Object, throw a TypeError exception. + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.map.call(null, () => 0); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.map.call(0, () => 0); +}); diff --git a/test/built-ins/Iterator/prototype/map/this-plain-iterator.js b/test/built-ins/Iterator/prototype/map/this-plain-iterator.js new file mode 100644 index 0000000000..851eed8e2f --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/this-plain-iterator.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Iterator.prototype.map supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let mapperCalls = 0; +iter = Iterator.prototype.map.call(iter, function (v) { + ++mapperCalls; + return v; +}); + +for (let e of iter); + +assert.sameValue(mapperCalls, 3); diff --git a/test/built-ins/Iterator/prototype/map/underlying-iterator-advanced-in-parallel.js b/test/built-ins/Iterator/prototype/map/underlying-iterator-advanced-in-parallel.js new file mode 100644 index 0000000000..bb95ca0765 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/underlying-iterator-advanced-in-parallel.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator is advanced after calling map +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let mapped = iterator.map(x => x); + +let { value, done } = iterator.next(); + +assert.sameValue(value, 0); +assert.sameValue(done, false); + +iterator.next(); +iterator.next(); + +({ value, done } = mapped.next()); + +assert.sameValue(value, 3); +assert.sameValue(done, false); + +({ value, done } = mapped.next()); + +assert.sameValue(value, 4); +assert.sameValue(done, false); + +({ value, done } = mapped.next()); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/map/underlying-iterator-closed-in-parallel.js b/test/built-ins/Iterator/prototype/map/underlying-iterator-closed-in-parallel.js new file mode 100644 index 0000000000..c83679632f --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/underlying-iterator-closed-in-parallel.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator is closed after calling map +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let mapped = iterator.map(() => 0); + +iterator.return(); + +let { value, done } = mapped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/map/underlying-iterator-closed.js b/test/built-ins/Iterator/prototype/map/underlying-iterator-closed.js new file mode 100644 index 0000000000..b49c27b793 --- /dev/null +++ b/test/built-ins/Iterator/prototype/map/underlying-iterator-closed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.map +description: > + Underlying iterator is closed before calling map +info: | + %Iterator.prototype%.map ( mapper ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +iterator.return(); + +let mapped = iterator.map(() => 0); + +let { value, done } = mapped.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/reduce/argument-effect-order.js b/test/built-ins/Iterator/prototype/reduce/argument-effect-order.js new file mode 100644 index 0000000000..25d809a2ca --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/argument-effect-order.js @@ -0,0 +1,58 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.reduce ( reducer ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + { + valueOf() { + effects.push('reducer valueOf'); + } + }, + { + valueOf() { + effects.push('initial value valueOf'); + } + } + ); +}); + +assert.compareArray(effects, []); + +Iterator.prototype.reduce.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + () => {}, + { + valueOf() { + effects.push('initial value valueOf'); + } + } +); + +assert.compareArray(effects, ['get next']); diff --git a/test/built-ins/Iterator/prototype/reduce/callable.js b/test/built-ins/Iterator/prototype/reduce/callable.js new file mode 100644 index 0000000000..c1a4c343e4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.reduce.call(g(), () => {}, 0); + +let iter = g(); +iter.reduce(() => {}, 0); diff --git a/test/built-ins/Iterator/prototype/reduce/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/reduce/get-next-method-only-once.js new file mode 100644 index 0000000000..89c30adb4e --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/get-next-method-only-once.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter <= 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue( + iterator.reduce(x => x), + 4 +); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/reduce/get-next-method-throws.js b/test/built-ins/Iterator/prototype/reduce/get-next-method-throws.js new file mode 100644 index 0000000000..c3816f2651 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/get-next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.reduce(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/is-function.js b/test/built-ins/Iterator/prototype/reduce/is-function.js new file mode 100644 index 0000000000..4f144c5882 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.reduce, 'function'); diff --git a/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-initial-value.js b/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-initial-value.js new file mode 100644 index 0000000000..71f332cf16 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-initial-value.js @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce returns the initial value when the iterator has already been exhausted +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +const initialValue = {}; +let result = iterator.reduce(() => {}, initialValue); +assert.sameValue(result, initialValue); diff --git a/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-no-initial-value.js b/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-no-initial-value.js new file mode 100644 index 0000000000..22dec14757 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/iterator-already-exhausted-no-initial-value.js @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce without an initial value throws when the iterator has already been exhausted +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +assert.throws(TypeError, function() { + iterator.reduce(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-initial-value.js b/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-initial-value.js new file mode 100644 index 0000000000..5f936c4946 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-initial-value.js @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce calls reducer once for each value yielded by the underlying iterator when passed an initial value +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; +} + +let iter = g(); + +let assertionCount = 0; +let initialValue = {}; +let result = iter.reduce((memo, v, count) => { + switch (v) { + case 'a': + assert.sameValue(memo, initialValue); + assert.sameValue(count, 0); + break; + default: + throw new Error(); + } + ++assertionCount; + return v; +}, initialValue); + +assert.sameValue(result, 'a'); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-no-initial-value.js b/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-no-initial-value.js new file mode 100644 index 0000000000..38c4fdaaad --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/iterator-yields-once-no-initial-value.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce calls reducer once for each value yielded by the underlying iterator except the first when not passed an initial value +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.reduce((memo, v, count) => { + ++assertionCount; + return v; +}); + +assert.sameValue(result, 'a'); +assert.sameValue(assertionCount, 0); diff --git a/test/built-ins/Iterator/prototype/reduce/length.js b/test/built-ins/Iterator/prototype/reduce/length.js new file mode 100644 index 0000000000..3b504529fe --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.reduce, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/reduce/name.js b/test/built-ins/Iterator/prototype/reduce/name.js new file mode 100644 index 0000000000..d79e858873 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + The "name" property of Iterator.prototype.reduce +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.reduce, 'name', { + value: 'reduce', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/reduce/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/reduce/next-method-returns-non-object.js new file mode 100644 index 0000000000..c23e1fd478 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.reduce(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..c855c5bc00 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.reduce(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..4682a6e2a8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.reduce(() => {}, 0); diff --git a/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..900958e0a5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.reduce(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/next-method-throws.js b/test/built-ins/Iterator/prototype/reduce/next-method-throws.js new file mode 100644 index 0000000000..09cec5cdc4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/next-method-throws.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.reduce(() => {}); +}); + +assert.throws(Test262Error, function () { + iterator.reduce(() => {}, 0); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/non-callable-reducer.js b/test/built-ins/Iterator/prototype/reduce/non-callable-reducer.js new file mode 100644 index 0000000000..9a2cdd4810 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/non-callable-reducer.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce expects to be called with a callable argument. +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () { + yield 1; +})(); + +assert.throws(TypeError, function () { + iterator.reduce(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/non-constructible.js b/test/built-ins/Iterator/prototype/reduce/non-constructible.js new file mode 100644 index 0000000000..83f6882b73 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/non-constructible.js @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.reduce(); +}); + +assert.throws(TypeError, () => { + new iter.reduce(() => {}); +}); + +assert.throws(TypeError, () => { + new iter.reduce(() => {}, 0); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.reduce(() => {}, 0); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.reduce(() => {}, 0); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/prop-desc.js b/test/built-ins/Iterator/prototype/reduce/prop-desc.js new file mode 100644 index 0000000000..1fca6a372a --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Property descriptor of Iterator.prototype.reduce +info: | + Iterator.prototype.reduce + + * is the initial value of the Iterator.prototype.reduce property of the global object. + + 17 ECMAScript Standard Built-in Objects + + every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'reduce', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/reduce/proto.js b/test/built-ins/Iterator/prototype/reduce/proto.js new file mode 100644 index 0000000000..18f9123a56 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.reduce is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.reduce), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-args-initial-value.js b/test/built-ins/Iterator/prototype/reduce/reducer-args-initial-value.js new file mode 100644 index 0000000000..1803917e81 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-args-initial-value.js @@ -0,0 +1,45 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce reducer is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let initialValue = {}; +let result = iter.reduce((memo, v, count) => { + switch (v) { + case 'a': + assert.sameValue(memo, initialValue); + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(memo, 'a'); + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(memo, 'b'); + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; + return v; +}, initialValue); + +assert.sameValue(result, 'c'); +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-args-no-initial-value.js b/test/built-ins/Iterator/prototype/reduce/reducer-args-no-initial-value.js new file mode 100644 index 0000000000..c1dfc6c242 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-args-no-initial-value.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce reducer is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.reduce((memo, v, count) => { + switch (v) { + case 'b': + assert.sameValue(memo, 'a'); + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(memo, 'b'); + assert.sameValue(count, 2); + break; + case 'a': + default: + throw new Error(); + } + ++assertionCount; + return v; +}); + +assert.sameValue(result, 'c'); +assert.sameValue(assertionCount, 2); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-memo-can-be-any-type.js b/test/built-ins/Iterator/prototype/reduce/reducer-memo-can-be-any-type.js new file mode 100644 index 0000000000..35a84a2152 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-memo-can-be-any-type.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce reducer can return any ECMAScript language value +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ + +const values = [undefined, null, true, false, 0, -0, 1, NaN, Infinity, "string", Symbol(), 0n, {}, [], () => {}]; + +let iter = values[Symbol.iterator](); + +let assertionCount = 0; +let initialValue = {}; +let result = iter.reduce((memo, v, count) => { + if (count == 0) { + assert.sameValue(memo, initialValue); + } else { + assert.sameValue(memo, values[count - 1]); + } + ++assertionCount; + return v; +}, initialValue); + +assert.sameValue(result, values[values.length - 1]); +assert.sameValue(assertionCount, values.length); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-this.js b/test/built-ins/Iterator/prototype/reduce/reducer-this.js new file mode 100644 index 0000000000..9932713b0a --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-this.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce reducer this value is undefined +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +let result = iter.reduce(function (memo, v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return memo; +}); + +assert.sameValue(result, 0); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/reduce/reducer-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..0eef70fa75 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Attempts to close iterator when reducer throws, but that throws +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator(); + +assert.throws(Test262Error, function () { + iterator.reduce(() => { + throw new Test262Error(); + }); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/reduce/reducer-throws.js b/test/built-ins/Iterator/prototype/reduce/reducer-throws.js new file mode 100644 index 0000000000..d1cd088241 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/reducer-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Closes iterator and throws when reducer throws +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let iterator = new TestIterator(); + +let callbackCalls = 0; + +assert.throws(Test262Error, function () { + iterator.reduce(() => { + ++callbackCalls; + throw new Test262Error(); + }); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/reduce/this-non-callable-next.js b/test/built-ins/Iterator/prototype/reduce/this-non-callable-next.js new file mode 100644 index 0000000000..48611726a2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/this-non-callable-next.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call({ next: 0 }, () => {}, 0); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/this-non-object.js b/test/built-ins/Iterator/prototype/reduce/this-non-object.js new file mode 100644 index 0000000000..5d9143e675 --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/this-non-object.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.reduce ( reducer ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call(null, () => {}); +}); + +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call(null, () => {}, 0); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); + +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call(0, () => {}); +}); + +assert.throws(TypeError, function () { + Iterator.prototype.reduce.call(0, () => {}, 0); +}); diff --git a/test/built-ins/Iterator/prototype/reduce/this-plain-iterator.js b/test/built-ins/Iterator/prototype/reduce/this-plain-iterator.js new file mode 100644 index 0000000000..2eddf1098a --- /dev/null +++ b/test/built-ins/Iterator/prototype/reduce/this-plain-iterator.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.reduce +description: > + Iterator.prototype.reduce supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.reduce ( reducer ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let reducerCalls = 0; +let result = Iterator.prototype.reduce.call(iter, function (memo, v) { + ++reducerCalls; + memo.push(v); + return memo; +}, []); + +assert.compareArray(result, [2, 1, 0]); +assert.sameValue(reducerCalls, 3); diff --git a/test/built-ins/Iterator/prototype/some/argument-effect-order.js b/test/built-ins/Iterator/prototype/some/argument-effect-order.js new file mode 100644 index 0000000000..d45acefd84 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/argument-effect-order.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.some ( predicate ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.some.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + null + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/some/callable.js b/test/built-ins/Iterator/prototype/some/callable.js new file mode 100644 index 0000000000..568bb60aff --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.some.call(g(), () => {}); + +let iter = g(); +iter.some(() => {}); diff --git a/test/built-ins/Iterator/prototype/some/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/some/get-next-method-only-once.js new file mode 100644 index 0000000000..9a0c940186 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/get-next-method-only-once.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter < 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue( + iterator.some(() => true), + true +); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/some/get-next-method-throws.js b/test/built-ins/Iterator/prototype/some/get-next-method-throws.js new file mode 100644 index 0000000000..6617aa659d --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/get-next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/get-return-method-throws.js b/test/built-ins/Iterator/prototype/some/get-return-method-throws.js new file mode 100644 index 0000000000..cce312d59c --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/get-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator has throwing return getter +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows([1, 2]); + +assert.throws(Test262Error, function () { + iterator.some(() => true); +}); diff --git a/test/built-ins/Iterator/prototype/some/is-function.js b/test/built-ins/Iterator/prototype/some/is-function.js new file mode 100644 index 0000000000..47de2a9339 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.some, 'function'); diff --git a/test/built-ins/Iterator/prototype/some/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/some/iterator-already-exhausted.js new file mode 100644 index 0000000000..d1172dfab9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/iterator-already-exhausted.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some returns true when the iterator has already been exhausted +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +let result = iterator.some(() => true); +assert.sameValue(result, false); + +result = iterator.some(() => false); +assert.sameValue(result, false); diff --git a/test/built-ins/Iterator/prototype/some/iterator-has-no-return.js b/test/built-ins/Iterator/prototype/some/iterator-has-no-return.js new file mode 100644 index 0000000000..28ed4c41b6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/iterator-has-no-return.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + The underlying iterator is sometimes unable to be closed (has no return method) +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = [1, 2, 3, 4, 5][Symbol.iterator](); + +assert.sameValue(iterator.return, undefined); + +let ret = iterator.some(v => v > 3); + +assert.sameValue(ret, true); + +let { done, value } = iterator.next(); +assert.sameValue(done, false); +assert.sameValue(value, 5); + +({ done, value } = iterator.next()); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/some/iterator-return-method-throws.js b/test/built-ins/Iterator/prototype/some/iterator-return-method-throws.js new file mode 100644 index 0000000000..d15240ebbf --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/iterator-return-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator has throwing return +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + next() { + return { + done: false, + value: 0, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.some(() => true); +}); diff --git a/test/built-ins/Iterator/prototype/some/length.js b/test/built-ins/Iterator/prototype/some/length.js new file mode 100644 index 0000000000..8a790b22ca --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.some, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/some/name.js b/test/built-ins/Iterator/prototype/some/name.js new file mode 100644 index 0000000000..6cd820c5c4 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + The "name" property of Iterator.prototype.some +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.some, 'name', { + value: 'some', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/some/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/some/next-method-returns-non-object.js new file mode 100644 index 0000000000..6d1655a22d --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..a87f60929d --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..29cbded935 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.some(() => {}); diff --git a/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..6293c1d5be --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/next-method-throws.js b/test/built-ins/Iterator/prototype/some/next-method-throws.js new file mode 100644 index 0000000000..26b9623de9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/non-callable-predicate.js b/test/built-ins/Iterator/prototype/some/non-callable-predicate.js new file mode 100644 index 0000000000..3b9cf32fe6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/non-callable-predicate.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some expects to be called with a callable argument. +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let nonCallable = {}; +let iterator = (function* () { + yield 1; +})(); + +assert.throws(TypeError, function () { + iterator.some(nonCallable); +}); diff --git a/test/built-ins/Iterator/prototype/some/non-constructible.js b/test/built-ins/Iterator/prototype/some/non-constructible.js new file mode 100644 index 0000000000..ca15f49095 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.some(); +}); + +assert.throws(TypeError, () => { + new iter.some(() => {}); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.some(() => {}); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.some(() => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/predicate-args.js b/test/built-ins/Iterator/prototype/some/predicate-args.js new file mode 100644 index 0000000000..5868b375b5 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-args.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some predicate is passed the yielded value and a counter as arguments +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 'a'; + yield 'b'; + yield 'c'; +} + +let iter = g(); + +let assertionCount = 0; +let result = iter.some((v, count) => { + switch (v) { + case 'a': + assert.sameValue(count, 0); + break; + case 'b': + assert.sameValue(count, 1); + break; + case 'c': + assert.sameValue(count, 2); + break; + default: + throw new Error(); + } + ++assertionCount; + return false; +}); + +assert.sameValue(result, false); +assert.sameValue(assertionCount, 3); diff --git a/test/built-ins/Iterator/prototype/some/predicate-returns-falsey-then-truthy.js b/test/built-ins/Iterator/prototype/some/predicate-returns-falsey-then-truthy.js new file mode 100644 index 0000000000..de62627f43 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-returns-falsey-then-truthy.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some returns true and closes the iterator when the predicate returns falsey for some iterated values and truthy for others +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + for (let i = 0; i < 5; ++i) { + yield i; + } +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.some(v => { + ++predicateCalls; + return v > 2; +}); + +assert.sameValue(result, true); +assert.sameValue(predicateCalls, 4); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/some/predicate-returns-falsey.js b/test/built-ins/Iterator/prototype/some/predicate-returns-falsey.js new file mode 100644 index 0000000000..69f0b42e4d --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-returns-falsey.js @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some returns false when the predicate returns falsey for all iterated values +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; + yield 3; +} + +let result = g().some(() => false); +assert.sameValue(result, false); diff --git a/test/built-ins/Iterator/prototype/some/predicate-returns-non-boolean.js b/test/built-ins/Iterator/prototype/some/predicate-returns-non-boolean.js new file mode 100644 index 0000000000..bd4e1d37c2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-returns-non-boolean.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some coerces predicate return value to boolean +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield ''; + yield null; + yield undefined; + yield 0; + yield 1; + yield 2; + yield 3; +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.some(v => { + ++predicateCalls; + return v; +}); + +assert.sameValue(result, true); +assert.sameValue(predicateCalls, 5); diff --git a/test/built-ins/Iterator/prototype/some/predicate-returns-truthy.js b/test/built-ins/Iterator/prototype/some/predicate-returns-truthy.js new file mode 100644 index 0000000000..26484864c9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-returns-truthy.js @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some returns true and closes the iterator when the predicate returns truthy immediately +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +let iter = g(); + +let predicateCalls = 0; +let result = iter.some(v => { + ++predicateCalls; + return true; +}); + +assert.sameValue(result, true); +assert.sameValue(predicateCalls, 1); + +let { done, value } = iter.next(); +assert.sameValue(done, true); +assert.sameValue(value, undefined); diff --git a/test/built-ins/Iterator/prototype/some/predicate-this.js b/test/built-ins/Iterator/prototype/some/predicate-this.js new file mode 100644 index 0000000000..0574184fe0 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-this.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some predicate this value is undefined +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; +} + +let iter = g(); + +let expectedThis = function () { + return this; +}.call(undefined); + +let assertionCount = 0; +let result = iter.some(function (v, count) { + assert.sameValue(this, expectedThis); + ++assertionCount; + return true; +}); + +assert.sameValue(result, true); +assert.sameValue(assertionCount, 1); diff --git a/test/built-ins/Iterator/prototype/some/predicate-throws-then-closing-iterator-also-throws.js b/test/built-ins/Iterator/prototype/some/predicate-throws-then-closing-iterator-also-throws.js new file mode 100644 index 0000000000..92bbda696f --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-throws-then-closing-iterator-also-throws.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Attempts to close iterator when predicate throws, but that throws +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + throw new Error(); + } +} + +let iterator = new TestIterator(); + +assert.throws(Test262Error, function () { + iterator.some(() => { + throw new Test262Error(); + }); +}); + +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/some/predicate-throws.js b/test/built-ins/Iterator/prototype/some/predicate-throws.js new file mode 100644 index 0000000000..91cdd170ba --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/predicate-throws.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Closes iterator and throws when predicate throws +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCalls = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCalls; + return {}; + } +} + +let iterator = new TestIterator(); + +let callbackCalls = 0; + +assert.throws(Test262Error, function () { + iterator.some(() => { + ++callbackCalls; + throw new Test262Error(); + }); +}); + +assert.sameValue(callbackCalls, 1); +assert.sameValue(returnCalls, 1); diff --git a/test/built-ins/Iterator/prototype/some/prop-desc.js b/test/built-ins/Iterator/prototype/some/prop-desc.js new file mode 100644 index 0000000000..80733f8f24 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Property descriptor of Iterator.prototype.some +info: | + Iterator.prototype.some + + * is the initial value of the Iterator.prototype.some property of the global object. + + 17 ECMAScript Standard Built-in Objects + + every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'some', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/some/proto.js b/test/built-ins/Iterator/prototype/some/proto.js new file mode 100644 index 0000000000..d32cc0cbe1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.some is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.some), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/some/result-is-boolean.js b/test/built-ins/Iterator/prototype/some/result-is-boolean.js new file mode 100644 index 0000000000..f4ae356641 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/result-is-boolean.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some returns a boolean +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); +assert.sameValue(typeof iter.some(() => {}), 'boolean'); diff --git a/test/built-ins/Iterator/prototype/some/this-non-callable-next.js b/test/built-ins/Iterator/prototype/some/this-non-callable-next.js new file mode 100644 index 0000000000..ad46eafd16 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/this-non-callable-next.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.some.call({ next: 0 }, () => true); +}); diff --git a/test/built-ins/Iterator/prototype/some/this-non-object.js b/test/built-ins/Iterator/prototype/some/this-non-object.js new file mode 100644 index 0000000000..8ae3b60c78 --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/this-non-object.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.some.call(null, () => {}); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.some.call(0, () => {}); +}); diff --git a/test/built-ins/Iterator/prototype/some/this-plain-iterator.js b/test/built-ins/Iterator/prototype/some/this-plain-iterator.js new file mode 100644 index 0000000000..40038d4e4b --- /dev/null +++ b/test/built-ins/Iterator/prototype/some/this-plain-iterator.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.some +description: > + Iterator.prototype.some supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.some ( predicate ) + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let predicateCalls = 0; +let result = Iterator.prototype.some.call(iter, function (v) { + ++predicateCalls; + return v === 0; +}); + +assert.sameValue(result, true); +assert.sameValue(predicateCalls, 3); diff --git a/test/built-ins/Iterator/prototype/take/argument-effect-order.js b/test/built-ins/Iterator/prototype/take/argument-effect-order.js new file mode 100644 index 0000000000..d37557cd73 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/argument-effect-order.js @@ -0,0 +1,72 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Arguments and this value are evaluated in the correct order +info: | + %Iterator.prototype%.take ( limit ) + + 1. Let O be the this value. + 2. If O is not an Object, throw a TypeError exception. + 3. Let numLimit be ? ToNumber(limit). + 4. If numLimit is NaN, throw a RangeError exception. + 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit). + 6. If integerLimit < 0, throw a RangeError exception. + 7. Let iterated be ? GetIteratorDirect(O). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let effects = []; + +Iterator.prototype.take.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + { + valueOf() { + effects.push('ToNumber limit'); + return 0; + }, + } +); + +assert.compareArray(effects, ['ToNumber limit', 'get next']); + +effects = []; + +assert.throws(TypeError, function () { + Iterator.prototype.take.call(null, { + valueOf() { + effects.push('ToNumber limit'); + return 0; + }, + }); +}); + +assert.compareArray(effects, []); + +effects = []; + +assert.throws(RangeError, function () { + Iterator.prototype.take.call( + { + get next() { + effects.push('get next'); + return function () { + return { done: true, value: undefined }; + }; + }, + }, + NaN + ); +}); + +assert.compareArray(effects, []); diff --git a/test/built-ins/Iterator/prototype/take/callable.js b/test/built-ins/Iterator/prototype/take/callable.js new file mode 100644 index 0000000000..75b1517a95 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.take.call(g(), 0); + +let iter = g(); +iter.take(0); diff --git a/test/built-ins/Iterator/prototype/take/exhaustion-calls-return.js b/test/built-ins/Iterator/prototype/take/exhaustion-calls-return.js new file mode 100644 index 0000000000..ae50a2a7dd --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/exhaustion-calls-return.js @@ -0,0 +1,68 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator return is called when result iterator is exhausted +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.i. If remaining is 0, then + 8.b.i.1. Return ? IteratorClose(iterated, NormalCompletion(undefined)). + +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +class TestIterator extends Iterator { + get next() { + let n = g(); + return function() { + return n.next(); + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator(); +iterator = iterator.take(0); +assert.throws(Test262Error, function () { + iterator.next(); +}); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.take(1); +iterator.next(); +assert.throws(Test262Error, function () { + iterator.next(); +}); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.take(1).take(1).take(1).take(1).take(1); +iterator.next(); +assert.throws(Test262Error, function () { + iterator.next(); +}); +iterator.next(); +iterator.next(); + +iterator = new TestIterator(); +iterator = iterator.take(5); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/take/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/take/get-next-method-only-once.js new file mode 100644 index 0000000000..8a9b8ae335 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/get-next-method-only-once.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Gets the next method from the underlying iterator only once +info: | + %Iterator.prototype%.take ( limit ) + + 7. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; +let nextCalls = 0; + +class CountingIterator extends Iterator { + get next() { + ++nextGets; + let iter = (function* () { + for (let i = 1; i < 5; ++i) { + yield i; + } + })(); + return function () { + ++nextCalls; + return iter.next(); + }; + } +} + +let iterator = new CountingIterator(); + +assert.sameValue(nextGets, 0); +assert.sameValue(nextCalls, 0); + +for (const value of iterator.take(2)); + +assert.sameValue(nextGets, 1); +assert.sameValue(nextCalls, 2); diff --git a/test/built-ins/Iterator/prototype/take/get-next-method-throws.js b/test/built-ins/Iterator/prototype/take/get-next-method-throws.js new file mode 100644 index 0000000000..0a0abc9df7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/get-next-method-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator has throwing next getter +info: | + %Iterator.prototype%.take ( limit ) + + 7. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.take(0); +}); diff --git a/test/built-ins/Iterator/prototype/take/get-return-method-throws.js b/test/built-ins/Iterator/prototype/take/get-return-method-throws.js new file mode 100644 index 0000000000..291a25beb6 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/get-return-method-throws.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator return is throwing getter +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + get return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().take(1); +iterator.next(); + +assert.throws(Test262Error, function () { + iterator.return(); +}); diff --git a/test/built-ins/Iterator/prototype/take/is-function.js b/test/built-ins/Iterator/prototype/take/is-function.js new file mode 100644 index 0000000000..5e3cacfc8e --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.take, 'function'); diff --git a/test/built-ins/Iterator/prototype/take/length.js b/test/built-ins/Iterator/prototype/take/length.js new file mode 100644 index 0000000000..b7a0e29939 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take has a "length" property whose value is 1. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.take, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/take/limit-greater-than-or-equal-to-total.js b/test/built-ins/Iterator/prototype/take/limit-greater-than-or-equal-to-total.js new file mode 100644 index 0000000000..2fe3e77bf8 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/limit-greater-than-or-equal-to-total.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Takes entries from this iterator until it is exhausted or the limit is reached. +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.iii. Let next be ? IteratorStep(iterated). + 8.b.iv. If next is false, return undefined. + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +assert.compareArray(Array.from(g().take(3)), [0, 1, 2]); +assert.compareArray(Array.from(g().take(4)), [0, 1, 2]); +assert.compareArray(Array.from(g().take(5)), [0, 1, 2]); +assert.compareArray(Array.from(g().take(Number.MAX_SAFE_INTEGER)), [0, 1, 2]); +assert.compareArray(Array.from(g().take(Infinity)), [0, 1, 2]); diff --git a/test/built-ins/Iterator/prototype/take/limit-less-than-total.js b/test/built-ins/Iterator/prototype/take/limit-less-than-total.js new file mode 100644 index 0000000000..d9a8689978 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/limit-less-than-total.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Takes entries from this iterator until the limit is reached. +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.i If remaining is 0, then + 8.b.i.1. Return ? IteratorClose(iterated, NormalCompletion(undefined)). + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +function* g() { + let i = 0; + while (true) { + yield i; + ++i; + } +} + +assert.compareArray(Array.from(g().take(0)), []); +assert.compareArray(Array.from(g().take(1)), [0]); +assert.compareArray(Array.from(g().take(2)), [0, 1]); +assert.compareArray(Array.from(g().take(3)), [0, 1, 2]); diff --git a/test/built-ins/Iterator/prototype/take/limit-rangeerror.js b/test/built-ins/Iterator/prototype/take/limit-rangeerror.js new file mode 100644 index 0000000000..f303d192d7 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/limit-rangeerror.js @@ -0,0 +1,36 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Throws a RangeError exception when limit argument is NaN or less than 0. +info: | + %Iterator.prototype%.take ( limit ) + + 4. If numLimit is NaN, throw a RangeError exception. + 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit). + 6. If integerLimit < 0, throw a RangeError exception. + +features: [iterator-helpers] +---*/ +let iterator = (function* () {})(); + +iterator.take(0); +iterator.take(-0.5); +iterator.take(null); + +assert.throws(RangeError, () => { + iterator.take(-1); +}); + +assert.throws(RangeError, () => { + iterator.take(); +}); + +assert.throws(RangeError, () => { + iterator.take(undefined); +}); + +assert.throws(RangeError, () => { + iterator.take(NaN); +}); diff --git a/test/built-ins/Iterator/prototype/take/limit-tonumber-throws.js b/test/built-ins/Iterator/prototype/take/limit-tonumber-throws.js new file mode 100644 index 0000000000..1859590dea --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/limit-tonumber-throws.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Throws a RangeError exception when limit argument valueOf throws. +info: | + %Iterator.prototype%.take ( limit ) + + 3. Let numLimit be ? ToNumber(limit). + +features: [iterator-helpers] +---*/ +let iterator = (function* () {})(); + +assert.throws(Test262Error, () => { + iterator.take({ + valueOf: function () { + throw new Test262Error(); + }, + }); +}); diff --git a/test/built-ins/Iterator/prototype/take/limit-tonumber.js b/test/built-ins/Iterator/prototype/take/limit-tonumber.js new file mode 100644 index 0000000000..ad870abb63 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/limit-tonumber.js @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Converts the limit argument to a Number using ToNumber and valueOf/toString. +info: | + %Iterator.prototype%.take ( limit ) + + 3. Let numLimit be ? ToNumber(limit). + +includes: [compareArray.js] +features: [iterator-helpers] +---*/ +function* g() { + yield 0; + yield 1; + yield 2; +} + +assert.compareArray( + Array.from( + g().take({ + valueOf: function () { + return 0; + }, + }) + ), + [] +); +assert.compareArray( + Array.from( + g().take({ + valueOf: function () { + return 1; + }, + }) + ), + [0] +); +assert.compareArray( + Array.from( + g().take({ + valueOf: function () { + return 2; + }, + }) + ), + [0, 1] +); +assert.compareArray(Array.from(g().take([1])), [0]); +assert.compareArray( + Array.from( + g().take({ + toString: function () { + return '1'; + }, + }) + ), + [0] +); diff --git a/test/built-ins/Iterator/prototype/take/name.js b/test/built-ins/Iterator/prototype/take/name.js new file mode 100644 index 0000000000..9b3dfe65eb --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + The "name" property of Iterator.prototype.take +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.take, 'name', { + value: 'take', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/take/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/take/next-method-returns-non-object.js new file mode 100644 index 0000000000..d3535d6816 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/next-method-returns-non-object.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.iii. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator().take(0); + +iterator.next(); + +iterator = new NonObjectIterator().take(1); + +assert.throws(TypeError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..aedc223667 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-done.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.iii. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ReturnCalledError extends Error {} +class DoneGetterError extends Error {} + +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new DoneGetterError(); + }, + value: 1, + }; + } + return() { + throw new ReturnCalledError(); + } +} + +let iterator = new ThrowingIterator().take(0); + +assert.throws(ReturnCalledError, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().take(1); + +assert.throws(DoneGetterError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..b464442756 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value-done.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +class ReturnCalledError extends Error {} +class ValueGetterError extends Error {} + +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new ValueGetterError(); + }, + }; + } + return() { + throw new ReturnCalledError(); + } +} + +let iterator = new ThrowingIterator().take(0); +assert.throws(ReturnCalledError, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().take(1); +iterator.next(); diff --git a/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..60d9509a3d --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.v. Let completion be Completion(Yield(? IteratorValue(next))). + +features: [iterator-helpers] +flags: [] +---*/ +class ReturnCalledError extends Error {} +class ValueGetterError extends Error {} + +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new ValueGetterError(); + }, + }; + } + return() { + throw new ReturnCalledError(); + } +} + +let iterator = new ThrowingIterator().take(0); + +assert.throws(ReturnCalledError, function () { + iterator.next(); +}); + +iterator = new ThrowingIterator().take(1); + +assert.throws(ValueGetterError, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/take/next-method-throws.js b/test/built-ins/Iterator/prototype/take/next-method-throws.js new file mode 100644 index 0000000000..8556583de0 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/next-method-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.take ( limit ) + + 8.b.iii. Let next be ? IteratorStep(iterated). + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator().take(0); + +iterator.next(); + +iterator = new ThrowingIterator().take(1); + +assert.throws(Test262Error, function () { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/prototype/take/non-constructible.js b/test/built-ins/Iterator/prototype/take/non-constructible.js new file mode 100644 index 0000000000..6fb0a43e72 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/non-constructible.js @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.take(); +}); + +assert.throws(TypeError, () => { + new iter.take(0); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.take(0); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.take(0); +}); diff --git a/test/built-ins/Iterator/prototype/take/prop-desc.js b/test/built-ins/Iterator/prototype/take/prop-desc.js new file mode 100644 index 0000000000..cd8f19f174 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Property descriptor of Iterator.prototype.take +info: | + Iterator.prototype.take + + * is the initial value of the Iterator.prototype.take property of the global object. + + 17 ECMAScript Standard Built-in Objects + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'take', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/take/proto.js b/test/built-ins/Iterator/prototype/take/proto.js new file mode 100644 index 0000000000..6e1e63dcce --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.take is the + intrinsic object %FunctionPrototype%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.take), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/take/result-is-iterator.js b/test/built-ins/Iterator/prototype/take/result-is-iterator.js new file mode 100644 index 0000000000..bc5cd4bf99 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/result-is-iterator.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.prototype.take is the + intrinsic object %IteratorHelperPrototype%. +features: [iterator-helpers] +---*/ + +assert((function* () {})().take(0) instanceof Iterator, 'function*(){}().take(0) must return an Iterator'); diff --git a/test/built-ins/Iterator/prototype/take/return-is-forwarded.js b/test/built-ins/Iterator/prototype/take/return-is-forwarded.js new file mode 100644 index 0000000000..08e2506f1f --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/return-is-forwarded.js @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator return is called when result iterator is closed +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: false, + value: 1, + }; + } + return() { + ++returnCount; + return {}; + } +} + +let iterator = new TestIterator().take(0); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); + +returnCount = 0; + +iterator = new TestIterator().take(1); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); + +returnCount = 0; + +iterator = new TestIterator().take(1).take(1).take(1).take(1).take(1); +assert.sameValue(returnCount, 0); +iterator.return(); +assert.sameValue(returnCount, 1); +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/prototype/take/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/prototype/take/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 0000000000..77192e57fd --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,50 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let returnCount = 0; + +class TestIterator extends Iterator { + next() { + return { + done: true, + value: undefined, + }; + } + return() { + throw new Test262Error(); + } +} + +let iterator = new TestIterator().take(0); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().take(1); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().take(1); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); + +iterator = new TestIterator().take(1).take(1).take(1).take(1).take(1); +assert.throws(Test262Error, function () { + iterator.return(); +}); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/prototype/take/this-non-callable-next.js b/test/built-ins/Iterator/prototype/take/this-non-callable-next.js new file mode 100644 index 0000000000..26b655fa01 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/this-non-callable-next.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.take ( limit ) + + 7. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = Iterator.prototype.take.call({ next: 0 }, 1); + +assert.throws(TypeError, function () { + iter.next(); +}); diff --git a/test/built-ins/Iterator/prototype/take/this-non-object.js b/test/built-ins/Iterator/prototype/take/this-non-object.js new file mode 100644 index 0000000000..e36b0e7bda --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/this-non-object.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.take ( limit ) + + 7. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.take.call(null, 1); +}); + +assert.throws(TypeError, function () { + Iterator.prototype.take.call(null, { + valueOf: function () { + throw new Test262Error(); + }, + }); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.take.call(0, 1); +}); diff --git a/test/built-ins/Iterator/prototype/take/this-plain-iterator.js b/test/built-ins/Iterator/prototype/take/this-plain-iterator.js new file mode 100644 index 0000000000..b494b3d5eb --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/this-plain-iterator.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Iterator.prototype.take supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.take ( limit ) + + 7. Let iterated be ? GetIteratorDirect(this value). + +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let takeIter = Iterator.prototype.take.call(iter, 1); + +let { done, value } = takeIter.next(); + +assert.sameValue(done, false); +assert.sameValue(value, 2); diff --git a/test/built-ins/Iterator/prototype/take/underlying-iterator-advanced-in-parallel.js b/test/built-ins/Iterator/prototype/take/underlying-iterator-advanced-in-parallel.js new file mode 100644 index 0000000000..2ef2a4dc3a --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/underlying-iterator-advanced-in-parallel.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator is advanced after calling take +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let taken = iterator.take(2); + +let { value, done } = iterator.next(); + +assert.sameValue(value, 0); +assert.sameValue(done, false); + +({ value, done } = taken.next()); + +assert.sameValue(value, 1); +assert.sameValue(done, false); + +({ value, done } = taken.next()); + +assert.sameValue(value, 2); +assert.sameValue(done, false); + +({ value, done } = taken.next()); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/take/underlying-iterator-closed-in-parallel.js b/test/built-ins/Iterator/prototype/take/underlying-iterator-closed-in-parallel.js new file mode 100644 index 0000000000..fc412d4013 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/underlying-iterator-closed-in-parallel.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator is closed after calling take +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +let taken = iterator.take(2); + +iterator.return(); + +let { value, done } = taken.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/take/underlying-iterator-closed.js b/test/built-ins/Iterator/prototype/take/underlying-iterator-closed.js new file mode 100644 index 0000000000..dc3837bf86 --- /dev/null +++ b/test/built-ins/Iterator/prototype/take/underlying-iterator-closed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.take +description: > + Underlying iterator is closed before calling take +info: | + %Iterator.prototype%.take ( limit ) + +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () { + for (let i = 0; i < 5; ++i) { + yield i; + } +})(); + +iterator.return(); + +let taken = iterator.take(2); + +let { value, done } = taken.next(); + +assert.sameValue(value, undefined); +assert.sameValue(done, true); diff --git a/test/built-ins/Iterator/prototype/toArray/callable.js b/test/built-ins/Iterator/prototype/toArray/callable.js new file mode 100644 index 0000000000..819b92132e --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/callable.js @@ -0,0 +1,13 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray is callable +features: [iterator-helpers] +---*/ +function* g() {} +Iterator.prototype.toArray.call(g()); + +let iter = g(); +iter.toArray(); diff --git a/test/built-ins/Iterator/prototype/toArray/get-next-method-only-once.js b/test/built-ins/Iterator/prototype/toArray/get-next-method-only-once.js new file mode 100644 index 0000000000..15362c96d3 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/get-next-method-only-once.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Gets the next method from the iterator only once +info: | + %Iterator.prototype%.toArray ( ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let nextGets = 0; + +class TestIterator extends Iterator { + get next() { + ++nextGets; + let counter = 5; + return function () { + if (counter <= 0) { + return { done: true, value: undefined }; + } else { + return { done: false, value: --counter }; + } + }; + } +} + +let iterator = new TestIterator(); + +assert.sameValue(nextGets, 0); +assert.compareArray(iterator.toArray(), [4, 3, 2, 1, 0]); +assert.sameValue(nextGets, 1); diff --git a/test/built-ins/Iterator/prototype/toArray/get-next-method-throws.js b/test/built-ins/Iterator/prototype/toArray/get-next-method-throws.js new file mode 100644 index 0000000000..06d7320638 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/get-next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator has throwing next getter +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class IteratorThrows extends Iterator { + get next() { + throw new Test262Error(); + } +} + +let iterator = new IteratorThrows(); + +assert.throws(Test262Error, function () { + iterator.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/is-function.js b/test/built-ins/Iterator/prototype/toArray/is-function.js new file mode 100644 index 0000000000..0bede61973 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/is-function.js @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray is a built-in function +features: [iterator-helpers] +---*/ + +assert.sameValue(typeof Iterator.prototype.toArray, 'function'); diff --git a/test/built-ins/Iterator/prototype/toArray/iterator-already-exhausted.js b/test/built-ins/Iterator/prototype/toArray/iterator-already-exhausted.js new file mode 100644 index 0000000000..9db33a71ac --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/iterator-already-exhausted.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray returns an empty array when the iterator has already been exhausted +info: | + %Iterator.prototype%.toArray ( ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let iterator = (function* () {})(); + +let { value, done } = iterator.next(); +assert.sameValue(value, undefined); +assert.sameValue(done, true); + +let result = iterator.toArray(); +assert.compareArray(result, []); + +result = iterator.toArray(); +assert.compareArray(result, []); diff --git a/test/built-ins/Iterator/prototype/toArray/length.js b/test/built-ins/Iterator/prototype/toArray/length.js new file mode 100644 index 0000000000..dadd069c5b --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray has a "length" property whose value is 0. +info: | + ECMAScript Standard Built-in Objects + + Unless otherwise specified, the length property of a built-in + Function object has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.toArray, 'length', { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/toArray/name.js b/test/built-ins/Iterator/prototype/toArray/name.js new file mode 100644 index 0000000000..fd970f676f --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + The "name" property of Iterator.prototype.toArray +info: | + 17 ECMAScript Standard Built-in Objects + + Every built-in Function object, including constructors, that is not + identified as an anonymous function has a name property whose value is a + String. Unless otherwise specified, this value is the name that is given to + the function in this specification. + + ... + + Unless otherwise specified, the name property of a built-in Function + object, if it exists, has the attributes { [[Writable]]: false, + [[Enumerable]]: false, [[Configurable]]: true }. +features: [iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype.toArray, 'name', { + value: 'toArray', + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/toArray/next-method-returns-non-object.js b/test/built-ins/Iterator/prototype/toArray/next-method-returns-non-object.js new file mode 100644 index 0000000000..22d08140f1 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/next-method-returns-non-object.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Underlying iterator next returns non-object +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class NonObjectIterator extends Iterator { + next() { + return null; + } +} + +let iterator = new NonObjectIterator(); + +assert.throws(TypeError, function () { + iterator.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-done.js b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-done.js new file mode 100644 index 0000000000..e725cf4049 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-done.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Underlying iterator next returns object with throwing done getter +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value-done.js new file mode 100644 index 0000000000..15ca5ab334 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value-done.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: true, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); +iterator.toArray(); diff --git a/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value.js b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value.js new file mode 100644 index 0000000000..084158ddbd --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/next-method-returns-throwing-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Underlying iterator next returns object with throwing value getter +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + return { + done: false, + get value() { + throw new Test262Error(); + }, + }; + } + return() { + throw new Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/next-method-throws.js b/test/built-ins/Iterator/prototype/toArray/next-method-throws.js new file mode 100644 index 0000000000..6473e8bb50 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/next-method-throws.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Underlying iterator has throwing next method +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +class ThrowingIterator extends Iterator { + next() { + throw new Test262Error(); + } +} + +let iterator = new ThrowingIterator(); + +assert.throws(Test262Error, function () { + iterator.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/non-constructible.js b/test/built-ins/Iterator/prototype/toArray/non-constructible.js new file mode 100644 index 0000000000..536deebdc9 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/non-constructible.js @@ -0,0 +1,24 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray is not constructible. + + Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function. +features: [iterator-helpers] +---*/ +function* g() {} +let iter = g(); + +assert.throws(TypeError, () => { + new iter.toArray(); +}); + +assert.throws(TypeError, () => { + new Iterator.prototype.toArray(); +}); + +assert.throws(TypeError, () => { + new class extends Iterator {}.toArray(); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/prop-desc.js b/test/built-ins/Iterator/prototype/toArray/prop-desc.js new file mode 100644 index 0000000000..e6c487a3f2 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Property descriptor of Iterator.prototype.toArray +info: | + Iterator.prototype.toArray + + * is the initial value of the Iterator.prototype.toArray property of the global object. + + 17 ECMAScript Standard Built-in Objects + + every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +features: [globalThis, iterator-helpers] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.prototype, 'toArray', { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/prototype/toArray/proto.js b/test/built-ins/Iterator/prototype/toArray/proto.js new file mode 100644 index 0000000000..142a82b4ae --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/proto.js @@ -0,0 +1,11 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + The value of the [[Prototype]] internal slot of Iterator.prototype.toArray is the + intrinsic object %Function%. +features: [iterator-helpers] +---*/ + +assert.sameValue(Object.getPrototypeOf(Iterator.prototype.toArray), Function.prototype); diff --git a/test/built-ins/Iterator/prototype/toArray/this-non-callable-next.js b/test/built-ins/Iterator/prototype/toArray/this-non-callable-next.js new file mode 100644 index 0000000000..f0b2a56868 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/this-non-callable-next.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray throws TypeError when its this value is an object with a non-callable next +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.toArray.call({ next: 0 }); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/this-non-object.js b/test/built-ins/Iterator/prototype/toArray/this-non-object.js new file mode 100644 index 0000000000..d21723e98e --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/this-non-object.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray throws TypeError when its this value is a non-object +info: | + %Iterator.prototype%.toArray ( ) + +features: [iterator-helpers] +flags: [] +---*/ +assert.throws(TypeError, function () { + Iterator.prototype.toArray.call(null); +}); + +Object.defineProperty(Number.prototype, 'next', { + get: function () { + throw new Test262Error(); + }, +}); +assert.throws(TypeError, function () { + Iterator.prototype.toArray.call(0); +}); diff --git a/test/built-ins/Iterator/prototype/toArray/this-plain-iterator.js b/test/built-ins/Iterator/prototype/toArray/this-plain-iterator.js new file mode 100644 index 0000000000..765bc1e913 --- /dev/null +++ b/test/built-ins/Iterator/prototype/toArray/this-plain-iterator.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Michael Ficarra. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-iteratorprototype.toArray +description: > + Iterator.prototype.toArray supports a this value that does not inherit from Iterator.prototype but implements the iterator protocol +info: | + %Iterator.prototype%.toArray ( ) + +includes: [compareArray.js] +features: [iterator-helpers] +flags: [] +---*/ +let iter = { + get next() { + let count = 3; + return function () { + --count; + return count >= 0 ? { done: false, value: count } : { done: true, value: undefined }; + }; + }, +}; + +let result = Iterator.prototype.toArray.call(iter); +assert.compareArray(result, [2, 1, 0]); diff --git a/test/built-ins/Iterator/subclassable.js b/test/built-ins/Iterator/subclassable.js new file mode 100644 index 0000000000..4a07db8c04 --- /dev/null +++ b/test/built-ins/Iterator/subclassable.js @@ -0,0 +1,27 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator-constructor +description: > + The Iterator constructor is designed to be subclassable. +info: | + The Iterator constructor + + - is designed to be subclassable. It may be used as the value of an extends clause of a class defintion. + +features: [iterator-helpers] +---*/ + +class SubIterator extends Iterator {} + +assert.sameValue( + new SubIterator() instanceof SubIterator, + true, + 'The result of `(new SubIterator() instanceof SubIterator)` is true' +); +assert.sameValue( + new SubIterator() instanceof Iterator, + true, + 'The result of `(new SubIterator() instanceof Iterator)` is true' +); diff --git a/test/built-ins/Object/prototype/toString/symbol-tag-non-str-builtin.js b/test/built-ins/Object/prototype/toString/symbol-tag-non-str-builtin.js index 7e2ca775a8..02f9fcb667 100644 --- a/test/built-ins/Object/prototype/toString/symbol-tag-non-str-builtin.js +++ b/test/built-ins/Object/prototype/toString/symbol-tag-non-str-builtin.js @@ -26,7 +26,7 @@ var strIter = ''[Symbol.iterator](); var strIterProto = Object.getPrototypeOf(strIter); assert.sameValue(toString.call(strIter), '[object String Iterator]'); delete strIterProto[Symbol.toStringTag]; -assert.sameValue(toString.call(strIter), '[object Object]'); +assert.sameValue(toString.call(strIter), '[object Iterator]'); var arrIter = [][Symbol.iterator](); var arrIterProto = Object.getPrototypeOf(arrIter)