Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
78 lines
3.8 KiB
JavaScript
78 lines
3.8 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import assert from 'node:assert/strict';
|
|
import createEngine from '../build_web_blender6/bin/web_engine.js';
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const stages = [];
|
|
const started = performance.now();
|
|
const engine = await createEngine({
|
|
wasmBinary: fs.readFileSync(path.join(root, 'build_web_blender6/bin/web_engine.wasm')),
|
|
});
|
|
stages.push({ stage: 'instantiate', seconds: (performance.now() - started) / 1000 });
|
|
const handle = engine._web_engine_create();
|
|
const pointers = engine._malloc(8);
|
|
const call = (name, data) => {
|
|
const start = performance.now();
|
|
const pointer = data ? engine._malloc(data.length) : 0;
|
|
try {
|
|
if (data) engine.HEAPU8.set(data, pointer);
|
|
const code = name === 'snapshot'
|
|
? engine._web_engine_get_scene_snapshot(handle, pointers, pointers + 4)
|
|
: name === 'open'
|
|
? engine._web_engine_open_blend(handle, pointer, data.length)
|
|
: engine._web_engine_call_json(handle, pointer, data.length, pointers, pointers + 4);
|
|
if (code !== 0) throw new Error(engine.UTF8ToString(engine._web_engine_last_error_message(handle)));
|
|
if (name === 'open') return null;
|
|
const output = engine.HEAPU32[pointers / 4];
|
|
const length = engine.HEAPU32[pointers / 4 + 1];
|
|
return JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(output, output + length)));
|
|
} finally {
|
|
if (pointer) engine._free(pointer);
|
|
stages.push({ stage: name, seconds: (performance.now() - start) / 1000 });
|
|
}
|
|
};
|
|
try {
|
|
call('open', fs.readFileSync(path.join(root, 'tests/files/web/sequencer_scene.blend')));
|
|
const snapshot = call('snapshot');
|
|
const scene = snapshot.scenes.find(scene => scene.name === 'SequencerScene');
|
|
const timeline = structuredClone(scene.sequencerTimeline);
|
|
if (process.argv.includes('--inspect')) {
|
|
console.log(JSON.stringify({ fixtureStrips: timeline.strips.map(strip => ({
|
|
id: strip.id, type: strip.type, sourceId: strip.sourceId, sourcePath: strip.sourcePath,
|
|
})) }));
|
|
}
|
|
const image = timeline.strips.find(strip => strip.type === 'IMAGE');
|
|
image.frameStart += 1;
|
|
image.frameEnd += 1;
|
|
const result = call('edit', Buffer.from(JSON.stringify({ cmd: 'applyCommand', params: {
|
|
command: { type: 'setSequencerStrips', sceneId: scene.id, timeline },
|
|
} })));
|
|
if (!result.ok) throw new Error(result.error);
|
|
const updated = call('snapshot').scenes.find(item => item.id === scene.id).sequencerTimeline;
|
|
const updatedImage = updated.strips.find(strip => strip.name === image.name);
|
|
assert.equal(updatedImage.frameStart, image.frameStart);
|
|
assert.equal(updatedImage.frameEnd, image.frameEnd);
|
|
assert.equal(updated.strips.length, timeline.strips.length);
|
|
const invalid = structuredClone(updated);
|
|
invalid.strips.push({ id: 'strip:MissingScene', name: 'Missing Scene', type: 'SCENE',
|
|
channel: 8, frameStart: 1, frameEnd: 25, sourceStart: 0, sourceEnd: 24,
|
|
speed: 1, muted: false, locked: false, sourceId: 'scene:MissingLocalTestScene' });
|
|
const rejected = call('reject-missing-scene', Buffer.from(JSON.stringify({ cmd: 'applyCommand', params: {
|
|
command: { type: 'setSequencerStrips', sceneId: scene.id, timeline: invalid },
|
|
} })));
|
|
assert.equal(rejected.ok, false);
|
|
assert.match(rejected.error, /missing scene/);
|
|
assert.deepEqual(call('snapshot').scenes.find(item => item.id === scene.id).sequencerTimeline.strips,
|
|
updated.strips);
|
|
console.log(JSON.stringify({ status: 'PASS', stages }));
|
|
} catch (error) {
|
|
console.log(JSON.stringify({ status: 'FAIL', error: error.message,
|
|
frames: String(error.stack).split('\n').filter(line => /wasm-function|wasm:/.test(line)).slice(0,12), stages }));
|
|
process.exitCode = 1;
|
|
} finally {
|
|
engine._free(pointers);
|
|
engine._web_engine_destroy(handle);
|
|
}
|