- Añade `streamArchiveEntry` que devuelve un stream para entradas internas de ZIP/7z - Añade tests unitarios que mockean `child_process.spawn` (7z + unzip fallback) - Mantiene `listArchiveEntries` y documenta dependencia de binarios en CI
70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
import { PassThrough } from 'stream';
|
|
import { EventEmitter } from 'events';
|
|
|
|
vi.mock('child_process', () => ({ spawn: vi.fn() }));
|
|
import * as child_process from 'child_process';
|
|
import { streamArchiveEntry } from '../../src/services/archiveReader';
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe('services/archiveReader streamArchiveEntry', () => {
|
|
it('streams entry using 7z stdout', async () => {
|
|
const pass = new PassThrough();
|
|
const proc = new EventEmitter() as any;
|
|
proc.stdout = pass;
|
|
|
|
(child_process.spawn as any).mockImplementation(() => proc as any);
|
|
|
|
// Emular producción de datos de forma asíncrona
|
|
setImmediate(() => {
|
|
pass.write(Buffer.from('content-from-7z'));
|
|
pass.end();
|
|
});
|
|
|
|
const stream = await streamArchiveEntry('/roms/archive.7z', 'path/file.txt');
|
|
expect(stream).not.toBeNull();
|
|
|
|
const chunks: Buffer[] = [];
|
|
for await (const chunk of stream as any) {
|
|
chunks.push(Buffer.from(chunk));
|
|
}
|
|
|
|
expect(Buffer.concat(chunks).toString()).toBe('content-from-7z');
|
|
});
|
|
|
|
it('falls back to unzip -p when 7z throws', async () => {
|
|
const pass = new PassThrough();
|
|
const proc2 = new EventEmitter() as any;
|
|
proc2.stdout = pass;
|
|
|
|
(child_process.spawn as any)
|
|
.mockImplementationOnce(() => {
|
|
throw new Error('spawn ENOENT');
|
|
})
|
|
.mockImplementationOnce(() => proc2 as any);
|
|
|
|
setImmediate(() => {
|
|
pass.write(Buffer.from('fallback-content'));
|
|
pass.end();
|
|
});
|
|
|
|
const stream = await streamArchiveEntry('/roms/archive.zip', 'file.dat');
|
|
expect(stream).not.toBeNull();
|
|
|
|
const chunks: Buffer[] = [];
|
|
for await (const chunk of stream as any) {
|
|
chunks.push(Buffer.from(chunk));
|
|
}
|
|
|
|
expect(Buffer.concat(chunks).toString()).toBe('fallback-content');
|
|
});
|
|
|
|
it('returns null for unsupported formats', async () => {
|
|
const res = await streamArchiveEntry('/roms/archive.bin', 'entry');
|
|
expect(res).toBeNull();
|
|
});
|
|
});
|