Skip to content

Testing

systemBlue edited this page Jun 11, 2026 · 1 revision

Testing

The package code ships only behind a passing test suite, and every pull request must keep new code covered.

The package suite

The Swift package's tests use Swift Testing and run from the repo root:

swift test

No REAPER, no audio hardware, and no network beyond the machine's own loopback interface are required; the suite runs anywhere the package builds.

Suite What it proves
OSCMessageTests, OSCMessageArgumentsTests OSC 1.0 messages encode byte-for-byte to the specification: address and type-tag padding, big-endian numbers, string termination.
OSCDecoderTests, OSCPacketTests The decoder reads spec-valid datagrams back into typed messages and rejects malformed bytes with a named error instead of crashing, including truncated strings, bad lengths, and over-deep bundles.
MCPStdioServerTests The JSON-RPC stdio loop answers initialize, tools/list, and tools/call, and answers protocol violations with the right JSON-RPC error codes.
ReaperToolRouterTests Every tool call validates its arguments before anything is sent: track numbers, normalized values, string content and length. A bad argument is rejected with a message naming the expectation.
ReaperWriteVerificationTests Confirmation is reported only when REAPER's feedback proves the write (the section below).
ReaperSessionCacheTests The feedback cache keeps the latest message per address and stays consistent under concurrent ingests and reads.
ReaperReadToolsTests, ReaperMarkerNavigationTests, ReaperCreationToolTests Read tools report cached state faithfully, and the marker, track, and project tools build the OSC the DAW expects.
UDPOSCMessageReceiverTests, OSCFeedbackListenerTests Real UDP sockets over loopback: datagrams arrive decoded, malformed ones are dropped, bind failures and double starts surface as errors.
ReaperServerConfigurationTests, ReaperCommandLineTests Launch arguments and terminal commands parse correctly, and every rejection points at the help to consult.

What write verification tests prove

REAPER does not acknowledge OSC commands, so the server confirms a write by listening to the feedback REAPER sends back and comparing it against what was commanded. The tests pin that protocol:

  • A write whose feedback echoes the commanded value reports it confirmed, with the value named.
  • A write whose feedback reports something else reports it unconfirmed, carrying the last value heard; a write with no feedback at all reports it unconfirmed with nothing claimed.
  • Confirmation asks REAPER to refresh its control surface before trusting the cache, so a stale value heard before the write never counts as proof.
  • Commands REAPER sends no feedback for, like marker edits, report only that the command was sent, with no confirmation claim.

The architecture page maps the feedback path this protects. The tests pin the invariant: "confirmed" in a tool result always means REAPER reported the commanded value.

The app's tests

The DAW app under apps/DeadCat carries its own targets in the DeadCat scheme: unit tests for the store and the recorder, and a UI test that records through a live simulator microphone, plays the take back, and relaunches the app to prove the session persisted. The UI test launches the app with no arguments, exactly as a user would. It runs only when DEADCAT_CAPTURE=1 is set in the test environment, with the simulator microphone already granted (xcrun simctl privacy booted grant microphone com.systemblue.deadcat); without the variable it skips, so the default test run stays quiet. The app's tests run in Xcode against a simulator and are not part of the package CI job.

Coverage

CI runs the package suite with coverage enabled, exports an lcov report with test files excluded, and uploads it to Codecov. The codecov/patch status is a required check on main: a pull request that adds uncovered lines fails the check and does not merge. The lines that stay uncovered need a failing kernel call or a live socket error to reach, or sit in exhaustive switch arms that are unreachable by construction.

Clone this wiki locally