Files
time/ventures/havre/tests/backup.test.mjs
T

62 lines
3.6 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import * as B from "../backup.js";
import * as R from "../memory.js";
import { normalizeCard } from "../card.js";
const ines = normalizeCard({ name: "Ines Corbel", persona: "You are Ines." });
const wren = normalizeCard({ name: "Wren", persona: "You are Wren." });
const threads = [
{ id: "t1", card: "ines-corbel", msgs: [{ id: "a", role: "user", content: "hi" }, { id: "b", role: "assistant", content: "", media: { kind: "photo", id: "p1" } }] },
{ id: "t2", card: "wren", msgs: [{ id: "c", role: "assistant", content: "", media: { kind: "photo", id: "p2" } }] },
];
const media = { p1: "data:image/webp;base64,AAAA", p2: "data:image/webp;base64,BBBB", p9: "data:image/webp;base64,CCCC" };
test("one character's bundle holds their card, memory, chats and only those chats' pictures", () => {
const mem = { notes: [R.note("They hate fog.", { at: 5 })], upTo: { t1: "b" }, at: 5 };
const b = B.bundleOne(ines, { memory: mem, threads, media, at: 9 });
assert.equal(b.havre_backup, 1);
assert.deepEqual(b.cards.map((c) => c.id), ["ines-corbel"]);
assert.deepEqual(Object.keys(b.memory), ["ines-corbel"]);
assert.deepEqual(b.threads.map((t) => t.id), ["t1"]);
assert.deepEqual(Object.keys(b.media), ["p1"]);
assert.equal(B.bundleName(ines), "ines-corbel.havre-full.json");
assert.match(B.bundleName(null, Date.UTC(2026, 9, 20)), /^havre-backup-2026-10-20\.json$/);
});
test("the whole harbor: everything, and the settings, never a key", () => {
const b = B.bundleAll({ cards: [ines, wren], memory: {}, threads, media, settings: { abilities: { own: true } } });
assert.equal(b.cards.length, 2);
assert.equal(b.threads.length, 2);
assert.deepEqual(Object.keys(b.media).sort(), ["p1", "p2", "p9"]);
assert.deepEqual(b.settings, { abilities: { own: true } });
assert.ok(!JSON.stringify(b).includes("key"));
});
test("a bundle reads back safely, and anything else is not one", () => {
assert.equal(B.readBundle({ cards: [] }), null);
assert.equal(B.readBundle("x"), null);
const b = B.readBundle(JSON.parse(JSON.stringify(B.bundleOne(ines, { memory: { notes: ["old"], upTo: {}, at: 1 }, threads, media }))));
assert.equal(b.cards[0].name, "Ines Corbel");
assert.deepEqual(b.memory["ines-corbel"].notes.map((n) => n.text), ["old"]);
assert.equal(b.threads.length, 1);
assert.deepEqual(Object.keys(b.media), ["p1"]);
assert.equal(b.settings, null);
const junk = B.readBundle({ havre_backup: 1, cards: [{ name: "X" }, null, 3], threads: [{ id: "t", card: "x", msgs: [{ role: "system" }, { role: "user", content: "k" }] }, {}], media: { ok: "data:image/png;base64,AA", bad: "javascript:x" } });
assert.equal(junk.cards.length, 1);
assert.equal(junk.threads.length, 1);
assert.equal(junk.threads[0].msgs.length, 1);
assert.deepEqual(Object.keys(junk.media), ["ok"]);
});
test("restoring merges: cards already there stay, notes are appended, chats by id are added if missing", () => {
const b = B.readBundle(B.bundleAll({ cards: [ines, wren], memory: { "ines-corbel": { notes: [R.note("new", { at: 3 })], upTo: { t1: "b" }, at: 3 } }, threads, media }));
const m = B.merge(b, { cards: [ines], memory: { "ines-corbel": { notes: [R.note("old", { at: 1 })], upTo: { t5: "z" }, at: 1 } }, threads: { t1: {} } });
assert.deepEqual(m.addCards.map((c) => c.id), ["wren"]);
assert.equal(m.skippedCards, 1);
assert.deepEqual(m.memory["ines-corbel"].notes.map((n) => n.text), ["old", "new"]);
assert.deepEqual(m.memory["ines-corbel"].upTo, { t1: "b", t5: "z" });
assert.deepEqual(m.addThreads.map((t) => t.id), ["t2"]);
assert.equal(m.skippedThreads, 1);
});