Implement comprehensive tests for pattern event parsing and normalization.
This commit is contained in:
101
tests/pattern-events.test.ts
Normal file
101
tests/pattern-events.test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { parsePatternEvents } from '../src/lib/parsers';
|
||||
|
||||
function buildPattern(records: number[][], bars: number = 4, declaredCount = records.length) {
|
||||
const data = new Uint8Array(4 + records.length * 8);
|
||||
data[1] = bars;
|
||||
data[2] = declaredCount & 0xff;
|
||||
data[3] = declaredCount >> 8;
|
||||
|
||||
records.forEach((record, index) => {
|
||||
data.set(record, 4 + index * 8);
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
test('parses note records without changing the derived note shape', () => {
|
||||
const result = parsePatternEvents(buildPattern([[0x34, 0x12, 3 << 3, 64, 99, 0x78, 0x56, 7]]));
|
||||
|
||||
assert.equal(result.bars, 4);
|
||||
assert.equal(result.recordCount, 1);
|
||||
assert.deepEqual(result.notes, {
|
||||
3: [{ note: 64, position: 0x1234, duration: 0x5678, velocity: 99 }],
|
||||
});
|
||||
assert.deepEqual(result.events[0], {
|
||||
type: 'note',
|
||||
kind: 0,
|
||||
position: 0x1234,
|
||||
source: 3,
|
||||
flags: 7,
|
||||
rawData: new Uint8Array([0x34, 0x12, 3 << 3, 64, 99, 0x78, 0x56, 7]),
|
||||
pad: 3,
|
||||
note: 64,
|
||||
velocity: 99,
|
||||
duration: 0x5678,
|
||||
});
|
||||
});
|
||||
|
||||
test('parses and normalizes fader records', () => {
|
||||
const result = parsePatternEvents(buildPattern([[0x60, 0, 1, 7, 9, 0xff, 0x7f, 128]]));
|
||||
|
||||
assert.deepEqual(result.notes, {});
|
||||
assert.deepEqual(result.events[0], {
|
||||
type: 'fader',
|
||||
kind: 1,
|
||||
position: 96,
|
||||
source: 0,
|
||||
flags: 128,
|
||||
rawData: new Uint8Array([0x60, 0, 1, 7, 9, 0xff, 0x7f, 128]),
|
||||
parameter: 7,
|
||||
reserved: 9,
|
||||
rawValue: 32767,
|
||||
value: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test('preserves MIDI and unknown records', () => {
|
||||
const midi = [1, 0, (4 << 3) | 2, 0xd0, 75, 3, 4, 5];
|
||||
const unknown = [2, 0, (5 << 3) | 6, 10, 11, 12, 13, 14];
|
||||
const result = parsePatternEvents(buildPattern([midi, unknown]));
|
||||
|
||||
assert.deepEqual(result.events[0], {
|
||||
type: 'midi',
|
||||
kind: 2,
|
||||
position: 1,
|
||||
source: 4,
|
||||
flags: 5,
|
||||
rawData: new Uint8Array(midi),
|
||||
data: new Uint8Array([0xd0, 75, 3, 4]),
|
||||
});
|
||||
assert.deepEqual(result.events[1], {
|
||||
type: 'unknown',
|
||||
kind: 6,
|
||||
position: 2,
|
||||
source: 5,
|
||||
flags: 14,
|
||||
rawData: new Uint8Array(unknown),
|
||||
data: new Uint8Array([10, 11, 12, 13]),
|
||||
});
|
||||
});
|
||||
|
||||
test('uses the uint16 header count and ignores undeclared or partial records', () => {
|
||||
const records = Array.from({ length: 300 }, (_, index) => [
|
||||
index & 0xff,
|
||||
index >> 8,
|
||||
0,
|
||||
60,
|
||||
100,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
]);
|
||||
const data = buildPattern([...records, [0, 0, 1, 0, 0, 0, 0, 0]], 8, 300);
|
||||
const truncated = data.slice(0, data.length - 3);
|
||||
const result = parsePatternEvents(truncated);
|
||||
|
||||
assert.equal(result.recordCount, 300);
|
||||
assert.equal(result.events.length, 300);
|
||||
assert.equal(result.events[299].position, 299);
|
||||
});
|
||||
Reference in New Issue
Block a user