profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
zip.test.ts 2,637 bytes
1 import { describe, expect, it } from 'vitest'
2 import { createZip } from './zip'
3
4 interface StoredEntry {
5 content: Buffer
6 localOffset: number
7 }
8
9 function readStoredEntries(zip: Buffer): Map<string, StoredEntry> {
10 const eocdOffset = zip.length - 22
11 expect(zip.readUInt32LE(eocdOffset)).toBe(0x06054b50)
12
13 const entryCount = zip.readUInt16LE(eocdOffset + 10)
14 const centralSize = zip.readUInt32LE(eocdOffset + 12)
15 const centralOffset = zip.readUInt32LE(eocdOffset + 16)
16 expect(centralOffset + centralSize).toBe(eocdOffset)
17
18 const entries = new Map<string, StoredEntry>()
19 let cursor = centralOffset
20
21 for (let index = 0; index < entryCount; index++) {
22 expect(zip.readUInt32LE(cursor)).toBe(0x02014b50)
23 expect(zip.readUInt16LE(cursor + 10)).toBe(0)
24
25 const storedSize = zip.readUInt32LE(cursor + 24)
26 const nameLength = zip.readUInt16LE(cursor + 28)
27 const extraLength = zip.readUInt16LE(cursor + 30)
28 const commentLength = zip.readUInt16LE(cursor + 32)
29 const localOffset = zip.readUInt32LE(cursor + 42)
30 const name = zip.subarray(cursor + 46, cursor + 46 + nameLength).toString('utf8')
31
32 expect(zip.readUInt32LE(localOffset)).toBe(0x04034b50)
33 expect(zip.readUInt16LE(localOffset + 8)).toBe(0)
34
35 const localSize = zip.readUInt32LE(localOffset + 22)
36 const localNameLength = zip.readUInt16LE(localOffset + 26)
37 const localExtraLength = zip.readUInt16LE(localOffset + 28)
38 const localName = zip
39 .subarray(localOffset + 30, localOffset + 30 + localNameLength)
40 .toString('utf8')
41 const contentOffset = localOffset + 30 + localNameLength + localExtraLength
42
43 expect(localName).toBe(name)
44 expect(localSize).toBe(storedSize)
45 entries.set(name, {
46 content: zip.subarray(contentOffset, contentOffset + storedSize),
47 localOffset,
48 })
49
50 cursor += 46 + nameLength + extraLength + commentLength
51 }
52
53 expect(cursor).toBe(eocdOffset)
54 return entries
55 }
56
57 describe('createZip', () => {
58 it('produces a valid stored zip with byte-for-byte content', () => {
59 const entries = [
60 { name: 'SPEC.md', content: Buffer.from('# SPEC\n\nsome content [S1]\n', 'utf8') },
61 { name: 'nested/HANDOFF.md', content: Buffer.from('claude "do the thing"\n', 'utf8') },
62 { name: 'empty.txt', content: Buffer.alloc(0) },
63 ]
64
65 const zipBuffer = createZip(entries, new Date('2026-01-15T10:30:00'))
66 const stored = readStoredEntries(zipBuffer)
67
68 for (const entry of entries) {
69 expect(stored.get(entry.name)?.content.equals(entry.content)).toBe(true)
70 }
71 expect([...stored.keys()]).toEqual(entries.map((entry) => entry.name))
72 })
73 })
74