77 lines
3.3 KiB
JavaScript
77 lines
3.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
import test from "node:test";
|
|
import ts from "typescript";
|
|
|
|
const repoRoot = path.resolve(import.meta.dirname, "../../..");
|
|
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "compositor-unsupported-unit-"));
|
|
const sourcePath = path.join(repoRoot, "web/protocol/compositor.ts");
|
|
const transpiled = ts.transpileModule(fs.readFileSync(sourcePath, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: sourcePath,
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(transpiled.diagnostics, []);
|
|
fs.writeFileSync(path.join(temporary, "compositor.mjs"), transpiled.outputText.replaceAll('from "./capability-gates"', 'from "./capability-gates.mjs"'));
|
|
const gates = ts.transpileModule(fs.readFileSync(path.join(repoRoot, "web/protocol/capability-gates.ts"), "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: path.join(repoRoot, "web/protocol/capability-gates.ts"),
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(gates.diagnostics, []);
|
|
fs.writeFileSync(path.join(temporary, "capability-gates.mjs"), gates.outputText);
|
|
const compositor = await import(pathToFileURL(path.join(temporary, "compositor.mjs")));
|
|
|
|
const node = (id, type, properties = {}, blenderType) => ({ id, type, name: id, properties, ...(blenderType ? { blenderType } : {}) });
|
|
const graph = () => ({
|
|
schemaVersion: 1,
|
|
id: "compositor:unsupported",
|
|
name: "Unsupported",
|
|
outputNodeId: "out",
|
|
resources: [],
|
|
nodes: [
|
|
node("color", "CONSTANT_COLOR", { color: [0.125, 0.25, 0.5, 0.75] }),
|
|
node("out", "COMPOSITE"),
|
|
node("glare", "UNSUPPORTED", {}, "CompositorNodeGlare"),
|
|
],
|
|
links: [{ fromNodeId: "color", fromSocket: "Image", toNodeId: "out", toSocket: "Image" }],
|
|
});
|
|
|
|
test("M11-08 preserves the unsupported graph and blocks CPU execution before evaluation", async () => {
|
|
const value = graph();
|
|
const before = structuredClone(value);
|
|
const gate = compositor.gateCompositorGraph(value, new Set());
|
|
assert.equal(gate.status, "BLOCKED");
|
|
assert.deepEqual(gate.issues.map((issue) => issue.code), ["COMPOSITOR_NODE_UNSUPPORTED"]);
|
|
let cancellationChecks = 0;
|
|
assert.throws(
|
|
() => compositor.executeCompositorGraph(value, new Map(), { width: 2, height: 2, cancelled: () => { cancellationChecks++; return false; } }),
|
|
{ code: "COMPOSITOR_NODE_UNSUPPORTED" },
|
|
);
|
|
assert.equal(cancellationChecks, 0);
|
|
assert.deepEqual(value, before);
|
|
});
|
|
|
|
test("M11-08 blocks a cached unsupported graph before a cache hit", async () => {
|
|
const value = graph();
|
|
const before = structuredClone(value);
|
|
const cache = new compositor.CompositorFrameCache(512);
|
|
const key = await compositor.compositorFrameCacheKey(value, new Map(), 1, 2, 2);
|
|
cache.set(key, {
|
|
composite: { width: 2, height: 2, data: new Float32Array(16), colorSpace: "LINEAR_SRGB" },
|
|
viewers: new Map(),
|
|
evaluatedNodeIds: ["cached"],
|
|
});
|
|
await assert.rejects(
|
|
() => compositor.executeCompositorGraphCached(value, new Map(), cache, { frame: 1, width: 2, height: 2 }),
|
|
{ code: "COMPOSITOR_NODE_UNSUPPORTED" },
|
|
);
|
|
assert.equal(cache.size, 1);
|
|
assert.deepEqual(value, before);
|
|
});
|
|
|
|
test.after(() => fs.rmSync(temporary, { recursive: true, force: true }));
|