@@ -10,6 +10,7 @@ const { |
10 | 10 | } = require('stream'); |
11 | 11 | const assert = require('assert'); |
12 | 12 | const http = require('http'); |
| 13 | +const fs = require('fs'); |
13 | 14 |
|
14 | 15 | async function tests() { |
15 | 16 | { |
@@ -338,11 +339,17 @@ async function tests() { |
338 | 339 | process.nextTick(async () => { |
339 | 340 | readable.on('close', common.mustNotCall()); |
340 | 341 | let received = 0; |
341 | | - for await (const k of readable) { |
342 | | - // Just make linting pass. This should never run. |
343 | | - assert.strictEqual(k, 'hello'); |
344 | | - received++; |
| 342 | + let err = null; |
| 343 | + try { |
| 344 | + for await (const k of readable) { |
| 345 | + // Just make linting pass. This should never run. |
| 346 | + assert.strictEqual(k, 'hello'); |
| 347 | + received++; |
| 348 | + } |
| 349 | + } catch (_err) { |
| 350 | + err = _err; |
345 | 351 | } |
| 352 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
346 | 353 | assert.strictEqual(received, 0); |
347 | 354 | }); |
348 | 355 | } |
@@ -412,8 +419,13 @@ async function tests() { |
412 | 419 |
|
413 | 420 | readable.destroy(); |
414 | 421 |
|
415 | | - const { done } = await readable[Symbol.asyncIterator]().next(); |
416 | | - assert.strictEqual(done, true); |
| 422 | + const it = await readable[Symbol.asyncIterator](); |
| 423 | + const next = it.next(); |
| 424 | + next |
| 425 | + .then(common.mustNotCall()) |
| 426 | + .catch(common.mustCall((err) => { |
| 427 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
| 428 | + })); |
417 | 429 | } |
418 | 430 |
|
419 | 431 | { |
@@ -458,7 +470,7 @@ async function tests() { |
458 | 470 | } |
459 | 471 |
|
460 | 472 | { |
461 | | - console.log('destroy mid-stream does not error'); |
| 473 | + console.log('destroy mid-stream errors'); |
462 | 474 | const r = new Readable({ |
463 | 475 | objectMode: true, |
464 | 476 | read() { |
@@ -467,10 +479,16 @@ async function tests() { |
467 | 479 | } |
468 | 480 | }); |
469 | 481 |
|
470 | | - // eslint-disable-next-line no-unused-vars |
471 | | - for await (const a of r) { |
472 | | - r.destroy(null); |
| 482 | + let err = null; |
| 483 | + try { |
| 484 | + // eslint-disable-next-line no-unused-vars |
| 485 | + for await (const a of r) { |
| 486 | + r.destroy(null); |
| 487 | + } |
| 488 | + } catch (_err) { |
| 489 | + err = _err; |
473 | 490 | } |
| 491 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
474 | 492 | } |
475 | 493 |
|
476 | 494 | { |
@@ -514,7 +532,7 @@ async function tests() { |
514 | 532 | } |
515 | 533 |
|
516 | 534 | { |
517 | | - console.log('all next promises must be resolved on destroy'); |
| 535 | + console.log('all next promises must be rejected on destroy'); |
518 | 536 | const r = new Readable({ |
519 | 537 | objectMode: true, |
520 | 538 | read() { |
@@ -525,7 +543,11 @@ async function tests() { |
525 | 543 | const c = b.next(); |
526 | 544 | const d = b.next(); |
527 | 545 | r.destroy(); |
528 | | - assert.deepStrictEqual(await c, { done: true, value: undefined }); |
| 546 | + c |
| 547 | + .then(common.mustNotCall()) |
| 548 | + .catch(common.mustCall((err) => { |
| 549 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
| 550 | + })); |
529 | 551 | assert.deepStrictEqual(await d, { done: true, value: undefined }); |
530 | 552 | } |
531 | 553 |
|
@@ -675,7 +697,7 @@ async function tests() { |
675 | 697 | } |
676 | 698 |
|
677 | 699 | { |
678 | | - // AsyncIterator should finish correctly if destroyed. |
| 700 | + // AsyncIterator should not finish correctly if destroyed. |
679 | 701 |
|
680 | 702 | const r = new Readable({ |
681 | 703 | objectMode: true, |
@@ -688,11 +710,34 @@ async function tests() { |
688 | 710 | const it = r[Symbol.asyncIterator](); |
689 | 711 | const next = it.next(); |
690 | 712 | next |
691 | | - .then(common.mustCall(({ done }) => assert.strictEqual(done, true))) |
692 | | - .catch(common.mustNotCall()); |
| 713 | + .then(common.mustNotCall()) |
| 714 | + .catch(common.mustCall((err) => { |
| 715 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
| 716 | + })); |
693 | 717 | }); |
694 | 718 | } |
695 | 719 |
|
| 720 | +{ |
| 721 | + // AsyncIterator should throw if prematurely closed |
| 722 | + // before end has been emitted. |
| 723 | + (async function() { |
| 724 | + const readable = fs.createReadStream(__filename); |
| 725 | + |
| 726 | + try { |
| 727 | + // eslint-disable-next-line no-unused-vars |
| 728 | + for await (const chunk of readable) { |
| 729 | + readable.close(); |
| 730 | + } |
| 731 | + |
| 732 | + assert.fail('should have thrown'); |
| 733 | + } catch (err) { |
| 734 | + assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE'); |
| 735 | + } |
| 736 | + |
| 737 | + assert.ok(readable.destroyed); |
| 738 | + })().then(common.mustCall()); |
| 739 | +} |
| 740 | + |
696 | 741 | // AsyncIterator non-destroying iterator |
697 | 742 | { |
698 | 743 | function createReadable() { |
|