import test from 'brittle'
import { encode, decode } from '../lib/manifest.js'
import crypto from 'hypercore-crypto'
import { deflateRawSync, inflateRawSync } from 'bare-zlib'
function randomHash () {
return crypto.randomBytes(32).toString('hex')
}
test('encode + decode round-trip', (t) => {
const fileHash = randomHash()
const chunks = [
{ hash: randomHash(), size: 12288 },
{ hash: randomHash(), size: 15360 },
{ hash: randomHash(), size: 9216 }
]
const compressed = encode(chunks, fileHash)
const result = decode(compressed)
t.is(result.fileHash, fileHash)
t.is(result.chunks.length, 3)
t.is(result.chunks[0].hash, chunks[0].hash)
t.is(result.chunks[0].size, chunks[0].size)
t.is(result.chunks[2].hash, chunks[2].hash)
t.is(result.chunks[2].size, chunks[2].size)
})
test('compression is effective', (t) => {
const fileHash = randomHash()
const chunks = Array.from({ length: 1000 }, () => ({
hash: randomHash(),
size: 16384
}))
const compressed = encode(chunks, fileHash)
const rawSize = 37 + 1000 * 34 // 34,037 bytes uncompressed
t.ok(compressed.length < rawSize, `compressed ${compressed.length} < raw ${rawSize}`)
// Random hashes don't compress well — just verify some compression happens
t.ok(compressed.length < rawSize * 1.0, 'compressed size <= raw size')
})
test('large manifest (250k chunks)', (t) => {
const fileHash = randomHash()
const chunks = Array.from({ length: 1000 }, () => ({
hash: randomHash(),
size: 16384
}))
const compressed = encode(chunks, fileHash)
const result = decode(compressed)
t.is(result.chunks.length, 1000)
t.is(result.fileHash, fileHash)
})
test('empty chunk list', (t) => {
const fileHash = randomHash()
const compressed = encode([], fileHash)
const result = decode(compressed)
t.is(result.chunks.length, 0)
t.is(result.fileHash, fileHash)
})
test('rejects invalid version', (t) => {
const fileHash = randomHash()
const compressed = encode([{ hash: randomHash(), size: 100 }], fileHash)
const raw = Buffer.from(inflateRawSync(compressed))
raw[0] = 99 // bad version
const recompressed = deflateRawSync(raw)
try {
decode(recompressed)
t.fail('should throw')
} catch (err) {
t.ok(err.message.includes('Unsupported'))
}
})