import { assert, assertEquals, assertRejects } from '@std/assert'; import { ChecksumMismatchError, InvalidSignatureError, TruncatedArchiveError } from '../lib/errors.ts'; import { readContainer, readNextHeader, readSignatureHeader } from '../lib/container.ts'; import { fromUint8Array } from '../lib/reader/common.ts'; const FIXTURES = new URL('./fixtures/commons-compress/', import.meta.url); const LIBARCHIVE_FIXTURES = new URL('./fixtures/libarchive/', import.meta.url); const loadFixture = (name: string): Uint8Array => { return Deno.readFileSync(new URL(name, FIXTURES)); }; const loadLibarchive = (name: string): Uint8Array => { return Deno.readFileSync(new URL(name, LIBARCHIVE_FIXTURES)); }; Deno.test('readSignatureHeader: valid mhc-off-copy fixture', async () => { const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); const start = await readSignatureHeader(reader); assertEquals(start.versionMajor, 0); // nextHeader is at offset 32 + 14 = 46 (after 14 bytes of "Hello, world!\n" payload) assertEquals(start.nextHeaderOffset, 14); assertEquals(start.nextHeaderSize, 86); }); Deno.test('readSignatureHeader: rejects non-7z input', async () => { const garbage = new Uint8Array(64); garbage.set([0x50, 0x4b, 0x03, 0x04]); // PK\x03\x04 (zip) const reader = fromUint8Array(garbage); await assertRejects(() => readSignatureHeader(reader), InvalidSignatureError); }); Deno.test('readSignatureHeader: rejects truncated input', async () => { const reader = fromUint8Array(new Uint8Array(10)); await assertRejects(() => readSignatureHeader(reader), TruncatedArchiveError); }); Deno.test('readSignatureHeader: rejects bad StartHeader CRC', async () => { const data = loadFixture('7z-hello-mhc-off-copy.7z'); const clone = new Uint8Array(data); clone[12] ^= 0xff; // mangle first byte of the StartHeader payload const reader = fromUint8Array(clone); await assertRejects(() => readSignatureHeader(reader), ChecksumMismatchError); }); Deno.test('readNextHeader: returns a plain Header for mhc-off-copy', async () => { const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); const start = await readSignatureHeader(reader); const raw = await readNextHeader(reader, start); assertEquals(raw.kind, 'header'); }); Deno.test('readContainer: mhc-off-copy parses to one file with one folder', async () => { const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); const container = await readContainer(reader); assertEquals(container.header.files.length, 1); assertEquals(container.header.files[0].name, 'Hello world.txt'); assertEquals(container.header.files[0].size, 14); assertEquals(container.header.files[0].hasStream, true); assertEquals(container.header.files[0].isDirectory, false); assert(container.header.files[0].crc !== undefined); assertEquals(container.header.folders.length, 1); assertEquals(container.header.folders[0].coders.length, 1); // Copy method has id 0x00, single zero byte assertEquals(container.header.folders[0].coders[0].methodId.length, 1); assertEquals(container.header.folders[0].coders[0].methodId[0], 0x00); assertEquals(container.header.pack.packSizes, [14]); assertEquals(container.packBase, 32); }); Deno.test('readContainer: mhc-off-lzma2 parses to one file with one lzma2 coder', async () => { const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-lzma2.7z')); const container = await readContainer(reader); assertEquals(container.header.files.length, 1); assertEquals(container.header.files[0].name, 'Hello world.txt'); assertEquals(container.header.files[0].size, 14); assertEquals(container.header.folders.length, 1); const coder = container.header.folders[0].coders[0]; assertEquals(coder.methodId.length, 1); assertEquals(coder.methodId[0], 0x21); // LZMA2 // LZMA2 stores a 1-byte dictionary descriptor as its property assertEquals(coder.properties.length, 1); }); Deno.test('readContainer: libarchive copy.7z (plain header) parses', async () => { const reader = fromUint8Array(loadLibarchive('test_read_format_7zip_copy.7z')); const container = await readContainer(reader); assertEquals(container.header.files.length, 1); assertEquals(container.header.files[0].name, 'file1'); assertEquals(container.header.folders.length, 1); // the copy fixture stores a single file with the Copy coder assertEquals(container.header.folders[0].coders[0].methodId[0], 0x00); assert(container.header.files[0].size > 0); }); Deno.test('readNextHeader: bla.7z carries an EncodedHeader', async () => { const reader = fromUint8Array(loadFixture('bla.7z')); const start = await readSignatureHeader(reader); const raw = await readNextHeader(reader, start); assertEquals(raw.kind, 'encoded'); }); Deno.test('readContainer: bla.7z decodes its encoded header', async () => { const reader = fromUint8Array(loadFixture('bla.7z')); const container = await readContainer(reader); assert(container.header.files.length > 0); assertEquals(container.header.files[0].name, 'test1.xml'); }); Deno.test('readContainer: mhc-off-empty has one zero-byte file and no folders', async () => { // commons-compress's "empty" mhc-off fixture records a file named "empty" // with no data stream (and consequently no folders or pack data). const reader = fromUint8Array(loadFixture('7z-empty-mhc-off.7z')); const container = await readContainer(reader); assertEquals(container.header.files.length, 1); assertEquals(container.header.files[0].name, 'empty'); assertEquals(container.header.files[0].size, 0); assertEquals(container.header.files[0].hasStream, false); assertEquals(container.header.files[0].isDirectory, false); assertEquals(container.header.folders.length, 0); });