Sapling/Tests/SaplingWorkspaceTests/WorkspaceManagerTests.swift

140 lines
5.8 KiB
Swift

import Foundation
import SaplingCore
import SaplingWorkspace
import XCTest
final class WorkspaceManagerTests: XCTestCase {
private var temporaryRoots: [URL] = []
override func tearDownWithError() throws {
for url in temporaryRoots {
try? FileManager.default.removeItem(at: url)
}
temporaryRoots = []
}
func testOpenWorkspaceBuildsFilesystemTree() async throws {
let rootURL = try makeTemporaryWorkspace()
try createDirectory("Notes", in: rootURL)
try writeFile("Notes/Index.md", in: rootURL, contents: "# Notes")
try writeFile("Notes/todo.txt", in: rootURL, contents: "todo")
try createDirectory("Research/Archive", in: rootURL)
try writeFile("Research/Archive/Paper.markdown", in: rootURL, contents: "# Paper")
let workspace = try await LocalWorkspaceManager().openWorkspace(at: rootURL)
XCTAssertEqual(workspace.rootURL, rootURL)
XCTAssertEqual(workspace.items.map(\.displayName), ["Notes", "Research"])
let notes = try XCTUnwrap(workspace.folder(named: "Notes"))
XCTAssertEqual(notes.children.map(\.displayName), ["Index.md", "todo.txt"])
XCTAssertEqual(try XCTUnwrap(notes.file(named: "Index.md")).kind, .markdown)
XCTAssertEqual(try XCTUnwrap(notes.file(named: "todo.txt")).kind, .other)
let archive = try XCTUnwrap(workspace.folder(named: "Research")?.folder(named: "Archive"))
XCTAssertEqual(try XCTUnwrap(archive.file(named: "Paper.markdown")).kind, .markdown)
}
func testGitRepositoriesAreDetectedAsProjectsWithChildren() async throws {
let rootURL = try makeTemporaryWorkspace()
try createGitRepository("Sapling", in: rootURL)
try writeFile("Sapling/README.md", in: rootURL, contents: "# Sapling")
try createGitRepository("Research", in: rootURL)
try writeFile("Research/Notes.md", in: rootURL, contents: "# Research")
try createDirectory("Ordinary", in: rootURL)
let workspace = try await LocalWorkspaceManager().openWorkspace(at: rootURL)
XCTAssertEqual(workspace.items.map(\.displayName), ["Ordinary", "Research", "Sapling"])
let research = try XCTUnwrap(workspace.project(named: "Research"))
let sapling = try XCTUnwrap(workspace.project(named: "Sapling"))
XCTAssertEqual(research.gitRepository.statusSummary, .unknown)
XCTAssertEqual(sapling.gitRepository.rootURL.lastPathComponent, "Sapling")
XCTAssertEqual(research.children.map(\.displayName), ["Notes.md"])
XCTAssertNil(research.folder(named: ".git"))
}
func testHiddenFilesAndGitInternalsAreExcluded() async throws {
let rootURL = try makeTemporaryWorkspace()
try writeFile(".hidden.md", in: rootURL, contents: "# Hidden")
try createGitRepository("Project", in: rootURL)
try writeFile("Project/.git/config", in: rootURL, contents: "[core]")
try writeFile("Project/Visible.md", in: rootURL, contents: "# Visible")
let workspace = try await LocalWorkspaceManager().openWorkspace(at: rootURL)
XCTAssertEqual(workspace.items.map(\.displayName), ["Project"])
let project = try XCTUnwrap(workspace.project(named: "Project"))
XCTAssertEqual(project.children.map(\.displayName), ["Visible.md"])
}
private func makeTemporaryWorkspace() throws -> URL {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("SaplingWorkspaceTests-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
temporaryRoots.append(url)
return url
}
private func createDirectory(_ path: String, in rootURL: URL) throws {
try FileManager.default.createDirectory(
at: rootURL.appendingPathComponent(path, isDirectory: true),
withIntermediateDirectories: true
)
}
private func createGitRepository(_ path: String, in rootURL: URL) throws {
try createDirectory(path, in: rootURL)
try createDirectory("\(path)/.git", in: rootURL)
}
private func writeFile(_ path: String, in rootURL: URL, contents: String) throws {
let url = rootURL.appendingPathComponent(path)
try FileManager.default.createDirectory(
at: url.deletingLastPathComponent(),
withIntermediateDirectories: true
)
try contents.write(to: url, atomically: true, encoding: .utf8)
}
}
private extension Workspace {
func folder(named name: String) -> WorkspaceFolder? {
items.compactMap { item -> WorkspaceFolder? in
guard case .folder(let folder) = item, folder.name == name else { return nil }
return folder
}.first
}
func project(named name: String) -> Project? {
items.compactMap { item -> Project? in
guard case .project(let project) = item, project.name == name else { return nil }
return project
}.first
}
}
private extension WorkspaceFolder {
func folder(named name: String) -> WorkspaceFolder? {
children.compactMap { item -> WorkspaceFolder? in
guard case .folder(let folder) = item, folder.name == name else { return nil }
return folder
}.first
}
func file(named name: String) -> WorkspaceFile? {
children.compactMap { item -> WorkspaceFile? in
guard case .file(let file) = item, file.name == name else { return nil }
return file
}.first
}
}
private extension Project {
func folder(named name: String) -> WorkspaceFolder? {
children.compactMap { item -> WorkspaceFolder? in
guard case .folder(let folder) = item, folder.name == name else { return nil }
return folder
}.first
}
}