import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { SIM_CASE_CATALOG } from "../workspace/sim-case-catalog.mjs"; import { loadSimulationCase } from "../workspace/sim-case-loader.mjs"; import { WorkspaceRuntime } from "../workspace/runtime.mjs"; import { startConfiguration } from "../workspace/configuration-startup.mjs"; const fetchImpl = async (url) => { try { const body = await readFile(new URL(`../../${String(url).replace(/^\//, "")}`, import.meta.url)); return { ok: true, text: async () => body.toString("utf8") }; } catch { return { ok: false, text: async () => "" }; } }; const core = { _sim_create() { return 0; }, _sim_load_workspace() { return 0; } }; async function matrixRun() { const rows = []; for (const catalog of SIM_CASE_CATALOG) { const bundle = await loadSimulationCase({ path: catalog.path, fetchImpl }); let startup = null; if (bundle.status === "ready") { startup = startConfiguration({ workspace: new WorkspaceRuntime({ files: bundle.files }), entrypoint: bundle.entrypoint, core, halManifest: bundle.halManifest }); } const first = startup?.diagnostics?.[0] ?? null; const classification = bundle.status !== "ready" ? "BLOCKED_RESOURCE" : startup.status === "ready" ? "TASK_READY" : first?.code === "startup_hal_blocked" ? "BLOCKED_HAL" : first?.code === "startup_ini_blocked" || first?.code === "ini_assignment_invalid" ? "BLOCKED_INI" : "BLOCKED_STARTUP"; rows.push({ path: catalog.path, source_sha256: catalog.source_sha256, static_status: catalog.status, loader_status: bundle.status, classification, fetched_count: bundle.fetched.length, missing: bundle.missing, runtime_fixtures: bundle.runtime_fixtures, loader_state_hash: bundle.state_hash, startup_state: startup?.state ?? "BLOCKED", startup_state_hash: startup?.state_hash ?? null, resource_blocked_count: startup?.resources?.blocked_count ?? null, hal_record_count: startup?.hal?.record_count ?? null, hal_blocked_count: startup?.hal?.blocked_count ?? null, first_diagnostic: first ? { code: first.code, source: first.source, line: first.line, path: first.path ?? null } : null, }); } rows.sort((left, right) => left.path.localeCompare(right.path)); const counts = Object.fromEntries([...new Set(rows.map((row) => row.classification))].sort().map((classification) => [classification, rows.filter((row) => row.classification === classification).length])); return { schema: "sim-case-matrix-s8-06-sample.v1", status: "verified", case_count: rows.length, counts, cases: rows }; } const first = await matrixRun(); const second = await matrixRun(); assert.equal(first.case_count, 235); assert.deepEqual(first.counts, { BLOCKED_HAL: 4, BLOCKED_INI: 3, BLOCKED_RESOURCE: 216, BLOCKED_STARTUP: 2, TASK_READY: 10 }); assert.deepEqual(first, second); for (const path of [ "linuxcnc/configs/sim/axis/minimal_xyz.ini", "linuxcnc/configs/sim/axis/corexy/corexy_by_kins.ini", "linuxcnc/configs/sim/axis/corexy/corexy_by_hal.ini", "linuxcnc/configs/sim/axis/ja_tests/xz/xz.ini", ]) assert.equal(first.cases.find((row) => row.path === path).classification, "TASK_READY"); assert.equal(first.cases.find((row) => row.path.endsWith("anglejog.ini")).classification, "BLOCKED_RESOURCE"); assert.equal(first.cases.find((row) => row.path.endsWith("histogram_demo.ini")).classification, "BLOCKED_INI"); console.log(JSON.stringify(first));