-
Notifications
You must be signed in to change notification settings - Fork 479
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test that async-from-sync iterator closes when throw is undefined.
These test paths from newly added call to IteratorClose in step 7.c of %AsyncFromSyncIteratorPrototype%.throw as per normative changes of ecma626 PR 2600
- Loading branch information
Showing
4 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
80 changes: 80 additions & 0 deletions
80
test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// 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] | ||
---*/ | ||
|
||
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(); | ||
|
||
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.constructor, TypeError, "TypeError"); | ||
assert.sameValue(err.message, 'The iterator does not provide a throw method'); | ||
assert.sameValue(returnCount, 1, 'iterator closed properly'); | ||
|
||
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); | ||
|
82 changes: 82 additions & 0 deletions
82
test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// 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] | ||
---*/ | ||
|
||
var returnCount = 0; | ||
var thrownError = new Error("Catch me."); | ||
|
||
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(); | ||
|
||
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"); | ||
assert.sameValue(returnCount, 1, 'iterator closed properly'); | ||
|
||
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); |
87 changes: 87 additions & 0 deletions
87
test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// 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] | ||
---*/ | ||
|
||
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(); | ||
|
||
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.constructor, TypeError, "TypeError"); | ||
assert.sameValue(err.message, '2 is not an object'); | ||
assert.sameValue(returnCount, 1, 'iterator closed properly'); | ||
|
||
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); |
82 changes: 82 additions & 0 deletions
82
test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// 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] | ||
---*/ | ||
|
||
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(); | ||
|
||
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.constructor, TypeError, "TypeError"); | ||
assert.sameValue(err.message, 'The iterator does not provide a throw method'); | ||
assert.sameValue(returnCount, 1, 'iterator closed properly'); | ||
|
||
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); | ||
|