75 lines
4.3 KiB
JavaScript
75 lines
4.3 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { parseJpwabc } from "../dist/domain/jpwabc.js";
|
|
import { modelFromParse, createEmptyDocument, rational, createNoteEvent } from "../dist/domain/score-model.js";
|
|
import { DeterministicFontMeasurementProvider } from "../dist/layout/font-measure.js";
|
|
import { DEFAULT_PAPER_CONFIG, layoutDocument, layoutSummary } from "../dist/layout/layout-engine.js";
|
|
import { probeSvg, renderSnapshotSvg } from "../dist/layout/svg-renderer.js";
|
|
|
|
async function kangdingModel() {
|
|
const bytes = await readFile("research/jpw7/demo/JP-Word练习曲-歌曲-康定情歌.jpwabc");
|
|
return modelFromParse(parseJpwabc(bytes), { fileName: "康定情歌.jpwabc" });
|
|
}
|
|
|
|
test("M3 waits for fonts, produces fixed A4 geometry and the 16-measure/6-line baseline", async () => {
|
|
const provider = new DeterministicFontMeasurementProvider();
|
|
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, provider);
|
|
const summary = layoutSummary(snapshot);
|
|
assert.deepEqual(snapshot.pageSizeMm, { width: 210, height: 297 });
|
|
assert.deepEqual(snapshot.contentRectMm, { x: 20, y: 20, width: 170, height: 257 });
|
|
assert.equal(summary.pageCount, 1);
|
|
assert.equal(summary.lineCount, 6);
|
|
assert.equal(summary.measureCount, 16);
|
|
assert.ok(snapshot.fontMeasurements.length > 0);
|
|
assert.ok(snapshot.fontMeasurements.every((measurement) => measurement.loaded === true));
|
|
assert.equal(snapshot.pages[0].widthMm, 210);
|
|
assert.equal(snapshot.pages[0].heightMm, 297);
|
|
});
|
|
|
|
test("M3 layout is deterministic for identical model, config and measurement provider", async () => {
|
|
const model = await kangdingModel();
|
|
const first = await layoutDocument(model, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
|
|
const second = await layoutDocument(model, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
|
|
assert.equal(first.deterministicKey, second.deterministicKey);
|
|
assert.deepEqual(first.pages, second.pages);
|
|
assert.deepEqual(first.warnings, second.warnings);
|
|
});
|
|
|
|
test("M3 reports an unbreakable over-wide measure instead of clipping it", async () => {
|
|
const document = createEmptyDocument("overflow-document");
|
|
const event = createNoteEvent("wide-event", 1, rational(1));
|
|
event.source = { raw: "X".repeat(800), range: null };
|
|
document.voices.push({ id: "wide-voice", name: "宽小节", sectionId: null, visible: true, measures: [{ id: "wide-measure", ordinal: 0, beats: rational(1), events: [event] }] });
|
|
const snapshot = await layoutDocument(document, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
|
|
const warning = snapshot.warnings.find((item) => item.code === "MEASURE_OVERFLOW");
|
|
assert.ok(warning);
|
|
assert.equal(warning.severity, "error");
|
|
assert.equal(snapshot.measures["wide-measure"].overflow, true);
|
|
});
|
|
|
|
test("M3 SVG renderer preserves A4 physical units, semantic IDs and layer separation", async () => {
|
|
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
|
|
const [svg] = renderSnapshotSvg(snapshot);
|
|
const probe = probeSvg(svg);
|
|
assert.equal(probe.width, "210mm");
|
|
assert.equal(probe.height, "297mm");
|
|
assert.equal(probe.viewBox, "0 0 21000 29700");
|
|
assert.equal(probe.pageNumber, 1);
|
|
assert.equal(probe.hasScoreLayer, true);
|
|
assert.equal(probe.hasAssistiveLayer, false);
|
|
assert.ok(probe.dataIds.length >= Object.keys(snapshot.symbols).length);
|
|
const titleFontSize = Number(svg.match(/data-role="document-id"[^>]*font-size="([0-9.]+)"/)?.[1] ?? 0);
|
|
const noteFontSize = Number(svg.match(/data-kind="note"[^>]*>[\s\S]*?font-size="([0-9.]+)"/)?.[1] ?? 0);
|
|
assert.ok(titleFontSize > 100);
|
|
assert.ok(noteFontSize > 100);
|
|
const accessibleProbe = probeSvg(renderSnapshotSvg(snapshot, true)[0]);
|
|
assert.equal(accessibleProbe.hasAssistiveLayer, true);
|
|
});
|
|
|
|
test("M3 overflow and orphan diagnostics are visible in the snapshot, not hidden by renderer", async () => {
|
|
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
|
|
assert.ok(snapshot.warnings.some((warning) => warning.code === "ORPHANED_ATTACHMENT"));
|
|
assert.ok(snapshot.pages.every((page) => page.widthMm === 210 && page.heightMm === 297));
|
|
});
|