streaming 7-Zip archive extractor
0

Configure Feed

Select the types of activity you want to include in your feed.

pkg-7zip / tests / cursor.test.ts
3.4 kB 99 lines
1import { assertEquals, assertThrows } from '@std/assert'; 2 3import { MalformedArchiveError, TruncatedArchiveError } from '../lib/errors.ts'; 4import { Cursor, readAllOrBoolVector, readBoolVector } from '../lib/utils/cursor.ts'; 5 6Deno.test('Cursor: seek rejects negative offsets', () => { 7 const c = new Cursor(new Uint8Array(16)); 8 assertThrows(() => c.seek(-1), MalformedArchiveError); 9}); 10 11Deno.test('Cursor: seek rejects offsets past end', () => { 12 const c = new Cursor(new Uint8Array(16)); 13 assertThrows(() => c.seek(17), MalformedArchiveError); 14}); 15 16Deno.test('Cursor: skip past end throws TruncatedArchiveError', () => { 17 const c = new Cursor(new Uint8Array(4)); 18 assertThrows(() => c.skip(5), TruncatedArchiveError); 19}); 20 21Deno.test('Cursor: readU8 / peekU8 / position track movement', () => { 22 const c = new Cursor(new Uint8Array([0x10, 0x20, 0x30])); 23 assertEquals(c.peekU8(), 0x10); 24 assertEquals(c.position, 0); 25 assertEquals(c.readU8(), 0x10); 26 assertEquals(c.position, 1); 27 assertEquals(c.readU8(), 0x20); 28 assertEquals(c.remaining, 1); 29}); 30 31Deno.test('Cursor: readU32LE / readU64LE round-trip a known little-endian payload', () => { 32 const bytes = new Uint8Array([0x78, 0x56, 0x34, 0x12, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12]); 33 const c = new Cursor(bytes); 34 assertEquals(c.readU32LE(), 0x12345678); 35 assertEquals(c.readU64LE(), 0x1234567890abcdefn); 36}); 37 38Deno.test('Cursor: readVarInt decodes a short value', () => { 39 // 0x05 = 0000_0101 → high bit clear, value = 5. 40 const c = new Cursor(new Uint8Array([0x05])); 41 assertEquals(c.readVarInt(), 5); 42}); 43 44Deno.test('Cursor: readVarInt decodes a 2-byte value', () => { 45 // 0x80 marker = "1 follow-up byte", tail = 0, follow-up 0x80 → 128. 46 const c = new Cursor(new Uint8Array([0x80, 0x80])); 47 assertEquals(c.readVarInt(), 128); 48}); 49 50Deno.test('Cursor: readVarInt rejects values beyond MAX_SAFE_INTEGER', () => { 51 // 0xff prefix = "8 follow-up bytes, no tail bits"; eight 0xff bytes ≈ 2^64-1. 52 const c = new Cursor(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); 53 assertThrows(() => c.readVarInt(), MalformedArchiveError); 54}); 55 56Deno.test('Cursor: readBytes returns a fresh copy independent of the source', () => { 57 const src = new Uint8Array([1, 2, 3, 4]); 58 const c = new Cursor(src); 59 const copy = c.readBytes(2); 60 copy[0] = 0xff; 61 assertEquals(src[0], 1); // source untouched 62}); 63 64Deno.test('Cursor: view returns a zero-copy alias into the source', () => { 65 const src = new Uint8Array([1, 2, 3, 4]); 66 const c = new Cursor(src); 67 const v = c.view(2); 68 v[0] = 0xff; 69 assertEquals(src[0], 0xff); // confirms aliasing 70}); 71 72Deno.test('readBoolVector: unpacks MSB-first bits across multiple bytes', () => { 73 // 0b1010_1010 then 0b1100_0000 → MSB-first 12-bit run 74 const c = new Cursor(new Uint8Array([0b1010_1010, 0b1100_0000])); 75 assertEquals(readBoolVector(c, 12), [ 76 true, 77 false, 78 true, 79 false, 80 true, 81 false, 82 true, 83 false, 84 true, 85 true, 86 false, 87 false, 88 ]); 89}); 90 91Deno.test('readAllOrBoolVector: leading non-zero byte expands to all true', () => { 92 const c = new Cursor(new Uint8Array([0x01])); 93 assertEquals(readAllOrBoolVector(c, 3), [true, true, true]); 94}); 95 96Deno.test('readAllOrBoolVector: leading zero byte falls through to readBoolVector', () => { 97 const c = new Cursor(new Uint8Array([0x00, 0b1010_0000])); 98 assertEquals(readAllOrBoolVector(c, 3), [true, false, true]); 99});