import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { ParserDiagnostic } from '../model/diagnostics.js'; import type { DesktopOneStore } from '../onestore/desktop-store.js'; import type { ExGuid, StoreObject } from '../onestore/types.js'; import { exGuidKey } from '../onestore/types.js'; import { FSSHTTP_PACKAGING_FORMAT, ONE_SECTION_FILE_TYPE, ONE_TOC_FILE_TYPE, } from './detect-format.js'; import { parseOneNoteTableOfContents } from './parse-toc.js'; const { parseFssHttpOneStoreMock } = vi.hoisted(() => ({ parseFssHttpOneStoreMock: vi.fn(), })); vi.mock('../onestore/fsshttp-store.js', () => ({ parseFssHttpOneStore: parseFssHttpOneStoreMock, })); const ROOT_ID: ExGuid = { guid: '{6B46CF9E-D34C-401E-90B3-9F4C3DB606C4}', value: 1, }; const CONTEXT_ID: ExGuid = { guid: '{00000000-0000-0000-0000-000000000000}', value: 0, }; describe('table-of-contents format dispatch', () => { beforeEach(() => { parseFssHttpOneStoreMock.mockReset(); }); it('accepts an FSSHTTP-shaped .onetoc2 through the shared store adapter', () => { parseFssHttpOneStoreMock.mockImplementation( ( _bytes: Uint8Array, _limits: unknown, diagnostics: ParserDiagnostic[] ) => { diagnostics.push({ severity: 'warning', code: 'FSSHTTP_TEST_DIAGNOSTIC', message: 'Retained adapter diagnostic.', structure: 'Storage Index', recoverable: true, }); return tableOfContentsStore(); } ); const result = parseOneNoteTableOfContents( fssHttpHeader(ONE_TOC_FILE_TYPE), { sourceName: 'Open Notebook.onetoc2', limits: { maxFileBytes: 4_096 }, } ); expect(parseFssHttpOneStoreMock).toHaveBeenCalledOnce(); expect(parseFssHttpOneStoreMock.mock.calls[0]?.[1]).toMatchObject({ maxFileBytes: 4_096, }); expect(result).toMatchObject({ sourceName: 'Open Notebook.onetoc2', fileIdentity: '{921D7914-E817-4615-AEB5-9B1B5EA2E973}', entries: [], diagnostics: [{ code: 'FSSHTTP_TEST_DIAGNOSTIC' }], }); }); it('rejects an FSSHTTP section even when the adapter returns a valid store', () => { parseFssHttpOneStoreMock.mockReturnValue(sectionStore()); expect(() => parseOneNoteTableOfContents(fssHttpHeader(ONE_SECTION_FILE_TYPE)) ).toThrowError( expect.objectContaining({ code: 'INVALID_FORMAT', structure: 'OneStore table of contents', }) ); }); }); function tableOfContentsStore(): DesktopOneStore { const root: StoreObject = { id: ROOT_ID, jcid: 0x0002_0001, props: { objectIds: [], objectSpaceIds: [], contextIds: [], properties: { entries: [] }, }, mapping: new Map(), contextId: CONTEXT_ID, }; const rootObjectSpace = { id: ROOT_ID, roots: new Map([[1, ROOT_ID]]), objects: new Map([[exGuidKey(ROOT_ID), root]]), }; return { kind: 'table-of-contents', variant: 'fsshttpb-package-store', fileIdentity: '{921D7914-E817-4615-AEB5-9B1B5EA2E973}', rootObjectSpace, objectSpaces: new Map(), }; } function sectionStore(): DesktopOneStore { return { ...tableOfContentsStore(), kind: 'section' }; } function fssHttpHeader(fileType: string): Uint8Array { const bytes = new Uint8Array(64); writeGuid(bytes, 0, fileType); writeGuid(bytes, 16, '{921D7914-E817-4615-AEB5-9B1B5EA2E973}'); writeGuid(bytes, 48, FSSHTTP_PACKAGING_FORMAT); return bytes; } function writeGuid(target: Uint8Array, offset: number, guid: string): void { const plain = guid.replace(/[{}-]/gu, ''); const canonical = Array.from({ length: 16 }, (_, index) => Number.parseInt(plain.slice(index * 2, index * 2 + 2), 16) ); const order = [3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15]; for (let index = 0; index < order.length; index += 1) { target[offset + order[index]!] = canonical[index]!; } }