diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype')
46 files changed, 2703 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js new file mode 100644 index 0000000000..ecba51e39c --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js @@ -0,0 +1,38 @@ +// |reftest| async +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: > + `next` method does not pass absent `value`. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + + [...] + 5. If value is present, then + [...] + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + [...] +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var nextArgumentsLength; +var syncIterator = { + [Symbol.iterator]() { + return this; + }, + next() { + nextArgumentsLength = arguments.length; + return {done: true}; + }, +}; + +asyncTest(async function () { + for await (let _ of syncIterator); + + assert.sameValue(nextArgumentsLength, 0); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js new file mode 100644 index 0000000000..27a06daace --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js @@ -0,0 +1,66 @@ +// |reftest| async +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + ... + 12. If done is true, or if closeOnRejection is false, then + ... + 13. Else, + a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called: + i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)). + b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »). + c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise. + 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability). + 15. Return promiseCapability.[[Promise]]. + + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var finallyCount = 0; +var caught = false; + +function* iterator() { + try { + yield Promise.reject("reject"); + } finally { + finallyCount += 1; + } +} + +asyncTest(async () => { + try { + for await (const x of iterator()); + } catch (e) { + caught = true; + assert.sameValue(e, "reject"); + } + + assert.sameValue(finallyCount, 1); + assert(caught); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js new file mode 100644 index 0000000000..60d7674aa6 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js @@ -0,0 +1,71 @@ +// |reftest| async +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + ... + 12. If done is true, or if closeOnRejection is false, then + ... + 13. Else, + a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called: + i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)). + b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »). + c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise. + 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability). + 15. Return promiseCapability.[[Promise]]. + + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +var caught = false; + +const syncIterator = { + [Symbol.iterator]() { + return { + next() { + return { value: Promise.reject("reject"), done: false }; + }, + return() { + returnCount += 1; + } + }; + } +} + +asyncTest(async () => { + try { + for await (let _ of syncIterator); + } catch (e) { + caught = true; + assert.sameValue(e, "reject"); + } + + assert.sameValue(returnCount, 1); + assert(caught); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js new file mode 100644 index 0000000000..eb493bece9 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js @@ -0,0 +1,53 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if getter `done` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let nextResult be IteratorNext(syncIteratorRecord, value). + 6. IfAbruptRejectPromise(nextResult, promiseCapability). + 7. Let nextDone be IteratorComplete(nextResult). + 8. IfAbruptRejectPromise(nextDone, promiseCapability). + ... + 18. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { + get done() { + throw thrownError; + }, + value: 1 + } + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +asyncg().next().then( + function (result) { + throw new Test262Error("Promise should be rejected."); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + } +).then($DONE, $DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js new file mode 100644 index 0000000000..6a0e49439d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js @@ -0,0 +1,55 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if getter `value` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let nextResult be IteratorNext(syncIteratorRecord, value). + 6. IfAbruptRejectPromise(nextResult, promiseCapability). + 7. Let nextDone be IteratorComplete(nextResult). + 8. If AbruptRejectPromise(nextDone, promiseCapability). + 9. Let nextValue be IteratorValue(nextResult). + 10. IfAbruptRejectPromise(nextValue, promiseCapability). + ... + 18. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { + get value() { + throw thrownError; + }, + done: false + } + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +asyncg().next().then( + function (result) { + throw new Test262Error("Promise should be rejected."); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + } +).then($DONE, $DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js new file mode 100644 index 0000000000..bbcd3f3a23 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js @@ -0,0 +1,68 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + 7. IfAbruptRejectPromise(valueWrapper, promiseCapability). + ... + + IfAbruptRejectPromise ( value, capability ) + 1. Assert: value is a Completion Record. + 2. If value is an abrupt completion, then + a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). + b. Return capability.[[Promise]]. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var finallyCount = 0; +function CatchError() {} +var thrownError = new CatchError(); + +function* gen() { + try { + const p = Promise.resolve('FAIL'); + Object.defineProperty(p, 'constructor', { + get() { + throw thrownError; + } + }); + yield p; + } finally { + finallyCount += 1; + } +} + +async function* iter() { + yield* gen(); +} + +asyncTest(async function () { + await assert.throwsAsync(CatchError, async () => iter().next(), "Promise should be rejected"); + assert.sameValue(finallyCount, 1, 'iterator closed properly'); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js new file mode 100644 index 0000000000..d3f638e48e --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js @@ -0,0 +1,43 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() returns a promise for an IteratorResult object +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let nextResult be IteratorNext(syncIteratorRecord, value). + 6. IfAbruptRejectPromise(nextResult, promiseCapability). + 7. Let nextDone be IteratorComplete(nextResult). + 8. If AbruptRejectPromise(nextDone, promiseCapability). + 9. Let nextValue be IteratorValue(nextResult). + 10. IfAbruptRejectPromise(nextValue, promiseCapability). + ... + 14. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions. + + Async-from-Sync Iterator Value Unwrap Functions + 1. Return ! CreateIterResultObject(value, F.[[Done]]). + +flags: [async] +features: [async-iteration] +---*/ + +function* g() {} + +async function* asyncg() { + yield* g(); +} + +asyncg().next().then(function (result) { + assert( + Object.prototype.hasOwnProperty.call(result, 'value'), 'Has "own" property `value`' + ); + assert( + Object.prototype.hasOwnProperty.call(result, 'done'), 'Has "own" property `done`' + ); + assert.sameValue(Object.getPrototypeOf(result), Object.prototype); +}).then($DONE, $DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js new file mode 100644 index 0000000000..8a5f9bf14a --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js @@ -0,0 +1,44 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if sync iterator next() function returns an aburpt completion +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let nextResult be IteratorNext(syncIteratorRecord, value). + 6. IfAbruptRejectPromise(nextResult, promiseCapability). + 7. Let nextDone be IteratorComplete(nextResult). + 8. If AbruptRejectPromise(nextDone, promiseCapability). + 9. Let nextValue be IteratorValue(nextResult). + 10. IfAbruptRejectPromise(nextValue, promiseCapability). + ... + 18. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +function* g() { + throw thrownError; +} + +async function* asyncg() { + yield* g(); +} + +asyncg().next().then( + function (result) { + throw new Test262Error("Promise should be rejected."); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + } +).then($DONE, $DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js new file mode 100644 index 0000000000..f77f3c2d96 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js @@ -0,0 +1,44 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will unwrap a Promise value return by the sync iterator +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let nextResult be IteratorNext(syncIteratorRecord, value). + 6. IfAbruptRejectPromise(nextResult, promiseCapability). + 7. Let nextDone be IteratorComplete(nextResult). + 8. If AbruptRejectPromise(nextDone, promiseCapability). + 9. Let nextValue be IteratorValue(nextResult). + 10. IfAbruptRejectPromise(nextValue, promiseCapability). + ... + 14. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions. + + Async-from-Sync Iterator Value Unwrap Functions + An async-from-sync iterator value unwrap function is an anonymous built-in + function that is used by methods of %AsyncFromSyncIteratorPrototype% when + processing the value field of an IteratorResult object, in order to wait for + its value if it is a promise and re-package the result in a new "unwrapped" + IteratorResult object. Each async iterator value unwrap function has a + [[Done]] internal slot. + +flags: [async] +features: [async-iteration] +---*/ + +function* g() { + yield Promise.resolve(1); +} + +async function* asyncg() { + yield* g(); +} + +asyncg().next().then(function (result) { + assert.sameValue(result.value, 1, "result.value should be unwrapped promise, got: " + result.value) +}).then($DONE, $DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js new file mode 100644 index 0000000000..f7b9c57549 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js @@ -0,0 +1,73 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + 7. IfAbruptRejectPromise(valueWrapper, promiseCapability). + ... + + IfAbruptRejectPromise ( value, capability ) + 1. Assert: value is a Completion Record. + 2. If value is an abrupt completion, then + a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). + b. Return capability.[[Promise]]. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +function CatchError() {} +var thrownError = new CatchError(); + +const obj = { + [Symbol.iterator]() { + return { + next() { + const p = Promise.resolve('FAIL'); + Object.defineProperty(p, 'constructor', { + get() { + throw thrownError; + } + }); + return { value: p, done: false }; + }, + return() { + returnCount += 1; + } + }; + } +}; + +async function* iter() { + yield* obj; +} + +asyncTest(async function () { + await assert.throwsAsync(CatchError, async () => iter().next(), "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js new file mode 100644 index 0000000000..4f6a112c45 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js @@ -0,0 +1,28 @@ +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: > + "next" returns a promise for an IteratorResult object +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 18. Return promiseCapability.[[Promise]]. + +features: [async-iteration] +---*/ + +function* g() { +} + +async function* asyncg() { + yield* g(); +} + +var result = asyncg().next(); +assert(result instanceof Promise) + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js new file mode 100644 index 0000000000..ae18ad584d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js @@ -0,0 +1,113 @@ +// GENERATED, DO NOT EDIT +// file: asyncHelpers.js +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + A collection of assertion and wrapper functions for testing asynchronous built-ins. +defines: [asyncTest] +---*/ + +function asyncTest(testFunc) { + if (!Object.hasOwn(globalThis, "$DONE")) { + throw new Test262Error("asyncTest called without async flag"); + } + if (typeof testFunc !== "function") { + $DONE(new Test262Error("asyncTest called with non-function argument")); + return; + } + try { + testFunc().then( + function () { + $DONE(); + }, + function (error) { + $DONE(error); + } + ); + } catch (syncError) { + $DONE(syncError); + } +} + +assert.throwsAsync = async function (expectedErrorConstructor, func, message) { + var innerThenable; + if (message === undefined) { + message = ""; + } else { + message += " "; + } + if (typeof func === "function") { + try { + innerThenable = func(); + if ( + innerThenable === null || + typeof innerThenable !== "object" || + typeof innerThenable.then !== "function" + ) { + message += + "Expected to obtain an inner promise that would reject with a" + + expectedErrorConstructor.name + + " but result was not a thenable"; + throw new Test262Error(message); + } + } catch (thrown) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise"; + throw new Test262Error(message); + } + } else { + message += + "assert.throwsAsync called with an argument that is not a function"; + throw new Test262Error(message); + } + + try { + return innerThenable.then( + function () { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but no exception was thrown at all"; + throw new Test262Error(message); + }, + function (thrown) { + var expectedName, actualName; + if (typeof thrown !== "object" || thrown === null) { + message += "Thrown value was not an object!"; + throw new Test262Error(message); + } else if (thrown.constructor !== expectedErrorConstructor) { + expectedName = expectedErrorConstructor.name; + actualName = thrown.constructor.name; + if (expectedName === actualName) { + message += + "Expected a " + + expectedName + + " but got a different error constructor with the same name"; + } else { + message += + "Expected a " + expectedName + " but got a " + actualName; + } + throw new Test262Error(message); + } + } + ); + } catch (thrown) { + if (typeof thrown !== "object" || thrown === null) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object "; + } else { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but a " + + thrown.constructor.name + + " was thrown synchronously"; + } + throw new Test262Error(message); + } +}; diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js new file mode 100644 index 0000000000..26c35b6312 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js @@ -0,0 +1,63 @@ +// |reftest| async +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + ... + 12. If done is true, or if closeOnRejection is false, then + ... + 13. Else, + a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called: + i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)). + b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »). + c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise. + 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability). + 15. Return promiseCapability.[[Promise]]. + + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var finallyCount = 0; +function Reject() {} + +function* iterator() { + try { + yield Promise.reject(new Reject()); + } finally { + finallyCount += 1; + } +} + +async function* asyncIterator() { + yield* iterator() +} + +asyncTest(async () => { + await assert.throwsAsync(Reject, async () => asyncIterator().next(), "Promise should be rejected"); + assert.sameValue(finallyCount, 1); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js new file mode 100644 index 0000000000..d747bce581 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js @@ -0,0 +1,68 @@ +// |reftest| async +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.next +description: next() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.next ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. If value is present, then + ... + 6. Else, + a. Let result be IteratorNext(syncIteratorRecord). + 7. IfAbruptRejectPromise(result, promiseCapability). + 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + ... + 12. If done is true, or if closeOnRejection is false, then + ... + 13. Else, + a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called: + i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)). + b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »). + c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise. + 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability). + 15. Return promiseCapability.[[Promise]]. + + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +function Reject() {} + +const syncIterator = { + [Symbol.iterator]() { + return { + next() { + return { value: Promise.reject(new Reject()), done: false }; + }, + return() { + returnCount += 1; + } + }; + } +} + +async function* asyncIterator() { + yield* syncIterator; +} + +asyncTest(async () => { + await assert.throwsAsync(Reject, async () => asyncIterator().next(), "Promise should be rejected"); + assert.sameValue(returnCount, 1); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js new file mode 100644 index 0000000000..21686a8896 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js @@ -0,0 +1,43 @@ +// |reftest| async +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: > + `return` method does not pass absent `value`. +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + + [...] + 8. If value is present, then + [...] + 9. Else, + a. Let result be Call(return, syncIterator). + [...] +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnArgumentsLength; +var syncIterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return {done: false}; + }, + return() { + returnArgumentsLength = arguments.length; + return {done: true}; + }, +}; + +asyncTest(async function () { + for await (let _ of syncIterator) { + break; + } + + assert.sameValue(returnArgumentsLength, 0); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js new file mode 100644 index 0000000000..de5639aa9d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js @@ -0,0 +1,71 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will reject promise if getter `done` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + ... + 8. Let returnResult be Call(return, syncIterator, « value »). + 9. IfAbruptRejectPromise(returnResult, promiseCapability). + ... + 11. Let returnDone be IteratorComplete(returnResult). + 12. IfAbruptRejectPromise(returnDone, promiseCapability). + 13. Let returnValue be IteratorValue(returnResult). + 14. IfAbruptRejectPromise(returnValue, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + return() { + return { + get done() { + throw thrownError; + }, + value: 1 + } + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js new file mode 100644 index 0000000000..369319f098 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js @@ -0,0 +1,71 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will reject promise if getter `value` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + ... + 8. Let returnResult be Call(return, syncIterator, « value »). + 9. IfAbruptRejectPromise(returnResult, promiseCapability). + ... + 11. Let returnDone be IteratorComplete(returnResult). + 12. IfAbruptRejectPromise(returnDone, promiseCapability). + 13. Let returnValue be IteratorValue(returnResult). + 14. IfAbruptRejectPromise(returnValue, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + + +var thrownError = new Error("Catch me."); +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + return() { + return { + get value() { + throw thrownError; + }, + done: false + } + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js new file mode 100644 index 0000000000..5d69a98f7f --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js @@ -0,0 +1,65 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will unwrap a Promise value return by the sync iterator +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + ... + 17. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions. + ... + 22. Return promiseCapability.[[Promise]]. + + Async-from-Sync Iterator Value Unwrap Functions + An async-from-sync iterator value unwrap function is an anonymous built-in + function that is used by methods of %AsyncFromSyncIteratorPrototype% when + processing the value field of an IteratorResult object, in order to wait for + its value if it is a promise and re-package the result in a new "unwrapped" + IteratorResult object. Each async iterator value unwrap function has a + [[Done]] internal slot. + +flags: [async] +features: [async-iteration] +---*/ + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + return() { + return { + value: Promise.resolve(42), + done: true + }; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +let iter = asyncg(); + +iter.next().then(function (result) { + iter.return().then( + function (result) { + assert.sameValue(result.value, 42, "Result.value should be unwrapped, got: " + result.value); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js new file mode 100644 index 0000000000..38ac3eeaa5 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js @@ -0,0 +1,56 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will return a iterator result object when built-in sync throw is called +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + ... + 8. Let returnResult be Call(return, syncIterator, « value »). + ... + 22. Return promiseCapability.[[Promise]]. + + Generator.prototype.return ( value ) + 1. Let g be the this value. + 2. Let C be Completion{[[Type]]: return, [[Value]]: value, [[Target]]: empty}. + 3. Return ? GeneratorResumeAbrupt(g, C). + +flags: [async] +features: [async-iteration] +---*/ + +function* g() { + yield 42; + throw new Test262Error('return closes iter'); + yield 43; +} + +async function* asyncg() { + yield* g(); +} + +var iter = asyncg(); +var val = 'some specific return value' + +iter.next().then(function(result) { + + // return will call sync generator prototype built-in function return + iter.return(val).then(function(result) { + + assert.sameValue(result.done, true, 'the iterator is completed'); + assert.sameValue(result.value, val, 'expect agrument to `return`'); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + + }).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js new file mode 100644 index 0000000000..c91a1954d5 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js @@ -0,0 +1,60 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will return rejected promise if getter of `return` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + 6. IfAbruptRejectPromise(return, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + get return() { + throw thrownError; + } + } + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js new file mode 100644 index 0000000000..19d2be92d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js @@ -0,0 +1,66 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will return rejected promise if getter of `return` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + 6. IfAbruptRejectPromise(return, promiseCapability). + ... + 8. Let returnResult be Call(return, syncIterator, « value »). + ... + 10. If Type(returnResult) is not Object, + a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »). + b. Return promiseCapability.[[Promise]]. + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + return() { + throw thrownError; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js new file mode 100644 index 0000000000..153ff47f41 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js @@ -0,0 +1,65 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: return() will return rejected promise if getter of `return` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + 6. IfAbruptRejectPromise(return, promiseCapability). + ... + 8. Let returnResult be Call(return, syncIterator, « value »). + ... + 10. If Type(returnResult) is not Object, + a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »). + b. Return promiseCapability.[[Promise]]. + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + return() { + return 1; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + let typeerror = err instanceof TypeError; + assert(typeerror, "Expect TypeError, got: " + err); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js new file mode 100644 index 0000000000..50f94bba85 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js @@ -0,0 +1,55 @@ +// |reftest| async +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.return +description: > + If syncIterator's "return" method is `null`, + a Promise resolved with `undefined` value is returned. +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + + [...] + 5. Let return be GetMethod(syncIterator, "return"). + [...] + 7. If return is undefined, then + a. Let iterResult be ! CreateIterResultObject(value, true). + b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »). + c. Return promiseCapability.[[Promise]]. + + GetMethod ( V, P ) + + [...] + 2. Let func be ? GetV(V, P). + 3. If func is either undefined or null, return undefined. +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var iterationCount = 0; +var returnGets = 0; + +var syncIterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return {value: 1, done: false}; + }, + get return() { + returnGets += 1; + return null; + }, +}; + +asyncTest(async function() { + for await (let _ of syncIterator) { + iterationCount += 1; + break; + } + + assert.sameValue(iterationCount, 1); + assert.sameValue(returnGets, 1); +}); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js new file mode 100644 index 0000000000..5e5e766288 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js @@ -0,0 +1,55 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: return() will return value undefined if sync `return` is undefined +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "return"). + 6. IfAbruptRejectPromise(return, promiseCapability). + 7. If return is undefined, then + a. Let iterResult be ! CreateIterResultObject(value, true). + b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »). + c. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.return().then(function(result) { + + assert.sameValue(result.done, true, 'the iterator is completed'); + assert.sameValue(result.value, undefined, 'expect value to be undefined'); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + + }).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js new file mode 100644 index 0000000000..ae18ad584d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js @@ -0,0 +1,113 @@ +// GENERATED, DO NOT EDIT +// file: asyncHelpers.js +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + A collection of assertion and wrapper functions for testing asynchronous built-ins. +defines: [asyncTest] +---*/ + +function asyncTest(testFunc) { + if (!Object.hasOwn(globalThis, "$DONE")) { + throw new Test262Error("asyncTest called without async flag"); + } + if (typeof testFunc !== "function") { + $DONE(new Test262Error("asyncTest called with non-function argument")); + return; + } + try { + testFunc().then( + function () { + $DONE(); + }, + function (error) { + $DONE(error); + } + ); + } catch (syncError) { + $DONE(syncError); + } +} + +assert.throwsAsync = async function (expectedErrorConstructor, func, message) { + var innerThenable; + if (message === undefined) { + message = ""; + } else { + message += " "; + } + if (typeof func === "function") { + try { + innerThenable = func(); + if ( + innerThenable === null || + typeof innerThenable !== "object" || + typeof innerThenable.then !== "function" + ) { + message += + "Expected to obtain an inner promise that would reject with a" + + expectedErrorConstructor.name + + " but result was not a thenable"; + throw new Test262Error(message); + } + } catch (thrown) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise"; + throw new Test262Error(message); + } + } else { + message += + "assert.throwsAsync called with an argument that is not a function"; + throw new Test262Error(message); + } + + try { + return innerThenable.then( + function () { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but no exception was thrown at all"; + throw new Test262Error(message); + }, + function (thrown) { + var expectedName, actualName; + if (typeof thrown !== "object" || thrown === null) { + message += "Thrown value was not an object!"; + throw new Test262Error(message); + } else if (thrown.constructor !== expectedErrorConstructor) { + expectedName = expectedErrorConstructor.name; + actualName = thrown.constructor.name; + if (expectedName === actualName) { + message += + "Expected a " + + expectedName + + " but got a different error constructor with the same name"; + } else { + message += + "Expected a " + expectedName + " but got a " + actualName; + } + throw new Test262Error(message); + } + } + ); + } catch (thrown) { + if (typeof thrown !== "object" || thrown === null) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object "; + } else { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but a " + + thrown.constructor.name + + " was thrown synchronously"; + } + throw new Test262Error(message); + } +}; diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js new file mode 100644 index 0000000000..bab1bf956d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js @@ -0,0 +1,70 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will reject promise if getter `done` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + ... + 8. Let throwResult be Call(throw, syncIterator, « value »). + ... + 11. Let throwDone be IteratorComplete(throwResult). + 12. IfAbruptRejectPromise(throwDone, promiseCapability). + 13. Let throwValue be IteratorValue(throwResult). + 14. IfAbruptRejectPromise(throwValue, promiseCapability). + ... + 20. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + return { + get done() { + throw thrownError; + }, + value: 1 + }; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.throw().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js new file mode 100644 index 0000000000..9745df52c1 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js @@ -0,0 +1,70 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will reject promise if getter `value` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + ... + 8. Let throwResult be Call(throw, syncIterator, « value »). + ... + 11. Let throwDone be IteratorComplete(throwResult). + 12. IfAbruptRejectPromise(throwDone, promiseCapability). + 13. Let throwValue be IteratorValue(throwResult). + 14. IfAbruptRejectPromise(throwValue, promiseCapability). + ... + 20. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + return { + get value() { + throw thrownError; + }, + done: false + }; + } + } + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.throw().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js new file mode 100644 index 0000000000..4d27039be8 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js @@ -0,0 +1,84 @@ +// |reftest| async +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. Let syncIterator be syncIteratorRecord.[[Iterator]]. + 6. Let throw be GetMethod(syncIterator, "throw"). + ... + 9. If value is present, then + ... + 10. Else, + a. Let result be Call(throw,syncIterator). + ... + 13. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + ... + 12. If done is true, or if closeOnRejection is false, then + ... + 13. Else, + a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called: + i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)). + b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »). + c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise. + 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability). + 15. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +function Reject() {} + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + return { + value: Promise.reject(new Reject()), + done: false + }; + }, + return() { + returnCount += 1; + } + }; + } +}; + +async function* asyncg() { + return yield* obj; +} + +let iter = asyncg(); + +asyncTest(async function () { + await assert.throwsAsync(Reject, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js new file mode 100644 index 0000000000..9542254c75 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js @@ -0,0 +1,66 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will unwrap a Promise value return by the sync iterator +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + ... + 17. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions. + ... + 20. Return promiseCapability.[[Promise]]. + + Async-from-Sync Iterator Value Unwrap Functions + An async-from-sync iterator value unwrap function is an anonymous built-in + function that is used by methods of %AsyncFromSyncIteratorPrototype% when + processing the value field of an IteratorResult object, in order to wait for + its value if it is a promise and re-package the result in a new "unwrapped" + IteratorResult object. Each async iterator value unwrap function has a + [[Done]] internal slot. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Don't catch me.") + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + return { + value: Promise.resolve(42), + done: true + }; + } + }; + } +}; + +async function* asyncg() { + return yield* obj; +} + +let iter = asyncg(); + +iter.next().then(function (result) { + iter.throw(thrownError).then( + function (result) { + assert.sameValue(result.value, 42, "Result.value should be unwrapped, got: " + result.value); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js new file mode 100644 index 0000000000..90b02da8c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js @@ -0,0 +1,60 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will call default sync throw +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + ... + 8. Let throwResult be Call(throw, syncIterator, « value ») + 9. IfAbruptRejectPromise(throwResult, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + + Generator.prototype.throw ( exception ) + 1. Let g be the this value. + 2. Let C be Completion{[[Type]]: throw, [[Value]]: exception, [[Target]]: empty}. + 3. Return ? GeneratorResumeAbrupt(g, C). + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me.") + +function* g() { + yield 42; + throw new Test262Error('throw closes iter'); + yield 43; +} + +async function* asyncg() { + yield* g(); +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + // throw will call sync generator prototype built-in function throw + iter.throw(thrownError).then( + function(result) { + throw new Test262Error('throw should cause rejection of promise'); + }, + function(err) { + assert.sameValue(err, thrownError, "promise should be reject with custom error, got: " + err) + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js new file mode 100644 index 0000000000..5a87c2e2ba --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js @@ -0,0 +1,59 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will return rejected promise if getter of `throw` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.return ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(throw, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + get throw() { + throw thrownError; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.throw().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js new file mode 100644 index 0000000000..15656dbff8 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js @@ -0,0 +1,61 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will return rejected promise if getter of `throw` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(throw, promiseCapability). + ... + 8. Let throwResult be Call(throw, syncIterator, « value »). + 9. IfAbruptRejectPromise(throwResult, promiseCapability). + ... + 22. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Catch me."); + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + throw thrownError; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.throw().then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + assert.sameValue(err, thrownError, "Promise should be rejected with thrown error"); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); +}).catch($DONE); diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js new file mode 100644 index 0000000000..f59d06cc8a --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js @@ -0,0 +1,65 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will return rejected promise if getter of `throw` abrupt completes +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let throw be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(thow, promiseCapability). + ... + 8. Let throwResult be Call(throw, syncIterator, « value »). + ... + 10. If Type(throwResult) is not Object, + a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »). + b. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +---*/ + +var thrownError = new Error("Don't catch me.") + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + return 1; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +iter.next().then(function(result) { + + iter.throw(thrownError).then( + function (result) { + throw new Test262Error("Promise should be rejected, got: " + result.value); + }, + function (err) { + let typeerror = err instanceof TypeError; + assert(typeerror, "Expect TypeError, got: " + err); + + iter.next().then(({ done, value }) => { + assert.sameValue(done, true, 'the iterator is completed'); + assert.sameValue(value, undefined, 'value is undefined'); + }).then($DONE, $DONE); + } + ).catch($DONE); + +}).catch($DONE); + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js new file mode 100644 index 0000000000..ae18ad584d --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js @@ -0,0 +1,113 @@ +// GENERATED, DO NOT EDIT +// file: asyncHelpers.js +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + A collection of assertion and wrapper functions for testing asynchronous built-ins. +defines: [asyncTest] +---*/ + +function asyncTest(testFunc) { + if (!Object.hasOwn(globalThis, "$DONE")) { + throw new Test262Error("asyncTest called without async flag"); + } + if (typeof testFunc !== "function") { + $DONE(new Test262Error("asyncTest called with non-function argument")); + return; + } + try { + testFunc().then( + function () { + $DONE(); + }, + function (error) { + $DONE(error); + } + ); + } catch (syncError) { + $DONE(syncError); + } +} + +assert.throwsAsync = async function (expectedErrorConstructor, func, message) { + var innerThenable; + if (message === undefined) { + message = ""; + } else { + message += " "; + } + if (typeof func === "function") { + try { + innerThenable = func(); + if ( + innerThenable === null || + typeof innerThenable !== "object" || + typeof innerThenable.then !== "function" + ) { + message += + "Expected to obtain an inner promise that would reject with a" + + expectedErrorConstructor.name + + " but result was not a thenable"; + throw new Test262Error(message); + } + } catch (thrown) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise"; + throw new Test262Error(message); + } + } else { + message += + "assert.throwsAsync called with an argument that is not a function"; + throw new Test262Error(message); + } + + try { + return innerThenable.then( + function () { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but no exception was thrown at all"; + throw new Test262Error(message); + }, + function (thrown) { + var expectedName, actualName; + if (typeof thrown !== "object" || thrown === null) { + message += "Thrown value was not an object!"; + throw new Test262Error(message); + } else if (thrown.constructor !== expectedErrorConstructor) { + expectedName = expectedErrorConstructor.name; + actualName = thrown.constructor.name; + if (expectedName === actualName) { + message += + "Expected a " + + expectedName + + " but got a different error constructor with the same name"; + } else { + message += + "Expected a " + expectedName + " but got a " + actualName; + } + throw new Test262Error(message); + } + } + ); + } catch (thrown) { + if (typeof thrown !== "object" || thrown === null) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object "; + } else { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but a " + + thrown.constructor.name + + " was thrown synchronously"; + } + throw new Test262Error(message); + } +}; diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js new file mode 100644 index 0000000000..afe9c0d2a3 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js @@ -0,0 +1,60 @@ +// |reftest| async +// Copyright (C) 2020 Alexey Shvayka. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: > + If syncIterator's "throw" method is `null`, + a Promise rejected with provided value is returned. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + + [...] + 6. Let throw be GetMethod(syncIterator, "throw"). + [...] + 8. If throw is undefined, then + ... + g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). + h. Return promiseCapability.[[Promise]]. + + GetMethod ( V, P ) + + [...] + 2. Let func be ? GetV(V, P). + 3. If func is either undefined or null, return undefined. +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var throwGets = 0; +var syncIterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return {value: 1, done: false}; + }, + get throw() { + throwGets += 1; + return null; + }, +}; + +async function* asyncGenerator() { + yield* syncIterator; +} + +var asyncIterator = asyncGenerator(); +var thrownError = { name: "err" }; + +asyncTest(async function () { + await assert.throwsAsync(TypeError, async () => { + await asyncIterator.next(); + return asyncIterator.throw(thrownError); + }, "Promise should be rejected"); + const result = await asyncIterator.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js new file mode 100644 index 0000000000..4edbcfe390 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js @@ -0,0 +1,91 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will reject promise if resolving result promise abrupt completes. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 3. Let promiseCapability be ! NewPromiseCapability(%Promise%). + 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]]. + 5. Let syncIterator be syncIteratorRecord.[[Iterator]]. + 6. Let throw be GetMethod(syncIterator, "throw"). + 7. IfAbruptRejectPromise(throw, promiseCapability). + 8. If throw is undefined, then + ... + 9. If value is present, then + ... + 10. Else, + a. Let result be Call(throw, syncIterator). + ... + 13. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true). + + AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection ) + 1. Let done be IteratorComplete(result). + 2. IfAbruptRejectPromise(done, promiseCapability). + 3. Let value be IteratorValue(result). + 4. IfAbruptRejectPromise(value, promiseCapability). + 5. Let valueWrapper be PromiseResolve(%Promise%, value). + 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then + a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper). + 7. IfAbruptRejectPromise(valueWrapper, promiseCapability). + ... + + IfAbruptRejectPromise ( value, capability ) + 1. Assert: value is a Completion Record. + 2. If value is an abrupt completion, then + a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). + b. Return capability.[[Promise]]. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +function CatchError() {} +var thrownError = new CatchError(); +var uncaughtError = new Error("Don't catch me"); + +const obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + }, + throw() { + const p = Promise.resolve('FAIL'); + Object.defineProperty(p, 'constructor', { + get() { + throw thrownError; + } + }); + return { value: p, done: false }; + }, + return() { + returnCount += 1; + return { value: undefined, done: true }; + } + }; + } +}; + +async function* asyncg() { + return yield* obj; +} + +let iter = asyncg(); + +asyncTest(async function () { + await assert.throwsAsync(CatchError, async () => { + await iter.next(); + return iter.throw(uncaughtError); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js new file mode 100644 index 0000000000..c3ef881b7b --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js @@ -0,0 +1,74 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: > + If syncIterator's "throw" method is `undefined`, + and its "return" method returns `undefined`, + the iterator will close returning the `undefined` value, + which will be ignored and instead a rejected Promise with a new TypeError is returned. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(throw, promiseCapability). + 7. If throw is undefined, then + a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability. + b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }. + c. Set result to IteratorClose(syncIteratorRecord, closeCompletion). + ... + g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). + h. Return promiseCapability.[[Promise]]. + ... + + IteratorClose ( iterator, completion ) + ... + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult.[[Type]] is normal, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; + +const obj = { + [Symbol.iterator]() { + return { + next() { + return {value: 1, done: false}; + }, + get return() { + returnCount += 1; + return undefined; + } + }; + } +}; + +async function* wrapper() { + yield* obj; +} + +var iter = wrapper(); + +asyncTest(async function () { + await assert.throwsAsync(TypeError, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) + diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js new file mode 100644 index 0000000000..5b0b5ae56a --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js @@ -0,0 +1,78 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will close the iterator and return rejected promise if sync `throw` undefined +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(throw, promiseCapability). + 7. If throw is undefined, then + a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability. + b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }. + c. Set result to IteratorClose(syncIteratorRecord, closeCompletion). + d. IfAbruptRejectPromise(result, promiseCapability). + e. NOTE: The next step throws a TypeError to indicate that there was a protocol violation: syncIterator does not have a throw method. + f. NOTE: If closing syncIterator does not throw then the result of that operation is ignored, even if it yields a rejected promise. + g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). + h. Return promiseCapability.[[Promise]]. + + IteratorClose ( iterator, completion ) + ... + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + ... + 6. If innerResult.[[Type]] is throw, return ? innerResult. + ... + + IfAbruptRejectPromise ( value, capability ) + 1. Assert: value is a Completion Record. + 2. If value is an abrupt completion, then + a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). + b. Return capability.[[Promise]]. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; +function CatchError() {} +var thrownError = new CatchError(); + +const obj = { + [Symbol.iterator]() { + return { + next() { + return {value: 1, done: false}; + }, + get return() { + returnCount += 1; + throw thrownError; + } + }; + } +}; + +async function* wrapper() { + yield* obj; +} + +var iter = wrapper(); + +asyncTest(async function () { + await assert.throwsAsync(CatchError, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js new file mode 100644 index 0000000000..28de5558e0 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js @@ -0,0 +1,81 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: > + If syncIterator's "throw" method is `undefined`, + and its "return" method returns `undefined`, + the iterator will close returning the `undefined` value, + which will be ignored and instead a rejected Promise with a new TypeError is returned. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "throw"). + 6. IfAbruptRejectPromise(throw, promiseCapability). + 7. If throw is undefined, then + a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability. + b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }. + c. Set result to IteratorClose(syncIteratorRecord, closeCompletion). + d. IfAbruptRejectPromise(result, promiseCapability). + ... + + IteratorClose ( iterator, completion ) + ... + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult.[[Type]] is normal, then + a. Let return be innerResult.[[Value]]. + ... + c. Set innerResult to Completion(Call(return, iterator)). + ... + 7. If innerResult.[[Value]] is not an Object, throw a TypeError exception. + ... + + IfAbruptRejectPromise ( value, capability ) + 1. Assert: value is a Completion Record. + 2. If value is an abrupt completion, then + a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). + b. Return capability.[[Promise]]. + ... + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; + +const obj = { + [Symbol.iterator]() { + return { + next() { + return {value: 1, done: false}; + }, + return() { + returnCount += 1; + return 2; + } + }; + } +}; + +async function* wrapper() { + yield* obj; +} + +var iter = wrapper(); + +asyncTest(async function () { + await assert.throwsAsync(TypeError, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js new file mode 100644 index 0000000000..30e660a0e8 --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js @@ -0,0 +1,75 @@ +// |reftest| async +// Copyright (C) 2023 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: > + If syncIterator's "throw" method is `undefined`, + and its "return" method returns `undefined`, + the iterator will close returning the `undefined` value, + which will be ignored and instead a rejected Promise with a new TypeError is returned. +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 5. Let return be GetMethod(syncIterator, "throw"). + ... + 7. If throw is undefined, then + a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability. + b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }. + c. Set result to IteratorClose(syncIteratorRecord, closeCompletion). + ... + g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). + h. Return promiseCapability.[[Promise]]. + ... + + IteratorClose ( iterator, completion ) + ... + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult.[[Type]] is normal, then + a. Let return be innerResult.[[Value]]. + ... + c. Set innerResult to Completion(Call(return, iterator)). + ... + 8. Return ? completion. + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var returnCount = 0; + +const obj = { + [Symbol.iterator]() { + return { + next() { + return {value: 1, done: false}; + }, + return() { + returnCount += 1; + return {value: 2, done: true}; + } + }; + } +}; + +async function* wrapper() { + yield* obj; +} + +var iter = wrapper(); + +asyncTest(async function () { + await assert.throwsAsync(TypeError, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + assert.sameValue(returnCount, 1, 'iterator closed properly'); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js new file mode 100644 index 0000000000..4c478c270b --- /dev/null +++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js @@ -0,0 +1,49 @@ +// |reftest| async +// Copyright (C) 2018 Valerie Young. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-%asyncfromsynciteratorprototype%.throw +description: throw() will return rejected promise if sync `throw` undefined +info: | + %AsyncFromSyncIteratorPrototype%.throw ( value ) + ... + 2. Let promiseCapability be ! NewPromiseCapability(%Promise%). + ... + 6. Let throw be GetMethod(syncIterator, "throw"). + [...] + 8. If throw is undefined, then + ... + g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »). + h. Return promiseCapability.[[Promise]]. + +flags: [async] +features: [async-iteration] +includes: [asyncHelpers.js] +---*/ + +var obj = { + [Symbol.iterator]() { + return { + next() { + return { value: 1, done: false }; + } + }; + } +}; + +async function* asyncg() { + yield* obj; +} + +var iter = asyncg(); + +asyncTest(async function () { + await assert.throwsAsync(TypeError, async () => { + await iter.next(); + return iter.throw(); + }, "Promise should be rejected"); + const result = await iter.next(); + assert(result.done, "the iterator is completed"); + assert.sameValue(result.value, undefined, "value is undefined"); +}) |