Advance M8-M11 parity workflows
This commit is contained in:
94
web/tests/unit/paint-stroke-session.test.mjs
Normal file
94
web/tests/unit/paint-stroke-session.test.mjs
Normal file
@@ -0,0 +1,94 @@
|
||||
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(), "paint-stroke-session-unit-"));
|
||||
|
||||
function transpile(sourceName, outputName, replacements = []) {
|
||||
const sourcePath = path.join(repoRoot, "web/protocol", sourceName);
|
||||
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, []);
|
||||
const output = replacements.reduce((source, [from, to]) => source.replace(from, to), transpiled.outputText);
|
||||
fs.writeFileSync(path.join(temporary, outputName), output);
|
||||
}
|
||||
|
||||
transpile("paint.ts", "paint.mjs");
|
||||
transpile("paint-stroke-session.ts", "paint-stroke-session.mjs", [['from "./paint"', 'from "./paint.mjs"']]);
|
||||
const sessions = await import(pathToFileURL(path.join(temporary, "paint-stroke-session.mjs")));
|
||||
|
||||
const begin = {
|
||||
schemaVersion: 1,
|
||||
pointerSessionId: "paint-pointer:unit-1",
|
||||
baseRevision: 7,
|
||||
target: { mode: "VERTEX_COLOR", meshId: "mesh:Paint", attributeName: "StrokeColor", domain: "POINT" },
|
||||
};
|
||||
|
||||
test("M9-10 merges ordered pointer chunks into one deterministic Main command", () => {
|
||||
const store = new sessions.PaintStrokeSessionStore();
|
||||
assert.equal(store.begin(begin, 7).state, "OPEN");
|
||||
store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 0, indices: [3, 1], values: [1, 0, 0, 1, 0, 1, 0, 1] }, 7);
|
||||
const buffered = store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 1, indices: [1, 2], values: [0, 0, 1, 1, 1, 1, 0, 1] }, 7);
|
||||
assert.deepEqual({ chunks: buffered.chunkCount, received: buffered.receivedEntryCount, unique: buffered.uniqueEntryCount, bytes: buffered.bufferedBytes }, { chunks: 2, received: 4, unique: 3, bytes: 80 });
|
||||
const committed = store.commit({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, expectedChunkCount: 2 }, 7);
|
||||
assert.deepEqual(committed.command, {
|
||||
type: "setVertexColors",
|
||||
meshId: "mesh:Paint",
|
||||
attributeName: "StrokeColor",
|
||||
domain: "POINT",
|
||||
indices: [1, 2, 3],
|
||||
colors: [0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1],
|
||||
});
|
||||
assert.equal(committed.receipt.state, "READY");
|
||||
assert.equal(store.activeCount, 0);
|
||||
});
|
||||
|
||||
test("M9-10 cancels without a Main command and rejects stale or discontinuous chunks", () => {
|
||||
const store = new sessions.PaintStrokeSessionStore();
|
||||
store.begin(begin, 7);
|
||||
assert.throws(() => store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 1, indices: [0], values: [1, 1, 1, 1] }, 7), (error) => error.code === "PAINT_SCHEMA_INVALID");
|
||||
assert.throws(() => store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 0, indices: [0], values: [1, 1, 1, 1] }, 8), (error) => error.code === "REVISION_CONFLICT");
|
||||
const cancelled = store.cancel({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7 });
|
||||
assert.equal(cancelled.state, "CANCELLED");
|
||||
assert.equal(store.activeCount, 0);
|
||||
});
|
||||
|
||||
test("M9-10 merges weight chunks with their normalize policy into one Main command", () => {
|
||||
const store = new sessions.PaintStrokeSessionStore();
|
||||
const weightBegin = {
|
||||
schemaVersion: 1,
|
||||
pointerSessionId: "paint-pointer:weight-unit",
|
||||
baseRevision: 9,
|
||||
target: { mode: "WEIGHT", objectId: "object:Paint", vertexGroup: "StrokeWeight", normalize: true, mirror: false },
|
||||
};
|
||||
store.begin(weightBegin, 9);
|
||||
store.append({ schemaVersion: 1, pointerSessionId: weightBegin.pointerSessionId, baseRevision: 9, chunkIndex: 0, indices: [4, 2], values: [0.25, 0.75] }, 9);
|
||||
store.append({ schemaVersion: 1, pointerSessionId: weightBegin.pointerSessionId, baseRevision: 9, chunkIndex: 1, indices: [4], values: [0.5] }, 9);
|
||||
const committed = store.commit({ schemaVersion: 1, pointerSessionId: weightBegin.pointerSessionId, baseRevision: 9, expectedChunkCount: 2 }, 9);
|
||||
assert.deepEqual(committed.command, {
|
||||
type: "setVertexWeights",
|
||||
objectId: "object:Paint",
|
||||
vertexGroup: "StrokeWeight",
|
||||
indices: [2, 4],
|
||||
values: [0.75, 0.5],
|
||||
normalize: true,
|
||||
mirror: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("M9-10 bounds chunks, values and final chunk counts before Main", () => {
|
||||
const store = new sessions.PaintStrokeSessionStore();
|
||||
store.begin(begin, 7);
|
||||
assert.throws(() => store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 0, indices: [0], values: [2, 0, 0, 1] }, 7), (error) => error.code === "PAINT_SCHEMA_INVALID");
|
||||
store.append({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, chunkIndex: 0, indices: [0], values: [1, 0, 0, 1] }, 7);
|
||||
assert.throws(() => store.commit({ schemaVersion: 1, pointerSessionId: begin.pointerSessionId, baseRevision: 7, expectedChunkCount: 2 }, 7), (error) => error.code === "PAINT_SCHEMA_INVALID");
|
||||
assert.equal(store.activeCount, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user