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

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

Issue 2645313003: [async-iteration] implement Async-from-Sync Iterator (Closed)
Patch Set: cleanmerge Created 3 years, 9 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
« no previous file with comments | « test/cctest/interpreter/test-bytecode-generator.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 function resolveLater(value) {
45 return new Promise(function(resolve) {
46 Promise.resolve().then(function() {
47 resolve(value);
48 });
49 });
50 }
51
52 function rejectLater(value) {
53 return new Promise(function(resolve, reject) {
54 Promise.resolve().then(function() {
55 reject(value);
56 });
57 });
58 }
59
60 const kNext = 1;
61 const kThrow = 2;
62 const kReturn = 4;
63 const kNextThrows = kNext | 8;
64 const kReturnThrows = kReturn | 16;
65 const kThrowNormal = kThrow | 32;
66 const kNextUnchanged = kNext | 64;
67 const kReturnUnchanged = kReturn | 128;
68 const kThrowUnchanged = kThrow | 256;
69 function sync(array, features, log) {
70 // `log` is a required parameter
71 if (log === void 0) %AbortJS("`log` is undefined");
72
73 let i = 0;
74 let methods = {
75 next(sent) {
76 let done = i >= array.length;
77 let value = array[i];
78 log.push({ method: "next", sent, value, done });
79 if ((features & kNextThrows) === kNextThrows) throw sent;
80 if ((features & kNextUnchanged) === kNextUnchanged) return sent;
81 i++;
82 return { value, done };
83 },
84 throw(sent) {
85 let done = i >= array.length;
86 log.push({ method: "throw", sent, done });
87 if ((features & kThrowNormal) === kThrowNormal)
88 return { value: sent, done };
89 if ((features & kThrowUnchanged) === kThrowUnchanged) return sent;
90 throw sent;
91 },
92 return(sent) {
93 let done = true;
94 log.push({ method: "return", sent, done });
95 if ((features & kReturnThrows) === kReturnThrows) throw sent;
96 if ((features & kReturnUnchanged) === kReturnUnchanged) return sent;
97 return { value: sent, done };
98 }
99 };
100 return {
101 [Symbol.iterator]() { return this; },
102 next: (features & kNext) ? methods.next : undefined,
103 throw: (features & kThrow) ? methods.throw : undefined,
104 return: (features & kReturn) ? methods.return : undefined
105 };
106 }
107
108 class MyError extends Error {};
109
110 (async function AsyncFromSyncWithGenerator() {
111 function* gen() {
112 yield "sync value";
113 try {
114 yield new Promise(function(resolve) {
115 resolve("async value");
116 });
117 } catch (error) {
118 throw error;
119 }
120 assertUnreachable("generator is closed");
121 }
122 let iter = %CreateAsyncFromSyncIterator(gen());
123
124 // [Async-from-Sync Iterator] wraps sync iterator values in a Promise
125 let promise = iter.next();
126 assertInstanceof(promise, Promise);
127 let iter_result = await promise;
128 assertEquals({ value: "sync value", done: false }, iter_result);
129
130 // [Async-from-Sync Iterator] will wait for resolution of Promise values
131 promise = iter.next();
132 assertInstanceof(promise, Promise);
133 iter_result = await promise;
134 assertEquals({ value: "async value", done: false }, iter_result);
135
136 // [Async-from-Sync Iterator].throw delegates to .throw() method of sync
137 // iterator.
138 promise = iter.throw(new MyError("Error#1"));
139 assertInstanceof(promise, Promise);
140 try {
141 await promise;
142 assertUnreachable("promise should be rejected");
143 } catch (e) {
144 // If assertUnreachable failed, rethrow
145 if (e instanceof MjsUnitAssertionError) throw e;
146 assertInstanceof(e, MyError);
147 assertEquals("Error#1", e.message);
148 }
149
150 // Generator is closed, subsequent calls to .next() will not resume.
151 promise = iter.next("floof");
152 iter_result = await promise;
153 assertEquals({ value: undefined, done: true }, iter_result);
154
155 promise = iter.return("generator closed");
156 assertInstanceof(promise, Promise);
157 iter_result = await promise;
158 assertEquals({ value: "generator closed", done: true }, iter_result);
159
160 // .next(), .return() and .throw() delegate to sync iterator methods, without
161 // keeping track of the state of the generator.
162 promise = iter.next("unused");
163 assertInstanceof(promise, Promise);
164 iter_result = await promise;
165 assertEquals({ value: undefined, done: true }, iter_result);
166
167 promise = iter.throw(new MyError("Error#2"));
168 assertInstanceof(promise, Promise);
169 try {
170 await promise;
171 assertUnreachable("promise should be rejected");
172 } catch (e) {
173 // If assertUnreachable failed, rethrow
174 if (e instanceof MjsUnitAssertionError) throw e;
175 assertInstanceof(e, MyError);
176 assertEquals("Error#2", e.message);
177 }
178
179 promise = iter.return("return-after-completed");
180 assertInstanceof(promise, Promise);
181 iter_result = await promise;
182 assertEquals({ value: "return-after-completed", done: true }, iter_result);
183 })().catch(function(error) {
184 testFailed = true;
185 testFailure = error;
186 });
187
188 %RunMicrotasks();
189 if (testFailed) {
190 throw testFailure;
191 }
192
193
194 (async function AsyncFromSyncOrderOfOperations() {
195 let log = [];
196 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0, log));
197
198 try {
199 await iter.next();
200 assertUnreachable("Iterator.next() method is not optional");
201 } catch (e) {
202 assertInstanceof(e, TypeError);
203 assertEquals([], log);
204 }
205
206 log = [];
207 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log));
208 assertEquals({ value: "sync-value", done: false }, await iter.next("a"));
209 assertEquals([
210 {
211 method: "next",
212 sent: "a",
213 value: "sync-value",
214 done: false
215 }
216 ], log);
217
218 log = [];
219 let asyncValue = resolveLater("async-value");
220 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
221 assertEquals({ value: "async-value", done: false }, await iter.next("b"));
222 assertEquals([
223 {
224 method: "next",
225 sent: "b",
226 value: asyncValue,
227 done: false
228 }
229 ], log);
230
231 // If [sync_iterator].next() produces a rejected Promise or an exception is
232 // thrown, Promise is rejected with thrown/rejected value.
233 log = [];
234 asyncValue = rejectLater("Boo!");
235 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log));
236 try {
237 await iter.next('c');
238 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
239 } catch (e) {
240 assertEquals("Boo!", e);
241 assertEquals([
242 {
243 method: 'next',
244 sent: 'c',
245 value: asyncValue,
246 done: false
247 }
248 ], log);
249 }
250
251 log = [];
252 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextThrows, log));
253 try {
254 await iter.next('Boo!');
255 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw');
256 } catch (e) {
257 assertEquals("Boo!", e);
258 assertEquals([
259 {
260 method: 'next',
261 sent: 'Boo!',
262 value: 'sync-value',
263 done: false
264 }
265 ], log);
266 }
267
268
269 // [Async-from-Sync Iterator].next() will be rejected with a TypeError if
270 // Type([sync_iterator].next()) is not Object.
271 log = [];
272 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextUnchanged,
273 log));
274 try {
275 await iter.next('not-a-JSReceiver');
276 assertUnreachable('Expected `iter.next(\'not-a-JSReceiver\')` to ' +
277 'throw, but did not throw')
278 } catch (e) {
279 assertEquals(e.constructor, TypeError);
280 }
281
282 assertEquals([
283 {
284 method: 'next',
285 sent: 'not-a-JSReceiver',
286 value: 'sync-value',
287 done: false
288 }
289 ], log);
290
291 // If [sync_iterator] does not have a .return() method, return a Promise
292 // resolved with the value `{ value: <<sent value>>, done: true }`.
293 log = [];
294 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log));
295 assertEquals({
296 value: 'd',
297 done: true
298 }, await iter.return('d'));
299
300 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
301 // whether [sync_iterator] is completed or not.
302 assertEquals({
303 value: 'sync-return',
304 done: false
305 }, await iter.next('e'));
306
307 assertEquals([
308 {
309 method: 'next',
310 sent: 'e',
311 value: 'sync-return',
312 done: false
313 }
314 ], log);
315
316 // If [sync_iterator] does have a .return() method, return a Promise
317 // fulfilled with the iterator result of [sync_iterator].return().
318 log = [];
319 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'],
320 kNext|kReturn, log));
321 assertEquals({
322 value: 'f',
323 done: true
324 }, await iter.return('f'));
325
326 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
327 // whether [sync_iterator] is completed or not.
328 assertEquals({
329 value: 'sync-return',
330 done: false
331 }, await iter.next('g'));
332
333 assertEquals([
334 {
335 method: 'return',
336 sent: 'f',
337 done: true
338 },
339 {
340 method: 'next',
341 sent: 'g',
342 value: 'sync-return',
343 done: false
344 }
345 ], log);
346
347 // If [sync_iterator].return() produces a rejected Promise or an exception is
348 // thrown, Promise is rejected with thrown/rejected value.
349 log = [];
350 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows,
351 log));
352 try {
353 await iter.return('Boo!!');
354 assertUnreachable('Expected `iter.return(\'Boo!!\')` to throw, but did ' +
355 'not throw');
356 } catch (e) {
357 assertEquals("Boo!!", e);
358 }
359
360 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
361 // whether [sync_iterator] is completed or not.
362 assertEquals({ value: 'sync-value', done: false }, await iter.next('h'));
363 assertEquals([
364 {
365 method: 'return',
366 sent: 'Boo!!',
367 done: true
368 },
369 {
370 method: 'next',
371 sent: 'h',
372 value: 'sync-value',
373 done: false
374 }
375 ], log);
376
377
378 log = [];
379 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturn, log));
380
381 let rejection = Promise.reject('Boo!!');
382 try {
383 await iter.return(rejection);
384 assertUnreachable('Expected `iter.return(Promise.reject(\'Boo!!\'))` to ' +
385 'throw, but did not throw');
386 } catch (e) {
387 assertEquals('Boo!!', e);
388 }
389
390 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
391 // whether [sync_iterator] is completed or not.
392 assertEquals({ value: 'sync-value', done: false }, await iter.next('i'));
393 assertEquals([
394 {
395 method: 'return',
396 sent: rejection,
397 done: true
398 },
399 {
400 method: 'next',
401 sent: 'i',
402 value: 'sync-value',
403 done: false
404 }
405 ], log);
406
407 // [Async-from-Sync Iterator].return() will be rejected with a TypeError if
408 // Type([sync_iterator].return()) is not Object.
409 log = [];
410 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'],
411 kNext|kReturnUnchanged, log));
412 try {
413 await iter.return('not-a-JSReceiver');
414 assertUnreachable('Expected `iter.return(\'not-a-JSReceiver\')` to ' +
415 'throw, but did not throw')
416 } catch (e) {
417 assertEquals(e.constructor, TypeError);
418 }
419
420 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
421 // whether [sync_iterator] is completed or not.
422 assertEquals({ value: 'sync-value', done: false }, await iter.next('j'));
423 assertEquals([
424 {
425 method: 'return',
426 sent: 'not-a-JSReceiver',
427 done: true
428 },
429 {
430 method: 'next',
431 sent: 'j',
432 value: 'sync-value',
433 done: false
434 }
435 ], log);
436
437 // If [sync_iterator] does not have a .throw method, return a Promise rejected
438 // with the sent value.
439 log = [];
440 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log));
441 try {
442 await iter.throw('Boo!!');
443 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
444 'throw');
445 } catch (e) {
446 assertEquals('Boo!!', e);
447 }
448
449 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
450 // whether [sync_iterator] is completed or not.
451 assertEquals({ value: 'sync-value', done: false }, await iter.next('k'));
452 assertEquals([
453 {
454 method: 'next',
455 sent: 'k',
456 value: 'sync-value',
457 done: false
458 }
459 ], log);
460
461
462 log = [];
463 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log));
464 try {
465 await iter.throw('Boo!!');
466 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' +
467 'throw');
468 } catch (e) {
469 assertEquals('Boo!!', e);
470 }
471
472 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
473 // whether [sync_iterator] is completed or not.
474 assertEquals({ value: 'sync-value', done: false }, await iter.next('l'));
475 assertEquals([
476 {
477 method: 'throw',
478 sent: 'Boo!!',
479 done: false
480 },
481 {
482 method: 'next',
483 sent: 'l',
484 value: 'sync-value',
485 done: false
486 }
487 ], log);
488
489 // If [sync_iterator].throw() returns a resolved Promise or a Completion
490 // with [[Type]] "normal" or "return", return a resolved Promise
491 log = [];
492 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal,
493 log));
494 assertEquals({
495 value: 'Boo!!',
496 done: false
497 }, await iter.throw('Boo!!'));
498
499 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
500 // whether [sync_iterator] is completed or not.
501 assertEquals({ value: 'sync-value', done: false }, await iter.next('m'));
502 assertEquals([
503 {
504 method: 'throw',
505 sent: 'Boo!!',
506 done: false
507 },
508 {
509 method: 'next',
510 sent: 'm',
511 value: 'sync-value',
512 done: false
513 }
514 ], log);
515
516 // [Async-from-Sync Iterator].throw() will be rejected with a TypeError if
517 // Type([sync_iterator].throw()) is not Object.
518 log = [];
519 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'],
520 kNext|kThrowUnchanged, log));
521 try {
522 await iter.throw('not-a-JSReceiver');
523 assertUnreachable('Expected `iter.throw(\'not-a-JSReceiver\')` to ' +
524 'throw, but did not throw')
525 } catch (e) {
526 assertEquals(e.constructor, TypeError);
527 }
528
529 // [Async-from-Sync Iterator] merely delegates, and does not keep track of
530 // whether [sync_iterator] is completed or not.
531 assertEquals({ value: 'sync-value', done: false }, await iter.next('n'));
532 assertEquals([
533 {
534 method: 'throw',
535 sent: 'not-a-JSReceiver',
536 done: false
537 },
538 {
539 method: 'next',
540 sent: 'n',
541 value: 'sync-value',
542 done: false
543 }
544 ], log);
545
546 // Let nextValue be IteratorValue(nextResult).
547 // IfAbruptRejectPromise(nextValue, promiseCapability).)
548 iter = %CreateAsyncFromSyncIterator({
549 next() { return { get value() { throw "BadValue!" }, done: false }; }
550 });
551 try {
552 await iter.next();
553 assertUnreachable('Expected `iter.next()` to throw, but did not throw');
554 } catch (e) {
555 assertEquals('BadValue!', e);
556 }
557
558 // Let nextDone be IteratorComplete(nextResult).
559 // IfAbruptRejectPromise(nextDone, promiseCapability).
560 iter = %CreateAsyncFromSyncIterator({
561 next() { return { value: undefined, get done() { throw "BadValue!" } }; }
562 });
563 try {
564 await iter.next();
565 assertUnreachable('Expected `iter.next()` to throw, but did not throw');
566 } catch (e) {
567 assertEquals('BadValue!', e);
568 }
569
570 // IfAbruptRejectPromise(returnResult, promiseCapability).
571 // Let returnValue be IteratorValue(returnResult).
572 iter = %CreateAsyncFromSyncIterator({
573 return() { return { get value() { throw "BadValue!" }, done: false }; }
574 });
575 try {
576 await iter.return();
577 assertUnreachable('Expected `iter.return()` to throw, but did not throw');
578 } catch (e) {
579 assertEquals('BadValue!', e);
580 }
581
582 // IfAbruptRejectPromise(returnValue, promiseCapability).
583 // Let returnDone be IteratorComplete(returnResult).
584 iter = %CreateAsyncFromSyncIterator({
585 return() { return { value: undefined, get done() { throw "BadValue!" } }; }
586 });
587 try {
588 await iter.return();
589 assertUnreachable('Expected `iter.return()` to throw, but did not throw');
590 } catch (e) {
591 assertEquals('BadValue!', e);
592 }
593
594 // IfAbruptRejectPromise(throwResult, promiseCapability).
595 // Let throwValue be IteratorValue(throwResult).
596 iter = %CreateAsyncFromSyncIterator({
597 throw() { return { get value() { throw "BadValue!" }, done: false }; }
598 });
599 try {
600 await iter.throw();
601 assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
602 } catch (e) {
603 assertEquals('BadValue!', e);
604 }
605
606 // IfAbruptRejectPromise(throwValue, promiseCapability).
607 // Let throwDone be IteratorComplete(throwResult).
608 iter = %CreateAsyncFromSyncIterator({
609 throw() { return { value: undefined, get done() { throw "BadValue!" } }; }
610 });
611 try {
612 await iter.throw();
613 assertUnreachable('Expected `iter.throw()` to throw, but did not throw');
614 } catch (e) {
615 assertEquals('BadValue!', e);
616 }
617 })().catch(function(error) {
618 testFailed = true;
619 testFailure = error;
620 });
621
622 %RunMicrotasks();
623 if (testFailed) {
624 throw testFailure;
625 }
626
627 (function ExtractedAsyncFromSyncIteratorMethods() {
628 // Async-from-Sync iterator methods can be extracted via function.caller.
629 // TODO(caitp): test extracted `throw` method using yield* in async generator.
630 let extractor = [0, 1, 2, 3, 4,5,6,7,8,9];
631 let extractedNext;
632 let extractedReturn;
633
634 extractor[Symbol.iterator] = function() {
635 let it = [][Symbol.iterator].call(extractor);
636 let origNext = it.next, origThrow = it.throw, origReturn = it.return;
637 function extractNext() {
638 extractedNext = extractNext.caller;
639 return origNext;
640 }
641 function extractReturn() {
642 extractedReturn = extractReturn.caller;
643 return origReturn;
644 }
645 Object.defineProperties(it, {
646 "next": { get: extractNext, configurable: true },
647 "return": { get: extractReturn, configurable: true }
648 });
649 return it;
650 };
651
652 async function f() {
653 let i;
654 let it = extractor[Symbol.iterator]();
655 for await (let x of it) break;
656 for await (let x of it) return "x";
657 }
658
659 // Cycle through `f` to extract iterator methods
660 f().catch(function() { %AbortJS("No error should have occurred"); });
661 %RunMicrotasks();
662
663 assertEquals(typeof extractedNext, "function");
664 assertThrowsAsync(() => extractedNext.call(undefined), TypeError);
665 assertThrowsAsync(() => extractedNext.call(1), TypeError);
666
667 assertEquals(typeof extractedReturn, "function");
668 assertThrowsAsync(() => extractedReturn.call(undefined), TypeError);
669 assertThrowsAsync(() => extractedReturn.call(1), TypeError);
670 })();
OLDNEW
« no previous file with comments | « 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