Skip to content

fix(tests): stop AppKit rewriting the uppercase-key-equivalent fixture - #400

Closed
skkap wants to merge 1 commit into
umputun:masterfrom
skkap:fix/live-menu-test-stock-title
Closed

fix(tests): stop AppKit rewriting the uppercase-key-equivalent fixture#400
skkap wants to merge 1 commit into
umputun:masterfrom
skkap:fix/live-menu-test-stock-title

Conversation

@skkap

@skkap skkap commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

make test-app fails on LiveMenuKeyEquivalentsTests.testUppercaseKeyEquivalentReportsImpliedShift():

XCTAssertEqual failed: ("cmd+shift+v") is not equal to ("cmd+opt+shift+v")

Product code is fine — the fixture is mutated before the code under test runs.

Cause

The test builds its item with the title "Paste and Match Style". AppKit recognises that as a standard menu item and, on NSMenu.addItem, rewrites it to the system-standard equivalent — so "V" + [.command, .option] becomes "v" + [.command, .shift]. collectKeyEquivalents then correctly reports cmd+shift+v for the item it was actually handed, and the assertion compares that against the cmd+opt+shift+v the test believed it built.

The rewrite keys off the title alone. Measured on macOS 26.5.2:

fixture after addItem
title "Paste and Match Style", key "V", mask [cmd, opt] key "v", mask [cmd, shift]
title "Totally Custom Title", key "V", mask [cmd, opt] key "V", mask [cmd, opt] — untouched
title "Paste and Match Style", key "Q", mask [cmd, opt] key "v", mask [cmd, shift]

The third row is the telling one: a completely different key equivalent is still replaced with ⇧⌘V, because the title is what AppKit matches on. Before addItem the item holds exactly what the test set, so the rewrite happens at insertion.

It is not key-equivalent localization — allowsAutomaticKeyEquivalentLocalization = false makes no difference — and it is not the chord logic, which never sees the original values.

Fix

Rename the fixture item to a non-stock title, and record why in a comment so it does not get "corrected" back to a realistic-looking stock name. One line of test data; chordSyntax is untouched.

After: make test-app reports TEST SUCCEEDED, and swiftlint --strict stays at 0 violations across 326 files.

Why it presumably passes in CI

I did not confirm this, so treat it as a guess: the rewrite depends on AppKit's standard-item table, so a different macOS version — or a different system language, since the match is against localized standard titles — would not fire it. Reproduced here on macOS 26.5.2 / Xcode 26, where it fails identically on unmodified master (4155ed9).

Split out of #398, which ran into it.

testUppercaseKeyEquivalentReportsImpliedShift built its menu item with the
title "Paste and Match Style". AppKit recognises that as a standard menu
item and, on NSMenu.addItem, rewrites it to the system-standard equivalent
-- so the fixture's uppercase "V" + [.command, .option] became "v" +
[.command, .shift] before collectKeyEquivalents ever ran, and the test
asserted cmd+opt+shift+v against an actual cmd+shift+v.

The rewrite keys off the title alone: the same key and mask under a custom
title are untouched, and the stock title with an entirely different key is
rewritten just the same. Rename the fixture item and say why, so the test
exercises the implied-shift path it describes.

Product code is unchanged -- chordSyntax was always correct; the fixture
was being mutated out from under it.
@skkap
skkap marked this pull request as ready for review August 8, 2026 13:06
@skkap
skkap requested a review from umputun as a code owner August 8, 2026 13:06
@umputun

umputun commented Aug 8, 2026

Copy link
Copy Markdown
Owner

this is already fixed on master by 16d8cbc, merged a day before your commit. Your branch forks from 4155ed9 and is 15 commits behind, so it doesn't carry the fix.

the cause isn't a standard-item table. AppKit substitutes NSUserKeyEquivalents, the App Shortcuts bound by hand in System Settings > Keyboard, and it matches on the menu-item title the moment the item joins a menu, detached menus included. That's why it fails on your machine and nowhere else, and it's neither macOS-version nor language specific. defaults read -g NSUserKeyEquivalents should show "Paste and Match Style" bound to ⇧⌘V on yours. The row in your table where key "Q" still comes back as ⇧⌘V is the giveaway: the system-standard equivalent for that command is ⌥⇧⌘V, which is what the test asserts and would have passed.

renaming the fixture also doesn't generalize. The substitution keys on any title, not only stock ones, so "Vendor Paste Special" is rewritten just the same on a machine where that string is bound. It leaves "Zoom" and "Close" untouched in the same file, and CloseSessionChordTests needs the real "Close" to test chord ownership against agterm's own item, so that one can't be renamed at all.

16d8cbc suppresses the substitution for the duration of each test class instead, NSMenuItem.usesUserKeyEquivalents = false in setUp with a restore in tearDown, in both classes. Titles stay as they are.

closing this one. Rebase #398 on master and the failure goes with it.

@umputun umputun closed this Aug 8, 2026
umputun added a commit that referenced this pull request Aug 8, 2026
The guard lived only in the setUp of LiveMenuKeyEquivalentsTests and
CloseSessionChordTests, so a new menu-fixture test hits the same trap with
nothing in the rules to point at it. Records the mechanism, the defaults
command that names the bindings, and why suppressing beats renaming fixtures.

Related to #400.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants