openpencil/tests/engine/io/fig/export/parse-failures.test.ts
Danila Poyarkov 86d6a63d0f fix(fig): restore strict parse validation
- Reject corrupt compressed Kiwi chunks instead of accepting raw garbage\n- Tolerate legacy source metadata without editedFields in renderer fallbacks\n- Align font, derived glyph, shared style, renderer mock, and ownership tests with current contracts\n- Restore clean quick and heavy unit quality gates
2026-07-18 03:58:18 +03:00

69 lines
2.3 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { parseFigKiwiContainer } from '@open-pencil/kiwi/fig/parse'
/**
* Build a minimal fig-kiwi container with a valid header + schema chunk
* but a corrupt (non-compressible) data chunk that will cause inflateSync
* to throw. This verifies that the decompressor does NOT silently fall
* back to raw compressed bytes.
*/
function buildCorruptFigKiwi(): Uint8Array {
const schemaDeflated = new Uint8Array([0x78, 0x01, 0x01, 0x00, 0x00]) // minimal deflate
// Data chunk: random bytes that are neither valid zlib nor valid zstd
const dataCorrupt = new Uint8Array(32)
for (let i = 0; i < dataCorrupt.length; i++) dataCorrupt[i] = (i * 37) & 0xff
const header = new TextEncoder().encode('fig-kiwi')
const total = 8 + 4 + 4 + schemaDeflated.length + 4 + dataCorrupt.length
const out = new Uint8Array(total)
const view = new DataView(out.buffer, out.byteOffset, out.byteLength)
let offset = 0
out.set(header, offset)
offset += 8
view.setUint32(offset, 101, true)
offset += 4
view.setUint32(offset, schemaDeflated.length, true)
offset += 4
out.set(schemaDeflated, offset)
offset += schemaDeflated.length
view.setUint32(offset, dataCorrupt.length, true)
offset += 4
out.set(dataCorrupt, offset)
return out
}
describe('parseFigKiwiContainer: decompression failures', () => {
test('throws on corrupt data chunk (not raw bytes)', () => {
const buf = buildCorruptFigKiwi()
expect(() => parseFigKiwiContainer(buf)).toThrow()
})
test('returns null for missing header', () => {
const buf = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
expect(parseFigKiwiContainer(buf)).toBeNull()
})
test('returns null for fewer than 2 chunks', () => {
const header = new TextEncoder().encode('fig-kiwi')
const schemaDeflated = new Uint8Array([0x78, 0x01])
// No data chunk — only one chunk total
const total = 8 + 4 + 4 + schemaDeflated.length
const out = new Uint8Array(total)
const view = new DataView(out.buffer, out.byteOffset, out.byteLength)
let offset = 0
out.set(header, offset)
offset += 8
view.setUint32(offset, 101, true)
offset += 4
view.setUint32(offset, schemaDeflated.length, true)
offset += 4
out.set(schemaDeflated, offset)
expect(parseFigKiwiContainer(out)).toBeNull()
})
})