import test from 'node:test'; import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; import { PassThrough } from 'node:stream'; import { readZipLines } from '../src/extract/rfb-extractor.mjs'; function fakeChild() { const child = new EventEmitter(); child.stdout = new PassThrough(); child.stderr = new PassThrough(); child.kill = () => child.emit('exit', null, 'SIGTERM'); return child; } test('readZipLines rejeita leitor ZIP que encerra com codigo nao zero e inclui stderr limitado', async () => { const child = fakeChild(); const zip = readZipLines({ name: 'fake', argsFor: () => [] }, 'ruim.zip', { spawn: () => child }); child.stderr.write('arquivo corrompido'); child.stdout.end(); child.emit('exit', 2, null); await assert.rejects(zip.done, /codigo 2.*arquivo corrompido/i); }); test('readZipLines rejeita erro de spawn mas nao trata kill intencional como corrupcao', async () => { const failed = fakeChild(); const zipFailed = readZipLines({ name: 'missing', argsFor: () => [] }, 'x.zip', { spawn: () => failed }); failed.emit('error', new Error('ENOENT')); await assert.rejects(zipFailed.done, /ENOENT/); const cancelled = fakeChild(); const zipCancelled = readZipLines({ name: 'fake', argsFor: () => [] }, 'x.zip', { spawn: () => cancelled }); zipCancelled.close(); await zipCancelled.done; }); test('readZipLines propaga erro do stream de saida do leitor', async () => { const child = fakeChild(); const zip = readZipLines({ name: 'fake', argsFor: () => [] }, 'x.zip', { spawn: () => child }); child.stdout.emit('error', new Error('falha de leitura')); await assert.rejects(zip.done, /falha de leitura/i); });