Advance M8-M11 parity workflows
This commit is contained in:
108
web/tests/e2e/geometry-node-field-budget.spec.ts
Normal file
108
web/tests/e2e/geometry-node-field-budget.spec.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
GEOMETRY_NODE_FIELD_BUDGET,
|
||||
parseGeometryNodeFieldMaterializationBatch,
|
||||
type GeometryNodeDomainCardinalityIR,
|
||||
} from "../../protocol/geometry-nodes";
|
||||
import { parseDepsgraphEvaluation, type DepsgraphEvaluationIR } from "../../protocol/depsgraph";
|
||||
|
||||
const root = path.resolve(import.meta.dirname, "../../..");
|
||||
const fixture = fs.readFileSync(path.join(root, "tests/files/web/geometry_node_allowlist_evaluator.blend"));
|
||||
|
||||
test("M10-04 binds field conversion budgets to native mesh domain cardinality", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
await page.goto("/");
|
||||
const result = await page.evaluate(async ({ bytes }) => {
|
||||
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
|
||||
const source = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
|
||||
const client = new WebEngineClient({ timeoutMs: 90_000 });
|
||||
await client.init();
|
||||
await client.openBlend(source);
|
||||
const evaluated = await client.evaluateDepsgraph();
|
||||
client.terminate();
|
||||
const mesh = evaluated.depsgraph.meshes.find((candidate) =>
|
||||
candidate.objectId === "object:M10GN_StoreAttribute");
|
||||
if (!mesh?.domainCardinality) throw new Error("Store Named Attribute domain cardinality is missing");
|
||||
return {
|
||||
depsgraph: evaluated.depsgraph,
|
||||
domainCardinality: mesh.domainCardinality,
|
||||
fieldMaterializations: mesh.fieldMaterializations ?? [],
|
||||
attributes: mesh.attributes ?? {},
|
||||
};
|
||||
}, { bytes: new Uint8Array(fixture) });
|
||||
|
||||
expect(result.domainCardinality).toEqual({
|
||||
POINT: 8,
|
||||
EDGE: 12,
|
||||
FACE: 6,
|
||||
CORNER: 24,
|
||||
CURVE: 0,
|
||||
INSTANCE: 0,
|
||||
LAYER: 0,
|
||||
});
|
||||
expect(result.fieldMaterializations).toEqual([{
|
||||
schemaVersion: 1,
|
||||
fieldId: "attribute:m10_value",
|
||||
domain: "POINT",
|
||||
dataType: "FLOAT",
|
||||
elementCount: 8,
|
||||
scalarValueCount: 8,
|
||||
materializedByteLength: 32,
|
||||
transport: "JSON",
|
||||
}]);
|
||||
expect(result.attributes.m10_value.values).toHaveLength(8);
|
||||
expect(result.attributes.m10_value.values.every((value: number) => value === 0.375)).toBe(true);
|
||||
|
||||
const rejects = (mutate: (candidate: DepsgraphEvaluationIR) => void): void => {
|
||||
const candidate = structuredClone(result.depsgraph);
|
||||
mutate(candidate);
|
||||
expect(() => parseDepsgraphEvaluation(candidate)).toThrow();
|
||||
};
|
||||
rejects((candidate) => {
|
||||
const target = candidate.meshes.find((entry) => entry.objectId === "object:M10GN_StoreAttribute")!;
|
||||
target.domainCardinality!.POINT += 1;
|
||||
});
|
||||
rejects((candidate) => {
|
||||
const target = candidate.meshes.find((entry) => entry.objectId === "object:M10GN_StoreAttribute")!;
|
||||
target.fieldMaterializations![0].materializedByteLength += 4;
|
||||
});
|
||||
rejects((candidate) => {
|
||||
const target = candidate.meshes.find((entry) => entry.objectId === "object:M10GN_StoreAttribute")!;
|
||||
(target.fieldMaterializations![0] as unknown as Record<string, unknown>).values = [0];
|
||||
});
|
||||
|
||||
const common = {
|
||||
schemaVersion: 1 as const,
|
||||
graphId: "node-group:M10GN_StoreAttributeGraph",
|
||||
graphHash: "a".repeat(64),
|
||||
revision: 1,
|
||||
transport: "JSON" as const,
|
||||
domainCardinality: result.domainCardinality as GeometryNodeDomainCardinalityIR,
|
||||
};
|
||||
const batch = parseGeometryNodeFieldMaterializationBatch([
|
||||
{
|
||||
...common,
|
||||
fieldId: "field:point-to-corner",
|
||||
sourceDomain: "POINT",
|
||||
targetDomain: "CORNER",
|
||||
dataType: "FLOAT",
|
||||
},
|
||||
{
|
||||
...common,
|
||||
fieldId: "field:constant-offset",
|
||||
sourceDomain: "CONSTANT",
|
||||
targetDomain: "POINT",
|
||||
dataType: "VECTOR",
|
||||
},
|
||||
]);
|
||||
expect(batch).toMatchObject({
|
||||
fieldCount: 2,
|
||||
domainConversionCount: 1,
|
||||
materializedElementCount: 32,
|
||||
materializedByteLength: 192,
|
||||
});
|
||||
expect(batch.fields.every((field) => field.scalarValueCount <=
|
||||
GEOMETRY_NODE_FIELD_BUDGET.maxJsonScalarValuesPerField)).toBe(true);
|
||||
});
|
||||
Reference in New Issue
Block a user