77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import { test } from 'node:test';
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { buildExport, mergeData, parseExport, planImport } from './dataExport';
|
||
|
|
|
||
|
|
const file = buildExport({
|
||
|
|
userId: '@a:hs',
|
||
|
|
accountData: {
|
||
|
|
'io.lotus.bookmarks': { bookmarks: [{ id: 'b1', note: 'x' }] },
|
||
|
|
'io.lotus.user_notes': { notes: { '@b:hs': 'met at LAN party' } },
|
||
|
|
'm.direct': { secret: true },
|
||
|
|
'io.lotus.settings': { theme: 'dark', fontSize: 16 },
|
||
|
|
},
|
||
|
|
decoration: 'halo',
|
||
|
|
localSettings: { callNoiseSuppression: 'ml' },
|
||
|
|
now: new Date('2026-10-25T00:00:00Z'),
|
||
|
|
});
|
||
|
|
|
||
|
|
test('[#114] export keeps only our own types', () => {
|
||
|
|
assert.equal(file.format, 'lotus-chat-data');
|
||
|
|
assert.equal(file.version, 1);
|
||
|
|
assert.deepEqual(Object.keys(file.accountData).sort(), [
|
||
|
|
'io.lotus.bookmarks',
|
||
|
|
'io.lotus.settings',
|
||
|
|
'io.lotus.user_notes',
|
||
|
|
]);
|
||
|
|
assert.equal(file.profile.decoration, 'halo');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('[#114] parse: round trip, wrong files, newer versions, foreign types', () => {
|
||
|
|
const r = parseExport(JSON.stringify(file));
|
||
|
|
assert.ok(r.ok);
|
||
|
|
assert.equal(parseExport('nope').ok, false);
|
||
|
|
assert.equal(parseExport('{"format":"other"}').ok, false);
|
||
|
|
const newer = parseExport(JSON.stringify({ ...file, version: 2 }));
|
||
|
|
assert.ok(!newer.ok && /newer Lotus Chat/.test(newer.error));
|
||
|
|
const sneaky = parseExport(
|
||
|
|
JSON.stringify({ ...file, accountData: { 'm.push_rules': {}, 'io.lotus.bookmarks': {} } }),
|
||
|
|
);
|
||
|
|
assert.ok(sneaky.ok);
|
||
|
|
assert.deepEqual(Object.keys(sneaky.file.accountData), ['io.lotus.bookmarks']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('[#114] merge: lists by id, maps by key, conflicts kept unless preferred', () => {
|
||
|
|
const mine = { bookmarks: [{ id: 'b1', note: 'mine' }, { id: 'b2' }] };
|
||
|
|
const theirs = { bookmarks: [{ id: 'b1', note: 'theirs' }, { id: 'b3' }] };
|
||
|
|
const keep = mergeData(mine, theirs);
|
||
|
|
assert.equal(keep.added, 1);
|
||
|
|
assert.equal(keep.conflicts, 1);
|
||
|
|
assert.deepEqual(keep.value, {
|
||
|
|
bookmarks: [{ id: 'b1', note: 'mine' }, { id: 'b2' }, { id: 'b3' }],
|
||
|
|
});
|
||
|
|
const take = mergeData(mine, theirs, true);
|
||
|
|
assert.deepEqual((take.value as typeof mine).bookmarks[0], { id: 'b1', note: 'theirs' });
|
||
|
|
|
||
|
|
const notes = mergeData({ a: 1, b: 2 }, { b: 3, c: 4 });
|
||
|
|
assert.deepEqual(notes, { value: { a: 1, b: 2, c: 4 }, added: 1, conflicts: 1 });
|
||
|
|
assert.deepEqual(mergeData(undefined, { x: 1 }), { value: { x: 1 }, added: 1, conflicts: 0 });
|
||
|
|
assert.deepEqual(mergeData(['a'], ['a', 'b']).value, ['a', 'b']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('[#114] plan summarises per category', () => {
|
||
|
|
const plan = planImport(file, {
|
||
|
|
accountData: { 'io.lotus.settings': { theme: 'light' } },
|
||
|
|
decoration: null,
|
||
|
|
localSettings: { callNoiseSuppression: 'ml' },
|
||
|
|
});
|
||
|
|
const by = Object.fromEntries(plan.map((p) => [p.key, p]));
|
||
|
|
assert.deepEqual(
|
||
|
|
[by['io.lotus.settings'].added, by['io.lotus.settings'].conflicts],
|
||
|
|
[1, 1],
|
||
|
|
'fontSize new, theme differs',
|
||
|
|
);
|
||
|
|
assert.equal(by['io.lotus.bookmarks'].added, 1);
|
||
|
|
assert.equal(by['profile.decoration'].added, 1);
|
||
|
|
assert.deepEqual([by['local.settings'].added, by['local.settings'].conflicts], [0, 0]);
|
||
|
|
});
|