Chromium Code Reviews| 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 |