src/kit/CustomRecorderControlSpecs.md
Line coverage:
CustomRecorderControlTestable.swift78% · refreshed 2026-05-27 by/coverage-explore
When the user records a shortcut in Settings, CustomRecorderControlTestable.isShortcutAcceptable
decides whether the recorded combination is allowed. It rejects unusable or conflicting combinations
before they're persisted, so the user can't bind something that won't work or that collides with an
existing AltTab shortcut or a macOS-reserved one.
candidateId handed in must be a well-formed bound preference key (isWellFormedCandidateId):
a holdShortcut/nextWindowShortcut id has to resolve to an in-range shortcut index. The recycled
ShortcutEditor regression fed a frozen placeholder ("nextWindowShortcut0", index -1) that matched
nothing and silently returned .accepted, so the conflict dialog stopped appearing. A #if DEBUG
assert now trips loudly if a malformed id ever reaches the check.Mirrors CustomRecorderControlTests.swift 1:1.
Guards the recycled-ShortcutEditor regression where a stale recorder id (id/identifier drift) reached the conflict check and silently suppressed the dialog.
"…Shortcut0" placeholders (index -1) and out-of-range ids are rejected; static/arrow/vim ids are always well-formed.Used by the keyboard matcher to recognize a chord whose modifiers are physically split between the configured holdShortcut and a local shortcut (e.g. commandShiftTab = ⌘⌥-hold + ⇧).
Shortcut.keyEquivalent (in CustomRecorderControlTestable.swift)This getter is used in production by ControlsTab.shortcutSummary (to render the Settings sidebar row summary) — not "for testing only" as the older comment in the source incorrectly claimed (now fixed). It's effectively untestable from the unit-tests target: it calls ShortcutRecorder's readableStringRepresentation(isASCII:), which throws NSInternalInconsistencyException: Unable to find bundle with resources when the framework's bundle isn't loaded (the case for unit tests). Testing it would need either bundle-loading test setup or extracting the formatting logic away from readableStringRepresentation. Left alone for now; recorded here so the 0% line coverage on this getter isn't mistaken for a forgotten gap.