Files
steipete--codexbar/Tests/CodexBarTests/MenuBarVisibilityWatcherTests.swift
2026-07-13 12:22:33 +08:00

631 lines
22 KiB
Swift

import CoreGraphics
import Foundation
import Testing
@testable import CodexBar
struct MenuBarVisibilityWatcherTests {
@Test
func `does not flag intentionally hidden status item`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 0)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `flags visible item without attached window`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `flags visible item without button`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: false,
hasWindow: false,
hasScreen: false,
buttonWidth: 0)
#expect(MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `flags visible item with zero width`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 0)
#expect(MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `allows visible item attached to a screen with width`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `window probe matches autosave name and reports display bounds`() {
let snapshots = MenuBarStatusItemWindowProbe.snapshots(
matching: ["codexbar-merged"],
windowInfo: [[
kCGWindowName as String: "codexbar-merged",
kCGWindowOwnerName as String: "Control Center",
kCGWindowIsOnscreen as String: true,
kCGWindowBounds as String: [
"X": 1680,
"Y": 0,
"Width": 70,
"Height": 24,
],
]],
displayBounds: [CGRect(x: 0, y: 0, width: 2056, height: 1329)])
#expect(snapshots.count == 1)
#expect(snapshots.first?.name == "codexbar-merged")
#expect(snapshots.first?.ownerName == "Control Center")
#expect(snapshots.first?.isOnscreen == true)
#expect(snapshots.first?.isWithinDisplayBounds == true)
}
@Test
func `window probe detects offscreen status item by bounds`() {
let snapshots = MenuBarStatusItemWindowProbe.snapshots(
matching: ["codexbar-merged"],
windowInfo: [[
kCGWindowName as String: "codexbar-merged",
kCGWindowOwnerName as String: "Control Center",
kCGWindowIsOnscreen as String: true,
kCGWindowBounds as String: [
"X": 2023,
"Y": 0,
"Width": 71,
"Height": 24,
],
]],
displayBounds: [CGRect(x: 0, y: 0, width: 2056, height: 1329)])
#expect(snapshots.count == 1)
#expect(snapshots.first?.isOnscreen == true)
#expect(snapshots.first?.isWithinDisplayBounds == false)
}
@Test
func `window probe identifies Tahoe Control Center blocked proxy geometry`() {
let snapshot = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 0, y: -22, width: 76, height: 22),
isOnscreen: true,
displayBounds: nil)
#expect(snapshot.isTahoeBlockedProxy)
}
@Test
func `window probe does not classify generic offscreen manager placement as Tahoe proxy`() {
let snapshot = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 2023, y: 0, width: 71, height: 24),
isOnscreen: true,
displayBounds: nil)
#expect(!snapshot.isTahoeBlockedProxy)
}
@Test
func `window probe does not classify stale hidden Control Center record as Tahoe proxy`() {
let snapshot = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 0, y: -22, width: 76, height: 22),
isOnscreen: false,
displayBounds: nil)
#expect(!snapshot.isTahoeBlockedProxy)
}
@Test
func `allows visible item attached to a detached screen`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
}
@Test
func `classifies detached live item as displaced but not blocked`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
#expect(MenuBarVisibilityWatcher.isDisplacedSnapshot(snapshot: snapshot))
}
@Test
func `classifies stale screen live item as displaced but not blocked`() {
let snapshot = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: snapshot))
#expect(MenuBarVisibilityWatcher.isDisplacedSnapshot(snapshot: snapshot))
}
@Test
func `guidance shows once then repeats after a day`() throws {
let defaults = try #require(UserDefaults(suiteName: "MenuBarVisibilityWatcherTests"))
defaults.removePersistentDomain(forName: "MenuBarVisibilityWatcherTests")
let now = Date(timeIntervalSince1970: 1000)
#expect(MenuBarVisibilityWatcher.shouldShowGuidance(defaults: defaults, now: now))
MenuBarVisibilityWatcher.markGuidanceShown(defaults: defaults, now: now)
#expect(!MenuBarVisibilityWatcher.shouldShowGuidance(
defaults: defaults,
now: now.addingTimeInterval(MenuBarVisibilityWatcher.guidanceRepeatInterval - 1)))
#expect(MenuBarVisibilityWatcher.shouldShowGuidance(
defaults: defaults,
now: now.addingTimeInterval(MenuBarVisibilityWatcher.guidanceRepeatInterval)))
}
@Test
func `startup recovery triggers for blocked visible snapshot`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let blocked = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [blocked]))
}
@Test
func `startup recovery retries detached Tahoe proxy corroborated by Control Center geometry`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let detachedProxy = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 76)
let blockedWindow = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 0, y: -22, width: 76, height: 22),
isOnscreen: true,
displayBounds: nil)
#expect(!MenuBarVisibilityWatcher.isBlockedSnapshot(snapshot: detachedProxy))
#expect(MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [detachedProxy],
windowSnapshots: [blockedWindow],
detectTahoeBlockedStatusItem: true))
}
@Test
func `startup recovery retries expected hidden Tahoe item with enabled default and no window`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 76)
let evidence = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: true,
snapshot: hidden)
#expect(MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [hidden],
evidence: [evidence],
detectTahoeBlockedStatusItem: true))
}
@Test
func `startup recovery ignores hidden Tahoe item without app and defaults visibility agreement`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 76)
let intentionallyHidden = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: false,
visibilityDefault: true,
snapshot: hidden)
let disabledByUser = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: false,
snapshot: hidden)
let unknownDefault = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: nil,
snapshot: hidden)
for evidence in [intentionallyHidden, disabledByUser, unknownDefault] {
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [hidden],
evidence: [evidence],
detectTahoeBlockedStatusItem: true))
}
}
@Test
func `startup recovery ignores hidden item when matching window still exists`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 76)
let evidence = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: true,
snapshot: hidden)
let existingWindow = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 1500, y: 0, width: 76, height: 24),
isOnscreen: true,
displayBounds: CGRect(x: 0, y: 0, width: 2056, height: 1329))
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [hidden],
evidence: [evidence],
windowSnapshots: [existingWindow],
detectTahoeBlockedStatusItem: true))
}
@Test
func `startup recovery ignores stale hidden matching window record`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 76)
let evidence = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: true,
snapshot: hidden)
let staleWindow = MenuBarStatusItemWindowSnapshot(
name: "codexbar-merged",
ownerName: "Control Center",
bounds: CGRect(x: 1500, y: 0, width: 76, height: 24),
isOnscreen: false,
displayBounds: CGRect(x: 0, y: 0, width: 2056, height: 1329))
#expect(MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [hidden],
evidence: [evidence],
windowSnapshots: [staleWindow],
detectTahoeBlockedStatusItem: true))
}
@Test
func `startup recovery keeps hidden no-window detection Tahoe only`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 76)
let evidence = StatusItemStartupVisibilityEvidence(
autosaveName: "codexbar-merged",
expectsVisibility: true,
visibilityDefault: true,
snapshot: hidden)
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [hidden],
evidence: [evidence]))
}
@Test
func `startup recovery ignores detached live item without Tahoe proxy corroboration`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let managed = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [managed],
detectTahoeBlockedStatusItem: true))
}
@Test
func `startup recovery ignores live item attached to a stale screen`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let managed = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [managed]))
}
@Test
func `startup recovery triggers when one split status item is blocked`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let healthy = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
let blocked = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [healthy, blocked]))
}
@Test
func `startup recovery ignores stale checks`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let blocked = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(MenuBarVisibilityWatcher.startupFreshnessInterval + 1),
snapshots: [blocked]))
}
@Test
func `startup recovery ignores healthy visible snapshot`() {
let launchedAt = Date(timeIntervalSince1970: 1000)
let healthy = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldAttemptStartupRecovery(
appLaunchedAt: launchedAt,
now: launchedAt.addingTimeInterval(2),
snapshots: [healthy]))
}
@Test
func `screen change placement refresh ignores display removal with healthy status item`() {
let healthy = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 2,
currentScreenCount: 1,
snapshots: [healthy]))
}
@Test
func `screen change placement refresh ignores display removal when no status item is visible`() {
let hidden = StatusItemVisibilitySnapshot(
isVisible: false,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 2,
currentScreenCount: 1,
snapshots: [hidden]))
}
@Test
func `screen change recovery triggers for blocked status item without display count change`() {
let blocked = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldAttemptScreenChangeRecovery(snapshots: [blocked]))
}
@Test
func `screen change placement refresh triggers for detached live item after display removal`() {
let displaced = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 2,
currentScreenCount: 1,
snapshots: [displaced]))
}
@Test
func `screen change placement refresh triggers for stale screen live item after display removal`() {
let displaced = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 2,
currentScreenCount: 1,
snapshots: [displaced]))
}
@Test
func `screen change placement refresh ignores healthy item when display count does not shrink`() {
let healthy = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 1,
currentScreenCount: 2,
snapshots: [healthy]))
}
@Test
func `screen change placement refresh triggers for displaced live item when display count is unchanged`() {
let displaced = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.shouldRefreshScreenChangePlacement(
previousScreenCount: 2,
currentScreenCount: 2,
snapshots: [displaced]))
}
@Test
func `manager parked item with live window is not blocked`() {
// A menu bar manager parks items off the active screen with the window intact.
// hasAnyBlockedVisibleSnapshot must return false so verifyScreenChangeRecoveryIfNeeded
// does not trigger repeated recreation that corrupts Control Center.
let managed = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.hasAnyBlockedVisibleSnapshot([managed]))
#expect(MenuBarVisibilityWatcher.hasAnyDisplacedVisibleSnapshot([managed]))
}
@Test
func `manager parked item with live window on stale screen is not blocked`() {
let managed = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: true,
hasScreen: true,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(!MenuBarVisibilityWatcher.hasAnyBlockedVisibleSnapshot([managed]))
#expect(MenuBarVisibilityWatcher.hasAnyDisplacedVisibleSnapshot([managed]))
}
@Test
func `item without window is blocked regardless of screen state`() {
// A missing window cannot be caused by a manager parking the item; it signals
// a genuine system block and must trigger recovery.
let blocked = StatusItemVisibilitySnapshot(
isVisible: true,
hasButton: true,
hasWindow: false,
hasScreen: false,
isOnCurrentScreen: false,
buttonWidth: 18)
#expect(MenuBarVisibilityWatcher.hasAnyBlockedVisibleSnapshot([blocked]))
#expect(!MenuBarVisibilityWatcher.hasAnyDisplacedVisibleSnapshot([blocked]))
}
}