Files
ST-Bionic-Memory-Ecology/tests/native-layout-parity.mjs
2026-04-13 16:11:43 +08:00

113 lines
2.9 KiB
JavaScript

import assert from "node:assert/strict";
import { solveLayoutWithJs } from "../ui/graph-layout-solver.js";
import {
getNativeModuleStatus,
solveLayout,
} from "../vendor/wasm/stbme_core.js";
const originalLoader = globalThis.__stBmeLoadRustWasmLayout;
function buildPayload(seed = 42, nodeCount = 180) {
let state = seed;
const rand = () => {
state = (state * 1664525 + 1013904223) >>> 0;
return state / 0xffffffff;
};
const regionRect = { x: 0, y: 0, w: 980, h: 620 };
const nodes = [];
for (let i = 0; i < nodeCount; i++) {
nodes.push({
x: regionRect.x + rand() * regionRect.w,
y: regionRect.y + rand() * regionRect.h,
vx: 0,
vy: 0,
pinned: false,
radius: 6 + rand() * 8,
regionKey: "objective",
regionRect,
});
}
const edges = [];
const edgeTarget = Math.max(nodeCount * 4, 1);
for (let i = 0; i < edgeTarget; i++) {
const from = Math.floor(rand() * nodeCount);
let to = Math.floor(rand() * nodeCount);
if (to === from) to = (to + 1) % nodeCount;
edges.push({
from,
to,
strength: 0.25 + rand() * 0.75,
});
}
return {
nodes,
edges,
config: {
iterations: 52,
repulsion: 2600,
springK: 0.05,
damping: 0.87,
centerGravity: 0.015,
minGap: 11,
speedCap: 3.2,
},
};
}
function meanAbsDiff(a = new Float32Array(0), b = new Float32Array(0)) {
const len = Math.min(a.length, b.length);
if (len === 0) return 0;
let sum = 0;
for (let i = 0; i < len; i++) {
sum += Math.abs(a[i] - b[i]);
}
return sum / len;
}
try {
globalThis.__stBmeLoadRustWasmLayout = async () => ({
solve_layout(payload) {
const jsResult = solveLayoutWithJs(payload);
return {
ok: true,
positions: Array.from(jsResult.positions),
diagnostics: {
solver: "mock-rust-wasm",
nodeCount: jsResult.diagnostics.nodeCount,
edgeCount: jsResult.diagnostics.edgeCount,
iterations: jsResult.diagnostics.iterations,
},
};
},
});
const payload = buildPayload();
const jsResult = solveLayoutWithJs(payload);
const nativeResult = await solveLayout(payload);
assert.equal(jsResult.ok, true);
assert.equal(nativeResult.ok, true);
assert.ok(nativeResult.positions instanceof Float32Array);
assert.equal(jsResult.positions.length, nativeResult.positions.length);
const mad = meanAbsDiff(jsResult.positions, nativeResult.positions);
const nativeStatus = getNativeModuleStatus();
const threshold = nativeStatus.source === "wasm-pack-artifact" ? 2e-4 : 1e-6;
assert.ok(
mad <= threshold,
`mean abs diff too high: ${mad} (source=${nativeStatus.source || "unknown"}, threshold=${threshold})`,
);
} finally {
if (typeof originalLoader === "function") {
globalThis.__stBmeLoadRustWasmLayout = originalLoader;
} else {
delete globalThis.__stBmeLoadRustWasmLayout;
}
}
console.log("native-layout-parity tests passed");