Files
2026-10-15 11:57:09 +02:00

126 lines
5.7 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createRequire } from 'node:module';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import zlib from 'node:zlib';
import { DEFAULTS, cleanPrefs, wikiToMarkdownLinks } from '../src/lib/prefs.js';
import { formatDate, dailyId, dailyBody } from '../src/lib/daily.js';
import { weekOf, monthGrid, weekdayNames } from '../src/lib/database.js';
const require = createRequire(import.meta.url);
test('cleanPrefs fills defaults and drops values of the wrong kind', () => {
assert.deepEqual(cleanPrefs(undefined), DEFAULTS);
assert.deepEqual(cleanPrefs('nope'), DEFAULTS);
const p = cleanPrefs({ density: 'huge', sidebarWidth: 9999, codeSize: '110', autoPair: 'yes', hiddenKinds: ['quote', 4], trashDays: -3, dateFormat: 'DD/MM' });
assert.equal(p.density, 'default');
assert.equal(p.sidebarWidth, 420);
assert.equal(p.codeSize, 110);
assert.equal(p.autoPair, true);
assert.deepEqual(p.hiddenKinds, ['quote']);
assert.equal(p.trashDays, 0);
assert.equal(p.dateFormat, 'YYYY-MM-DD');
assert.equal(cleanPrefs({ historyKeep: '' }).historyKeep, DEFAULTS.historyKeep);
});
test('daily note names follow the chosen format', () => {
const d = new Date(2026, 0, 5);
assert.equal(formatDate(d), '2026-01-05');
assert.equal(formatDate(d, 'DD-MM-YYYY'), '05-01-2026');
assert.equal(formatDate(d, 'MMMM D, YYYY', 'en-US'), 'January 5, 2026');
assert.equal(formatDate(d, 'YYYY-MM-DD dddd', 'en-US'), '2026-01-05 Monday');
assert.equal(dailyId('Daily', d, 'YYYY.MM.DD'), 'Daily/2026.01.05');
assert.equal(dailyId('Daily', d), 'Daily/2026-01-05');
});
test('the daily template fills in the date and weekday', () => {
const d = new Date(2026, 0, 5);
assert.equal(dailyBody('## {{weekday}} {{ date }}', d, 'DD-MM-YYYY', 'en-US'), '## Monday 05-01-2026');
assert.equal(dailyBody('', d), '');
});
test('calendar weeks can start on Sunday', () => {
assert.equal(weekOf('2026-01-07')[0].iso, '2026-01-05'); // Monday
assert.equal(weekOf('2026-01-07', true)[0].iso, '2026-01-04'); // Sunday
assert.equal(weekOf('2026-01-04', true)[0].iso, '2026-01-04');
assert.deepEqual(weekdayNames(true).slice(0, 2), ['Sun', 'Mon']);
const g = monthGrid(2026, 1, true); // February 2026 starts on a Sunday: a Sunday-first grid has no lead days
assert.equal(g[0][0].iso, '2026-02-01');
assert.equal(g.length, 4);
});
test('Markdown export can write links as Markdown links', () => {
const md = 'See [[My Page]] and [[Other|that one]], ![[photo.png]], [[Page#Some Heading]].\n`[[kept]]`\n```\n[[kept too]]\n```';
const out = wikiToMarkdownLinks(md);
assert.match(out, /\[My Page\]\(My%20Page\.md\)/);
assert.match(out, /\[that one\]\(Other\.md\)/);
assert.match(out, /!\[\]\(photo\.png\)/);
assert.match(out, /\(Page\.md#some-heading\)/);
assert.match(out, /`\[\[kept\]\]`/);
assert.match(out, /\n\[\[kept too\]\]\n/);
});
test('a backup is a readable zip without history and trash', async () => {
const { zipFolder, backup, due, crc32 } = require('../electron/backup.cjs');
assert.equal(crc32(Buffer.from('123456789')), 0xcbf43926);
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ink-bk-'));
const out = fs.mkdtempSync(path.join(os.tmpdir(), 'ink-bk-out-'));
fs.mkdirSync(path.join(root, 'A'), { recursive: true });
fs.mkdirSync(path.join(root, '.notes', 'history', 'A'), { recursive: true });
fs.writeFileSync(path.join(root, 'A.md'), '# Hello\n'.repeat(50));
fs.writeFileSync(path.join(root, 'A', 'Sub é.md'), 'x');
fs.writeFileSync(path.join(root, '.notes', 'history', 'A', '1.md'), 'old');
const file = path.join(out, 'x.zip');
assert.equal(await zipFolder(root, file), 2);
// read it back: end record -> central directory -> entries
const buf = fs.readFileSync(file);
const end = buf.length - 22;
assert.equal(buf.readUInt32LE(end), 0x06054b50);
const n = buf.readUInt16LE(end + 10);
let at = buf.readUInt32LE(end + 16);
const found = {};
for (let i = 0; i < n; i++) {
const method = buf.readUInt16LE(at + 10), crc = buf.readUInt32LE(at + 16), csize = buf.readUInt32LE(at + 20), size = buf.readUInt32LE(at + 24);
const nameLen = buf.readUInt16LE(at + 28), off = buf.readUInt32LE(at + 42);
const name = buf.toString('utf8', at + 46, at + 46 + nameLen);
const dataAt = off + 30 + buf.readUInt16LE(off + 26) + buf.readUInt16LE(off + 28);
const raw = buf.subarray(dataAt, dataAt + csize);
const data = method === 8 ? zlib.inflateRawSync(raw) : raw;
assert.equal(data.length, size);
assert.equal(crc32(data), crc);
found[name] = data.toString();
at += 46 + nameLen;
}
assert.deepEqual(Object.keys(found).sort(), ['A.md', 'A/Sub é.md']);
assert.equal(found['A/Sub é.md'], 'x');
// keeping only the newest few
for (const f of ['2020-01-01 0000', '2020-01-02 0000', '2020-01-03 0000']) fs.writeFileSync(path.join(out, `${path.basename(root)} ${f}.zip`), 'z');
await backup(root, out, 2);
assert.equal(fs.readdirSync(out).filter((f) => f.startsWith(path.basename(root))).length, 2);
assert.equal(due('off', 0), false);
assert.equal(due('daily', 0), true);
assert.equal(due('daily', Date.now() - 3600e3), false);
assert.equal(due('weekly', Date.now() - 3 * 864e5), false);
});
test('history limits can be changed', async () => {
const { Vault, setLimits } = require('../electron/vault.cjs');
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ink-hist-'));
const v = new Vault(dir);
setLimits({ historyKeep: 3, historyGapMin: 1 });
try {
for (let i = 0; i < 6; i++) {
await v.write('P', {}, 'v' + i);
await v.snapshot('P', 'text ' + i, { force: true });
}
assert.equal((await v.listHistory('P')).length, 3);
} finally {
setLimits({ historyKeep: 100, historyGapMin: 5 });
}
});