Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: test/mjsunit/harmony/async-from-sync-iterator.js

Issue 2645313003: [async-iteration] implement Async-from-Sync Iterator (Closed)
Patch Set: rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Flags: --harmony-async-iteration --allow-natives-syntax
6
7 let testFailed = false;
8 let testFailure;
9
10 function assertThrowsAsync(run, errorType, message) {
11 var actual;
12 var hadValue = false;
13 var hadError = false;
14 var promise = run();
15
16 if (typeof promise !== "object" || typeof promise.then !== "function") {
17 throw new MjsUnitAssertionError(
18 "Expected " + run.toString() +
19 " to return a Promise, but it returned " + PrettyPrint(promise));
20 }
21
22 promise.then(function(value) { hadValue = true; actual = value; },
23 function(error) { hadError = true; actual = error; });
24
25 assertFalse(hadValue || hadError);
26
27 %RunMicrotasks();
28
29 if (!hadError) {
30 throw new MjsUnitAssertionError(
31 "Expected " + run + "() to throw " + errorType.name +
32 ", but did not throw.");
33 }
34 if (!(actual instanceof errorType))
35 throw new MjsUnitAssertionError(
36 "Expected " + run + "() to throw " + errorType.name +
37 ", but threw '" + actual + "'");
38 if (message !== void 0 && actual.message !== message)
39 throw new MjsUnitAssertionError(
40 "Expected " + run + "() to throw '" + message + "', but threw '" +
41 actual.message + "'");
42 };
43
44 class MyError extends Error {};
45
46 (async function() {
47 function* gen() {
48 yield "sync value";
49 try {
50 yield new Promise(function(resolve) {
51 resolve("async value");
52 });
53 } catch (error) {
54 throw error;
55 }
56 assertUnreachable("generator is closed");
57 }
58 let iter = %CreateAsyncFromSyncIterator(gen());
59
60 // [Async-from-Sync Iterator] wraps sync iterator values in a Promise
61 let promise = iter.next();
62 assertInstanceof(promise, Promise);
63 let iter_result = await promise;
64 assertEquals({ value: "sync value", done: false }, iter_result);
65
66 // [Async-from-Sync Iterator] will wait for resolution of Promise values
67 promise = iter.next();
68 assertInstanceof(promise, Promise);
69 iter_result = await promise;
70 assertEquals({ value: "async value", done: false }, iter_result);
71
72 // [Async-from-Sync Iterator].throw delegates to .throw() method of sync
73 // iterator.
74 promise = iter.throw(new MyError("Error#1"));
75 assertInstanceof(promise, Promise);
76 try {
77 await promise;
78 assertUnreachable("promise should be rejected");
79 } catch (e) {
80 assertInstanceof(e, MyError);
81 assertEquals("Error#1", e.message);
82 }
83
84 promise = iter.return("generator closed");
85 assertInstanceof(promise, Promise);
86 iter_result = await promise;
87 assertEquals({ value: "generator closed", done: true }, iter_result);
88
89 // .next(), .return() and .throw() delegate to sync iterator methods, without
90 // keeping track of the state of the generator.
91 promise = iter.next("unused");
92 assertInstanceof(promise, Promise);
93 iter_result = await promise;
94 assertEquals({ value: undefined, done: true }, iter_result);
95
96 promise = iter.throw(new MyError("Error#2"));
97 assertInstanceof(promise, Promise);
98 try {
99 await promise;
100 } catch (e) {
101 assertInstanceof(e, MyError);
102 assertEquals("Error#2", e.message);
103 }
104
105 promise = iter.return("return-after-completed");
106 assertInstanceof(promise, Promise);
107 iter_result = await promise;
108 assertEquals({ value: "return-after-completed", done: true }, iter_result);
109
110 function resolveLater(value) {
111 return new Promise(function(resolve) {
112 Promise.resolve().then(function() {
113 resolve(value);
114 });
115 });
116 }
117
118 function rejectLater(value) {
119 return new Promise(function(resolve, reject) {
120 Promise.resolve().then(function() {
121 reject(value);
122 });
123 });
124 }
125
126 const kNext = 1;
127 const kThrow = 2;
128 const kReturn = 4;
129 const kNextThrows = kNext | 8;
130 const kReturnThrows = kReturn | 16;
131 const kThrowNormal = kThrow | 32;
132 function sync(array, features, log = []) {
133 let i = 0;
134 let methods = {
135 next(sent) {
136 let done = i >= array.length;
137 let value = array[i];
138 log.push({ method: "next", sent, value, done });
139 if ((features & kNextThrows) === kNextThrows) throw sent;
140 i++;
141 return { value, done };
142 },
143 throw(sent) {
144 let done = i >= array.length;
145 let value = undefined;
146 log.push({ method: "throw", sent, value, done });
147 if ((features & kThrowNormal) === kThrowNormal)
148 return { value: sent, done };
149 throw sent;
150 },
151 return(sent) {
152 let done = true;
153 let value = undefined;
154 log.push({ method: "return", sent, value, done });
155 if ((features & kReturnThrows) === kReturnThrows) throw sent;
156 return { value, done };
157 }
158 };
159 return {
160 [Symbol.iterator]() { return this; },
161 next: (features & kNext) ? methods.next : undefined,
162 throw: (features & kThrow) ? methods.throw : undefined,
163 return: (features & kReturn) ? methods.return : undefined
164 };
165 }
166
167 let log = [];
168 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0));
169
170 try {
171 await iter.next();
172 assertUnreachable("Iterator.next() method is not optional");
173 } catch (e) {
174 assertInstanceof(e, TypeError);
175 assertEquals([], log);
176 }
177
178 log = [];
179 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log));
180 assertEquals({ value: "sync-value", done: false }, await iter.next("a"));
181 assertEquals([
182 {
183 method: "next",
184 sent: "a",
185 value: "sync-value",
186 done: false
187 }
188 ], log);
189
190 log = [];
191 let asyncValue = resolveLater("async-value");
192 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
193 assertEquals({ value: "async-value", done: false }, await iter.next("b"));
194 assertEquals([
195 {
196 method: "next",
197 sent: "b",
198 value: asyncValue,
199 done: false
200 }
201 ], log);
202
203 // If [sync_iterator].next() produces a rejected Promise or an exception is
204 // thrown, Promise is rejected with thrown/rejected value.
205 log = [];
206 asyncValue = rejectLater("Boo!");
207 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
208 try {
209 await iter.next('c');
210 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
211 } catch (e) {
212 assertEquals("Boo!", e);
213 assertEquals([
214 {
215 method: 'next',
216 sent: 'c',
217 value: asyncValue,
218 done: false
219 }
220 ], log);
221 }
222
223 // If [sync_iterator].return() does not exist, return a Promise resolved with
224 // the value `{ value: <<sent value>>, done: true }`.
225 log = [];
226 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log));
227 assertEquals({
228 value: 'd',
229 done: true
230 }, await iter.return('d'));
231
232 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
233 // whether [sync_iterator] is completed or not.
234 assertEquals({
235 value: 'sync-return',
236 done: false
237 }, await iter.next('e'));
238
239 assertEquals([
240 {
241 method: 'next',
242 sent: 'e',
243 value: 'sync-return',
244 done: false
245 }
246 ], log);
247
248 // If [sync_iterator].return() does exist, return a Promise resolved with
249 // the iterator result of [sync_iterator].return().
250 log = [];
251 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'],
252 kNext|kReturn, log));
253 assertEquals({
254 value: undefined,
255 done: true
256 }, await iter.return('f'));
257
258 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
259 // whether [sync_iterator] is completed or not.
260 assertEquals({
261 value: 'sync-return',
262 done: false
263 }, await iter.next('g'));
264
265 assertEquals([
266 {
267 method: 'return',
268 sent: 'f',
269 value: undefined,
270 done: true
271 },
272 {
273 method: 'next',
274 sent: 'g',
275 value: 'sync-return',
276 done: false
277 }
278 ], log);
279
280 // If [sync_iterator].return() produces a rejected Promise or an exception is
281 // thrown, Promise is rejected with thrown/rejected value.
282 log = [];
283 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows,
284 log));
285 try {
286 await iter.return('Boo!!');
287 assertUnreachable('Expected `iter.return(\'Boo!!\') to throw, but did ' +
288 'not throw');
289 } catch (e) {
290 assertEquals("Boo!!", e);
291 }
292
293 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
294 // whether [sync_iterator] is completed or not.
295 assertEquals({ value: 'sync-value', done: false }, await iter.next('h'));
296 assertEquals([
297 {
298 method: 'return',
299 sent: 'Boo!!',
300 value: undefined,
301 done: true
302 },
303 {
304 method: 'next',
305 sent: 'h',
306 value: 'sync-value',
307 done: false
308 }
309 ], log);
310
311 // If [sync_iterator].throw() does exist, return a Promise rejected with
312 // the sent value.
313 log = [];
314 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log));
315 try {
316 await iter.throw('Boo!!');
317 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
318 'throw');
319 } catch (e) {
320 assertEquals('Boo!!', e);
321 }
322
323 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
324 // whether [sync_iterator] is completed or not.
325 assertEquals({ value: 'sync-value', done: false }, await iter.next('i'));
326 assertEquals([
327 {
328 method: 'next',
329 sent: 'i',
330 value: 'sync-value',
331 done: false
332 }
333 ], log);
334
335 log = [];
336 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log));
337 try {
338 await iter.throw('Boo!!');
339 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
340 'throw');
341 } catch (e) {
342 assertEquals('Boo!!', e);
343 }
344
345 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
346 // whether [sync_iterator] is completed or not.
347 assertEquals({ value: 'sync-value', done: false }, await iter.next('j'));
348 assertEquals([
349 {
350 method: 'throw',
351 sent: 'Boo!!',
352 value: undefined,
353 done: false
354 },
355 {
356 method: 'next',
357 sent: 'j',
358 value: 'sync-value',
359 done: false
360 }
361 ], log);
362
363 // If [sync_iterator].throw() returns a resolved Promise or a Completion
364 // with [[Type]] "normal" or "return", return a resolved Promise
365 log = [];
366 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal,
367 log));
368 assertEquals({
369 value: 'Boo!!',
370 done: false
371 }, await iter.throw('Boo!!'));
372
373 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
374 // whether [sync_iterator] is completed or not.
375 assertEquals({ value: 'sync-value', done: false }, await iter.next('k'));
376 assertEquals([
377 {
378 method: 'throw',
379 sent: 'Boo!!',
380 value: undefined,
381 done: false
382 },
383 {
384 method: 'next',
385 sent: 'k',
386 value: 'sync-value',
387 done: false
388 }
389 ], log);
390
391 // Let nextValue be IteratorValue(nextResult).
392 // IfAbruptRejectPromise(nextValue, promiseCapability).)
393 iter = %CreateAsyncFromSyncIterator({
394 next() { return { get value() { throw "BadValue!" }, done: false }; }
395 });
396 try {
397 await iter.next();
398 assertUnreachable('Expected `iter.next()` to throw, but did not throw');
399 } catch (e) {
400 assertEquals('BadValue!', e);
401 }
402
403 // Let nextDone be IteratorComplete(nextResult).
404 // IfAbruptRejectPromise(nextDone, promiseCapability).
405 iter = %CreateAsyncFromSyncIterator({
406 next() { return { value: undefined, get done() { throw "BadValue!" } }; }
407 });
408 try {
409 await iter.next();
410 assertUnreachable('Expected `iter.next()` to throw, but did not throw');
411 } catch (e) {
412 assertEquals('BadValue!', e);
413 }
414
415 // IfAbruptRejectPromise(returnResult, promiseCapability).
416 // Let returnValue be IteratorValue(returnResult).
417 iter = %CreateAsyncFromSyncIterator({
418 return() { return { get value() { throw "BadValue!" }, done: false }; }
419 });
420 try {
421 await iter.return();
422 assertUnreachable('Expected `iter.return()` to throw, but did not throw');
423 } catch (e) {
424 assertEquals('BadValue!', e);
425 }
426
427 // IfAbruptRejectPromise(returnValue, promiseCapability).
428 // Let returnDone be IteratorComplete(returnResult).
429 iter = %CreateAsyncFromSyncIterator({
430 return() { return { value: undefined, get done() { throw "BadValue!" } }; }
431 });
432 try {
433 await iter.return();
434 assertUnreachable('Expected `iter.return()` to throw, but did not throw');
435 } catch (e) {
436 assertEquals('BadValue!', e);
437 }
438
439 // IfAbruptRejectPromise(throwResult, promiseCapability).
440 // Let throwValue be IteratorValue(throwResult).
441 iter = %CreateAsyncFromSyncIterator({
442 throw() { return { get value() { throw "BadValue!" }, done: false }; }
443 });
444 try {
445 await iter.throw();
446 assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
447 } catch (e) {
448 assertEquals('BadValue!', e);
449 }
450
451 // IfAbruptRejectPromise(throwValue, promiseCapability).
452 // Let throwDone be IteratorComplete(throwResult).
453 iter = %CreateAsyncFromSyncIterator({
454 throw() { return { value: undefined, get done() { throw "BadValue!" } }; }
455 });
456 try {
457 await iter.throw();
458 assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
459 } catch (e) {
460 assertEquals('BadValue!', e);
461 }
462
463 // Async-from-Sync iterator methods can be extracted via function.caller.
464 // TODO(caitp): test extracted `throw` method using yield* in async generator.
465 let extractor = [0, 1, 2, 3, 4,5,6,7,8,9];
466 let extractedNext;
467 let extractedReturn;
468
469 extractor[Symbol.iterator] = function() {
470 let it = [][Symbol.iterator].call(extractor);
471 let origNext = it.next, origThrow = it.throw, origReturn = it.return;
472 function extractNext() {
473 extractedNext = extractNext.caller;
474 return origNext;
475 }
476 function extractReturn() {
477 extractedReturn = extractReturn.caller;
478 return origReturn;
479 }
480 Object.defineProperties(it, {
481 "next": { get: extractNext, configurable: true },
482 "return": { get: extractReturn, configurable: true }
483 });
484 return it;
485 };
486
487 async function f() {
488 let i;
489 let it = extractor[Symbol.iterator]();
490 for await (let x of it) break;
491 for await (let x of it) return "x";
492 }
493 await f();
494
495 assertEquals(typeof extractedNext, "function");
496 try {
497 await extractedNext.call(undefined);
498 throw new MjsUnitAssertionError(
499 "Expected [Async-from-Sync Iterator].next.call(undefined) to throw " +
500 "a TypeError, but did not throw.");
501 }
502 catch (e) {
503 if (e.constructor !== TypeError) {
504 throw new MjsUnitAssertionError(
505 "Expected [Async-from-Sync Iterator].next.call(undefined) to throw " +
506 "a TypeError, but threw '" + e + "'");
507 }
508 }
509 try {
510 await extractedNext.call(1);
511 throw new MjsUnitAssertionError(
512 "Expected [Async-from-Sync Iterator].next.call(1) to throw " +
513 "a TypeError, but did not throw.");
514 }
515 catch (e) {
516 if (e.constructor !== TypeError) {
517 throw new MjsUnitAssertionError(
518 "Expected [Async-from-Sync Iterator].next.call(1) to throw " +
519 "a TypeError, but threw '" + e + "'");
520 }
521 }
522
523 assertEquals(typeof extractedReturn, "function");
524 try {
525 await extractedReturn.call(undefined);
526 throw new MjsUnitAssertionError(
527 "Expected [Async-from-Sync Iterator].return.call(undefined) to throw " +
528 "a TypeError, but did not throw.");
529 }
530 catch (e) {
531 if (e.constructor !== TypeError) {
532 throw new MjsUnitAssertionError(
533 "Expected [Async-from-Sync Iterator].return.call(undefined) to " +
534 "throw a TypeError, but threw '" + e + "'");
535 }
536 }
537 try {
538 await extractedReturn.call(1);
539 throw new MjsUnitAssertionError(
540 "Expected [Async-from-Sync Iterator].return.call(1) to throw " +
541 "a TypeError, but did not throw.");
542 }
543 catch (e) {
544 if (e.constructor !== TypeError) {
545 throw new MjsUnitAssertionError(
546 "Expected [Async-from-Sync Iterator].return.call(1) to throw " +
547 "a TypeError, but threw '" + e + "'");
548 }
549 }
550 })().catch(function(error) {
551 testFailed = true;
552 testFailure = error;
553 });
554
555 %RunMicrotasks();
556
557 if (testFailed) {
558 throw testFailure;
559 }
OLDNEW
« src/runtime/runtime-internal.cc ('K') | « test/cctest/interpreter/test-bytecode-generator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698