import assert from "node:assert/strict"; import { WorkspaceRuntime, normalizeWorkspacePath } from "../workspace/runtime.mjs"; assert.equal(normalizeWorkspacePath("/workspace/config/main.ini"), "config/main.ini"); assert.throws(() => normalizeWorkspacePath("/etc/passwd"), /workspace_host_path/); assert.throws(() => normalizeWorkspacePath("/workspace/../escape"), /workspace_path_escape/); assert.throws(() => normalizeWorkspacePath("config\\main.ini"), /workspace_path_invalid/); const workspace = new WorkspaceRuntime({ quotaBytes: 64 }); const tx = workspace.begin("op-1"); workspace.write("op-1", "/workspace/config/main.ini", "[EMC]\n"); workspace.write("op-1", "program.ngc", "G21\n"); assert.equal(workspace.commit("op-1").status, "committed"); assert.equal(workspace.read("/workspace/config/main.ini"), "[EMC]\n"); assert.equal(workspace.list().length, 2); const hash = workspace.hash(); const aborted = workspace.begin("op-abort"); workspace.write("op-abort", "unused", "x"); assert.equal(workspace.abort("op-abort").status, "aborted"); assert.equal(workspace.hash(), hash); const tooLarge = workspace.begin("op-large"); workspace.write("op-large", "large", "x".repeat(65)); assert.throws(() => workspace.commit("op-large"), /workspace_(?:quota_exceeded|file_quota)/); assert.equal(workspace.hash(), hash); assert.throws(() => workspace.read("missing"), /workspace_file_missing/); const restored = new WorkspaceRuntime({ quotaBytes: 128 }); assert.equal(restored.restore(workspace.export()).state_hash, hash); const tampered = workspace.export(); tampered.files["config/main.ini"] = "tampered"; assert.throws(() => restored.restore(tampered), /workspace_restore_invalid/); console.log(`workspace_runtime=passed files=${workspace.list().length} state_hash=${hash}`);