* Build a minimal fake ssh2 ClientChannel that satisfies SSHProcess's needs: * * - behaves as a Readable (for stdout) via PassThrough * - exposes .stderr as a Readable via a second PassThrough * - records .signal() and .close() calls * - emits 'close' / 'exit' on-demand
()
| 14 | * - emits 'close' / 'exit' on-demand |
| 15 | */ |
| 16 | function createFakeChannel(): { |
| 17 | channel: unknown; |
| 18 | signalCalls: string[]; |
| 19 | closeCalls: number; |
| 20 | emitClose: () => void; |
| 21 | emitExit: (code: number) => void; |
| 22 | } { |
| 23 | const stdout = new PassThrough(); |
| 24 | const stderr = new PassThrough(); |
| 25 | const signalCalls: string[] = []; |
| 26 | let closeCalls = 0; |
| 27 | |
| 28 | // Listeners registered via channel.on(...) |
| 29 | const listeners = new Map<string, Array<(...args: unknown[]) => void>>(); |
| 30 | |
| 31 | const channel = Object.assign(stdout, { |
| 32 | stderr, |
| 33 | signal(name: string): void { |
| 34 | signalCalls.push(name); |
| 35 | }, |
| 36 | close(): void { |
| 37 | closeCalls++; |
| 38 | }, |
| 39 | // Override .on to capture lifecycle listeners ('close', 'exit') while |
| 40 | // still letting the underlying Readable receive 'data'/'end'/'error'. |
| 41 | on(event: string, cb: (...args: unknown[]) => void): unknown { |
| 42 | if (event === 'close' || event === 'exit') { |
| 43 | let arr = listeners.get(event); |
| 44 | if (!arr) { |
| 45 | arr = []; |
| 46 | listeners.set(event, arr); |
| 47 | } |
| 48 | arr.push(cb); |
| 49 | return channel; |
| 50 | } |
| 51 | return PassThrough.prototype.on.call(stdout, event, cb); |
| 52 | }, |
| 53 | }); |
| 54 | |
| 55 | function emit(event: string, ...args: unknown[]): void { |
| 56 | const arr = listeners.get(event); |
| 57 | if (!arr) return; |
| 58 | for (const cb of arr) { |
| 59 | cb(...args); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | return { |
| 64 | channel, |
| 65 | signalCalls, |
| 66 | get closeCalls() { |
| 67 | return closeCalls; |
| 68 | }, |
| 69 | emitClose: () => { |
| 70 | emit('close'); |
| 71 | }, |
| 72 | emitExit: (code: number) => { |
| 73 | emit('exit', code); |
no test coverage detected