import { test } from "node:test"; import assert from "node:assert/strict"; import { join } from "node:path"; import { BusinessError, loadProject, projectFilePath, validateProjectDocument } from "../src/index.mjs"; import { tmp, writeJson } from "./helpers.mjs"; function refuses(fn, pattern, exitCode = 2) { assert.throws(fn, (error) => { assert.ok(error instanceof BusinessError, `expected BusinessError, got ${error}`); assert.equal(error.exitCode, exitCode); assert.match(error.message, pattern); return true; }); } const doc = (extra = {}) => ({ projectVersion: 1, id: "stack", vars: { "tracker.project": 3, "git.workingBranch": "refactor", "git.protectedBranches": ["main", "next"] }, roles: { coder: { vars: { "limits.tools": ["read", "bash"] } } }, ...extra, }); test("path and load", () => { assert.equal(projectFilePath("/w/stack"), "/w/stack/.mosaic/project.json"); const root = tmp(); writeJson(projectFilePath(root), doc()); const project = loadProject(root); assert.equal(project.id, "stack"); assert.equal(project.file, projectFilePath(root)); assert.deepEqual(project.roles.coder.vars["limits.tools"], ["read", "bash"]); assert.ok(Object.isFrozen(project.vars)); }); test("refusals", () => { refuses(() => loadProject("relative"), /normalized absolute path/); refuses(() => loadProject("/a/../b"), /normalized absolute path/); refuses(() => loadProject(tmp()), /project file not found/, 4); const v = (d) => validateProjectDocument(d, "/p/.mosaic/project.json"); refuses(() => v(doc({ projectVersion: 2 })), /projectVersion/); refuses(() => v(doc({ id: "Stack" })), /project id/); refuses(() => v(doc({ owner: "x" })), /unsupported project file key: "owner"/); refuses(() => v(doc({ vars: { harness: "pi" } })), /harness can't be set at the project layer/); refuses(() => v(doc({ vars: { "tracker.baseUrl": "http://x" } })), /project layer/); refuses(() => v(doc({ roles: { coder: { vars: { model: "x" } } } })), /roles\.coder\.vars: variable model can't be set at the project layer/); refuses(() => v(doc({ roles: { coder: { holder: "x" } } })), /unsupported .*roles\.coder key: "holder"/); refuses(() => v(doc({ roles: { "Coder!": {} } })), /role instance/); assert.deepEqual(v(doc({ vars: undefined, roles: undefined })).roles, {}); });