From a44a64d2562a1ebd1699298a10332c8270a3f6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Thu, 14 Nov 2024 15:57:39 +0100 Subject: [PATCH] Add initial tests for the "iterator-sequencing" proposal --- features.txt | 4 ++ .../concat/arguments-checked-in-order.js | 42 ++++++++++++ .../Iterator/concat/fresh-iterator-result.js | 49 ++++++++++++++ .../concat/get-iterator-method-only-once.js | 52 ++++++++++++++ .../concat/get-iterator-method-throws.js | 27 ++++++++ .../concat/inner-iterator-created-in-order.js | 52 ++++++++++++++ test/built-ins/Iterator/concat/is-function.js | 15 +++++ test/built-ins/Iterator/concat/length.js | 23 +++++++ .../Iterator/concat/many-arguments.js | 45 +++++++++++++ test/built-ins/Iterator/concat/name.js | 30 +++++++++ .../next-method-called-with-zero-arguments.js | 51 ++++++++++++++ .../concat/next-method-returns-non-object.js | 37 ++++++++++ .../next-method-returns-throwing-done.js | 45 +++++++++++++ ...next-method-returns-throwing-value-done.js | 49 ++++++++++++++ .../next-method-returns-throwing-value.js | 45 +++++++++++++ .../Iterator/concat/next-method-throws.js | 37 ++++++++++ .../Iterator/concat/non-constructible.js | 17 +++++ test/built-ins/Iterator/concat/prop-desc.js | 27 ++++++++ test/built-ins/Iterator/concat/proto.js | 16 +++++ .../Iterator/concat/result-is-iterator.js | 13 ++++ .../Iterator/concat/return-is-forwarded.js | 58 ++++++++++++++++ ...eturn-is-not-forwarded-after-exhaustion.js | 43 ++++++++++++ ...n-is-not-forwarded-before-initial-start.js | 32 +++++++++ ...eturn-method-called-with-zero-arguments.js | 67 +++++++++++++++++++ .../Iterator/concat/single-argument.js | 37 ++++++++++ ...ypeerror-when-generator-is-running-next.js | 47 +++++++++++++ ...eerror-when-generator-is-running-return.js | 53 +++++++++++++++ ...s-typeerror-when-iterable-not-an-object.js | 44 ++++++++++++ ...error-when-iterator-method-not-callable.js | 50 ++++++++++++++ ...s-typeerror-when-iterator-not-an-object.js | 49 ++++++++++++++ .../Iterator/concat/zero-arguments.js | 28 ++++++++ 31 files changed, 1184 insertions(+) create mode 100644 test/built-ins/Iterator/concat/arguments-checked-in-order.js create mode 100644 test/built-ins/Iterator/concat/fresh-iterator-result.js create mode 100644 test/built-ins/Iterator/concat/get-iterator-method-only-once.js create mode 100644 test/built-ins/Iterator/concat/get-iterator-method-throws.js create mode 100644 test/built-ins/Iterator/concat/inner-iterator-created-in-order.js create mode 100644 test/built-ins/Iterator/concat/is-function.js create mode 100644 test/built-ins/Iterator/concat/length.js create mode 100644 test/built-ins/Iterator/concat/many-arguments.js create mode 100644 test/built-ins/Iterator/concat/name.js create mode 100644 test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js create mode 100644 test/built-ins/Iterator/concat/next-method-returns-non-object.js create mode 100644 test/built-ins/Iterator/concat/next-method-returns-throwing-done.js create mode 100644 test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js create mode 100644 test/built-ins/Iterator/concat/next-method-returns-throwing-value.js create mode 100644 test/built-ins/Iterator/concat/next-method-throws.js create mode 100644 test/built-ins/Iterator/concat/non-constructible.js create mode 100644 test/built-ins/Iterator/concat/prop-desc.js create mode 100644 test/built-ins/Iterator/concat/proto.js create mode 100644 test/built-ins/Iterator/concat/result-is-iterator.js create mode 100644 test/built-ins/Iterator/concat/return-is-forwarded.js create mode 100644 test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js create mode 100644 test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js create mode 100644 test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js create mode 100644 test/built-ins/Iterator/concat/single-argument.js create mode 100644 test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js create mode 100644 test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js create mode 100644 test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js create mode 100644 test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js create mode 100644 test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js create mode 100644 test/built-ins/Iterator/concat/zero-arguments.js diff --git a/features.txt b/features.txt index dc88a06b8d9..78f9620b065 100644 --- a/features.txt +++ b/features.txt @@ -84,6 +84,10 @@ Atomics.pause # https://github.com/tc39/proposal-is-error Error.isError +# Iterator Sequencing +# https://github.com/tc39/proposal-iterator-sequencing +iterator-sequencing + ## Standard language features # # Language features that have been included in a published version of the diff --git a/test/built-ins/Iterator/concat/arguments-checked-in-order.js b/test/built-ins/Iterator/concat/arguments-checked-in-order.js new file mode 100644 index 00000000000..cce03abdf63 --- /dev/null +++ b/test/built-ins/Iterator/concat/arguments-checked-in-order.js @@ -0,0 +1,42 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Arguments are validated in order. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + a. If item is not an Object, throw a TypeError exception. + b. Let method be ? GetMethod(item, %Symbol.iterator%). + ... +features: [iterator-sequencing] +---*/ + +let getIterator = 0; + +let iterable1 = { + get [Symbol.iterator]() { + getIterator++; + return function() { + throw new Test262Error(); + }; + } +}; + +let iterable2 = { + get [Symbol.iterator]() { + throw new Test262Error(); + } +}; + +assert.sameValue(getIterator, 0); + +assert.throws(TypeError, function() { + Iterator.concat(iterable1, null, iterable2); +}); + +assert.sameValue(getIterator, 1); diff --git a/test/built-ins/Iterator/concat/fresh-iterator-result.js b/test/built-ins/Iterator/concat/fresh-iterator-result.js new file mode 100644 index 00000000000..744bdaa3563 --- /dev/null +++ b/test/built-ins/Iterator/concat/fresh-iterator-result.js @@ -0,0 +1,49 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Returns a fresh iterator result object +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + 2. If innerValue is done, then + ... + 3. Else, + a. Let completion be Completion(Yield(innerValue)). + ... +features: [iterator-sequencing] +---*/ + +let oldIterResult = { + done: false, + value: 123, +}; + +let testIterator = { + next() { + return oldIterResult; + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +let iterResult = iterator.next(); + +assert.sameValue(iterResult.done, false); +assert.sameValue(iterResult.value, 123); + +assert.notSameValue(iterResult, oldIterResult); diff --git a/test/built-ins/Iterator/concat/get-iterator-method-only-once.js b/test/built-ins/Iterator/concat/get-iterator-method-only-once.js new file mode 100644 index 00000000000..34cba98081c --- /dev/null +++ b/test/built-ins/Iterator/concat/get-iterator-method-only-once.js @@ -0,0 +1,52 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Gets the iterator method from the input iterables only once. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + a. If item is not an Object, throw a TypeError exception. + b. Let method be ? GetMethod(item, %Symbol.iterator%). + c. If method is undefined, throw a TypeError exception. + d. Append the Record { [[OpenMethod]]: method, [[Iterable]]: item } to iterables. + ... +features: [iterator-sequencing] +includes: [compareArray.js] +---*/ + +let iteratorGets = 0; +let iteratorCalls = 0; +let array = [1, 2, 3]; + +class CountingIterable { + get [Symbol.iterator]() { + ++iteratorGets; + + return function () { + ++iteratorCalls; + return array[Symbol.iterator](); + }; + } +} + +let iterable = new CountingIterable(); + +assert.sameValue(iteratorGets, 0); +assert.sameValue(iteratorCalls, 0); + +let iter = Iterator.concat(iterable); + +assert.sameValue(iteratorGets, 1); +assert.sameValue(iteratorCalls, 0); + +let result = [...iter]; + +assert.sameValue(iteratorGets, 1); +assert.sameValue(iteratorCalls, 1); + +assert.compareArray(result, array); diff --git a/test/built-ins/Iterator/concat/get-iterator-method-throws.js b/test/built-ins/Iterator/concat/get-iterator-method-throws.js new file mode 100644 index 00000000000..76d66f87fa5 --- /dev/null +++ b/test/built-ins/Iterator/concat/get-iterator-method-throws.js @@ -0,0 +1,27 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Error thrown when retrieving the iterator method. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + a. If item is not an Object, throw a TypeError exception. + b. Let method be ? GetMethod(item, %Symbol.iterator%). + ... +features: [iterator-sequencing] +---*/ + +var iterable = { + get [Symbol.iterator]() { + throw new Test262Error(); + } +}; + +assert.throws(Test262Error, function() { + Iterator.concat(iterable); +}); diff --git a/test/built-ins/Iterator/concat/inner-iterator-created-in-order.js b/test/built-ins/Iterator/concat/inner-iterator-created-in-order.js new file mode 100644 index 00000000000..a1da225f358 --- /dev/null +++ b/test/built-ins/Iterator/concat/inner-iterator-created-in-order.js @@ -0,0 +1,52 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Inner iterators created in order +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + i. Let iter be ? Call(iterable.[[OpenMethod]], iterable.[[Iterable]]). + ... + v. Repeat, while innerAlive is true, + ... +features: [iterator-sequencing] +includes: [compareArray.js] +---*/ + +let calledIterator = []; + +let iterable1 = { + [Symbol.iterator]() { + calledIterator.push("iterable1"); + return [1][Symbol.iterator](); + } +}; + +let iterable2 = { + [Symbol.iterator]() { + calledIterator.push("iterable2"); + return [2][Symbol.iterator](); + } +}; + +let iterator = Iterator.concat(iterable1, iterable2); + +assert.compareArray(calledIterator, []); + +let iterResult = iterator.next(); +assert.sameValue(iterResult.done, false); +assert.sameValue(iterResult.value, 1); + +assert.compareArray(calledIterator, ["iterable1"]); + +iterResult = iterator.next(); +assert.sameValue(iterResult.done, false); +assert.sameValue(iterResult.value, 2); + +assert.compareArray(calledIterator, ["iterable1", "iterable2"]); diff --git a/test/built-ins/Iterator/concat/is-function.js b/test/built-ins/Iterator/concat/is-function.js new file mode 100644 index 00000000000..4422c1e30d5 --- /dev/null +++ b/test/built-ins/Iterator/concat/is-function.js @@ -0,0 +1,15 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat is a built-in function +features: [iterator-sequencing] +---*/ + +assert.sameValue( + typeof Iterator.concat, + "function", + "The value of `typeof Iterator.concat` is 'function'" +); diff --git a/test/built-ins/Iterator/concat/length.js b/test/built-ins/Iterator/concat/length.js new file mode 100644 index 00000000000..27df83ad9a4 --- /dev/null +++ b/test/built-ins/Iterator/concat/length.js @@ -0,0 +1,23 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat 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-sequencing] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.concat, "length", { + value: 0, + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/concat/many-arguments.js b/test/built-ins/Iterator/concat/many-arguments.js new file mode 100644 index 00000000000..a8bc9d2c658 --- /dev/null +++ b/test/built-ins/Iterator/concat/many-arguments.js @@ -0,0 +1,45 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat when called with many arguments. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + b. Return ReturnCompletion(undefined). + ... + 6. Return gen. +features: [iterator-sequencing] +---*/ + +let iterables = [ + [/* empty */], + [1], + [2, 3], + [4, 5, 6], + [7, 8, 9, 10], +]; + +let iterator = Iterator.concat(...iterables); + +let array = [].concat(...iterables); + +for (let i = 0; i < array.length; i++) { + let iterResult = iterator.next(); + + assert.sameValue(iterResult.done, false); + assert.sameValue(iterResult.value, array[i]); +} + +let iterResult = iterator.next(); + +assert.sameValue(iterResult.done, true); +assert.sameValue(iterResult.value, undefined); diff --git a/test/built-ins/Iterator/concat/name.js b/test/built-ins/Iterator/concat/name.js new file mode 100644 index 00000000000..027c0d7e3fe --- /dev/null +++ b/test/built-ins/Iterator/concat/name.js @@ -0,0 +1,30 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + The "name" property of Iterator.concat +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-sequencing] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator.concat, "name", { + value: "concat", + writable: false, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js b/test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js new file mode 100644 index 00000000000..2b8c1122a11 --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js @@ -0,0 +1,51 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator's next method is called with zero arguments. +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +let nextCalled = 0; + +let testIterator = { + next() { + nextCalled++; + assert.sameValue(arguments.length, 0); + + return { + done: false, + value: 0, + }; + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); +assert.sameValue(nextCalled, 0); + +iterator.next(); +assert.sameValue(nextCalled, 1); + +iterator.next(1); +assert.sameValue(nextCalled, 2); + +iterator.next(1, 2); +assert.sameValue(nextCalled, 3); diff --git a/test/built-ins/Iterator/concat/next-method-returns-non-object.js b/test/built-ins/Iterator/concat/next-method-returns-non-object.js new file mode 100644 index 00000000000..283a8df5b6f --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-returns-non-object.js @@ -0,0 +1,37 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator next returns non-object +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +let nonObjectIterator = { + next() { + return null; + } +}; + +let iterable = { + [Symbol.iterator]() { + return nonObjectIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +assert.throws(TypeError, function() { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/concat/next-method-returns-throwing-done.js b/test/built-ins/Iterator/concat/next-method-returns-throwing-done.js new file mode 100644 index 00000000000..2e7d6151c0a --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-returns-throwing-done.js @@ -0,0 +1,45 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator next returns object with throwing done getter +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +let throwingIterator = { + next() { + return { + get done() { + throw new Test262Error(); + }, + value: 1, + }; + }, + return() { + throw new Error(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return throwingIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +assert.throws(Test262Error, function() { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js b/test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js new file mode 100644 index 00000000000..1dc0491ec61 --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js @@ -0,0 +1,49 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator next returns object with throwing value getter, but is already done +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +class ReturnCalledError extends Error {} +class ValueGetterError extends Error {} + +let throwingIterator = { + next() { + return { + get value() { + throw new ValueGetterError(); + }, + done: true, + }; + }, + return() { + throw new ReturnCalledError(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return throwingIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +let iterResult = iterator.next(); + +assert.sameValue(iterResult.done, true); +assert.sameValue(iterResult.value, undefined); diff --git a/test/built-ins/Iterator/concat/next-method-returns-throwing-value.js b/test/built-ins/Iterator/concat/next-method-returns-throwing-value.js new file mode 100644 index 00000000000..3949f4ac574 --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-returns-throwing-value.js @@ -0,0 +1,45 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator next returns object with throwing value getter +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +let throwingIterator = { + next() { + return { + get value() { + throw new Test262Error(); + }, + done: false, + }; + }, + return() { + throw new Error(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return throwingIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +assert.throws(Test262Error, function() { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/concat/next-method-throws.js b/test/built-ins/Iterator/concat/next-method-throws.js new file mode 100644 index 00000000000..93ebd451a79 --- /dev/null +++ b/test/built-ins/Iterator/concat/next-method-throws.js @@ -0,0 +1,37 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator has throwing next method +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + 1. Let innerValue be ? IteratorStepValue(iteratorRecord). + ... +features: [iterator-sequencing] +---*/ + +let throwingIterator = { + next() { + throw new Test262Error(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return throwingIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +assert.throws(Test262Error, function() { + iterator.next(); +}); diff --git a/test/built-ins/Iterator/concat/non-constructible.js b/test/built-ins/Iterator/concat/non-constructible.js new file mode 100644 index 00000000000..8ea0738b82f --- /dev/null +++ b/test/built-ins/Iterator/concat/non-constructible.js @@ -0,0 +1,17 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat 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-sequencing] +---*/ + +assert.throws(TypeError, () => { + new Iterator.concat(); +}); diff --git a/test/built-ins/Iterator/concat/prop-desc.js b/test/built-ins/Iterator/concat/prop-desc.js new file mode 100644 index 00000000000..9c5e3f105b5 --- /dev/null +++ b/test/built-ins/Iterator/concat/prop-desc.js @@ -0,0 +1,27 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Property descriptor of Iterator.concat +info: | + Iterator.concat + + * is the initial value of the Iterator.concat 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: [iterator-sequencing] +includes: [propertyHelper.js] +---*/ + +verifyProperty(Iterator, "concat", { + value: Iterator.concat, + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/test/built-ins/Iterator/concat/proto.js b/test/built-ins/Iterator/concat/proto.js new file mode 100644 index 00000000000..aad388ea25e --- /dev/null +++ b/test/built-ins/Iterator/concat/proto.js @@ -0,0 +1,16 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + The value of the [[Prototype]] internal slot of Iterator.concat is the + intrinsic object %FunctionPrototype%. +features: [iterator-sequencing] +---*/ + +assert.sameValue( + Object.getPrototypeOf(Iterator.concat), + Function.prototype, + "Object.getPrototypeOf(Iterator.concat) must return the value of Function.prototype" +); diff --git a/test/built-ins/Iterator/concat/result-is-iterator.js b/test/built-ins/Iterator/concat/result-is-iterator.js new file mode 100644 index 00000000000..3a845ff6811 --- /dev/null +++ b/test/built-ins/Iterator/concat/result-is-iterator.js @@ -0,0 +1,13 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + The value of the [[Prototype]] internal slot of the return value of Iterator.concat + is the intrinsic object %IteratorHelperPrototype%. +features: [iterator-sequencing] +---*/ + +var iter = Iterator.concat(); +assert(iter instanceof Iterator, "Iterator.concat() must return an Iterator"); diff --git a/test/built-ins/Iterator/concat/return-is-forwarded.js b/test/built-ins/Iterator/concat/return-is-forwarded.js new file mode 100644 index 00000000000..e49d0694d37 --- /dev/null +++ b/test/built-ins/Iterator/concat/return-is-forwarded.js @@ -0,0 +1,58 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator return is called when result iterator is closed +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + ... + 3. Else, + a. Let completion be Completion(Yield(innerValue)). + b. If completion is an abrupt completion, then + i. Return ? IteratorClose(iteratorRecord, completion). + ... +features: [iterator-sequencing] +---*/ + +let returnCount = 0; + +let testIterator = { + next() { + return { + done: false, + value: 1, + }; + }, + return() { + ++returnCount; + return {}; + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); +assert.sameValue(returnCount, 0); + +let iterResult = iterator.next(); +assert.sameValue(returnCount, 0); +assert.sameValue(iterResult.done, false); +assert.sameValue(iterResult.value, 1); + +iterator.return(); +assert.sameValue(returnCount, 1); + +iterator.return(); +assert.sameValue(returnCount, 1); diff --git a/test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js b/test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js new file mode 100644 index 00000000000..44d41c0695a --- /dev/null +++ b/test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js @@ -0,0 +1,43 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator return is not called after result iterator observes that underlying iterator is exhausted +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + ... + 2. If innerValue is done, then + a. Set innerAlive to false. + ... +features: [iterator-sequencing] +---*/ + +let testIterator = { + next() { + return { + done: true, + value: undefined, + }; + }, + return() { + throw new Test262Error(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js b/test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js new file mode 100644 index 00000000000..9aebfe9cb15 --- /dev/null +++ b/test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js @@ -0,0 +1,32 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator return is not called before initial call to next method +features: [iterator-sequencing] +---*/ + +let testIterator = { + next() { + return { + done: false, + value: 1, + }; + }, + return() { + throw new Test262Error(); + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); +iterator.return(); +iterator.next(); +iterator.return(); diff --git a/test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js b/test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js new file mode 100644 index 00000000000..2adcd12415c --- /dev/null +++ b/test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js @@ -0,0 +1,67 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Underlying iterator's return method is called with zero arguments. +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + v. Repeat, while innerAlive is true, + ... + 3. Else, + ... + b. If completion is an abrupt completion, then + i. Return ? IteratorClose(iteratorRecord, completion). +features: [iterator-sequencing] +---*/ + +let returnCalled = 0; + +let testIterator = { + next() { + return {done: false}; + }, + return() { + returnCalled++; + assert.sameValue(arguments.length, 0); + return {done: true}; + } +}; + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator; + +// Call with zero arguments. +iterator = Iterator.concat(iterable); +iterator.next(); +assert.sameValue(returnCalled, 0); + +iterator.return(); +assert.sameValue(returnCalled, 1); + +// Call with one argument. +iterator = Iterator.concat(iterable); +iterator.next(); +assert.sameValue(returnCalled, 1); + +iterator.return(1); +assert.sameValue(returnCalled, 2); + +// Call with two arguments. +iterator = Iterator.concat(iterable); +iterator.next(); +assert.sameValue(returnCalled, 2); + +iterator.return(1, 2); +assert.sameValue(returnCalled, 3); diff --git a/test/built-ins/Iterator/concat/single-argument.js b/test/built-ins/Iterator/concat/single-argument.js new file mode 100644 index 00000000000..419ee3b0b71 --- /dev/null +++ b/test/built-ins/Iterator/concat/single-argument.js @@ -0,0 +1,37 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat when called with a single argument. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + b. Return ReturnCompletion(undefined). + ... + 6. Return gen. +features: [iterator-sequencing] +---*/ + +let array = [1, 2, 3]; + +let iterator = Iterator.concat(array); + +for (let i = 0; i < array.length; i++) { + let iterResult = iterator.next(); + + assert.sameValue(iterResult.done, false); + assert.sameValue(iterResult.value, array[i]); +} + +let iterResult = iterator.next(); + +assert.sameValue(iterResult.done, true); +assert.sameValue(iterResult.value, undefined); diff --git a/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js b/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js new file mode 100644 index 00000000000..e1fe968de12 --- /dev/null +++ b/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js @@ -0,0 +1,47 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Throws a TypeError when the closure generator is already running. +info: | + 27.1.2.1.1 %IteratorHelperPrototype%.next ( ) + 1. Return ? GeneratorResume(this value, undefined, "Iterator Helper"). + + 27.5.3.3 GeneratorResume ( generator, value, generatorBrand ) + 1. Let state be ? GeneratorValidate(generator, generatorBrand). + ... + + 27.5.3.2 GeneratorValidate ( generator, generatorBrand ) + ... + 6. If state is executing, throw a TypeError exception. + ... +features: [iterator-sequencing] +---*/ + +let enterCount = 0; + +let testIterator = { + next() { + enterCount++; + iterator.next(); + return {done: false}; + } +} + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +assert.sameValue(enterCount, 0); + +assert.throws(TypeError, function() { + iterator.next(); +}); + +assert.sameValue(enterCount, 1); diff --git a/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js b/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js new file mode 100644 index 00000000000..61c29ef4cb8 --- /dev/null +++ b/test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js @@ -0,0 +1,53 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Throws a TypeError when the closure generator is already running. +info: | + 27.1.2.1.2 %IteratorHelperPrototype%.return ( ) + ... + 6. Return ? GeneratorResumeAbrupt(O, C, "Iterator Helper"). + + 27.5.3.4 GeneratorResumeAbrupt ( generator, abruptCompletion, generatorBrand ) + 1. Let state be ? GeneratorValidate(generator, generatorBrand). + ... + + 27.5.3.2 GeneratorValidate ( generator, generatorBrand ) + ... + 6. If state is executing, throw a TypeError exception. + ... +features: [iterator-sequencing] +---*/ + +let enterCount = 0; + +let testIterator = { + next() { + return {done: false}; + }, + return() { + enterCount++; + iterator.return(); + return {done: false}; + } +} + +let iterable = { + [Symbol.iterator]() { + return testIterator; + } +}; + +let iterator = Iterator.concat(iterable); + +iterator.next(); + +assert.sameValue(enterCount, 0); + +assert.throws(TypeError, function() { + iterator.return(); +}); + +assert.sameValue(enterCount, 1); diff --git a/test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js b/test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js new file mode 100644 index 00000000000..5dc4395bd1d --- /dev/null +++ b/test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js @@ -0,0 +1,44 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Throws a TypeError when the iterable is not an object. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + a. If item is not an Object, throw a TypeError exception. + ... +features: [iterator-sequencing] +---*/ + +assert.throws(TypeError, function() { + Iterator.concat(undefined); +}, "iterable is undefined"); + +assert.throws(TypeError, function() { + Iterator.concat(null); +}, "iterable is null"); + +assert.throws(TypeError, function() { + Iterator.concat(true); +}, "iterable is boolean"); + +assert.throws(TypeError, function() { + Iterator.concat(123); +}, "iterable is number"); + +assert.throws(TypeError, function() { + Iterator.concat(123n); +}, "iterable is bigint"); + +assert.throws(TypeError, function() { + Iterator.concat("test"); +}, "iterable is string"); + +assert.throws(TypeError, function() { + Iterator.concat(Symbol()); +}, "iterable is symbol"); diff --git a/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js b/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js new file mode 100644 index 00000000000..05e5e17416e --- /dev/null +++ b/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js @@ -0,0 +1,50 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Throws a TypeError when the iterator method is not callable. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + a. If item is not an Object, throw a TypeError exception. + b. Let method be ? GetMethod(item, %Symbol.iterator%). + c. If method is undefined, throw a TypeError exception. + ... +features: [iterator-sequencing] +---*/ + +assert.throws(TypeError, function() { + Iterator.concat({}); +}, "iterable has no iterator method"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: undefined}); +}, "iterator method is undefined"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: null}); +}, "iterator method is null"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: true}); +}, "iterator method is boolean"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: 123}); +}, "iterator method is number"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: 123n}); +}, "iterator method is bigint"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: "abc"}); +}, "iterator method is string"); + +assert.throws(TypeError, function() { + Iterator.concat({[Symbol.iterator]: Symbol()}); +}, "iterator method is symbol"); diff --git a/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js b/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js new file mode 100644 index 00000000000..b413aa3a55c --- /dev/null +++ b/test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js @@ -0,0 +1,49 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Throws a TypeError when the iterator is not an object. +info: | + Iterator.concat ( ...items ) + + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + i. Let iter be ? Call(iterable.[[OpenMethod]], iterable.[[Iterable]]). + ii. If iter is not an Object, throw a TypeError exception. + ... +features: [iterator-sequencing] +---*/ + +function MakeIterable(iterator) { + return { + [Symbol.iterator]() { + return iterator; + } + }; +} + +var iterator; + +iterator = Iterator.concat(MakeIterable(undefined)); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is undefined"); + +iterator = Iterator.concat(MakeIterable(null)); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is null"); + +iterator = Iterator.concat(MakeIterable(true)); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is boolean"); + +iterator = Iterator.concat(MakeIterable(123)); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is number"); + +iterator = Iterator.concat(MakeIterable(123n)); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is bigint"); + +iterator = Iterator.concat(MakeIterable("abc")); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is string"); + +iterator = Iterator.concat(MakeIterable(Symbol())); +assert.throws(TypeError, function() { iterator.next(); }, "iterator is symbol"); diff --git a/test/built-ins/Iterator/concat/zero-arguments.js b/test/built-ins/Iterator/concat/zero-arguments.js new file mode 100644 index 00000000000..9c8a9411502 --- /dev/null +++ b/test/built-ins/Iterator/concat/zero-arguments.js @@ -0,0 +1,28 @@ +// Copyright (C) 2024 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-iterator.concat +description: > + Iterator.concat when called with zero arguments. +info: | + Iterator.concat ( ...items ) + + 1. Let iterables be a new empty List. + 2. For each element item of items, do + ... + 3. Let closure be a new Abstract Closure with no parameters that captures iterables and performs the following steps when called: + a. For each Record iterable of iterables, do + ... + b. Return ReturnCompletion(undefined). + ... + 6. Return gen. +features: [iterator-sequencing] +---*/ + +let iterator = Iterator.concat(); + +let iterResult = iterator.next(); + +assert.sameValue(iterResult.done, true); +assert.sameValue(iterResult.value, undefined);