OLD | NEW |
---|---|
(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 let i = 0; | |
71 | |
72 // Abort if `log` was not passed, otherwise TypeError may be eaten. | |
73 if (log === void 0) %AbortJS("`log` is undefined"); | |
neis
2017/02/21 12:48:09
Nit: move this up.
caitp
2017/02/21 14:36:53
Acknowledged.
| |
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 assertInstanceof(e, MyError); | |
145 assertEquals("Error#1", e.message); | |
146 } | |
147 | |
148 promise = iter.return("generator closed"); | |
149 assertInstanceof(promise, Promise); | |
150 iter_result = await promise; | |
151 assertEquals({ value: "generator closed", done: true }, iter_result); | |
152 | |
153 // .next(), .return() and .throw() delegate to sync iterator methods, without | |
154 // keeping track of the state of the generator. | |
155 promise = iter.next("unused"); | |
156 assertInstanceof(promise, Promise); | |
157 iter_result = await promise; | |
158 assertEquals({ value: undefined, done: true }, iter_result); | |
159 | |
160 promise = iter.throw(new MyError("Error#2")); | |
161 assertInstanceof(promise, Promise); | |
162 try { | |
163 await promise; | |
164 } catch (e) { | |
165 assertInstanceof(e, MyError); | |
166 assertEquals("Error#2", e.message); | |
167 } | |
168 | |
169 promise = iter.return("return-after-completed"); | |
170 assertInstanceof(promise, Promise); | |
171 iter_result = await promise; | |
172 assertEquals({ value: "return-after-completed", done: true }, iter_result); | |
173 })().catch(function(error) { | |
174 testFailed = true; | |
175 testFailure = error; | |
176 }); | |
177 | |
178 %RunMicrotasks(); | |
179 if (testFailed) { | |
180 throw testFailure; | |
181 } | |
182 | |
183 | |
184 (async function AsyncFromSyncOrderOfOperations() { | |
185 let log = []; | |
186 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], 0, log)); | |
187 | |
188 try { | |
189 await iter.next(); | |
190 assertUnreachable("Iterator.next() method is not optional"); | |
191 } catch (e) { | |
192 assertInstanceof(e, TypeError); | |
193 assertEquals([], log); | |
194 } | |
195 | |
196 log = []; | |
197 iter = %CreateAsyncFromSyncIterator(sync(["sync-value"], kNext, log)); | |
198 assertEquals({ value: "sync-value", done: false }, await iter.next("a")); | |
199 assertEquals([ | |
200 { | |
201 method: "next", | |
202 sent: "a", | |
203 value: "sync-value", | |
204 done: false | |
205 } | |
206 ], log); | |
207 | |
208 log = []; | |
209 let asyncValue = resolveLater("async-value"); | |
210 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log)); | |
211 assertEquals({ value: "async-value", done: false }, await iter.next("b")); | |
212 assertEquals([ | |
213 { | |
214 method: "next", | |
215 sent: "b", | |
216 value: asyncValue, | |
217 done: false | |
218 } | |
219 ], log); | |
220 | |
221 // If [sync_iterator].next() produces a rejected Promise or an exception is | |
222 // thrown, Promise is rejected with thrown/rejected value. | |
223 log = []; | |
224 asyncValue = rejectLater("Boo!"); | |
225 iter = %CreateAsyncFromSyncIterator(sync([asyncValue], kNext, log)); | |
226 try { | |
227 await iter.next('c'); | |
228 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw'); | |
229 } catch (e) { | |
230 assertEquals("Boo!", e); | |
231 assertEquals([ | |
232 { | |
233 method: 'next', | |
234 sent: 'c', | |
235 value: asyncValue, | |
236 done: false | |
237 } | |
238 ], log); | |
239 } | |
240 | |
241 log = []; | |
242 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNextThrows, log)); | |
243 try { | |
244 await iter.next('Boo!'); | |
245 assertUnreachable('Expected `iter.next(\'c\') to throw, but did not throw'); | |
246 } catch (e) { | |
247 assertEquals("Boo!", e); | |
248 assertEquals([ | |
249 { | |
250 method: 'next', | |
251 sent: 'Boo!', | |
252 value: 'sync-value', | |
253 done: false | |
254 } | |
255 ], log); | |
256 } | |
257 | |
258 | |
259 // [Async-from-Sync Iterator].next() will be rejected with a TypeError if | |
260 // Type([sync_iterator].next()) is not Object. | |
261 log = []; | |
262 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], | |
263 kNext|kNextUnchanged, log)); | |
neis
2017/02/21 12:48:09
Nit: kNextUnchanged includes kNext.
caitp
2017/02/21 14:36:52
Acknowledged.
| |
264 try { | |
265 await iter.next('not-a-JSReceiver'); | |
266 assertUnreachable('Expected `iter.next(\'not-a-JSReceiver\')` to ' + | |
267 'throw, but did not throw') | |
268 } catch (e) { | |
269 assertEquals(e.constructor, TypeError); | |
270 } | |
271 | |
272 assertEquals([ | |
273 { | |
274 method: 'next', | |
275 sent: 'not-a-JSReceiver', | |
276 value: 'sync-value', | |
277 done: false | |
278 } | |
279 ], log); | |
280 | |
281 // If [sync_iterator] does not have a .return() method, return a Promise | |
282 // resolved with the value `{ value: <<sent value>>, done: true }`. | |
283 log = []; | |
284 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], kNext, log)); | |
285 assertEquals({ | |
286 value: 'd', | |
287 done: true | |
288 }, await iter.return('d')); | |
289 | |
290 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
291 // whether [sync_iterator] is completed or not. | |
292 assertEquals({ | |
293 value: 'sync-return', | |
294 done: false | |
295 }, await iter.next('e')); | |
296 | |
297 assertEquals([ | |
298 { | |
299 method: 'next', | |
300 sent: 'e', | |
301 value: 'sync-return', | |
302 done: false | |
303 } | |
304 ], log); | |
305 | |
306 // If [sync_iterator] does have a .return() method, return a Promise | |
307 // fulfilled with the iterator result of [sync_iterator].return(). | |
308 log = []; | |
309 iter = %CreateAsyncFromSyncIterator(sync(['sync-return'], | |
310 kNext|kReturn, log)); | |
311 assertEquals({ | |
312 value: 'f', | |
313 done: true | |
314 }, await iter.return('f')); | |
315 | |
316 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
317 // whether [sync_iterator] is completed or not. | |
318 assertEquals({ | |
319 value: 'sync-return', | |
320 done: false | |
321 }, await iter.next('g')); | |
322 | |
323 assertEquals([ | |
324 { | |
325 method: 'return', | |
326 sent: 'f', | |
327 done: true | |
328 }, | |
329 { | |
330 method: 'next', | |
331 sent: 'g', | |
332 value: 'sync-return', | |
333 done: false | |
334 } | |
335 ], log); | |
336 | |
337 // If [sync_iterator].return() produces a rejected Promise or an exception is | |
338 // thrown, Promise is rejected with thrown/rejected value. | |
339 log = []; | |
340 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturnThrows, | |
341 log)); | |
342 try { | |
343 await iter.return('Boo!!'); | |
344 assertUnreachable('Expected `iter.return(\'Boo!!\')` to throw, but did ' + | |
345 'not throw'); | |
346 } catch (e) { | |
347 assertEquals("Boo!!", e); | |
348 } | |
349 | |
350 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
351 // whether [sync_iterator] is completed or not. | |
352 assertEquals({ value: 'sync-value', done: false }, await iter.next('h')); | |
353 assertEquals([ | |
354 { | |
355 method: 'return', | |
356 sent: 'Boo!!', | |
357 done: true | |
358 }, | |
359 { | |
360 method: 'next', | |
361 sent: 'h', | |
362 value: 'sync-value', | |
363 done: false | |
364 } | |
365 ], log); | |
366 | |
367 | |
368 log = []; | |
369 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kReturn, log)); | |
370 | |
371 let rejection = Promise.reject('Boo!!'); | |
372 try { | |
373 await iter.return(rejection); | |
374 assertUnreachable('Expected `iter.return(Promise.reject(\'Boo!!\'))` to ' + | |
375 'throw, but did not throw'); | |
376 } catch (e) { | |
377 assertEquals('Boo!!', e); | |
378 } | |
379 | |
380 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
381 // whether [sync_iterator] is completed or not. | |
382 assertEquals({ value: 'sync-value', done: false }, await iter.next('i')); | |
383 assertEquals([ | |
384 { | |
385 method: 'return', | |
386 sent: rejection, | |
387 done: true | |
388 }, | |
389 { | |
390 method: 'next', | |
391 sent: 'i', | |
392 value: 'sync-value', | |
393 done: false | |
394 } | |
395 ], log); | |
396 | |
397 // [Async-from-Sync Iterator].return() will be rejected with a TypeError if | |
398 // Type([sync_iterator].return()) is not Object. | |
399 log = []; | |
400 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], | |
401 kNext|kReturnUnchanged, log)); | |
402 try { | |
403 await iter.return('not-a-JSReceiver'); | |
404 assertUnreachable('Expected `iter.return(\'not-a-JSReceiver\')` to ' + | |
405 'throw, but did not throw') | |
406 } catch (e) { | |
407 assertEquals(e.constructor, TypeError); | |
408 } | |
409 | |
410 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
411 // whether [sync_iterator] is completed or not. | |
412 assertEquals({ value: 'sync-value', done: false }, await iter.next('j')); | |
413 assertEquals([ | |
414 { | |
415 method: 'return', | |
416 sent: 'not-a-JSReceiver', | |
417 done: true | |
418 }, | |
419 { | |
420 method: 'next', | |
421 sent: 'j', | |
422 value: 'sync-value', | |
423 done: false | |
424 } | |
425 ], log); | |
426 | |
427 // If [sync_iterator] does not have a .throw method, return a Promise rejected | |
428 // with the sent value. | |
429 log = []; | |
430 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext, log)); | |
431 try { | |
432 await iter.throw('Boo!!'); | |
433 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' + | |
434 'throw'); | |
435 } catch (e) { | |
436 assertEquals('Boo!!', e); | |
437 } | |
438 | |
439 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
440 // whether [sync_iterator] is completed or not. | |
441 assertEquals({ value: 'sync-value', done: false }, await iter.next('k')); | |
442 assertEquals([ | |
443 { | |
444 method: 'next', | |
445 sent: 'k', | |
446 value: 'sync-value', | |
447 done: false | |
448 } | |
449 ], log); | |
450 | |
451 | |
452 log = []; | |
453 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrow, log)); | |
454 try { | |
455 await iter.throw('Boo!!'); | |
456 assertUnreachable('Expected iter.throw(\'Boo!!\') to throw, but did not ' + | |
457 'throw'); | |
458 } catch (e) { | |
459 assertEquals('Boo!!', e); | |
460 } | |
461 | |
462 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
463 // whether [sync_iterator] is completed or not. | |
464 assertEquals({ value: 'sync-value', done: false }, await iter.next('l')); | |
465 assertEquals([ | |
466 { | |
467 method: 'throw', | |
468 sent: 'Boo!!', | |
469 done: false | |
470 }, | |
471 { | |
472 method: 'next', | |
473 sent: 'l', | |
474 value: 'sync-value', | |
475 done: false | |
476 } | |
477 ], log); | |
478 | |
479 // If [sync_iterator].throw() returns a resolved Promise or a Completion | |
480 // with [[Type]] "normal" or "return", return a resolved Promise | |
481 log = []; | |
482 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], kNext|kThrowNormal, | |
483 log)); | |
484 assertEquals({ | |
485 value: 'Boo!!', | |
486 done: false | |
487 }, await iter.throw('Boo!!')); | |
488 | |
489 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
490 // whether [sync_iterator] is completed or not. | |
491 assertEquals({ value: 'sync-value', done: false }, await iter.next('m')); | |
492 assertEquals([ | |
493 { | |
494 method: 'throw', | |
495 sent: 'Boo!!', | |
496 done: false | |
497 }, | |
498 { | |
499 method: 'next', | |
500 sent: 'm', | |
501 value: 'sync-value', | |
502 done: false | |
503 } | |
504 ], log); | |
505 | |
506 // [Async-from-Sync Iterator].throw() will be rejected with a TypeError if | |
507 // Type([sync_iterator].throw()) is not Object. | |
508 log = []; | |
509 iter = %CreateAsyncFromSyncIterator(sync(['sync-value'], | |
510 kNext|kThrowUnchanged, log)); | |
511 try { | |
512 await iter.throw('not-a-JSReceiver'); | |
513 assertUnreachable('Expected `iter.throw(\'not-a-JSReceiver\')` to ' + | |
514 'throw, but did not throw') | |
515 } catch (e) { | |
516 assertEquals(e.constructor, TypeError); | |
517 } | |
518 | |
519 // [Async-from-Sync Iterator] merely delegates, and does not keep track of | |
520 // whether [sync_iterator] is completed or not. | |
521 assertEquals({ value: 'sync-value', done: false }, await iter.next('n')); | |
522 assertEquals([ | |
523 { | |
524 method: 'throw', | |
525 sent: 'not-a-JSReceiver', | |
526 done: false | |
527 }, | |
528 { | |
529 method: 'next', | |
530 sent: 'n', | |
531 value: 'sync-value', | |
532 done: false | |
533 } | |
534 ], log); | |
535 | |
536 // Let nextValue be IteratorValue(nextResult). | |
537 // IfAbruptRejectPromise(nextValue, promiseCapability).) | |
538 iter = %CreateAsyncFromSyncIterator({ | |
539 next() { return { get value() { throw "BadValue!" }, done: false }; } | |
540 }); | |
541 try { | |
542 await iter.next(); | |
543 assertUnreachable('Expected `iter.next()` to throw, but did not throw'); | |
544 } catch (e) { | |
545 assertEquals('BadValue!', e); | |
546 } | |
547 | |
548 // Let nextDone be IteratorComplete(nextResult). | |
549 // IfAbruptRejectPromise(nextDone, promiseCapability). | |
550 iter = %CreateAsyncFromSyncIterator({ | |
551 next() { return { value: undefined, get done() { throw "BadValue!" } }; } | |
552 }); | |
553 try { | |
554 await iter.next(); | |
555 assertUnreachable('Expected `iter.next()` to throw, but did not throw'); | |
556 } catch (e) { | |
557 assertEquals('BadValue!', e); | |
558 } | |
559 | |
560 // IfAbruptRejectPromise(returnResult, promiseCapability). | |
561 // Let returnValue be IteratorValue(returnResult). | |
562 iter = %CreateAsyncFromSyncIterator({ | |
563 return() { return { get value() { throw "BadValue!" }, done: false }; } | |
564 }); | |
565 try { | |
566 await iter.return(); | |
567 assertUnreachable('Expected `iter.return()` to throw, but did not throw'); | |
568 } catch (e) { | |
569 assertEquals('BadValue!', e); | |
570 } | |
571 | |
572 // IfAbruptRejectPromise(returnValue, promiseCapability). | |
573 // Let returnDone be IteratorComplete(returnResult). | |
574 iter = %CreateAsyncFromSyncIterator({ | |
575 return() { return { value: undefined, get done() { throw "BadValue!" } }; } | |
576 }); | |
577 try { | |
578 await iter.return(); | |
579 assertUnreachable('Expected `iter.return()` to throw, but did not throw'); | |
580 } catch (e) { | |
581 assertEquals('BadValue!', e); | |
582 } | |
583 | |
584 // IfAbruptRejectPromise(throwResult, promiseCapability). | |
585 // Let throwValue be IteratorValue(throwResult). | |
586 iter = %CreateAsyncFromSyncIterator({ | |
587 throw() { return { get value() { throw "BadValue!" }, done: false }; } | |
588 }); | |
589 try { | |
590 await iter.throw(); | |
591 assertUnreachable('Expected `iter.throw()` to throw, but did not throw'); | |
592 } catch (e) { | |
593 assertEquals('BadValue!', e); | |
594 } | |
595 | |
596 // IfAbruptRejectPromise(throwValue, promiseCapability). | |
597 // Let throwDone be IteratorComplete(throwResult). | |
598 iter = %CreateAsyncFromSyncIterator({ | |
599 throw() { return { value: undefined, get done() { throw "BadValue!" } }; } | |
600 }); | |
601 try { | |
602 await iter.throw(); | |
603 assertUnreachable('Expected `iter.throw()` to throw, but did not throw'); | |
604 } catch (e) { | |
605 assertEquals('BadValue!', e); | |
606 } | |
607 })().catch(function(error) { | |
608 testFailed = true; | |
609 testFailure = error; | |
610 }); | |
611 | |
612 %RunMicrotasks(); | |
613 if (testFailed) { | |
614 throw testFailure; | |
615 } | |
616 | |
617 (function ExtractedAsyncFromSyncIteratorMethods() { | |
618 // Async-from-Sync iterator methods can be extracted via function.caller. | |
619 // TODO(caitp): test extracted `throw` method using yield* in async generator. | |
620 let extractor = [0, 1, 2, 3, 4,5,6,7,8,9]; | |
621 let extractedNext; | |
622 let extractedReturn; | |
623 | |
624 extractor[Symbol.iterator] = function() { | |
625 let it = [][Symbol.iterator].call(extractor); | |
626 let origNext = it.next, origThrow = it.throw, origReturn = it.return; | |
627 function extractNext() { | |
628 extractedNext = extractNext.caller; | |
629 return origNext; | |
630 } | |
631 function extractReturn() { | |
632 extractedReturn = extractReturn.caller; | |
633 return origReturn; | |
634 } | |
635 Object.defineProperties(it, { | |
636 "next": { get: extractNext, configurable: true }, | |
637 "return": { get: extractReturn, configurable: true } | |
638 }); | |
639 return it; | |
640 }; | |
641 | |
642 async function f() { | |
643 let i; | |
644 let it = extractor[Symbol.iterator](); | |
645 for await (let x of it) break; | |
646 for await (let x of it) return "x"; | |
647 } | |
648 | |
649 // Cycle through `f` to extract iterator methods | |
650 f().catch(function() { assertUnreachable("No error should have occurred"); }); | |
neis
2017/02/21 12:48:09
This assertUnreachable would go unnoticed.
caitp
2017/02/21 14:36:52
Good point, using %AbortJS instead.
| |
651 %RunMicrotasks(); | |
652 | |
653 assertEquals(typeof extractedNext, "function"); | |
654 assertThrowsAsync(() => extractedNext.call(undefined), TypeError); | |
655 assertThrowsAsync(() => extractedNext.call(1), TypeError); | |
656 | |
657 assertEquals(typeof extractedReturn, "function"); | |
658 assertThrowsAsync(() => extractedReturn.call(undefined), TypeError); | |
659 assertThrowsAsync(() => extractedReturn.call(1), TypeError); | |
660 })(); | |
OLD | NEW |