From 5426df763458985b93c675ec67ab2f32ace226ca Mon Sep 17 00:00:00 2001 From: Leo Li Date: Sat, 10 Oct 2026 19:11:06 -0700 Subject: [PATCH] test: ignore NSTextView's own delegate reads during init on macOS 27 On macOS 27, NSTextView's initializer reads its own `delegate` four times. The probes that check cmux never touches the unsafe-unretained NSTextView.delegate counted those AppKit reads, so four tests failed with "4 is not equal to 0" on the macOS 27 minis while passing on the macOS 15/26 runners. Reset each probe's counter after construction so only reads made by the code under test are counted. Co-Authored-By: Claude Opus 5.5 --- cmuxTests/BrowserConfigTests.swift | 14 ++++++++++++++ cmuxTests/ShortcutAndCommandPaletteTests.swift | 7 +++++++ cmuxTests/TerminalAndGhosttyTests.swift | 7 +++++++ 3 files changed, 28 insertions(+) diff --git a/cmuxTests/BrowserConfigTests.swift b/cmuxTests/BrowserConfigTests.swift index f0bf1742555a..80d5b5c200b9 100644 --- a/cmuxTests/BrowserConfigTests.swift +++ b/cmuxTests/BrowserConfigTests.swift @@ -312,6 +312,12 @@ final class CmuxWebViewKeyEquivalentTests: XCTestCase { super.delegate = newValue } } + + /// macOS 27's NSTextView initializer reads its own `delegate`. Only + /// reads after construction belong to the code under test. + func resetDelegateReadCount() { + delegateReadCount = 0 + } } private final class FieldEditorProbeTextView: NSTextView { @@ -329,6 +335,12 @@ final class CmuxWebViewKeyEquivalentTests: XCTestCase { } } + /// macOS 27's NSTextView initializer reads its own `delegate`. Only + /// reads after construction belong to the code under test. + func resetDelegateReadCount() { + delegateReadCount = 0 + } + override var isFieldEditor: Bool { get { true } set {} @@ -991,6 +1003,7 @@ final class CmuxWebViewKeyEquivalentTests: XCTestCase { window.contentView = container let textView = DelegateProbeTextView(frame: NSRect(x: 0, y: 0, width: 100, height: 40)) + textView.resetDelegateReadCount() container.addSubview(textView) window.makeKeyAndOrderFront(nil) @@ -1028,6 +1041,7 @@ final class CmuxWebViewKeyEquivalentTests: XCTestCase { webView.addSubview(descendant) let fieldEditor = FieldEditorProbeTextView(frame: NSRect(x: 0, y: 0, width: 100, height: 20)) + fieldEditor.resetDelegateReadCount() window.makeKeyAndOrderFront(nil) defer { diff --git a/cmuxTests/ShortcutAndCommandPaletteTests.swift b/cmuxTests/ShortcutAndCommandPaletteTests.swift index 8b36c1a963e3..95fc9d47a903 100644 --- a/cmuxTests/ShortcutAndCommandPaletteTests.swift +++ b/cmuxTests/ShortcutAndCommandPaletteTests.swift @@ -719,6 +719,12 @@ final class CommandPaletteFocusStealerClassificationTests: XCTestCase { super.delegate = newValue } } + + /// macOS 27's NSTextView initializer reads its own `delegate`. Only + /// reads after construction belong to the code under test. + func resetDelegateReadCount() { + delegateReadCount = 0 + } } func testTreatsGhosttySurfaceViewAsFocusStealer() { @@ -748,6 +754,7 @@ final class CommandPaletteFocusStealerClassificationTests: XCTestCase { func testDoesNotReadTextViewDelegateForFocusStealerClassification() { let textView = DelegateTrackingTextView(frame: NSRect(x: 0, y: 0, width: 120, height: 24)) + textView.resetDelegateReadCount() XCTAssertFalse(textView.isCommandPaletteFocusStealingTerminalOrBrowser) XCTAssertEqual( diff --git a/cmuxTests/TerminalAndGhosttyTests.swift b/cmuxTests/TerminalAndGhosttyTests.swift index 35707e40954e..b59a88628b74 100644 --- a/cmuxTests/TerminalAndGhosttyTests.swift +++ b/cmuxTests/TerminalAndGhosttyTests.swift @@ -2984,6 +2984,12 @@ final class GhosttyResponderResolutionTests: XCTestCase { super.delegate = newValue } } + + /// macOS 27's NSTextView initializer reads its own `delegate`. Only + /// reads after construction belong to the code under test. + func resetDelegateReadCount() { + delegateReadCount = 0 + } } func testResolvesGhosttyViewFromDescendantResponder() { @@ -3044,6 +3050,7 @@ final class GhosttyResponderResolutionTests: XCTestCase { func testDoesNotReadTextViewDelegateForGhosttyResponderResolution() { let textView = DelegateTrackingTextView(frame: NSRect(x: 0, y: 0, width: 40, height: 40)) + textView.resetDelegateReadCount() XCTAssertNil(textView.cmuxStrictOwningGhosttyView()) XCTAssertEqual(