import { describe, expect, it } from "@suaveplan/testing/runner"; import fc from "fast-check"; import { decodeMessage } from "../src/message/decode.js"; import { encodeMessage } from "../src/message/encode.js"; import type { MidiMessage } from "../src/message/message.types.js"; const channel = fc.integer({ min: 0, max: 15 }); const data7 = fc.integer({ min: 0, max: 127 }); const data14 = fc.integer({ min: 0, max: 16383 }); const channelVoiceArbs: fc.Arbitrary[] = [ fc.record({ type: fc.constant("noteOff" as const), channel, note: data7, velocity: data7, }), fc.record({ type: fc.constant("noteOn" as const), channel, note: data7, velocity: data7, }), fc.record({ type: fc.constant("polyPressure" as const), channel, note: data7, pressure: data7, }), fc.record({ type: fc.constant("controlChange" as const), channel, controller: data7, value: data7, }), fc.record({ type: fc.constant("programChange" as const), channel, program: data7, }), fc.record({ type: fc.constant("channelPressure" as const), channel, pressure: data7, }), fc.record({ type: fc.constant("pitchBend" as const), channel, value: data14, }), ]; const systemArbs: fc.Arbitrary[] = [ fc.record({ type: fc.constant("timeCode" as const), channel: fc.constant(null), value: data7, }), fc.record({ type: fc.constant("songPosition" as const), channel: fc.constant(null), position: data14, }), fc.record({ type: fc.constant("songSelect" as const), channel: fc.constant(null), song: data7, }), fc.record({ type: fc.constant("tuneRequest" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("clock" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("start" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("continue" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("stop" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("activeSensing" as const), channel: fc.constant(null), }), fc.record({ type: fc.constant("reset" as const), channel: fc.constant(null), }), ]; const sysexArb: fc.Arbitrary = fc .uint8Array({ minLength: 0, maxLength: 32, min: 0, max: 0x7f }) .map((payload) => ({ type: "systemExclusive" as const, channel: null, payload, })); const anyMessageArb = fc.oneof(...channelVoiceArbs, ...systemArbs, sysexArb); describe("property: encode/decode round-trip", () => { it("every variant round-trips", { timeout: 30000 }, () => { fc.assert( fc.property(anyMessageArb, (msg) => { const bytes = encodeMessage(msg); const { msg: decoded, next } = decodeMessage(bytes, 0); expect(next).toBe(bytes.length); if ( msg.type === "systemExclusive" && decoded.type === "systemExclusive" ) { expect(Array.from(decoded.payload)).toEqual( Array.from(msg.payload) ); } else { expect(decoded).toEqual(msg); } }), { numRuns: 1000 } ); }); });