feat: add local OneNote and ONEPKG reader
This commit is contained in:
114
src/onenote/onepkg/joplin-fixture.test.ts
Normal file
114
src/onenote/onepkg/joplin-fixture.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { parseOneNoteSection } from '../parser/parse-section.js';
|
||||
import { enumerateCabinet, extractCabinet } from './cabinet.js';
|
||||
import { openOneNotePackage } from './package.js';
|
||||
|
||||
/*
|
||||
* Joplin CLI test fixture, AGPL-3.0-or-later. See tests/fixtures/README.md.
|
||||
* Pinned upstream revision: 1e73aad7eb08fde5d9e4cb533df40052a5cd32d7
|
||||
*/
|
||||
const encodedFixture = readFileSync(
|
||||
resolve(process.cwd(), 'tests/fixtures/joplin-test.onepkg.base64'),
|
||||
'utf8'
|
||||
);
|
||||
const JOPLIN_ONEPKG = Uint8Array.from(
|
||||
Buffer.from(encodedFixture.replaceAll(/\s/gu, ''), 'base64')
|
||||
);
|
||||
|
||||
const ONE_MAGIC = Uint8Array.from([
|
||||
0xe4, 0x52, 0x5c, 0x7b, 0x8c, 0xd8, 0xa7, 0x4d, 0xae, 0xb1, 0x53, 0x78, 0xd0,
|
||||
0x29, 0x96, 0xd3,
|
||||
]);
|
||||
|
||||
const EXPECTED_PATHS = [
|
||||
'Another section.one',
|
||||
'Open Notebook.onetoc2',
|
||||
'Section group/A.one',
|
||||
'Section group/B.one',
|
||||
'Section group/Open Notebook.onetoc2',
|
||||
'Tést!.one',
|
||||
'⅀⸨ Unicode ⸩.one',
|
||||
];
|
||||
|
||||
describe('pinned Joplin .onepkg fixture', () => {
|
||||
it('retains the reviewed upstream bytes', () => {
|
||||
expect(JOPLIN_ONEPKG).toHaveLength(11_066);
|
||||
expect(createHash('sha256').update(JOPLIN_ONEPKG).digest('hex')).toBe(
|
||||
'83cb622d40f0ab127038b629553b6926be3e2a6ce642f169df0e2614c13e8469'
|
||||
);
|
||||
});
|
||||
|
||||
it('enumerates all seven UTF-8/nested entries using LZX 0x1203', () => {
|
||||
const listing = enumerateCabinet(JOPLIN_ONEPKG);
|
||||
expect(listing.entries.map((entry) => entry.normalizedPath)).toEqual(
|
||||
EXPECTED_PATHS
|
||||
);
|
||||
expect(listing.folders).toHaveLength(1);
|
||||
expect(listing.folders[0]).toMatchObject({
|
||||
dataBlockCount: 3,
|
||||
compression: { kind: 'lzx', raw: 0x1203, windowBits: 18 },
|
||||
});
|
||||
expect(
|
||||
listing.diagnostics.filter(
|
||||
(diagnostic) => diagnostic.code === 'cab-unmarked-utf8-name'
|
||||
)
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('extracts every entry and preserves native .one headers', async () => {
|
||||
const extraction = await extractCabinet(JOPLIN_ONEPKG);
|
||||
expect(
|
||||
extraction.extractedEntries.map((entry) => entry.normalizedPath)
|
||||
).toEqual(EXPECTED_PATHS);
|
||||
const sections = extraction.extractedEntries.filter((entry) =>
|
||||
entry.normalizedPath.toLowerCase().endsWith('.one')
|
||||
);
|
||||
expect(sections).toHaveLength(5);
|
||||
for (const section of sections) {
|
||||
expect(section.bytes.subarray(0, ONE_MAGIC.length)).toEqual(ONE_MAGIC);
|
||||
}
|
||||
|
||||
const opened = await openOneNotePackage(JOPLIN_ONEPKG, {
|
||||
sourceName: 'test.onepkg',
|
||||
});
|
||||
expect(opened.package.entries).toHaveLength(7);
|
||||
expect(opened.package.sections).toHaveLength(5);
|
||||
expect(
|
||||
opened.package.sections.every(
|
||||
(section) => section.parseStatus === 'not-requested'
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('opens and parses all five packaged sections end to end', async () => {
|
||||
const opened = await openOneNotePackage(JOPLIN_ONEPKG, {
|
||||
sourceName: 'test.onepkg',
|
||||
parseSection: ({ bytes, normalizedPath }) => ({
|
||||
status: 'parsed',
|
||||
value: parseOneNoteSection(bytes, { sourceName: normalizedPath }),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(opened.package.sections).toHaveLength(5);
|
||||
expect(
|
||||
opened.package.sections.map((section) => section.parseStatus)
|
||||
).toEqual(['parsed', 'parsed', 'parsed', 'parsed', 'parsed']);
|
||||
expect(
|
||||
opened.package.entries.some((entry) => entry.parseStatus === 'failed')
|
||||
).toBe(false);
|
||||
|
||||
const testSection = opened.package.sections.find(
|
||||
(section) => section.path === 'Tést!.one'
|
||||
);
|
||||
expect(testSection?.section?.sectionName).toBe('Tést!');
|
||||
expect(testSection?.section?.pages[0]).toMatchObject({
|
||||
title: 'Testing…',
|
||||
text: 'Link to page: Page 2',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user