81 lines
3.7 KiB
JavaScript
81 lines
3.7 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import ts from "typescript";
|
|
|
|
const repoRoot = path.resolve(import.meta.dirname, "../../..");
|
|
const sourcePath = path.join(repoRoot, "web/protocol/recent-projects.ts");
|
|
const transpiled = ts.transpileModule(fs.readFileSync(sourcePath, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: sourcePath,
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(transpiled.diagnostics, []);
|
|
const moduleUrl = "data:text/javascript;base64," + Buffer.from(transpiled.outputText).toString("base64");
|
|
const {
|
|
normalizeRecentProjects,
|
|
parseRecentProjectIndex,
|
|
removeRecentProject,
|
|
upsertRecentProject,
|
|
classifyRecentProjectIdentity,
|
|
} = await import(moduleUrl);
|
|
|
|
function project(projectId, overrides = {}) {
|
|
return {
|
|
schemaVersion: 1,
|
|
projectId,
|
|
displayName: `${projectId}.blend`,
|
|
revision: 7,
|
|
bytes: 1024,
|
|
sha256: (projectId.charCodeAt(0) % 16).toString(16).repeat(64),
|
|
updatedAt: "2026-08-15T12:00:00.000Z",
|
|
lastOpenedAt: "2026-08-15T12:00:00.000Z",
|
|
backend: "opfs",
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test("M7-09 recent projects sort and deduplicate deterministically", () => {
|
|
const older = project("alpha", { revision: 2, updatedAt: "2026-08-15T08:00:00-04:00", lastOpenedAt: "2026-08-15T08:00:00-04:00" });
|
|
const newer = project("alpha", { revision: 3, updatedAt: "2026-08-15T12:01:00.000Z", lastOpenedAt: "2026-08-15T12:01:00.000Z" });
|
|
const second = project("beta", { lastOpenedAt: "2026-08-15T11:59:00.000Z" });
|
|
const forward = normalizeRecentProjects([older, second, newer]);
|
|
const reverse = normalizeRecentProjects([newer, second, older]);
|
|
|
|
assert.deepEqual(forward, reverse);
|
|
assert.deepEqual(forward.index.projects.map(({ projectId, revision }) => [projectId, revision]), [["alpha", 3], ["beta", 7]]);
|
|
assert.equal(forward.index.projects[0].updatedAt, "2026-08-15T12:01:00.000Z");
|
|
});
|
|
|
|
test("M7-09 malformed records are quarantined without hiding valid projects", () => {
|
|
const parsed = parseRecentProjectIndex({
|
|
schemaVersion: 1,
|
|
projects: [project("valid"), { ...project("bad"), sha256: "not-a-digest" }, { ...project("blank"), displayName: " " }],
|
|
});
|
|
assert.equal(parsed.quarantined, 2);
|
|
assert.deepEqual(parsed.index.projects.map((item) => item.projectId), ["valid"]);
|
|
assert.deepEqual(parseRecentProjectIndex({ schemaVersion: 99, projects: [] }), {
|
|
index: { schemaVersion: 1, projects: [] },
|
|
quarantined: 1,
|
|
});
|
|
});
|
|
|
|
test("M7-09 upsert and removal keep a bounded stable index", () => {
|
|
let index = { schemaVersion: 1, projects: [] };
|
|
index = upsertRecentProject(index, project("alpha"));
|
|
index = upsertRecentProject(index, project("alpha", { revision: 9, lastOpenedAt: "2026-08-15T12:02:00Z" }));
|
|
index = upsertRecentProject(index, project("beta"));
|
|
assert.deepEqual(index.projects.map(({ projectId, revision }) => [projectId, revision]), [["alpha", 9], ["beta", 7]]);
|
|
assert.deepEqual(removeRecentProject(index, "alpha").projects.map((item) => item.projectId), ["beta"]);
|
|
assert.equal(normalizeRecentProjects(index.projects, 0).index.projects.length, 0);
|
|
});
|
|
|
|
test("M7-10 recent project integrity classifies missing and mismatched content", () => {
|
|
const expected = { revision: 7, bytes: 1024, sha256: "a".repeat(64) };
|
|
assert.equal(classifyRecentProjectIdentity(expected, undefined), "MISSING");
|
|
assert.equal(classifyRecentProjectIdentity(expected, { ...expected, sha256: "b".repeat(64) }), "HASH_MISMATCH");
|
|
assert.equal(classifyRecentProjectIdentity(expected, { ...expected, revision: 8 }), "METADATA_MISMATCH");
|
|
assert.equal(classifyRecentProjectIdentity(expected, expected), undefined);
|
|
});
|