diff --git a/packages/fs/fs.walk/src/providers/stream.spec.ts b/packages/fs/fs.walk/src/providers/stream.spec.ts index a8b4af55..485ca3a5 100644 --- a/packages/fs/fs.walk/src/providers/stream.spec.ts +++ b/packages/fs/fs.walk/src/providers/stream.spec.ts @@ -10,10 +10,12 @@ import StreamProvider from './stream'; class TestProvider extends StreamProvider { protected readonly _reader: AsyncReader = new tests.TestAsyncReader() as unknown as AsyncReader; - protected readonly _stream: Readable = sinon.createStubInstance(Readable) as unknown as Readable; constructor(_root: string, _settings: Settings = new Settings()) { super(_root, _settings); + + this._stream.emit = sinon.stub(); + this._stream.push = sinon.stub(); } public get reader(): tests.TestAsyncReader { @@ -73,5 +75,16 @@ describe('Providers → Stream', () => { assert.deepStrictEqual(provider.stream.push.args, [[null]]); }); + + it('should do not destroy reader when it is already destroyed', () =>{ + const provider = new TestProvider('directory'); + + const stream = provider.read(); + + stream.destroy(); + + assert.ok(stream.destroyed); + assert.doesNotThrow(() => stream.destroy()); + }); }); }); diff --git a/packages/fs/fs.walk/src/providers/stream.ts b/packages/fs/fs.walk/src/providers/stream.ts index 8a86ed70..a43a93a0 100644 --- a/packages/fs/fs.walk/src/providers/stream.ts +++ b/packages/fs/fs.walk/src/providers/stream.ts @@ -7,7 +7,11 @@ export default class StreamProvider { protected readonly _stream: Readable = new Readable({ objectMode: true, read: () => { /* noop */ }, - destroy: this._reader.destroy.bind(this._reader) + destroy: () => { + if (!this._reader.isDestroyed) { + this._reader.destroy(); + } + } }); constructor(private readonly _root: string, private readonly _settings: Settings) { } diff --git a/packages/fs/fs.walk/src/readers/async.spec.ts b/packages/fs/fs.walk/src/readers/async.spec.ts index c576aa4d..07754390 100644 --- a/packages/fs/fs.walk/src/readers/async.spec.ts +++ b/packages/fs/fs.walk/src/readers/async.spec.ts @@ -211,6 +211,14 @@ describe('Readers → Async', () => { reader.read(); }); + it('should mark stream as "destroyed" after first destroy', () => { + const reader = new TestReader('directory'); + + reader.destroy(); + + assert.ok(reader.isDestroyed); + }); + it('should throw an error when trying to destroy reader twice', () => { const reader = new TestReader('directory'); diff --git a/packages/fs/fs.walk/src/readers/async.ts b/packages/fs/fs.walk/src/readers/async.ts index 4393df17..d82884a9 100644 --- a/packages/fs/fs.walk/src/readers/async.ts +++ b/packages/fs/fs.walk/src/readers/async.ts @@ -41,6 +41,10 @@ export default class AsyncReader extends Reader { return this._emitter; } + public get isDestroyed(): boolean { + return this._isDestroyed; + } + public destroy(): void { if (this._isDestroyed) { throw new Error('The reader is already destroyed');