1'use strict'; 2const common = require('../common'); 3const assert = require('assert'); 4 5const { Readable, Writable } = require('stream'); 6 7const source = Readable({ read: () => {} }); 8const dest1 = Writable({ write: () => {} }); 9const dest2 = Writable({ write: () => {} }); 10 11source.pipe(dest1); 12source.pipe(dest2); 13 14dest1.on('unpipe', common.mustCall()); 15dest2.on('unpipe', common.mustCall()); 16 17assert.strictEqual(source._readableState.pipes[0], dest1); 18assert.strictEqual(source._readableState.pipes[1], dest2); 19assert.strictEqual(source._readableState.pipes.length, 2); 20 21// Should be able to unpipe them in the reverse order that they were piped. 22 23source.unpipe(dest2); 24 25assert.strictEqual(source._readableState.pipes, dest1); 26assert.notStrictEqual(source._readableState.pipes, dest2); 27 28dest2.on('unpipe', common.mustNotCall()); 29source.unpipe(dest2); 30 31source.unpipe(dest1); 32 33assert.strictEqual(source._readableState.pipes, null); 34 35{ 36 // Test `cleanup()` if we unpipe all streams. 37 const source = Readable({ read: () => {} }); 38 const dest1 = Writable({ write: () => {} }); 39 const dest2 = Writable({ write: () => {} }); 40 41 let destCount = 0; 42 const srcCheckEventNames = ['end', 'data']; 43 const destCheckEventNames = ['close', 'finish', 'drain', 'error', 'unpipe']; 44 45 const checkSrcCleanup = common.mustCall(() => { 46 assert.strictEqual(source._readableState.pipes, null); 47 assert.strictEqual(source._readableState.pipesCount, 0); 48 assert.strictEqual(source._readableState.flowing, false); 49 50 srcCheckEventNames.forEach((eventName) => { 51 assert.strictEqual( 52 source.listenerCount(eventName), 0, 53 `source's '${eventName}' event listeners not removed` 54 ); 55 }); 56 }); 57 58 function checkDestCleanup(dest) { 59 const currentDestId = ++destCount; 60 source.pipe(dest); 61 62 const unpipeChecker = common.mustCall(() => { 63 assert.deepStrictEqual( 64 dest.listeners('unpipe'), [unpipeChecker], 65 `destination{${currentDestId}} should have a 'unpipe' event ` + 66 'listener which is `unpipeChecker`' 67 ); 68 dest.removeListener('unpipe', unpipeChecker); 69 destCheckEventNames.forEach((eventName) => { 70 assert.strictEqual( 71 dest.listenerCount(eventName), 0, 72 `destination{${currentDestId}}'s '${eventName}' event ` + 73 'listeners not removed' 74 ); 75 }); 76 77 if (--destCount === 0) 78 checkSrcCleanup(); 79 }); 80 81 dest.on('unpipe', unpipeChecker); 82 } 83 84 checkDestCleanup(dest1); 85 checkDestCleanup(dest2); 86 source.unpipe(); 87} 88