Yep. AI rewrote the whole thing.

This commit is contained in:
2026-03-13 03:24:24 +11:00
parent e4719cb9f4
commit fe6c7d8c12
47 changed files with 5348 additions and 1182 deletions

View File

@@ -0,0 +1,248 @@
import XCTest
import Combine
@testable import CommandNotch
@MainActor
final class NotchOrchestratorTests: XCTestCase {
func testHoverOpenSchedulesOpenAfterDelay() {
let screenID = "screen-a"
let screen = makeScreenContext(screenID: screenID)
let registry = TestScreenRegistry(activeScreenID: screenID, screens: [screen])
let host = TestNotchPresentationHost()
let scheduler = TestScheduler()
let orchestrator = NotchOrchestrator(
screenRegistry: registry,
host: host,
settingsController: makeSettingsController(),
scheduler: scheduler
)
orchestrator.handleHoverChange(true, for: screenID)
XCTAssertEqual(screen.notchState, .closed)
scheduler.runScheduledActions()
XCTAssertEqual(screen.notchState, .open)
XCTAssertEqual(host.openedScreenIDs, [screenID])
}
func testHoverExitCancelsPendingOpen() {
let screenID = "screen-a"
let screen = makeScreenContext(screenID: screenID)
let registry = TestScreenRegistry(activeScreenID: screenID, screens: [screen])
let host = TestNotchPresentationHost()
let scheduler = TestScheduler()
let orchestrator = NotchOrchestrator(
screenRegistry: registry,
host: host,
settingsController: makeSettingsController(),
scheduler: scheduler
)
orchestrator.handleHoverChange(true, for: screenID)
orchestrator.handleHoverChange(false, for: screenID)
scheduler.runScheduledActions()
XCTAssertEqual(screen.notchState, .closed)
XCTAssertTrue(host.openedScreenIDs.isEmpty)
}
func testCloseWhileHoveringSuppressesReopenUntilHoverExit() {
let screenID = "screen-a"
let screen = makeScreenContext(screenID: screenID)
let registry = TestScreenRegistry(activeScreenID: screenID, screens: [screen])
let host = TestNotchPresentationHost()
let scheduler = TestScheduler()
let orchestrator = NotchOrchestrator(
screenRegistry: registry,
host: host,
settingsController: makeSettingsController(),
scheduler: scheduler
)
orchestrator.handleHoverChange(true, for: screenID)
scheduler.runScheduledActions()
XCTAssertEqual(screen.notchState, .open)
orchestrator.handleHoverChange(true, for: screenID)
orchestrator.close(screenID: screenID)
scheduler.runScheduledActions()
XCTAssertEqual(screen.notchState, .closed)
XCTAssertFalse(screen.isCloseTransitionActive)
XCTAssertTrue(screen.suppressHoverOpenUntilHoverExit)
XCTAssertEqual(host.closedScreenIDs, [screenID])
scheduler.runScheduledActions()
XCTAssertEqual(screen.notchState, .closed)
XCTAssertEqual(host.openedScreenIDs, [screenID])
orchestrator.handleHoverChange(false, for: screenID)
XCTAssertFalse(screen.suppressHoverOpenUntilHoverExit)
}
func testOpeningSharedWorkspaceOnAnotherScreenClosesPreviousPresenter() {
let workspaceID = UUID()
let firstScreen = makeScreenContext(screenID: "screen-a", workspaceID: workspaceID)
let secondScreen = makeScreenContext(screenID: "screen-b", workspaceID: workspaceID)
let registry = TestScreenRegistry(activeScreenID: "screen-b", screens: [firstScreen, secondScreen])
let host = TestNotchPresentationHost()
let orchestrator = NotchOrchestrator(
screenRegistry: registry,
host: host,
settingsController: makeSettingsController(),
scheduler: TestScheduler()
)
orchestrator.open(screenID: "screen-a")
orchestrator.open(screenID: "screen-b")
XCTAssertEqual(firstScreen.notchState, .closed)
XCTAssertEqual(secondScreen.notchState, .open)
XCTAssertEqual(host.closedScreenIDs, ["screen-a"])
XCTAssertEqual(registry.presentingScreenID(for: workspaceID), "screen-b")
}
func testOpeningDifferentWorkspaceDoesNotCloseOtherOpenScreen() {
let firstScreen = makeScreenContext(screenID: "screen-a", workspaceID: UUID())
let secondScreen = makeScreenContext(screenID: "screen-b", workspaceID: UUID())
let registry = TestScreenRegistry(activeScreenID: "screen-b", screens: [firstScreen, secondScreen])
let host = TestNotchPresentationHost()
let orchestrator = NotchOrchestrator(
screenRegistry: registry,
host: host,
settingsController: makeSettingsController(),
scheduler: TestScheduler()
)
orchestrator.open(screenID: "screen-a")
orchestrator.open(screenID: "screen-b")
XCTAssertEqual(firstScreen.notchState, .open)
XCTAssertEqual(secondScreen.notchState, .open)
XCTAssertTrue(host.closedScreenIDs.isEmpty)
XCTAssertEqual(registry.presentingScreenID(for: firstScreen.workspaceID), "screen-a")
XCTAssertEqual(registry.presentingScreenID(for: secondScreen.workspaceID), "screen-b")
}
private func makeScreenContext(screenID: ScreenID, workspaceID: WorkspaceID = UUID()) -> ScreenContext {
ScreenContext(
id: screenID,
workspaceID: workspaceID,
settingsController: makeSettingsController(),
screenProvider: { _ in nil }
)
}
private func makeSettingsController() -> AppSettingsController {
let store = TestOrchestratorSettingsStore()
var settings = AppSettings.default
settings.behavior.openNotchOnHover = true
settings.behavior.minimumHoverDuration = 0.3
store.storedSettings = settings
return AppSettingsController(store: store)
}
}
@MainActor
private final class TestScreenRegistry: ScreenRegistryType {
private let activeID: ScreenID
private var screensByID: [ScreenID: ScreenContext]
private var workspacePresenters: [WorkspaceID: ScreenID] = [:]
init(activeScreenID: ScreenID, screens: [ScreenContext]) {
self.activeID = activeScreenID
self.screensByID = Dictionary(uniqueKeysWithValues: screens.map { ($0.id, $0) })
}
func allScreens() -> [ScreenContext] {
Array(screensByID.values)
}
func screenContext(for id: ScreenID) -> ScreenContext? {
screensByID[id]
}
func activeScreenID() -> ScreenID? {
activeID
}
func presentingScreenID(for workspaceID: WorkspaceID) -> ScreenID? {
workspacePresenters[workspaceID]
}
func claimWorkspacePresentation(for screenID: ScreenID) -> ScreenID? {
guard let workspaceID = screensByID[screenID]?.workspaceID else { return nil }
let previous = workspacePresenters[workspaceID]
workspacePresenters[workspaceID] = screenID
return previous == screenID ? nil : previous
}
func releaseWorkspacePresentation(for screenID: ScreenID) {
workspacePresenters = workspacePresenters.filter { $0.value != screenID }
}
}
@MainActor
private final class TestNotchPresentationHost: NotchPresentationHost {
var openedScreenIDs: [ScreenID] = []
var closedScreenIDs: [ScreenID] = []
func canPresentNotch(for screenID: ScreenID) -> Bool {
true
}
func performOpenPresentation(for screenID: ScreenID) {
openedScreenIDs.append(screenID)
}
func performClosePresentation(for screenID: ScreenID) {
closedScreenIDs.append(screenID)
}
}
private final class TestScheduler: SchedulerType {
private final class ScheduledAction {
let action: @MainActor () -> Void
var isCancelled = false
init(action: @escaping @MainActor () -> Void) {
self.action = action
}
}
private var scheduledActions: [ScheduledAction] = []
@MainActor
func schedule(after interval: TimeInterval, action: @escaping @MainActor () -> Void) -> AnyCancellable {
let scheduledAction = ScheduledAction(action: action)
scheduledActions.append(scheduledAction)
return AnyCancellable {
scheduledAction.isCancelled = true
}
}
@MainActor
func runScheduledActions() {
let actions = scheduledActions
scheduledActions.removeAll()
for scheduledAction in actions where !scheduledAction.isCancelled {
scheduledAction.action()
}
}
}
private final class TestOrchestratorSettingsStore: AppSettingsStoreType {
var storedSettings = AppSettings.default
func load() -> AppSettings {
storedSettings
}
func save(_ settings: AppSettings) {
storedSettings = settings
}
}