1import AppKit2import Testing34@testable import Haven56@MainActor7private final class PopoverStub: NSPopover {8 var stubShown = false9 var showCount = 010 var closeCount = 011 override var isShown: Bool { stubShown }12 override func show(13 relativeTo positioningRect: NSRect, of positioningView: NSView,14 preferredEdge: NSRectEdge15 ) {16 stubShown = true17 showCount += 118 }19 override func performClose(_ sender: Any?) {20 stubShown = false21 closeCount += 122 }23}2425@MainActor26private final class OpenPanelStub: NSOpenPanel {27 var completion: ((NSApplication.ModalResponse) -> Void)?2829 override func begin(30 completionHandler handler: @escaping (NSApplication.ModalResponse) -> Void31 ) {32 completion = handler33 }34}3536@Suite("AppKit adapters", .serialized)37@MainActor38struct PlatformCoverageTests {39 @Test("Application delegate creates the status item and menu controller")40 func appDelegateLaunch() {41 let delegate = AppDelegate()4243 delegate.applicationDidFinishLaunching(44 Notification(name: NSApplication.didFinishLaunchingNotification)45 )4647 #expect(delegate.statusItem != nil)48 #expect(delegate.menuController != nil)49 #expect(delegate.statusItem.button?.image != nil)50 }5152 @Test("Menu controller exercises popover and modal lifecycle")53 func menuControllerLifecycle() {54 let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)55 let popover = PopoverStub()56 let controller = MenuController(statusItem: statusItem, popover: popover)5758 #expect(MenuController.shared === controller)59 controller.beginModalPresentation()60 #expect(controller.popover.behavior == .applicationDefined)61 controller.endModalPresentation()62 #expect(controller.popover.behavior == .transient)6364 popover.stubShown = true65 controller.endModalPresentation()66 controller.eventMonitor?.handler(nil)67 popover.stubShown = true68 controller.togglePopover(nil)6970 controller.showPopover(sender: nil)71 controller.togglePopover(nil)72 controller.togglePopover(nil)73 controller.closePopover(sender: nil)74 controller.togglePopover(nil)75 controller.closePopover(sender: nil)76 #expect(popover.showCount > 0)77 #expect(popover.closeCount > 0)7879 NSStatusBar.system.removeStatusItem(statusItem)80 }8182 @Test("Event monitor start and stop are idempotent")83 func eventMonitorLifecycle() {84 var eventSeen = false85 let monitor = EventMonitor(mask: [.leftMouseDown]) { _ in eventSeen = true }8687 monitor.start()88 monitor.stop()89 monitor.stop()9091 #expect(!eventSeen)92 }9394 @Test("Screen manager exposes AppKit screen metadata")95 func screenManager() {96 let manager = ScreenManager.shared97 #expect(manager.screens == NSScreen.screens)98 if let screen = manager.screens.first {99 #expect(manager.screenName(for: screen) == screen.localizedName)100 }101 }102103 @Test("Application bootstrap wires the delegate and optional event loop")104 func applicationBootstrap() {105 let delegate = AppDelegate()106 var received: AppDelegate?107 var runs = 0108 HavenApplication.start(109 delegate: delegate, shouldRun: false,110 setDelegate: { received = $0 }, run: { runs += 1 })111 #expect(received === delegate)112 #expect(runs == 0)113114 HavenApplication.start(115 delegate: delegate, shouldRun: true,116 setDelegate: { received = $0 }, run: { runs += 1 })117 #expect(runs == 1)118 }119120 @Test("Folder panel adapter configures directory selection")121 func folderPanel() {122 let directory = URL(fileURLWithPath: "/tmp")123 let configured = AppState.makeFolderPanel(at: directory)124 #expect(!configured.canChooseFiles)125 #expect(configured.canChooseDirectories)126 #expect(configured.canCreateDirectories)127 #expect(!configured.allowsMultipleSelection)128 #expect(configured.directoryURL == directory)129 }130131 @Test("Folder picker adapter forwards cancellation")132 func folderPicker() {133 let panel = OpenPanelStub()134 var result: URL? = URL(fileURLWithPath: "/sentinel")135136 AppState.presentFolderPicker(panel: panel) { result = $0 }137 #expect(panel.completion != nil)138139 panel.completion?(.cancel)140 #expect(result == nil)141 }142}