import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const outputPath = path.join(root, "tests/golden/WBV2/internal-submodule-smoke-regression-report.json"); const loaderPath = path.join(root, "web/app/src/vendor/blender/web_engine.js"); const wasmPath = path.join(root, "web/app/src/vendor/blender/web_engine.wasm"); const fixturePath = path.join(root, "tests/files/web/basic_scene.blend"); const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); if (fs.existsSync(outputPath)) { process.stderr.write("wbv2-add-modifier-regression-once-only: report already exists\n"); process.exit(2); } let engine; let handle = 0; const rawCall = (cmd, params = {}) => { const request = new TextEncoder().encode(JSON.stringify({ cmd, params })); const input = engine._malloc(request.byteLength); const dataOut = engine._malloc(4); const lengthOut = engine._malloc(4); engine.HEAPU8.set(request, input); let resultPointer = 0; try { engine._web_engine_call_json(handle, input, request.byteLength, dataOut, lengthOut); resultPointer = engine.HEAPU32[dataOut >>> 2]; const length = engine.HEAPU32[lengthOut >>> 2]; return length ? JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(resultPointer, resultPointer + length))) : null; } finally { if (resultPointer) engine._web_engine_free_buffer(resultPointer); engine._free(input); engine._free(dataOut); engine._free(lengthOut); } }; let response = null; let added = null; let error = null; try { const factory = (await import(pathToFileURL(loaderPath))).default; engine = await factory({ wasmBinary: fs.readFileSync(wasmPath) }); handle = engine._web_engine_create(); const fixture = fs.readFileSync(fixturePath); const pointer = engine._malloc(fixture.byteLength); engine.HEAPU8.set(fixture, pointer); const openCode = engine._web_engine_open_blend(handle, pointer, fixture.byteLength); engine._free(pointer); if (openCode !== 0) throw new Error("addModifier regression could not open basic_scene.blend"); const before = rawCall("snapshot")?.result; const mesh = before?.meshes?.[0]; if (!mesh) throw new Error("basic_scene.blend has no mesh"); response = rawCall("applyCommand", { command: { type: "addModifier", meshId: mesh.id, modifierType: "SUBSURF", name: "WBV2 RNA Identifier Regression" } }); const after = rawCall("snapshot")?.result; added = after?.meshes?.find((item) => item.id === mesh.id)?.modifierStack?.find((modifier) => modifier.name === "WBV2 RNA Identifier Regression") ?? null; } catch (cause) { error = cause instanceof Error ? cause.message : String(cause); } finally { if (engine && handle) engine._web_engine_destroy(handle); } const passed = response?.ok === true && added?.type === "SUBSURF"; const report = { schemaVersion: 1, operation: "ADD_MODIFIER_RNA_IDENTIFIER_FOCUSED_REGRESSION", submoduleId: "addModifier", status: passed ? "PASS" : "FAIL", verificationAttempts: 1, retries: 0, input: { modifierType: "SUBSURF" }, result: response?.result ?? null, addedModifier: added, error: error ?? response?.error ?? null, artifact: { wasmSha256: sha256(wasmPath), loaderSha256: sha256(loaderPath), fixtureSha256: sha256(fixturePath) }, }; fs.writeFileSync(outputPath, `${JSON.stringify(report, null, 2)}\n`); process.stdout.write(`wbv2-add-modifier-regression-${report.status.toLowerCase()} attempts=1 retries=0\n`); process.exit(passed ? 0 : 1);