Skip to content

Commit eed39a2

Browse files
authored
Merge pull request #5137 from varruunnn/abc
Update abc.js tests to achieve ~99% code coverage
2 parents 860695d + ae93b0c commit eed39a2

File tree

1 file changed

+259
-20
lines changed

1 file changed

+259
-20
lines changed

js/__tests__/abc.test.js

Lines changed: 259 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ global.NOTATIONROUNDDOWN = 4;
2626
global.NOTATIONINSIDECHORD = 5; // deprecated
2727
global.NOTATIONSTACCATO = 6;
2828

29-
global.frequencyToPitch = jest.fn(freq => ["G♯", "4"]);
29+
global.frequencyToPitch = jest.fn(freq => {
30+
if (freq === 440) return ["A", "4"];
31+
return ["G♯", "4"];
32+
});
33+
3034
global.toFraction = jest.fn(num => [1, 1]);
3135

3236
const {
@@ -44,7 +48,7 @@ describe("getABCHeader", () => {
4448
});
4549
});
4650

47-
describe("processABCNotes", () => {
51+
describe("processABCNotes - Basic Note Processing", () => {
4852
let logo;
4953

5054
beforeEach(() => {
@@ -66,8 +70,250 @@ describe("processABCNotes", () => {
6670
processABCNotes(logo, "0");
6771
expect(logo.notationNotes["0"]).toBe("G^4 G^4 F4 F4 G^2 G^8 ");
6872
});
73+
74+
it("should insert a newline after every 8 notes", () => {
75+
const notes = [];
76+
// Add 9 notes
77+
for (let i = 0; i < 9; i++) {
78+
notes.push([["C4"], 4, 0, null, null, -1, false]);
79+
}
80+
logo.notation.notationStaging["0"] = notes;
81+
82+
processABCNotes(logo, "0");
83+
// Check if newline exists in the output
84+
expect(logo.notationNotes["0"]).toMatch(/\n/);
85+
});
86+
});
87+
describe("processABCNotes - Advanced Note Handling", () => {
88+
let logo;
89+
90+
beforeEach(() => {
91+
logo = { notationNotes: { "0": "" }, notation: { notationStaging: { "0": [] } } };
92+
});
93+
94+
it("should handle frequency (number) inputs", () => {
95+
logo.notation.notationStaging["0"] = [
96+
[[440], 4, 0, null, null, -1, false] // 440Hz -> A4
97+
];
98+
processABCNotes(logo, "0");
99+
expect(logo.notationNotes["0"]).toContain("A4");
100+
expect(global.frequencyToPitch).toHaveBeenCalledWith(440);
101+
});
102+
103+
it("should handle staccato and dots", () => {
104+
logo.notation.notationStaging["0"] = [[["C4"], 4, 2, null, null, -1, true]];
105+
processABCNotes(logo, "0");
106+
expect(logo.notationNotes["0"]).toContain("C4..");
107+
expect(logo.notationNotes["0"]).toContain(".");
108+
});
109+
110+
it("should convert durations using the map and fallback to string", () => {
111+
logo.notation.notationStaging["0"] = [
112+
[["C4"], 64, 0, null, null, -1, false], // Map: 1/4
113+
[["D4"], 32, 0, null, null, -1, false], // Map: 1/2
114+
[["E4"], 1, 0, null, null, -1, false], // Map: 16
115+
[["F4"], 5, 0, null, null, -1, false] // No map: "5"
116+
];
117+
processABCNotes(logo, "0");
118+
const output = logo.notationNotes["0"];
119+
expect(output).toContain("C1/4");
120+
expect(output).toContain("D1/2");
121+
expect(output).toContain("E16");
122+
expect(output).toContain("F5");
123+
});
124+
});
125+
describe("processABCNotes - Control Strings", () => {
126+
let logo;
127+
beforeEach(() => {
128+
logo = { notationNotes: { "0": "" }, notation: { notationStaging: { "0": [] } } };
129+
});
130+
131+
it("should handle all string commands correctly", () => {
132+
logo.notation.notationStaging["0"] = [
133+
"break",
134+
[["C4"], 4, 0, null, null, -1, false],
135+
"break",
136+
"begin articulation",
137+
[["D4"], 4, 0, null, null, -1, false],
138+
"end articulation",
139+
"begin crescendo",
140+
"end crescendo",
141+
"begin decrescendo",
142+
"end decrescendo",
143+
"begin slur",
144+
[["E4"], 4, 0, null, null, -1, false],
145+
"end slur",
146+
"tie",
147+
"voice one",
148+
"voice two",
149+
"voice three",
150+
"voice four",
151+
"one voice",
152+
"unknown command"
153+
];
154+
155+
processABCNotes(logo, "0");
156+
const out = logo.notationNotes["0"];
157+
158+
expect(out).toContain("\n");
159+
expect(out).toContain("!<(!");
160+
expect(out).toContain("!<)!");
161+
expect(out).toContain("!>(!");
162+
expect(out).toContain("V:1");
163+
expect(out).toContain("V:2");
164+
expect(out).toContain("V:3");
165+
expect(out).toContain("V:4");
166+
expect(out).toContain("unknown command");
167+
});
168+
169+
it("should handle meter command", () => {
170+
logo.notation.notationStaging["0"] = ["meter", "4", "4"];
171+
processABCNotes(logo, "0");
172+
expect(logo.notationNotes["0"]).toContain("M:4/4");
173+
});
174+
175+
it("should handle pickup command", () => {
176+
logo.notation.notationStaging["0"] = ["pickup", "8"];
177+
processABCNotes(logo, "0");
178+
expect(logo.notationNotes["0"]).toContain("K: pickup=8");
179+
});
180+
});
181+
182+
describe("processABCNotes - Chords", () => {
183+
let logo;
184+
beforeEach(() => {
185+
logo = { notationNotes: { "0": "" }, notation: { notationStaging: { "0": [] } } };
186+
});
187+
188+
it("should handle chords correctly (Start, Middle, End)", () => {
189+
const chordID = 123;
190+
logo.notation.notationStaging["0"] = [
191+
[["C4"], 4, 0, null, null, chordID, false],
192+
[["E4"], 4, 0, null, null, chordID, false],
193+
[["G4"], 4, 0, null, null, chordID, false],
194+
[["A4"], 4, 0, null, null, 999, false]
195+
];
196+
197+
processABCNotes(logo, "0");
198+
const out = logo.notationNotes["0"];
199+
expect(out).toContain("C4 [C");
200+
expect(out).toContain("E4");
201+
expect(out).toContain("G4 G]4");
202+
});
203+
204+
it("should handle articulation inside chords", () => {
205+
const chordID = 55;
206+
logo.notation.notationStaging["0"] = [
207+
"begin articulation",
208+
[["C4"], 4, 0, null, null, chordID, false],
209+
[["E4"], 4, 0, null, null, chordID, false],
210+
"end articulation"
211+
];
212+
213+
processABCNotes(logo, "0");
214+
expect(logo.notationNotes["0"]).toContain("C4 [C");
215+
});
69216
});
70217

218+
describe("processABCNotes - Tuplet Handling", () => {
219+
let logo;
220+
beforeEach(() => {
221+
logo = { notationNotes: { "0": "" }, notation: { notationStaging: { "0": [] } } };
222+
});
223+
224+
it("should process standard tuplets correctly", () => {
225+
logo.notation.notationStaging["0"] = [
226+
[["G♯4"], 4, 0, 3, 2, -1, false],
227+
[["F4"], 4, 0, 3, 2, -1, false],
228+
[["G♯4"], 4, 0, 3, 2, -1, false]
229+
];
230+
231+
processABCNotes(logo, "0");
232+
expect(logo.notationNotes["0"]).toBe("(1:1G^ 2G^ 2G^ 2 ");
233+
});
234+
235+
it("should handle array of notes (chords) inside tuplets", () => {
236+
logo.notation.notationStaging["0"] = [[["C4", "E4"], 4, 0, 1, 1, -1, false]];
237+
238+
processABCNotes(logo, "0");
239+
expect(logo.notationNotes["0"]).toContain("[C E ]");
240+
});
241+
242+
it("should handle staccato inside tuplets", () => {
243+
logo.notation.notationStaging["0"] = [[["C4", "E4"], 4, 0, 1, 1, -1, true]];
244+
245+
processABCNotes(logo, "0");
246+
expect(logo.notationNotes["0"]).toContain(".");
247+
});
248+
249+
it("should handle incomplete/mixed tuplets logic", () => {
250+
logo.notation.notationStaging["0"] = [
251+
[["A4"], 4, 0, 3, 2, -1, false],
252+
[["B4"], 4, 0, 3, 2, -1, false]
253+
];
254+
processABCNotes(logo, "0");
255+
expect(logo.notationNotes["0"]).toContain("(");
256+
});
257+
258+
it("should handle tuplet with matching chord IDs (skip logic)", () => {
259+
logo.notation.notationStaging["0"] = [
260+
[["A4"], 4, 0, 2, 2, 100, false],
261+
[["B4"], 4, 0, 2, 2, 100, false],
262+
[["C4"], 4, 0, 2, 2, -1, false]
263+
];
264+
processABCNotes(logo, "0");
265+
expect(logo.notationNotes["0"]).not.toBe("");
266+
});
267+
});
268+
269+
describe("processABCNotes - Edge Cases for 100% Coverage", () => {
270+
let logo;
271+
272+
beforeEach(() => {
273+
logo = { notationNotes: { "0": "" }, notation: { notationStaging: { "0": [] } } };
274+
});
275+
276+
it("should handle array of notes in NOTATIONNOTE field", () => {
277+
logo.notation.notationStaging["0"] = [[["C4", "E4"], 4, 0, null, null, -1, false]];
278+
processABCNotes(logo, "0");
279+
expect(logo.notationNotes["0"]).toContain("C4");
280+
});
281+
it("should handle incomplete tuplets with different tuplet values", () => {
282+
logo.notation.notationStaging["0"] = [
283+
[["A4"], 4, 0, 3, 2, -1, false],
284+
[["B4"], 4, 0, 5, 2, -1, false]
285+
];
286+
processABCNotes(logo, "0");
287+
expect(logo.notationNotes["0"]).toContain("(");
288+
});
289+
it("should handle closing parenthesis in notation staging", () => {
290+
logo.notation.notationStaging["0"] = [
291+
[["C4"], 4, 0, 3, 2, -1, false],
292+
[["D4"], 4, 0, 3, 2, -1, false],
293+
[["E4"], 4, 0, 3, 2, -1, false],
294+
")"
295+
];
296+
processABCNotes(logo, "0");
297+
expect(logo.notationNotes["0"]).not.toBe("");
298+
});
299+
it("should handle chords with multiple notes outside tuplets", () => {
300+
logo.notation.notationStaging["0"] = [[["C4", "E4", "G4"], 4, 0, null, null, -1, false]];
301+
processABCNotes(logo, "0");
302+
const out = logo.notationNotes["0"];
303+
expect(out).toContain("[");
304+
expect(out).toContain("]");
305+
});
306+
it("should handle dots when closing chords", () => {
307+
const chordID = 456;
308+
logo.notation.notationStaging["0"] = [
309+
[["C4"], 4, 2, null, null, chordID, false],
310+
[["E4"], 4, 2, null, null, chordID, false],
311+
[["G4"], 4, 0, null, null, -1, false]
312+
];
313+
processABCNotes(logo, "0");
314+
expect(logo.notationNotes["0"]).toContain(" ");
315+
});
316+
});
71317
describe("saveAbcOutput", () => {
72318
let activity;
73319

@@ -78,11 +324,7 @@ describe("saveAbcOutput", () => {
78324
notationNotes: { "0": "" },
79325
notation: {
80326
notationStaging: {
81-
"0": [
82-
[["G♯4"], 4, 0, null, null, -1, false],
83-
[["F4"], 4, 0, null, null, -1, false],
84-
[["G♯4"], 2, 0, null, null, -1, false]
85-
]
327+
"0": [[["G♯4"], 4, 0, null, null, -1, false]]
86328
}
87329
}
88330
},
@@ -96,18 +338,15 @@ describe("saveAbcOutput", () => {
96338
};
97339
});
98340

99-
it("should generate the correct ABC notation output", () => {
100-
const expectedOutput =
101-
"X:1\n" +
102-
"T:Music Blocks composition\n" +
103-
"C:Mr. Mouse\n" +
104-
"L:1/16\n" +
105-
"M:C\n" +
106-
"K:CMAJOR\n" +
107-
"G^4 G^4 F4 F4 G^2 G^8 \n";
341+
it("should generate the correct ABC notation output with key signature replacements", () => {
342+
activity.turtles.ithTurtle = () => ({
343+
singer: { keySignature: "B ♭ major" }
344+
});
108345

109346
const result = saveAbcOutput(activity);
110-
expect(result).toBe(expectedOutput);
347+
348+
expect(result).toContain("K:Bb MAJOR");
349+
expect(result).toContain("b");
111350
});
112351
});
113352

@@ -118,9 +357,9 @@ describe("processABCNotes - Tuplet Handling", () => {
118357
notation: {
119358
notationStaging: {
120359
"0": [
121-
[["G♯4"], 4, 0, 3, 2, -1, false], // Tuplet
122-
[["F4"], 4, 0, 3, 2, -1, false], // Tuplet
123-
[["G♯4"], 4, 0, 3, 2, -1, false] // Tuplet
360+
[["G♯4"], 4, 0, 3, 2, -1, false],
361+
[["F4"], 4, 0, 3, 2, -1, false],
362+
[["G♯4"], 4, 0, 3, 2, -1, false]
124363
]
125364
}
126365
}

0 commit comments

Comments
 (0)