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]); });