Files
downterm/CommandNotch/CommandNotchTests/WorkspaceRegistryTests.swift

231 lines
8.2 KiB
Swift

import XCTest
@testable import CommandNotch
@MainActor
final class WorkspaceRegistryTests: XCTestCase {
func testRegistryCreatesDefaultWorkspaceWhenEmpty() {
let registry = makeRegistry()
XCTAssertEqual(registry.allWorkspaceSummaries().count, 1)
XCTAssertEqual(registry.allWorkspaceSummaries().first?.name, "Main")
XCTAssertNotNil(registry.controller(for: registry.defaultWorkspaceID))
}
func testCreateRenameAndDeleteWorkspaceUpdatesSummaries() {
let registry = makeRegistry()
let createdID = registry.createWorkspace(named: "Docs")
XCTAssertEqual(registry.allWorkspaceSummaries().map(\.name), ["Main", "Docs"])
registry.renameWorkspace(id: createdID, to: "Review")
XCTAssertEqual(registry.allWorkspaceSummaries().map(\.name), ["Main", "Review"])
registry.deleteWorkspace(id: createdID)
XCTAssertEqual(registry.allWorkspaceSummaries().map(\.name), ["Main"])
}
func testDeletingLastWorkspaceIsIgnored() {
let registry = makeRegistry()
let onlyWorkspaceID = registry.defaultWorkspaceID
registry.deleteWorkspace(id: onlyWorkspaceID)
XCTAssertEqual(registry.allWorkspaceSummaries().count, 1)
XCTAssertEqual(registry.allWorkspaceSummaries().first?.id, onlyWorkspaceID)
}
func testDeletionFallbackPrefersRequestedWorkspaceWhenAvailable() {
let registry = makeRegistry()
let docsID = registry.createWorkspace(named: "Docs")
let reviewID = registry.createWorkspace(named: "Review")
let fallback = registry.deletionFallbackWorkspaceID(
forDeleting: docsID,
preferredFallback: reviewID
)
XCTAssertEqual(fallback, reviewID)
}
func testRegistryLoadsPersistedWorkspacesFromStore() {
let store = InMemoryWorkspaceStore()
let docsID = UUID(uuidString: "11111111-1111-1111-1111-111111111111")!
store.savedSummaries = [WorkspaceSummary(id: docsID, name: "Docs")]
let registry = makeRegistry(initialWorkspaces: nil, store: store)
XCTAssertEqual(registry.allWorkspaceSummaries().count, 1)
XCTAssertEqual(registry.allWorkspaceSummaries().first?.id, docsID)
XCTAssertEqual(registry.allWorkspaceSummaries().first?.name, "Docs")
XCTAssertEqual(registry.defaultWorkspaceID, docsID)
}
func testRegistryPersistsWorkspaceSummaryChanges() {
let store = InMemoryWorkspaceStore()
let registry = makeRegistry(store: store)
let createdID = registry.createWorkspace(named: "Docs")
XCTAssertEqual(store.savedSummaries.map(\.name), ["Main", "Docs"])
registry.renameWorkspace(id: createdID, to: "Review")
XCTAssertEqual(store.savedSummaries.map(\.name), ["Main", "Review"])
registry.deleteWorkspace(id: createdID)
XCTAssertEqual(store.savedSummaries.map(\.name), ["Main"])
}
func testUpdateWorkspaceHotkeyPersistsAndUpdatesSummary() {
let store = InMemoryWorkspaceStore()
let registry = makeRegistry(store: store)
let docsID = registry.createWorkspace(named: "Docs")
let hotkey = HotkeyBinding.cmdShiftDigit(4)
registry.updateWorkspaceHotkey(id: docsID, to: hotkey)
XCTAssertEqual(registry.summary(for: docsID)?.hotkey, hotkey)
XCTAssertEqual(store.savedSummaries.last?.hotkey, hotkey)
}
func testNextAndPreviousWorkspaceWrapAroundRegistryOrder() {
let registry = makeRegistry()
let mainID = registry.defaultWorkspaceID
let docsID = registry.createWorkspace(named: "Docs")
let reviewID = registry.createWorkspace(named: "Review")
XCTAssertEqual(registry.nextWorkspaceID(after: mainID), docsID)
XCTAssertEqual(registry.nextWorkspaceID(after: reviewID), mainID)
XCTAssertEqual(registry.previousWorkspaceID(before: mainID), reviewID)
XCTAssertEqual(registry.previousWorkspaceID(before: docsID), mainID)
}
private func makeRegistry(
initialWorkspaces: [WorkspaceSummary]? = [],
store: (any WorkspaceStoreType)? = nil
) -> WorkspaceRegistry {
let settingsProvider = TestSettingsProvider()
let sessionFactory = UnusedTerminalSessionFactory()
return WorkspaceRegistry(
initialWorkspaces: initialWorkspaces,
store: store,
controllerFactory: { summary in
WorkspaceController(
summary: summary,
sessionFactory: sessionFactory,
settingsProvider: settingsProvider,
bootstrapDefaultTab: false
)
}
)
}
}
@MainActor
final class WorkspaceControllerTests: XCTestCase {
func testNewTabUsesActiveTabCurrentDirectory() {
let factory = RecordingTerminalSessionFactory()
let controller = WorkspaceController(
summary: WorkspaceSummary(name: "Main"),
sessionFactory: factory,
settingsProvider: TestSettingsProvider(),
bootstrapDefaultTab: false
)
controller.newTab()
controller.activeTab?.currentDirectory = "/tmp/Raycast"
controller.newTab()
XCTAssertEqual(factory.requestedDirectories, [nil, "/tmp/Raycast"])
XCTAssertEqual(controller.activeTab?.currentDirectory, "/tmp/Raycast")
XCTAssertEqual(controller.tabs.count, 2)
XCTAssertEqual(controller.activeTabIndex, 1)
}
func testNewTabNormalizesCurrentDirectoryFileURL() {
let factory = RecordingTerminalSessionFactory()
let controller = WorkspaceController(
summary: WorkspaceSummary(name: "Main"),
sessionFactory: factory,
settingsProvider: TestSettingsProvider(),
bootstrapDefaultTab: false
)
let expectedPath = "/tmp/Raycast Folder"
controller.newTab()
controller.activeTab?.currentDirectory = URL(fileURLWithPath: expectedPath).absoluteString
controller.newTab()
XCTAssertEqual(controller.activeTab?.currentDirectory, expectedPath)
}
func testNewTabFallsBackToHomeDirectoryWhenWorkspaceHasNoTabs() {
let factory = RecordingTerminalSessionFactory()
let controller = WorkspaceController(
summary: WorkspaceSummary(name: "Main"),
sessionFactory: factory,
settingsProvider: TestSettingsProvider(),
bootstrapDefaultTab: false
)
controller.newTab()
XCTAssertEqual(factory.requestedDirectories, [nil])
XCTAssertEqual(controller.activeTab?.currentDirectory, NSHomeDirectory())
XCTAssertEqual(controller.tabs.count, 1)
XCTAssertEqual(controller.activeTabIndex, 0)
}
}
private final class InMemoryWorkspaceStore: WorkspaceStoreType {
var savedSummaries: [WorkspaceSummary] = []
func loadWorkspaceSummaries() -> [WorkspaceSummary] {
savedSummaries
}
func saveWorkspaceSummaries(_ summaries: [WorkspaceSummary]) {
savedSummaries = summaries
}
}
private final class TestSettingsProvider: TerminalSessionConfigurationProviding {
let terminalSessionConfiguration = TerminalSessionConfiguration(fontSize: 13, theme: .terminalApp, shellPath: "")
let hotkeySettings = AppSettings.default.hotkeys
let terminalSizePresets = TerminalSizePresetStore.loadDefaults()
}
private final class RecordingTerminalSessionFactory: TerminalSessionFactoryType {
private(set) var requestedDirectories: [String?] = []
@MainActor
func makeSession(
fontSize: CGFloat,
theme: TerminalTheme,
shellPath: String,
initialDirectory: String?
) -> TerminalSession {
requestedDirectories.append(initialDirectory)
return TerminalSession(
fontSize: fontSize,
theme: theme,
shellPath: shellPath,
initialDirectory: initialDirectory,
startImmediately: false
)
}
}
private struct UnusedTerminalSessionFactory: TerminalSessionFactoryType {
@MainActor
func makeSession(
fontSize: CGFloat,
theme: TerminalTheme,
shellPath: String,
initialDirectory: String?
) -> TerminalSession {
fatalError("WorkspaceRegistryTests should not create live terminal sessions.")
}
}