import { describe, expect, it } from 'vitest'; import { BinaryReader } from '../binary/BinaryReader.js'; import { resolveParserLimits } from '../parser/limits.js'; import { parseFssHttpDataElementPackage } from './data-elements.js'; import { FSSHTTP_OBJECT } from './types.js'; function start(type: number, compound: boolean, body: number[]): number[] { const raw = (body.length << 9) | (type << 3) | (compound ? 0x04 : 0x00); return [raw & 0xff, raw >>> 8, ...body]; } function end(type: number): number[] { return [(type << 2) | 0x01]; } function objectGroupDataEntry(): number[] { return start(FSSHTTP_OBJECT.objectGroupDataExcluded, false, [ 0x03, // One object reference. 0x00, // Nil ExGUID. 0x03, // One cell reference. 0x00, // Nil context ExGUID. 0x00, // Nil object-space ExGUID. 0x00, // Excluded object data size. ]); } function packageWithReferenceArrays(entryCount: number): Uint8Array { const dataEntries = Array.from({ length: entryCount }, () => objectGroupDataEntry() ).flat(); return Uint8Array.from([ ...start(FSSHTTP_OBJECT.dataElementPackage, true, [0x00]), ...start(FSSHTTP_OBJECT.dataElement, true, [ 0x00, // Nil data-element ExGUID. 0x00, // Nil serial number. 0x0b, // Object Group data-element type (5). ]), ...start(FSSHTTP_OBJECT.objectGroupDeclaration, true, []), ...end(FSSHTTP_OBJECT.objectGroupDeclaration), ...start(FSSHTTP_OBJECT.objectGroupData, true, []), ...dataEntries, ...end(FSSHTTP_OBJECT.objectGroupData), ...end(FSSHTTP_OBJECT.dataElement), ...end(FSSHTTP_OBJECT.dataElementPackage), ]); } describe('FSSHTTPB data elements', () => { it('enforces one aggregate budget across many reference arrays', () => { const bytes = packageWithReferenceArrays(16); expect(() => parseFssHttpDataElementPackage( // Every array contains one reference, but the package contains 32. new BinaryReader(bytes), resolveParserLimits({ maxObjectReferences: 31 }) ) ).toThrowError( expect.objectContaining({ code: 'LIMIT_EXCEEDED', structure: 'FSSHTTPB object and cell references', }) ); const parsed = parseFssHttpDataElementPackage( new BinaryReader(bytes), resolveParserLimits({ maxObjectReferences: 32 }) ); expect(parsed.objectGroups.values().next().value?.data).toHaveLength(16); }); });