openpencil/tests/engine/io/fig/thumbnail-range.test.ts
Danila Poyarkov 4fe27dd1e6 fix(storage): harden workspace previews
- Validate ranged thumbnail payloads and S3 bounds

- Invalidate stale previews and expose loading errors

- Document the public document workspace composable
2026-08-10 20:02:58 +03:00

52 lines
1.8 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { readFileSync } from 'node:fs'
import { zipSync } from 'fflate'
import { extractFigThumbnailFromReader } from '@open-pencil/fig'
function memoryReader(bytes: Uint8Array, ranges: Array<[number, number]>) {
return {
size: bytes.byteLength,
async read(start: number, endExclusive: number) {
ranges.push([start, endExclusive])
return bytes.slice(start, endExclusive)
}
}
}
describe('fig ranged thumbnail extraction', () => {
test('extracts thumbnail.png without reading the complete fig', async () => {
const bytes = new Uint8Array(readFileSync('tests/fixtures/gold-preview.fig'))
const ranges: Array<[number, number]> = []
const thumbnail = await extractFigThumbnailFromReader(memoryReader(bytes, ranges), {
maxTailBytes: 4 * 1024 * 1024
})
expect(thumbnail?.subarray(0, 8)).toEqual(
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
)
expect(ranges.length).toBeGreaterThanOrEqual(2)
expect(ranges.every(([start, end]) => start !== 0 || end !== bytes.byteLength)).toBe(true)
expect(ranges.reduce((total, [start, end]) => total + end - start, 0)).toBeLessThan(
bytes.byteLength
)
})
test('rejects malformed thumbnail payloads', async () => {
const bytes = zipSync({
'canvas.fig': new Uint8Array([1]),
'thumbnail.png': new TextEncoder().encode('not a png')
})
expect(await extractFigThumbnailFromReader(memoryReader(bytes, []))).toBeNull()
})
test('rejects thumbnails above configured output limits', async () => {
const bytes = new Uint8Array(readFileSync('tests/fixtures/gold-preview.fig'))
const thumbnail = await extractFigThumbnailFromReader(memoryReader(bytes, []), {
maxOutputBytes: 32
})
expect(thumbnail).toBeNull()
})
})