import assert from "node:assert/strict"; import { WorkspaceRuntime } from "../workspace/runtime.mjs"; import { parseIni } from "../workspace/ini-parser.mjs"; const workspace = new WorkspaceRuntime({ files: { "config/main.ini": "[EMC]\nMACHINE = ${MACHINE}\n[VAR]\nSCALE = 2\ninclude sub.ini\n", "config/sub.ini": "[TRAJ]\nLINEAR_UNITS = mm\nCOUNT = $SCALE\n", } }); const parsed = parseIni({ workspace, entrypoint: "config/main.ini", variables: { MACHINE: "web-sim" } }); assert.equal(parsed.schema, "ini-resource-graph.v1"); assert.equal(parsed.sections.EMC.MACHINE, "web-sim"); assert.equal(parsed.sections.TRAJ.COUNT, "2"); assert.deepEqual(parsed.graph, ["config/main.ini", "config/sub.ini"]); assert.equal(parsed.includes[0].line, 5); assert.match(parsed.state_hash, /^fnv1a64:/); assert.throws(() => parseIni({ workspace, entrypoint: "config/missing.ini" }), /ini_source_missing/); assert.throws(() => parseIni({ workspace: new WorkspaceRuntime({ files: { "a.ini": "include b.ini\n", "b.ini": "include a.ini\n" } }), entrypoint: "a.ini" }), /ini_include_cycle/); assert.throws(() => parseIni({ workspace: new WorkspaceRuntime({ files: { "a.ini": "[A]\nX=${MISSING}\n" } }), entrypoint: "a.ini" }), /ini_variable_missing/); assert.throws(() => parseIni({ workspace: new WorkspaceRuntime({ files: { "a.ini": "include /etc/passwd\n" } }), entrypoint: "a.ini" }), /ini_include_path_invalid/); assert.throws(() => parseIni({ workspace: new WorkspaceRuntime({ files: { "a.ini": "X=1\n" } }), entrypoint: "a.ini" }), /ini_section_invalid/); const second = parseIni({ workspace, entrypoint: "config/main.ini", variables: { MACHINE: "web-sim" } }); assert.equal(second.state_hash, parsed.state_hash); console.log(`ini_parser=passed sections=${Object.keys(parsed.sections).length} graph=${parsed.graph.length} state_hash=${parsed.state_hash}`);