import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { createHash } from "node:crypto"; import { classifyMissingResources, isOptionalSourceKey, LINUXCNC_SOURCE_SEMANTICS_SCHEMA } from "./linuxcnc-source-semantics.mjs"; const report = JSON.parse(await readFile(new URL("../../coverage/linuxcnc-source-semantics-contract.json", import.meta.url), "utf8")); assert.equal(report.schema, "linuxcnc-source-semantics-contract.v1"); assert.equal(LINUXCNC_SOURCE_SEMANTICS_SCHEMA, "linuxcnc-source-semantics.v1"); assert.equal(isOptionalSourceKey("OPEN_FILE", "DISPLAY"), true); assert.equal(isOptionalSourceKey("INTRO_GRAPHIC", "DISPLAY"), true); assert.equal(isOptionalSourceKey("OPEN_FILE", "RS274NGC"), false); assert.equal(classifyMissingResources(["linuxcnc/configs/sim/craftsman/custom.hal"]), "BLOCKED_HAL"); assert.equal(classifyMissingResources(["linuxcnc/configs/sim/qtplasmac/metric_parameters.txt"]), "BLOCKED_RESOURCE"); assert.equal(report.control_panel_contract.projection_only, true); assert.ok(report.control_panel_contract.required_fields.includes("state_hash")); const canonical = (value) => { if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`; if (value && typeof value === "object") return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`; return JSON.stringify(value); }; const copy = structuredClone(report); const expected = copy.report_sha256; delete copy.report_sha256; assert.equal(expected, createHash("sha256").update(canonical(copy)).digest("hex")); console.log(JSON.stringify({ schema: report.schema, status: "verified", optional_open_file: true, hal_missing: "BLOCKED_HAL", resource_missing: "BLOCKED_RESOURCE", projection_only: true }));