| Index: test/mjsunit/harmony/async-from-sync-iterator.js
|
| diff --git a/test/mjsunit/harmony/async-from-sync-iterator.js b/test/mjsunit/harmony/async-from-sync-iterator.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2f0e674a316b2c561b0f5d5a6993e8ee27061f33
|
| --- /dev/null
|
| +++ b/test/mjsunit/harmony/async-from-sync-iterator.js
|
| @@ -0,0 +1,437 @@
|
| +// Copyright 2017 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Flags: --harmony-async-iteration --allow-natives-syntax
|
| +
|
| +let testFailed = false;
|
| +let testFailure;
|
| +
|
| +class MyError extends Error {};
|
| +
|
| +(async function() {
|
| + function* gen() {
|
| + yield "sync value";
|
| + try {
|
| + yield new Promise(function(resolve) {
|
| + resolve("async value");
|
| + });
|
| + } catch (error) {
|
| + throw error;
|
| + }
|
| + assertUnreachable("generator is closed");
|
| + }
|
| + let iter = %CreateAsyncFromSyncIterator(gen());
|
| +
|
| + // [Async-from-Sync Iterator] wraps sync iterator values in a Promise
|
| + let promise = iter.next();
|
| + assertInstanceof(promise, Promise);
|
| + let iter_result = await promise;
|
| + assertEquals({ value: "sync value", done: false }, iter_result);
|
| +
|
| + // [Async-from-Sync Iterator] will wait for resolution of Promise values
|
| + promise = iter.next();
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "async value", done: false }, iter_result);
|
| +
|
| + // [Async-from-Sync Iterator].throw delegates to .throw() method of sync
|
| + // iterator.
|
| + promise = iter.throw(new MyError("Error#1"));
|
| + assertInstanceof(promise, Promise);
|
| + try {
|
| + await promise;
|
| + assertUnreachable("promise should be rejected");
|
| + } catch (e) {
|
| + assertInstanceof(e, MyError);
|
| + assertEquals("Error#1", e.message);
|
| + }
|
| +
|
| + promise = iter.return("generator closed");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "generator closed", done: true }, iter_result);
|
| +
|
| + // .next(), .return() and .throw() delegate to sync iterator methods, without
|
| + // keeping track of the state of the generator.
|
| + promise = iter.next("unused");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: undefined, done: true }, iter_result);
|
| +
|
| + promise = iter.throw(new MyError("Error#2"));
|
| + assertInstanceof(promise, Promise);
|
| + try {
|
| + await promise;
|
| + } catch (e) {
|
| + assertInstanceof(e, MyError);
|
| + assertEquals("Error#2", e.message);
|
| + }
|
| +
|
| + promise = iter.return("return-after-completed");
|
| + assertInstanceof(promise, Promise);
|
| + iter_result = await promise;
|
| + assertEquals({ value: "return-after-completed", done: true }, iter_result);
|
| +
|
| + function resolveLater(value) {
|
| + return new Promise(function(resolve) {
|
| + Promise.resolve().then(function() {
|
| + resolve(value);
|
| + });
|
| + });
|
| + }
|
| +
|
| + function rejectLater(value) {
|
| + return new Promise(function(resolve, reject) {
|
| + Promise.resolve().then(function() {
|
| + reject(value);
|
| + });
|
| + });
|
| + }
|
| +
|
| + const kNext = 1;
|
| + const kThrow = 2;
|
| + const kReturn = 4;
|
| + const kNextThrows = kNext | 8;
|
| + const kReturnThrows = kReturn | 16;
|
| + const kThrowNormal = kThrow | 32;
|
| + function sync(array, features, log = []) {
|
| + let i = 0;
|
| + let methods = {
|
| + next(sent) {
|
| + let done = i >= array.length;
|
| + let value = array[i];
|
| + log.push({ method: "next", sent, value, done });
|
| + if ((features & kNextThrows) === kNextThrows) throw sent;
|
| + i++;
|
| + return { value, done };
|
| + },
|
| + throw(sent) {
|
| + let done = i >= array.length;
|
| + let value = undefined;
|
| + log.push({ method: "throw", sent, value, done });
|
| + if ((features & kThrowNormal) === kThrowNormal)
|
| + return { value: sent, done };
|
| + throw sent;
|
| + },
|
| + return(sent) {
|
| + let done = true;
|
| + let value = undefined;
|
| + log.push({ method: "return", sent, value, done });
|
| + if ((features & kReturnThrows) === kReturnThrows) throw sent;
|
| + return { value, done };
|
| + }
|
| + };
|
| + return {
|
| + [Symbol.iterator]() { return this; },
|
| + next: (features & kNext) ? methods.next : undefined,
|
| + throw: (features & kThrow) ? methods.throw : undefined,
|
| + return: (features & kReturn) ? methods.return : undefined
|
| + };
|
| + }
|
| +
|
| + let log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0));
|
| +
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable("Iterator.next() method is not optional");
|
| + } catch (e) {
|
| + assertInstanceof(e, TypeError);
|
| + assertEquals([], log);
|
| + }
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log));
|
| + assertEquals({ value: "sync-value", done: false }, await iter.next("a"));
|
| + assertEquals([
|
| + {
|
| + method: "next",
|
| + sent: "a",
|
| + value: "sync-value",
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + log = [];
|
| + let asyncValue = resolveLater("async-value");
|
| + iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
|
| + assertEquals({ value: "async-value", done: false }, await iter.next("b"));
|
| + assertEquals([
|
| + {
|
| + method: "next",
|
| + sent: "b",
|
| + value: asyncValue,
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].next() produces a rejected Promise or an exception is
|
| + // thrown, Promise is rejected with thrown/rejected value.
|
| + log = [];
|
| + asyncValue = rejectLater("Boo!");
|
| + iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
|
| + try {
|
| + await iter.next('c');
|
| + assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals("Boo!", e);
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'c',
|
| + value: asyncValue,
|
| + done: false
|
| + }
|
| + ], log);
|
| + }
|
| +
|
| + // If [sync_iterator].return() does not exist, return a Promise resolved with
|
| + // the value `{ value: <<sent value>>, done: true }`.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log));
|
| + assertEquals({
|
| + value: 'd',
|
| + done: true
|
| + }, await iter.return('d'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({
|
| + value: 'sync-return',
|
| + done: false
|
| + }, await iter.next('e'));
|
| +
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'e',
|
| + value: 'sync-return',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].return() does exist, return a Promise resolved with
|
| + // the iterator result of [sync_iterator].return().
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-return'],
|
| + kNext|kReturn, log));
|
| + assertEquals({
|
| + value: undefined,
|
| + done: true
|
| + }, await iter.return('f'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({
|
| + value: 'sync-return',
|
| + done: false
|
| + }, await iter.next('g'));
|
| +
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: 'f',
|
| + value: undefined,
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'g',
|
| + value: 'sync-return',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].return() produces a rejected Promise or an exception is
|
| + // thrown, Promise is rejected with thrown/rejected value.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows,
|
| + log));
|
| + try {
|
| + await iter.return('Boo!!');
|
| + assertUnreachable('Expected `iter.return(\'Boo!!\') to throw, but did ' +
|
| + 'not throw');
|
| + } catch (e) {
|
| + assertEquals("Boo!!", e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('h'));
|
| + assertEquals([
|
| + {
|
| + method: 'return',
|
| + sent: 'Boo!!',
|
| + value: undefined,
|
| + done: true
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'h',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].throw() does exist, return a Promise rejected with
|
| + // the sent value.
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log));
|
| + try {
|
| + await iter.throw('Boo!!');
|
| + assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
|
| + 'throw');
|
| + } catch (e) {
|
| + assertEquals('Boo!!', e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('i'));
|
| + assertEquals([
|
| + {
|
| + method: 'next',
|
| + sent: 'i',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log));
|
| + try {
|
| + await iter.throw('Boo!!');
|
| + assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
|
| + 'throw');
|
| + } catch (e) {
|
| + assertEquals('Boo!!', e);
|
| + }
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('j'));
|
| + assertEquals([
|
| + {
|
| + method: 'throw',
|
| + sent: 'Boo!!',
|
| + value: undefined,
|
| + done: false
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'j',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // If [sync_iterator].throw() returns a resolved Promise or a Completion
|
| + // with [[Type]] "normal" or "return", return a resolved Promise
|
| + log = [];
|
| + iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal,
|
| + log));
|
| + assertEquals({
|
| + value: 'Boo!!',
|
| + done: false
|
| + }, await iter.throw('Boo!!'));
|
| +
|
| + // [Async-from-Sync Iterator] merely delegates, and does not keep track of
|
| + // whether [sync_iterator] is completed or not.
|
| + assertEquals({ value: 'sync-value', done: false }, await iter.next('k'));
|
| + assertEquals([
|
| + {
|
| + method: 'throw',
|
| + sent: 'Boo!!',
|
| + value: undefined,
|
| + done: false
|
| + },
|
| + {
|
| + method: 'next',
|
| + sent: 'k',
|
| + value: 'sync-value',
|
| + done: false
|
| + }
|
| + ], log);
|
| +
|
| + // Let nextValue be IteratorValue(nextResult).
|
| + // IfAbruptRejectPromise(nextValue, promiseCapability).)
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + next() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable('Expected `iter.next()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // Let nextDone be IteratorComplete(nextResult).
|
| + // IfAbruptRejectPromise(nextDone, promiseCapability).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + next() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.next();
|
| + assertUnreachable('Expected `iter.next()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(returnResult, promiseCapability).
|
| + // Let returnValue be IteratorValue(returnResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + return() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.return();
|
| + assertUnreachable('Expected `iter.return()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(returnValue, promiseCapability).
|
| + // Let returnDone be IteratorComplete(returnResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + return() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.return();
|
| + assertUnreachable('Expected `iter.return()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(throwResult, promiseCapability).
|
| + // Let throwValue be IteratorValue(throwResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + throw() { return { get value() { throw "BadValue!" }, done: false }; }
|
| + });
|
| + try {
|
| + await iter.throw();
|
| + assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +
|
| + // IfAbruptRejectPromise(throwValue, promiseCapability).
|
| + // Let throwDone be IteratorComplete(throwResult).
|
| + iter = %CreateAsyncFromSyncIterator({
|
| + throw() { return { value: undefined, get done() { throw "BadValue!" } }; }
|
| + });
|
| + try {
|
| + await iter.throw();
|
| + assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
|
| + } catch (e) {
|
| + assertEquals('BadValue!', e);
|
| + }
|
| +})().catch(function(error) {
|
| + testFailed = true;
|
| + testFailure = error;
|
| +});
|
| +
|
| +%RunMicrotasks();
|
| +
|
| +if (testFailed) {
|
| + throw testFailure;
|
| +}
|
|
|