satie
Version:
A sheet music renderer for the web
234 lines (217 loc) • 8.2 kB
text/typescript
/**
* This file is part of Satie music engraver <https://github.com/jnetterf/satie>.
* Copyright (C) Joshua Netterfield <joshua.ca> 2015 - present.
*
* Satie is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Satie is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Satie. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file part of Satie test suite
*/
import {IRefreshMeasureOpts, refreshMeasure, layoutMeasure, RefreshMode}
from "../engine_processors_measure";
import {getApproximateMeasureWidth} from "../engine_processors_layout";
import {expect} from "chai";
import {Type} from "../document";
import {normalizeDivisionsInPlace} from "../engine_divisions";
import {createFakeVoiceSegment, createFakeStaffSegment, fakeFactory} from "./etestutil";
describe("[engine/measureProcessor.ts]", function() {
describe("reduce", function() {
it("can lay out multiple voices", function() {
let segments = [
createFakeStaffSegment(4, 4, 1), // 00001111
createFakeVoiceSegment(2, 6, 1), // 00111111
createFakeVoiceSegment(1, 7, 2) // 01111111
];
segments[0].owner = 1;
segments[0].part = "P1";
segments[1].owner = 1;
segments[1].part = "P1";
segments[2].owner = 2;
segments[2].part = "P1";
normalizeDivisionsInPlace(fakeFactory, segments);
// test without alignment
let opts: IRefreshMeasureOpts = {
document: {
__fakeDocument: true
} as any,
preview: false,
print: null,
fixup: null,
lineBarOnLine: 0,
lineCount: 1,
lineIndex: 0,
lineShortest: 1,
lineTotalBarsOnLine: 1,
header: null,
measure: {
idx: 0,
uuid: 777,
number: "1",
parts: {},
version: 0,
},
measureX: 100,
segments: segments,
noAlign: true,
factory: fakeFactory,
mode: RefreshMode.RefreshLayout,
attributes: {"P1": []},
singleLineMode: false,
};
let layout = refreshMeasure(opts).elements;
expect(layout[0].length).to.equal(2);
expect(layout[0][0].x).to.equal(100, "without merging");
// Occurs after division 1 or 2, so add the end of the measure
expect(layout[0][1].x).to.equal(190, "without merging");
expect(layout[2].length).to.equal(2);
expect(layout[2][0].x).to.equal(110, "without merging"); // + 10 for staff
expect(layout[2][1].x).to.equal(120, "without merging");
expect(layout[1].length).to.equal(2);
expect(layout[1][0].x).to.equal(110, "without merging");
expect(layout[1][1].x).to.equal(130, "without merging");
// Now test
opts.noAlign = false;
layout = refreshMeasure(opts).elements;
layout[1].map(l => delete (<any>l).key);
expect(layout[1]).to.deep.equal(
[
{
division: 0,
x: 100,
model: null,
renderClass: Type.Attributes
},
{
boundingBoxes: [],
division: 0,
expandPolicy: "after",
x: 110,
part: "P1",
model: segments[1][0], // from first voice.
renderClass: Type.Chord
},
{
division: 1,
expandPolicy: "after",
x: 120,
model: null,
renderClass: Type.Chord
},
{
boundingBoxes: [],
expandPolicy: "after",
division: 2,
x: 130,
part: "P1",
model: segments[1][1],
renderClass: Type.Chord
},
{
division: 4,
x: 190,
model: null,
renderClass: Type.Attributes
},
]
);
});
});
describe("layoutMeasure", function() {
it("lays out a case with multiple voices", function() {
let staffSegments = [
null,
createFakeStaffSegment(4, 4, 1)
];
let voiceSegments = [
null,
createFakeVoiceSegment(2, 6, 1),
createFakeVoiceSegment(1, 7, 2)
];
let layout = layoutMeasure({
document: {
__fakeDocument: true
} as any,
preview: false,
print: null,
fixup: null,
header: <any> {
partList: [
{
_class: "ScorePart",
id: "P1"
}
]
},
measure: {
idx: 0,
number: "1",
version: 0,
parts: {
"P1": {
voices: voiceSegments,
staves: staffSegments
}
},
uuid: 248,
width: NaN
},
x: 100,
lineBarOnLine: 0,
lineTotalBarsOnLine: 0,
lineShortest: 42,
lineCount: 1,
lineIndex: 0,
factory: fakeFactory,
attributes: {"P1": []},
singleLineMode: false,
});
// We've tested this exact case in ISegment.layout$, so we can be
// a bit soft here.
expect(layout.paddingBottom).to.deep.equal([, 0]);
expect(layout.paddingTop).to.deep.equal([, 0]);
expect(layout.elements[0].length).to.equal(5);
expect(layout.elements[0][4].x).to.equal(190);
expect(layout.elements[0][0].x).to.equal(100);
expect(layout.width).to.equal(100);
});
});
describe("approximateWidth", function() {
it("approximates mid-line width", function() {
let staffSegments = [
null,
createFakeStaffSegment(4, 4, 1)
];
let voiceSegments = [
null,
createFakeVoiceSegment(2, 6, 1),
createFakeVoiceSegment(1, 7, 2)
];
let width = getApproximateMeasureWidth({
idx: 0,
number: "1",
version: 0,
parts: {
"P1": {
voices: voiceSegments,
staves: staffSegments
}
},
uuid: 1248,
width: NaN
}, 42);
// 100 - 10 for attribute 1. See createFakeStaffSegment
expect(width).to.equal(90);
});
});
});