Remove useless tests

This commit is contained in:
Kaede Akino committed 2026-09-16 23:10:52 +08:00
1 parent e54f5c81c9
commit 1d6792d66a
24 files changed
+98 -1316

No files matched your search

+4 -2
View File
@@ -42,7 +42,10 @@ and bundle-derived Keychain access group, with target-specific signing.
Shared localized resources are copied into each app bundle. Platform icons and
metadata remain app-owned. Framework, macOS, and mobile tests stay separate;
architecture tests fail closed when an expected production directory is absent or
empty.
empty. Source-based checks are limited to module dependencies, native-list import
allowlists, AgentKit type ownership, and SwiftData model ownership. They do not pin
UI copy, source layout, call-site spellings, retired paths, or shared-component wiring;
those concerns rely on behavioral tests or explicit visual review.
## State, navigation, and ownership
@@ -623,7 +626,6 @@ Presentation owns the shared command-history subtitle, Vault sync status label,
and the exported SFTP drag type. App targets retain native card/list composition,
selection, menus, and clipboard behavior.
### Assistant transcript presentation parity (2026-09-12)
TermindPresentation owns tool summaries, batch status semantics, bounded result previews, timestamp formatting,
+10
View File
@@ -118,3 +118,13 @@ Verification and remaining limitations (2026-09-16):
- The full TFI action did not build or execute tests: the supplied simulator destination UUID was unavailable. This is not a passing iOS verification. A fresh device listing found an available booted iPhone 17 Pro, but the owner requested an immediate commit before rerunning either platform.
- Strict Swift formatting across all production/test targets, `Scripts/check-zh-localization.sh`, the removed desktop-helper reference scan, and `git diff --check` passed. Xcode successfully resolved modules that standalone SourceKit could not find. Existing generic SwiftLint file/type/function-size and complexity findings remain outside this independent refactor; no inline suppressions were added. Dependencies and localization catalogs are unchanged.
- Submitted at the owner's explicit request with these verification limitations retained rather than deleting unrelated behavioral tests to obtain a green result.
## Remove Low-Value UI and Source Assertions (2026-09-16)
- **Implemented; full verification in progress.** Evidence: `rg -n '#filePath|sourceRoot|String\(contentsOf|source\.contains' FrameworkTests TFMTests TFITests -g '*.swift'` found 35 architecture tests plus eight source snapshots in Color System, Menu Symbol, SSH Import, Keychain Order, Commerce Configuration, and Mobile Navigation Parity. At the owner's request, removed implementation-spelling/layout snapshots, enum and palette echoes, fixed-canvas render checks, disconnected standard-library sorting tests, and orphaned helpers; trimmed literal copy from mixed behavioral tests. Removed 52 test declarations and a net 1,230 Swift lines against an estimated 1,000–1,200-line reduction. Source assertions dropped from 43 tests to nine narrow module/dependency and ownership guards. The ListViewKit import allowlist now permits removing an importer without requiring a snapshot update, while still rejecting new unapproved importers. Retained language/catalog validation, protocol/data contracts, behavioral lifecycle/rendering coverage, and opt-in screenshot capture. Grouped host-list coverage now checks row placement using fixture data rather than localized headings. No production, dependency, or localization catalog changed; existing architecture-document edits were preserved.
Verification in progress:
- Initial pinned Xcode checks passed all 18 selected macOS tests and five selected iOS tests, compiling both test targets. Results: `/tmp/termind-test-cleanup-initial-macos.xcresult` and `/tmp/termind-test-cleanup-initial-ios.xcresult`.
- Strict Swift formatting across production/test targets, `Scripts/check-zh-localization.sh`, the remaining-source-assertion scan, and `git diff --check` passed. Active standalone SourceKit checks could not resolve the Xcode test module graph and were partly inconclusive; Xcode compilation is the authoritative check. Pre-existing generic SwiftLint size, tuple, pixel-coordinate naming, and force-try findings were left outside this deletion; no inline suppressions were added.
- Full pinned macOS and iOS test actions are running sequentially. No unrelated behavioral test is being removed to hide a failing result.
@@ -1,4 +1,3 @@
import AgentKit
import SwiftUI
import TermindDomain
import Testing
@@ -8,59 +7,6 @@ import UIKit
@Suite(.serialized) @MainActor
struct MobileAISettingsToolbarTests {
@Test func managementPagesExposeTheirNativeToolbarActions() async throws {
let app = try MobileAppModel(inMemory: true)
try await withNavigation(MobileModelsSettingsView(ai: app.ai)) { names in
#expect(names.contains("Add Provider"))
}
try await withNavigation(MobileSkillSettings(skills: app.skills)) { names in
#expect(names.contains("Add Skill"))
#expect(names.contains("More"))
#expect(!names.contains("Import Skill…"))
}
try await withNavigation(MobileMCPSettings(ai: app.ai, pro: app.pro)) { names in
#expect(names.contains("Add Server"))
}
}
@Test func mcpServerUsesPushedEditorToolbar() async throws {
let app = try MobileAppModel(inMemory: true)
let server = MCPServer(name: "Test", url: "https://example.invalid/mcp")
try await withNavigation(MobileMCPEditor(ai: app.ai, pro: app.pro, server: server)) { names in
#expect(names.contains("More"))
#expect(names.contains("Save"))
#expect(!names.contains("Cancel"))
}
}
@Test func workspacePagesExposeTheirExpectedToolbarActions() async throws {
let app = try MobileAppModel(inMemory: true)
let host = TermindDomain.Host(name: "Test", host: "example.invalid")
app.library.upsert(host)
for kind in [ConnectionHistoryEntry.Kind.ssh, .sftp] {
let workspace = MobileWorkspace(
descriptor: MobileWorkspaceDescriptor(hostID: host.id, title: host.name, kind: kind),
hosts: app.library)
try await withNavigation(
MobileWorkspaceView(
library: app.library, pro: app.pro, commandGenerator: app.commandGenerator,
workspace: workspace, workspaces: [workspace],
selectWorkspace: { _ in }, renameWorkspace: { _ in },
openSameDirectory: { _ in }, closeWorkspace: { _ in })
) { names in
#expect(names.contains("More"))
#expect(!names.contains("History"))
#expect(!names.contains("Transfers"))
#expect(!names.contains("Close"))
#expect(!names.contains("Previous Location"))
#expect(!names.contains("Next Location"))
}
}
}
@Test func workspaceDetailHidesTheRootTabBar() async throws {
let app = try MobileAppModel(inMemory: true)
let host = TermindDomain.Host(name: "Test", host: "example.invalid")
@@ -82,16 +28,6 @@ struct MobileAISettingsToolbarTests {
}
}
private func withNavigation<Content: View>(
_ content: Content,
check: (Set<String>) throws -> Void
) async throws {
try await withHostedView(NavigationStack { content }) { controller in
let navigation = try #require(descendant(of: UINavigationController.self, in: controller))
try check(Set(toolbarNames(in: navigation.topViewController?.navigationItem)))
}
}
private func withHostedView<Content: View>(
_ content: Content,
check: (UIViewController) async throws -> Void
@@ -112,18 +48,6 @@ struct MobileAISettingsToolbarTests {
try await check(controller)
}
private func toolbarNames(in item: UINavigationItem?) -> [String] {
guard let item else { return [] }
let buttons =
item.leadingItemGroups.flatMap(\.barButtonItems)
+ item.trailingItemGroups.flatMap(\.barButtonItems)
+ (item.leftBarButtonItems ?? [])
+ (item.rightBarButtonItems ?? [])
return buttons.compactMap { button in
button.accessibilityLabel ?? button.title ?? button.customView?.accessibilityLabel
}
}
private func descendant<T: UIViewController>(of type: T.Type, in controller: UIViewController) -> T? {
var pending = [controller]
var visited = Set<ObjectIdentifier>()
@@ -23,13 +23,6 @@ struct MobileAssistantTranscriptTests {
#expect(long <= 320)
}
@Test func activityUsesTheAvailableWidthToKeepItsTitleLeading() {
let controller = UIHostingController(rootView: MobileAssistantActivity())
let size = controller.sizeThatFits(in: CGSize(width: 320, height: 1_000))
#expect(size.width == 320)
}
@Test func imageFlowKeepsEveryUserRowTrailingAndAssistantRowsLeading() {
let tile = CGSize(width: 104, height: 104)
let sizes = Array(repeating: tile, count: 5)
@@ -9,23 +9,6 @@ import UIKit
/// Opt-in native screenshots cover the connection states without opening a transport.
@Suite(.serialized) @MainActor
struct MobileConnectionJourneyRenderingTests {
@Test func failedJourneyWithoutEndpointsRenders() throws {
let journey = ConnectionJourney()
journey.fail("Network unavailable")
let view = MobileConnectionJourneyView(
journey: journey, library: HostLibraryModel(), authenticationPrompt: nil, hostKey: nil,
reconnectState: nil, submit: { _, _, _, _, _, _ in }, accept: { _ in }, retry: {},
retryReconnectNow: {}, stopReconnecting: {}, cancel: {}
)
.frame(width: 390, height: 844)
let renderer = ImageRenderer(content: view)
renderer.scale = 1
let image = try #require(renderer.uiImage)
#expect(image.size == CGSize(width: 390, height: 844))
}
@Test func renderConnectionJourneyStates() async throws {
guard ProcessInfo.processInfo.environment["TERMIND_JOURNEY_SCREENSHOTS"] == "1" else { return }
let host = TermindDomain.Host(name: "Production Gateway", host: "gateway.example.invalid")
+1 -60
View File
@@ -82,34 +82,7 @@ struct MobileConnectionPickerTests {
#expect(Set(rows.map { "\($0.entry.hostID.uuidString):\($0.entry.kind.rawValue)" }).count == rows.count)
}
@Test func sharedHostPickerUsesConfiguredTitleWithoutHostsHeaderOrProtocolControl() async throws {
let app = try MobileAppModel(inMemory: true)
app.library.upsert(Host(name: "Production", host: "production.example.invalid"))
try await withNavigation(
MobileHostPicker(
library: app.library,
title: "Add Server",
emptyDescription: "Add a saved Linux server to start monitoring.",
cancel: {},
select: { _ in }),
language: "en"
) { navigation in
#expect(navigation.topViewController?.navigationItem.title == "Add Server")
#expect(descendant(of: UISegmentedControl.self, in: navigation) == nil)
#expect(!labels(in: navigation.view).contains("Hosts"))
}
try await withNavigation(
MobileConnectionPicker(library: app.library, connect: { _, _ in }, cancel: {}),
language: "en"
) { navigation in
#expect(descendant(of: UISegmentedControl.self, in: navigation) != nil)
#expect(!labels(in: navigation.view).contains("Hosts"))
}
}
@Test func snippetHostPickerUsesContextualTitlesAndCheckmarkConfirmation() async throws {
@Test func snippetHostPickerGatesConfirmationOnRequiredSelection() async throws {
let app = try MobileAppModel(inMemory: true)
let host = Host(name: "Production", host: "production.example.invalid")
app.library.upsert(host)
@@ -120,7 +93,6 @@ struct MobileConnectionPickerTests {
requiresSelection: true, save: { _ in }),
language: "en"
) { navigation in
#expect(navigation.topViewController?.navigationItem.title == "Execute on Hosts")
let execute = try #require(toolbarButton(named: "Execute", in: navigation))
#expect(!execute.isEnabled)
}
@@ -131,7 +103,6 @@ struct MobileConnectionPickerTests {
requiresSelection: false, save: { _ in }),
language: "en"
) { navigation in
#expect(navigation.topViewController?.navigationItem.title == "Add Hosts")
let done = try #require(toolbarButton(named: "Done", in: navigation))
#expect(done.isEnabled)
}
@@ -164,18 +135,6 @@ struct MobileConnectionPickerTests {
}
}
@Test func workspaceToolbarKeepsMoreAndConnectAvailableWithoutWorkspaces() async throws {
try await withNavigation(
ToolbarHost(hasWorkspaces: false, closeAll: {}, connect: {}),
language: "en"
) { navigation in
let more = try #require(toolbarButton(named: "More", in: navigation))
#expect(more.isEnabled)
let connect = try #require(toolbarButton(named: "Connect", in: navigation))
#expect(connect.isEnabled)
}
}
private func withNavigation<Content: View>(
_ content: Content,
language: String,
@@ -245,24 +204,6 @@ struct MobileConnectionPickerTests {
}
return nil
}
private func descendant<T: UIView>(of type: T.Type, in viewController: UIViewController) -> T? {
descendant(of: type, in: viewController.view)
}
private func descendant<T: UIView>(of type: T.Type, in view: UIView) -> T? {
if let result = view as? T { return result }
for child in view.subviews {
if let result = descendant(of: type, in: child) { return result }
}
return nil
}
private func labels(in view: UIView) -> [String] {
var result = (view as? UILabel).flatMap(\.text).map { [$0] } ?? []
for child in view.subviews { result.append(contentsOf: labels(in: child)) }
return result
}
}
private struct ToolbarHost: View {
+2 -11
View File
@@ -8,19 +8,11 @@ import UIKit
@Suite(.serialized) @MainActor
struct MobileEditorToolbarTests {
@Test(arguments: ["en", "zh-Hans", "zh-Hant"])
func iconButtonsKeepTheirNamesAndSaveLifecycle(language: String) async throws {
func saveDisablesActionsUntilCompletionAndThenDismisses(language: String) async throws {
let state = EditorState()
try await withEditor(state, language: language) { _, navigation in
let cancel = try #require(cancelButton(in: navigation))
let save = try #require(saveButton(in: navigation))
#expect(accessibleName(cancel) == (language == "en" ? "Cancel" : "取消"))
let expectedSave =
switch language {
case "zh-Hans": "保存"
case "zh-Hant": "儲存"
default: "Save"
}
#expect(accessibleName(save) == expectedSave)
#expect(cancel.isEnabled)
#expect(!save.isEnabled)
state.canSave = true
@@ -51,8 +43,7 @@ struct MobileEditorToolbarTests {
#expect(state.isPresented)
#expect(state.title == "Example")
#expect(saveButton(in: navigation)?.isEnabled == true)
let alert = try #require(descendant(of: UIAlertController.self, in: controller))
#expect(alert.title == "Unable to Save")
_ = try #require(descendant(of: UIAlertController.self, in: controller))
}
}
@@ -7,17 +7,6 @@ import Testing
@Suite @MainActor
struct MobileNavigationParityTests {
@Test func speechAudioTapDoesNotInheritMainActorIsolation() throws {
let root = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
let source = try String(
contentsOf: root.appending(path: "TFI/Platform/IOSSpeechAudioInput.swift"), encoding: .utf8)
#expect(source.contains("nonisolated static func makeTapHandler"))
#expect(source.contains("block: Self.makeTapHandler"))
}
@Test func vaultReplacesWelcomeAndMetricsRemainsBelowItOnIPad() {
let features = MobileFeatureRegistry.standard()
#expect(features.registrations(on: .phoneTab).map(\.id) == [.vault, .workspaces, .assistant, .settings])
@@ -27,10 +16,6 @@ struct MobileNavigationParityTests {
)
}
@Test func aiSettingsUseThreeNativeManagementPages() {
#expect(MobileAISettingsDestination.allCases == [.models, .skills, .mcp])
}
@Test func metricsUsesAvailableWidthRatherThanDeviceOrientation() {
#expect(!MobileMetricsDetailPage.showsBothColumns(width: 430))
#expect(!MobileMetricsDetailPage.showsBothColumns(width: 680))
-28
View File
@@ -53,34 +53,6 @@ struct MobileTerminalListTests {
}
}
@Test func nativeHistoryRemeasuresForAccessibilityDynamicType() async throws {
let app = try MobileAppModel(inMemory: true)
let host = TermindDomain.Host(name: "Test", host: "example.invalid")
app.library.upsert(host)
app.commandHistory.record("echo a command that needs two lines in the compact sheet", for: host.id)
let workspace = MobileWorkspace(
descriptor: MobileWorkspaceDescriptor(hostID: host.id, title: host.name, kind: .ssh),
hosts: app.library,
commandHistory: app.commandHistory)
try await withHostedView(
MobileCommandHistoryView(workspace: workspace)
.environment(\.dynamicTypeSize, .accessibility3)
) { root in
let cell = try #require(nativeVisibleCells(in: root.view).first)
#expect(cell.bounds.height > 100)
}
}
@Test func terminalRiskIndicatorsShareTheCompactPalette() {
#expect(MobileTerminalRiskIndicator.color(for: .safe) == .systemGreen)
#expect(MobileTerminalRiskIndicator.color(for: .caution) == .systemOrange)
#expect(MobileTerminalRiskIndicator.color(for: .destructive) == .systemRed)
#expect(MobileTerminalRiskIndicator.accessibilityIdentifier(for: .safe) == "TerminalRisk.safe")
#expect(MobileTerminalRiskIndicator.accessibilityIdentifier(for: .caution) == "TerminalRisk.caution")
#expect(MobileTerminalRiskIndicator.accessibilityIdentifier(for: .destructive) == "TerminalRisk.destructive")
}
private func withHostedView<Content: View>(
_ content: Content, check: (UIViewController) async throws -> Void
) async throws {
+1 -2
View File
@@ -761,11 +761,10 @@ struct AgentRuntimeTests {
event: { event in Task { await events.append(event) } }
)
guard case .deny(let reason) = await broker.authorize(request, mode: .approveForMe) else {
guard case .deny = await broker.authorize(request, mode: .approveForMe) else {
Issue.record("Expected timeout denial")
return
}
#expect(reason.contains("timed out"))
try? await Task.sleep(for: .milliseconds(10))
#expect(
await events.values.contains {
+2 -90
View File
@@ -191,17 +191,11 @@ struct AgentToolPresentationTests {
Issue.record("Expected a grouped host listing")
return
}
#expect(listing.summary == "3 hosts · 1 connected · 1 temporary")
#expect(
listing.sections.map(\.title) == [
"Production · 1 host", "Production / Edge · 0 hosts",
"Ungrouped · 1 host", "Temporary · 1 host",
listing.sections.map { $0.rows.map(\.title) } == [
["API Server"], [], ["Loose Box"], ["Current Terminal"],
])
#expect(listing.sections[0].rows[0].title == "API Server")
#expect(listing.sections[0].rows[0].subtitle == "deploy@api.example.com · Connected")
#expect(listing.sections[0].rows[0].badges == ["prod", "nginx"])
#expect(listing.sections[2].rows[0].subtitle == "root@10.0.0.2 · Failed")
#expect(listing.sections[3].rows[0].subtitle == "root@10.0.0.8 · Reconnecting")
let rendered = String(describing: detail)
#expect(!rendered.contains(productionID))
#expect(!rendered.contains("aaaaaaaa-aaaa"))
@@ -594,88 +588,6 @@ struct AgentToolPresentationTests {
)
}
@Test
func sshExecBatchCountsCommandsAcrossLifecycleStatesAndLocales() {
let presentation = AgentToolDescriptor.Presentation(
symbol: "terminal",
activity: .semanticArgument(key: "command", fallback: .sshCommand),
actionKind: .run
)
func cards(_ state: AgentToolCard.State) -> [AgentToolCard] {
["uname -a", "uptime"].map { command in
var card = makeCard(
name: "ssh_exec", target: .host,
arguments: ["command": .string(command)], presentation: presentation
)
card.state = state
return card
}
}
let english = Locale(identifier: "en")
#expect(AgentToolPresentation.batchSummary(for: cards(.running), locale: english) == "Running 2 commands")
#expect(AgentToolPresentation.batchSummary(for: cards(.completed), locale: english) == "Ran 2 commands")
#expect(AgentToolPresentation.batchSummary(for: cards(.failed), locale: english) == "Failed to run 2 commands")
#expect(
AgentToolPresentation.batchSummary(
for: cards(.completed), locale: Locale(identifier: "zh-Hans")
) == "已运行2条命令"
)
#expect(
AgentToolPresentation.batchSummary(
for: cards(.completed), locale: Locale(identifier: "zh-Hant")
) == "已執行2條指令"
)
}
@Test
func manageTasksBatchCountsWholeListUpdates() {
let presentation = AgentToolDescriptor.Presentation(
symbol: "checklist", activity: .semanticLabel(.taskList),
actionKind: .update
)
let cards = (0..<2).map { _ in
var card = makeCard(name: "manage_tasks", target: .user, presentation: presentation)
card.state = .completed
return card
}
#expect(
AgentToolPresentation.batchSummary(for: cards, locale: Locale(identifier: "en"))
== "Updated the task list 2 times"
)
#expect(
AgentToolPresentation.batchSummary(
for: cards, locale: Locale(identifier: "zh-Hans")
) == "已更新任务列表2次"
)
#expect(
AgentToolPresentation.batchSummary(
for: cards, locale: Locale(identifier: "zh-Hant")
) == "已更新任務清單2次"
)
}
@Test
func unknownSemanticBatchKeepsGenericToolCallFallback() {
let presentation = AgentToolDescriptor.Presentation(
symbol: "wrench.and.screwdriver",
activity: .semanticLabel(.init("database")),
actionKind: .inspect
)
let cards = (0..<2).map { _ in
var card = makeCard(name: "custom_inspect", target: .mcp, presentation: presentation)
card.state = .completed
return card
}
#expect(
AgentToolPresentation.batchSummary(for: cards, locale: Locale(identifier: "en"))
== "Inspected 2 tool calls"
)
}
@Test
func reasoningBatchTitleIsPlainSingleLineText() {
let title = AgentToolPresentation.reasoningTitle(
+77 -696
View File
@@ -1,318 +1,10 @@
import Foundation
import TermindApplication
import TermindDomain
import TermindInfrastructure
import TermindPersistence
import TermindPresentation
import TermindRemoteInfrastructure
import Testing
@Suite
struct ArchitectureBoundaryTests {
@Test
func resumableTransferStateRemainsProcessLocal() throws {
let root = sourceRoot.deletingLastPathComponent()
let checkpoint = try String(
contentsOf: root.appending(
path: "Frameworks/TermindRemoteInfrastructure/Transfers/SFTPResumeState.swift"), encoding: .utf8)
for forbidden in ["Codable", "SwiftData", "UserDefaults", "bookmark", "FileHandle", "FileManager"] {
#expect(!checkpoint.contains(forbidden))
}
let upload = try String(
contentsOf: sourceRoot.appending(
path: "Application/MCPServer/MCPUploadCoordinator.swift"), encoding: .utf8)
#expect(upload.contains("upload-offset"))
#expect(upload.contains("ticket.runID"))
let download = try String(
contentsOf: sourceRoot.appending(
path: "Application/MCPServer/MCPDownloadCoordinator.swift"), encoding: .utf8)
#expect(download.contains("Content-Range"))
#expect(download.contains("ticket.expiresAt > now()"))
}
@Test
func httpDownloadsUseCheckedRemoteStreamsWithoutLocalFilesOrScratch() throws {
let root = sourceRoot.deletingLastPathComponent()
let coordinator = try String(
contentsOf: sourceRoot.appending(path: "Application/MCPServer/MCPDownloadCoordinator.swift"),
encoding: .utf8)
for forbidden in [
"AgentScratchWorkspace", "FileHandle", "FileManager", "localURL", "startAccessingSecurityScopedResource",
] {
#expect(!coordinator.contains(forbidden))
}
let stream = try String(
contentsOf: root.appending(
path: "Frameworks/TermindRemoteInfrastructure/Transfers/SFTPDownloadStream.swift"), encoding: .utf8)
for forbidden in ["HTTPRequest", "HTTPResponse", "import Network", "AgentScratchWorkspace", "FileHandle"] {
#expect(!stream.contains(forbidden))
}
let tools = try String(
contentsOf: sourceRoot.appending(path: "Application/MCPServer/MCPServerTools.swift"), encoding: .utf8)
#expect(tools.contains("openDownloadStream("))
#expect(tools.contains("withDedicatedSFTP("))
let native = try String(
contentsOf: root.appending(path: "Frameworks/TermindRemoteInfrastructure/SSH/SFTPClient.swift"),
encoding: .utf8)
#expect(native.contains("readDownloadChunk(id:"))
#expect(native.contains("libssh2_sftp_fstat_ex(entry.handle"))
#expect(native.contains("entry.modificationTime"))
}
@Test
func httpUploadsStayOutsideScratchAndDoNotReadClientFilePaths() throws {
let root = sourceRoot.deletingLastPathComponent()
let coordinator = try String(
contentsOf: sourceRoot.appending(path: "Application/MCPServer/MCPUploadCoordinator.swift"), encoding: .utf8)
for forbidden in [
"AgentScratchWorkspace", "FileHandle", "FileManager", "localURL", "startAccessingSecurityScopedResource",
] {
#expect(!coordinator.contains(forbidden))
}
let stream = try String(
contentsOf: root.appending(
path: "Frameworks/TermindRemoteInfrastructure/Transfers/SFTPStreamUploadOperation.swift"),
encoding: .utf8)
for forbidden in ["HTTPRequest", "HTTPResponse", "import Network", "AgentScratchWorkspace", "FileHandle"] {
#expect(!stream.contains(forbidden))
}
#expect(stream.contains("digestMismatch"))
#expect(stream.contains("relay.finishWriting()"))
let bridge = try String(contentsOf: root.appending(path: "TermindMCPBridge/main.swift"), encoding: .utf8)
#expect(!bridge.contains("/uploads/"))
}
@Test
func singleLineEditingIsSharedButNativeFieldEditorsRemainAppOwned() throws {
let root = sourceRoot.deletingLastPathComponent()
let policy = try String(
contentsOf: root.appending(path: "Frameworks/TermindPresentation/SingleLineTextInput.swift"),
encoding: .utf8)
for forbidden in ["import AppKit", "import UIKit", "import TermindPersistence", "import AgentKit"] {
#expect(!policy.contains(forbidden))
}
let native = try String(
contentsOf: sourceRoot.appending(path: "UI/Components/SingleLineFieldEditing.swift"), encoding: .utf8)
#expect(native.contains("SingleLineTextInput.normalized"))
#expect(native.contains("hasMarkedText()"))
for path in [
"TFM/Features/AI/ConversationTranscriptView.swift",
"TFI/Features/AI/MobileAssistantComposer.swift",
"TFI/Features/AI/MobileAssistantInteraction.swift",
] {
let content = try String(contentsOf: root.appending(path: path), encoding: .utf8)
#expect(!content.contains(".singleLineText"))
}
}
@Test
func aiSettingsUsePortableModelsAndSyncedSkills() throws {
let root = sourceRoot.deletingLastPathComponent()
let library = try String(
contentsOf: root.appending(path: "Frameworks/TermindApplication/FeatureModels/SkillLibraryModel.swift"),
encoding: .utf8)
for forbidden in ["import SwiftData", "import AppKit", "import UIKit", "import TermindPersistence"] {
#expect(!library.contains(forbidden))
}
let role = try String(
contentsOf: root.appending(path: "Frameworks/TermindPresentation/ModelRoleSettings.swift"), encoding: .utf8)
#expect(role.contains("role.unsetLabel"))
#expect(!role.contains("AppModel"))
let mobile = try String(contentsOf: root.appending(path: "TFI/App/MobileAppModel.swift"), encoding: .utf8)
#expect(mobile.contains("SyncedSkillLibraryPersistence"))
#expect(mobile.contains("skills.applyRemoteSnapshot"))
let settings = try String(
contentsOf: root.appending(path: "TFI/Features/Settings/MobileAISettingsView.swift"), encoding: .utf8)
#expect(!settings.contains("AgentRuntime("))
}
@Test
func screenshotScenesShareTheProductionWindowHost() throws {
let source = try String(contentsOf: sourceRoot.appending(path: "App/TermindApp.swift"), encoding: .utf8)
#expect(source.components(separatedBy: "RootView(").count == 2)
#expect(!source.contains("ScreenshotDemoWindow"))
#expect(!source.contains(".suppressed"))
#expect(source.contains(".restorationBehavior("))
}
@Test
func reviewInvitationsStayLocalAndOutsideTheAgentRuntime() throws {
let sync = try String(
contentsOf: sourceRoot.appending(path: "../Frameworks/TermindDomain/Settings/SettingsSyncTypes.swift"),
encoding: .utf8
)
#expect(!sync.contains("reviewFirstUse"))
#expect(!sync.contains("reviewLastAttempt"))
let controller = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindApplication/FeatureModels/AppReviewController.swift"), encoding: .utf8
)
for forbidden in ["import StoreKit", "import AppKit", "import SwiftUI", "import AgentKit"] {
#expect(!controller.contains(forbidden))
}
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Platform/MobileAppReviewWindowReader.swift"),
encoding: .utf8
)
#expect(mobile.contains("ReviewInteractionGestureRecognizer"))
#expect(mobile.contains("controller.removeSurface(surfaceID)"))
}
@Test
func assistantCompositionIsSharedAndMobileInputRemainsSwiftUI() throws {
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Application/Agent/MobileAssistantModel.swift"),
encoding: .utf8)
let desktop = try String(contentsOf: sourceRoot.appending(path: "App/AppModel.swift"), encoding: .utf8)
for source in [mobile, desktop] {
#expect(source.contains("AssistantExecutionController("))
#expect(!source.contains("AgentRuntime("))
}
let composer = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/AI/MobileAssistantComposer.swift"), encoding: .utf8)
#expect(composer.contains("axis: .vertical"))
#expect(!composer.contains("UITextView"))
#expect(!composer.contains("UIViewRepresentable"))
try assertNoImports(
in: "../Frameworks/TermindApplication/Agent",
forbidden: ["TermindInfrastructure", "TermindRemoteInfrastructure", "UIKit", "AppKit", "PDFKit", "Speech"])
}
private var sourceRoot: URL {
URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM", directoryHint: .isDirectory)
}
@Test
func settingsSyncKeepsExecutionHistoryAndLocalPermissionsOutsideItsPayloads() throws {
let records = try String(
contentsOf: sourceRoot.appending(path: "../Frameworks/TermindDomain/Settings/SettingsSyncTypes.swift"),
encoding: .utf8)
for excluded in [
"AgentPermissionMode", "AgentRun", "AgentConversation", "mcpServerPort", "mcpServerEnabled",
"mcpServerDisabledTools", "mcpserver.token",
] {
#expect(!records.contains(excluded))
}
let localServer = try String(
contentsOf: sourceRoot.appending(path: "App/MCPServerController.swift"), encoding: .utf8)
#expect(localServer.contains("MCPServerTokenStore"))
#expect(!localServer.contains("AIConfigurationModel"))
let terminal = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindPersistence/TerminalPreferences+Defaults.swift"),
encoding: .utf8)
#expect(!terminal.contains("dictionaryRepresentation"))
#expect(!terminal.contains("agentPermissionMode"))
}
@Test
func metricsViewsCannotOwnTransportsAndSecretsAreResolvedOffMainActor() throws {
try assertNoConcreteImplementations(in: "Features/Metrics")
let model = try String(
contentsOf: sourceRoot.appending(path: "../Frameworks/TermindApplication/Metrics/ServerMetricsModel.swift"),
encoding: .utf8)
#expect(!model.contains("hosts.sshConnectionConfiguration("))
#expect(model.contains("workers[server.id] = Task.detached"))
#expect(model.contains("private nonisolated func run("))
#expect(model.contains("try await beginRunAttempt("))
let preparation = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindApplication/Connections/SSHConnectionPreparation.swift"),
encoding: .utf8)
#expect(preparation.contains("Task.detached"))
let view = try String(
contentsOf: sourceRoot.appending(path: "Features/Metrics/MetricsView.swift"), encoding: .utf8)
#expect(!view.contains("SSHExecSession"))
#expect(!view.contains("KeychainSecretStore"))
}
@Test
func metricsToolDependsOnSnapshotsAndMonitoringDoesNotImportAgentKit() throws {
let tool = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindRemoteInfrastructure/Agent/GetMetricsTool.swift"), encoding: .utf8)
#expect(tool.contains("any MetricsSnapshotReading"))
for forbidden in [
"SSHMetricsSampler", "AgentConnectionPool", "ServerMetricsModel", "observeDetails(",
"requestAuthentication(",
] {
#expect(!tool.contains(forbidden))
}
for path in [
"../Frameworks/TermindApplication/Metrics/MetricsSnapshot.swift",
"../Frameworks/TermindApplication/Metrics/ServerMetricsModel.swift",
] {
let source = try String(contentsOf: sourceRoot.appending(path: path), encoding: .utf8)
#expect(!source.contains("import AgentKit"))
}
}
@Test
func coreDirectoryIsGone() {
let core = sourceRoot.appending(path: "Core", directoryHint: .isDirectory)
#expect(!FileManager.default.fileExists(atPath: core.path))
}
@Test
func retiredFeatureDirectoriesAreGone() {
for directory in ["Tabs", "ContextPanel"] {
let url = sourceRoot.appending(path: "Features/\(directory)", directoryHint: .isDirectory)
#expect(!FileManager.default.fileExists(atPath: url.path))
}
}
@Test
func appTargetsDoNotReintroduceFrameworkForwardingAliases() throws {
let forwarding = try Regex(
#"(?m)^typealias\s+[A-Za-z_][A-Za-z0-9_]*\s*=\s*(?:Termind|Shared)[A-Za-z0-9_.]*"#
)
for directory in ["", "../TFI"] {
for file in try swiftFiles(in: directory) {
let source = try String(contentsOf: file, encoding: .utf8)
#expect(
source.firstMatch(of: forwarding) == nil,
"\(file.path) forwards a framework type instead of importing its owner"
)
}
}
for file in try swiftFiles(in: "../Frameworks/TermindPersistence") {
#expect(!file.lastPathComponent.hasPrefix("Shared"))
}
let sharedDeclaration = try Regex(
#"(?m)^public\s+(?:nonisolated\s+)?(?:final\s+)?(?:struct|class|enum|actor|protocol|typealias)\s+Shared[A-Z]"#
)
for module in [
"TermindDomain", "TermindApplication", "TermindInfrastructure",
"TermindRemoteInfrastructure", "TermindPresentation", "TermindPersistence",
] {
for file in try swiftFiles(in: "../Frameworks/\(module)") {
let source = try String(contentsOf: file, encoding: .utf8)
#expect(
source.firstMatch(of: sharedDeclaration) == nil,
"\(file.path) uses Shared as a framework namespace"
)
}
}
}
@Test
func mobileTargetUsesTheDesktopLayerVocabulary() throws {
let mobile = sourceRoot.appending(path: "../TFI", directoryHint: .isDirectory)
for name in [
"App", "Application", "Design", "DesignSystem", "Features", "Infrastructure", "Platform", "UI",
] {
let directory = mobile.appending(path: name, directoryHint: .isDirectory)
var isDirectory: ObjCBool = false
#expect(FileManager.default.fileExists(atPath: directory.path, isDirectory: &isDirectory))
#expect(isDirectory.boolValue)
#expect(!(try swiftFiles(in: "../TFI/\(name)")).isEmpty)
}
func mobileLayersKeepUIAndInfrastructureSeparate() throws {
try assertNoImports(
in: "../TFI/Application",
forbidden: ["SwiftUI", "UIKit", "SwiftData", "TermindPersistence"])
@@ -322,199 +14,6 @@ struct ArchitectureBoundaryTests {
try assertNoConcreteImplementations(in: "../TFI/Features")
}
@Test
func mobileFeaturesAndLiveServicesEnterThroughRegistries() throws {
let root = try String(
contentsOf: sourceRoot.appending(path: "../TFI/App/MobileRootView.swift"), encoding: .utf8)
let features = try String(
contentsOf: sourceRoot.appending(path: "../TFI/App/MobileFeatureRegistry.swift"), encoding: .utf8)
#expect(root.contains("features.registrations(on: .phoneTab)"))
#expect(root.contains("features.registrations(on: .padSidebar)"))
#expect(!root.contains("switch scene.selectedDestination"))
#expect(features.contains("mutating func register("))
#expect(features.contains("Duplicate mobile feature registration"))
#expect(features.contains("model: scene.assistant"))
#expect(!features.contains("model: app.assistant"))
let scene = try String(
contentsOf: sourceRoot.appending(path: "../TFI/App/MobileSceneModel.swift"), encoding: .utf8)
#expect(scene.contains("let assistant: MobileAssistantSceneModel"))
let descriptor = try String(
contentsOf: sourceRoot.appending(
path: "../TFI/Application/Workspaces/MobileWorkspaceDescriptor.swift"), encoding: .utf8)
#expect(descriptor.contains("var kind: ConnectionHistoryEntry.Kind"))
#expect(!descriptor.contains("enum Kind"))
let assistant = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Application/Agent/MobileAssistantModel.swift"),
encoding: .utf8)
let metrics = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Application/Metrics/MobileMetricsModel.swift"),
encoding: .utf8)
for concrete in ["SSHExecSession()", "SFTPClient()"] {
#expect(!assistant.contains(concrete))
}
for concrete in ["SSHMetricsSampler", "SSHExecSession"] {
#expect(!metrics.contains(concrete))
}
}
@Test
func sessionFeaturesDependOnTheConnectionPort() throws {
for path in ["Features/Terminal/SSHSessionModel.swift", "Features/SFTP/SFTPSessionModel.swift"] {
let text = try String(
contentsOf: sourceRoot.appending(path: path), encoding: .utf8
)
#expect(!text.contains("HostLibraryModel"), "\(path) bypasses RemoteSessionHostStore")
}
}
@Test
func sshHostKeyTrustStaysInsideTheLiveConnectionAttempt() throws {
let request = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindApplication/SSHConnectionTypes.swift"
),
encoding: .utf8
)
#expect(request.contains("struct SSHConnectionRequest"))
#expect(request.contains("SSHHostKeyAuthorizer"))
for root in [
"../Frameworks/TermindRemoteInfrastructure", "Features/Terminal",
"Features/SFTP", "../TFI",
] {
for file in try swiftFiles(in: root) {
let source = try String(contentsOf: file, encoding: .utf8)
#expect(!source.contains("discoverHostKey"), "\(file.path) opens a separate host-key probe")
#expect(!source.contains("probe complete"), "\(file.path) closes an unauthenticated probe")
}
}
}
@Test
func remoteDirectoryStateDependsOnTheApplicationPort() throws {
let value = try String(
contentsOf: sourceRoot.appending(path: "../Frameworks/TermindDomain/Transfers/RemoteFile.swift"),
encoding: .utf8
)
#expect(value.contains("struct RemoteFile"))
#expect(!value.contains("symbol:"))
#expect(!value.contains("sftpKindDescription"))
let transport = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindRemoteInfrastructure/SSH/SFTPClient.swift"),
encoding: .utf8
)
#expect(transport.contains("SFTPClientProtocol: RemoteFileSystem"))
#expect(!transport.contains("struct RemoteFile"))
#expect(transport.contains("sourceSucceeded()"))
#expect(transport.contains("observeCancellation { relay.stop() }"))
let copy = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindRemoteInfrastructure/Agent/SFTPCopyTool.swift"),
encoding: .utf8
)
#expect(copy.contains("withDedicatedSFTP"))
#expect(!copy.contains("AgentScratchWorkspace"))
#expect(!copy.contains("SFTPClient()"))
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Application/Transfers/MobileSFTPSessionModel.swift"),
encoding: .utf8
)
#expect(mobile.contains("any RemoteFileSystem"))
#expect(!mobile.contains("TermindRemoteInfrastructure"))
let workspace = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/Workspaces/MobileWorkspace.swift"),
encoding: .utf8
)
#expect(!workspace.contains("private(set) var files: [RemoteFile]"))
#expect(!workspace.contains("var path = \"/\""))
}
@Test
func terminalPresentationPolicyIsSharedAcrossApps() throws {
let presentation = try String(
contentsOf: sourceRoot.appending(
path: "../Frameworks/TermindPresentation/Terminal/TerminalAppearance.swift"),
encoding: .utf8
)
#expect(presentation.contains("enum TermindTerminalThemeCatalog"))
#expect(presentation.contains("func applyPreferences"))
#expect(
!FileManager.default.fileExists(
atPath: sourceRoot.appending(path: "../TFI/Platform/MobileTerminalAppearance.swift").path
)
)
let desktopTheme = try String(
contentsOf: sourceRoot.appending(path: "Design/TerminalTheme.swift"), encoding: .utf8)
#expect(!desktopTheme.contains("enum TermindTerminalThemeCatalog"))
#expect(!desktopTheme.contains("func applyAppearance"))
for path in [
"Features/Terminal/SSHSessionModel.swift",
"Features/Terminal/SerialSessionModel.swift",
"../TFI/Features/Workspaces/MobileWorkspace.swift",
] {
let source = try String(contentsOf: sourceRoot.appending(path: path), encoding: .utf8)
#expect(source.contains("TerminalFindController("), "\(path) does not use shared Find state")
#expect(!source.contains("var findQuery ="), "\(path) owns a second Find query")
}
for path in [
"UI/Components/ConnectionJourneyView.swift",
"../TFI/UI/Components/MobileConnectionJourneyView.swift",
] {
let source = try String(contentsOf: sourceRoot.appending(path: path), encoding: .utf8)
#expect(source.contains("ConnectionJourneyHeader("))
#expect(source.contains("ConnectionJourneyReconnectStatus("))
#expect(!source.contains("private var headerSymbol"))
}
}
@Test
func retiredContextPanelTypesAreGone() throws {
for file in try swiftFiles(in: "Features") {
let text = try String(contentsOf: file, encoding: .utf8)
#expect(!text.contains("ContextPanel"), "\(file.path) retains retired ContextPanel naming")
}
}
@Test
func customKeyboardShortcutsUseTheApplicationRegistry() throws {
for file in try swiftFiles(in: "")
where file.lastPathComponent != "AppShortcut.swift" {
let lines = try String(contentsOf: file, encoding: .utf8)
.split(separator: "\n", omittingEmptySubsequences: false)
for (offset, line) in lines.enumerated() where line.contains(".keyboardShortcut(") {
let isStandardDialogAction =
line.contains(".defaultAction")
|| line.contains(".cancelAction")
#expect(
isStandardDialogAction,
"\(file.path):\(offset + 1) bypasses AppShortcut"
)
}
}
}
@Test
func featureFacadesDoNotExposeTheirBackingLibrary() throws {
for file in try swiftFiles(in: "../Frameworks/TermindApplication/FeatureModels") {
let text = try String(contentsOf: file, encoding: .utf8)
#expect(
!text.contains("\n let library: HostLibraryModel"),
"\(file.path) exposes the backing aggregate"
)
}
}
@Test
func domainImportsOnlyPlatformIndependentFrameworks() throws {
try assertNoImports(
@@ -574,23 +73,87 @@ struct ArchitectureBoundaryTests {
}
)
#expect(importers == allowed)
#expect(importers.isSubset(of: allowed))
}
let mobileConsumers = try Set(
swiftFiles(in: "../TFI").compactMap { file -> String? in
let text = try String(contentsOf: file, encoding: .utf8)
guard text.contains("MobileNativeList(") else { return nil }
return file.standardizedFileURL.path.replacingOccurrences(
of: repositoryRoot.path + "/", with: "")
}
/// App-local types shadow imports, so redefining these would silently fork AgentKit.
@Test
func typesOwnedByTheAgentPackageAreNotRedefinedHere() throws {
let owned = [
"AgentRuntime", "AgentToolExecutor", "AgentToolScheduler", "AgentTurnDriver",
"AgentToolCatalog", "AgentToolRegistry", "AgentEventChannel", "AgentContextPipeline",
"AgentSecretLifecycle", "AgentApprovalBroker", "SecretBroker", "AgentProviderClient",
"AgentModelRetryPolicy", "AgentModelRetryProgress",
"MCPClient", "MCPServer", "ModelProvider", "AIModel", "AgentSkill",
]
let declaration = try Regex(
#"(?m)^\s*(?:public |internal |private |fileprivate |nonisolated |final |indirect )*"#
+ #"(?:struct|class|enum|actor|protocol|typealias)\s+([A-Za-z_][A-Za-z0-9_]*)"#
)
#expect(
mobileConsumers == [
"TFI/Features/AI/MobileAssistantConversation.swift",
"TFI/Features/SFTP/MobileSFTPBrowser.swift",
for file in try swiftFiles(in: "") {
let text = try String(contentsOf: file, encoding: .utf8)
for match in text.matches(of: declaration) {
let name = String(match.output[1].substring ?? "")
#expect(
!owned.contains(name),
"\(file.path) redefines \(name), which AgentKit owns"
)
}
}
}
@Test
func sharedFrameworksCannotImportPlatformAppsOrUI() throws {
for module in [
"TermindDomain", "TermindApplication", "TermindInfrastructure", "TermindRemoteInfrastructure",
"TermindPersistence",
] {
try assertNoImports(
in: "../Frameworks/\(module)",
forbidden: ["Termind", "TermindIOS", "AppKit", "UIKit", "IOKit", "ServiceManagement"])
}
try assertNoImports(
in: "../Frameworks/TermindApplication",
forbidden: ["TermindInfrastructure", "TermindPersistence", "SwiftData"])
try assertNoImports(
in: "../Frameworks/TermindPersistence",
forbidden: ["TermindInfrastructure", "TermindRemoteInfrastructure"])
}
@Test
func sharedPresentationHasNoPlatformOrStorageDependency() throws {
try assertNoImports(
in: "../Frameworks/TermindPresentation",
forbidden: [
"Termind", "TermindIOS", "UIKit", "AppKit", "SwiftData", "TermindPersistence",
"TermindRemoteInfrastructure",
])
}
@Test
func swiftDataModelsHaveOneSharedOwner() throws {
for directory in [
"", "../TFI", "../Frameworks/TermindDomain", "../Frameworks/TermindApplication",
"../Frameworks/TermindInfrastructure",
] {
for file in try swiftFiles(in: directory) {
let source = try String(contentsOf: file, encoding: .utf8)
#expect(
source.range(of: #"(?m)^\s*@Model\b"#, options: .regularExpression) == nil,
"\(file.path) declares a model outside TermindPersistence")
}
}
let models = try swiftFiles(in: "../Frameworks/TermindPersistence")
#expect(!models.isEmpty)
}
private var sourceRoot: URL {
URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM", directoryHint: .isDirectory)
}
private func assertNoImports(in directory: String, forbidden: Set<String>) throws {
for file in try swiftFiles(in: directory) {
let text = try String(contentsOf: file, encoding: .utf8)
@@ -632,188 +195,6 @@ struct ArchitectureBoundaryTests {
}
}
/// The agent runtime lives in AgentKit and must keep living there.
///
/// A redefinition here would compile: Swift resolves the app's own type
/// ahead of an imported one, so the app would silently fork the runtime and
/// nothing would fail until a card drawn by one was replayed by the other.
/// Checked by definition rather than by import, because the app is expected
/// to import AgentKit everywhere.
@Test
func typesOwnedByTheAgentPackageAreNotRedefinedHere() throws {
let owned = [
"AgentRuntime", "AgentToolExecutor", "AgentToolScheduler", "AgentTurnDriver",
"AgentToolCatalog", "AgentToolRegistry", "AgentEventChannel", "AgentContextPipeline",
"AgentSecretLifecycle", "AgentApprovalBroker", "SecretBroker", "AgentProviderClient",
"AgentModelRetryPolicy", "AgentModelRetryProgress",
"MCPClient", "MCPServer", "ModelProvider", "AIModel", "AgentSkill",
]
let declaration = try Regex(
#"(?m)^\s*(?:public |internal |private |fileprivate |nonisolated |final |indirect )*"#
+ #"(?:struct|class|enum|actor|protocol|typealias)\s+([A-Za-z_][A-Za-z0-9_]*)"#
)
for file in try swiftFiles(in: "") {
let text = try String(contentsOf: file, encoding: .utf8)
for match in text.matches(of: declaration) {
let name = String(match.output[1].substring ?? "")
#expect(
!owned.contains(name),
"\(file.path) redefines \(name), which AgentKit owns"
)
}
}
}
@Test
func mobilePortUsesSharedStoresAndSeparateSigningFiles() throws {
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/App/MobileAppModel.swift"), encoding: .utf8)
#expect(mobile.contains("SyncedAIConfigurationPersistence(settingsPersistence)"))
#expect(mobile.contains("settingsSync?.didApplyRemote"))
#expect(mobile.contains("vaultSync?.didApplyRemote"))
let project = try String(
contentsOf: sourceRoot.appending(path: "../Termind.xcodeproj/project.pbxproj"), encoding: .utf8)
#expect(project.contains("TFI/TFI.entitlements"))
#expect(project.contains("TFM/TFM.entitlements"))
#expect(!project.contains("Termind.entitlements"))
let terminal = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/Settings/MobileTerminalSettingsView.swift"),
encoding: .utf8)
#expect(!terminal.contains("remoteWindowTitleInMenuBar"))
let cloud = try swiftFiles(in: "../Frameworks/TermindInfrastructure/Cloud")
#expect(cloud.count == 3)
}
@Test
func forwardingEditorsShareTheFlatFormAndContextualLabels() throws {
let desktop = try String(
contentsOf: sourceRoot.appending(path: "Features/Ports/PortForwardingView.swift"), encoding: .utf8)
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/Ports/MobileForwardingEditor.swift"),
encoding: .utf8)
let mobileHost = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/HostEditor/MobileHostEditor.swift"),
encoding: .utf8)
let shared = try String(
contentsOf: sourceRoot.appending(path: "../Frameworks/TermindPresentation/PortForwardingFields.swift"),
encoding: .utf8)
#expect(shared.contains("Section(\"Port Forwarding\")"))
for editor in [desktop, mobile] {
#expect(editor.contains("PortForwardingFields(rule: $draft)"))
#expect(editor.contains("New Forwarding"))
#expect(editor.contains("Edit Forwarding"))
}
#expect(desktop.contains("FormNavigationAction(title: \"Add Forwarding\")"))
#expect(desktop.contains("Button(\"Enable All\""))
#expect(desktop.contains("Button(\"Disable All\""))
#expect(desktop.contains("Waiting for Save"))
#expect(mobileHost.contains("Button(\"Add Forwarding\", systemImage: \"plus\")"))
#expect(mobileHost.contains("Waiting for Save"))
#expect(mobileHost.contains("isNew: !draftForwardings.contains"))
for removed in ["Add Port Forward", "New Port Forward", "Edit Port Forward"] {
#expect(!desktop.contains(removed))
#expect(!mobile.contains(removed))
#expect(!mobileHost.contains(removed))
}
for removed in ["DisclosureGroup(\"Advanced\"", "Section(\"SSH Host\")", "Section(\"Route Preview\")"] {
#expect(!desktop.contains(removed))
}
}
@Test
func sharedFrameworksCannotImportPlatformAppsOrUI() throws {
for module in [
"TermindDomain", "TermindApplication", "TermindInfrastructure", "TermindRemoteInfrastructure",
"TermindPersistence",
] {
try assertNoImports(
in: "../Frameworks/\(module)",
forbidden: ["Termind", "TermindIOS", "AppKit", "UIKit", "IOKit", "ServiceManagement"])
}
try assertNoImports(
in: "../Frameworks/TermindApplication",
forbidden: ["TermindInfrastructure", "TermindPersistence", "SwiftData"])
try assertNoImports(
in: "../Frameworks/TermindPersistence",
forbidden: ["TermindInfrastructure", "TermindRemoteInfrastructure"])
}
@Test
func sharedPresentationHasNoPlatformOrStorageDependency() throws {
try assertNoImports(
in: "../Frameworks/TermindPresentation",
forbidden: [
"Termind", "TermindIOS", "UIKit", "AppKit", "SwiftData", "TermindPersistence",
"TermindRemoteInfrastructure",
])
}
@Test
func fullSurfaceDropOverlayHasOneSharedPresentationOwner() throws {
let sharedPath = sourceRoot.appending(
path: "../Frameworks/TermindPresentation/DropTargetOverlay.swift")
let shared = try String(contentsOf: sharedPath, encoding: .utf8)
#expect(shared.contains("public struct DropTargetOverlay"))
#expect(shared.contains("public nonisolated struct DropTargetPresentation"))
#expect(
!FileManager.default.fileExists(
atPath: sourceRoot.appending(path: "UI/Components/DropTargetOverlay.swift").path
)
)
for path in [
"Features/AI/ConversationTranscriptView.swift",
"../TFI/Features/AI/MobileAssistantConversation.swift",
"../TFI/Features/Workspaces/MobileWorkspaceView.swift",
] {
let consumer = try String(
contentsOf: sourceRoot.appending(path: path), encoding: .utf8)
#expect(consumer.contains("DropTargetOverlay("), "\(path) does not reuse the shared overlay")
}
}
@Test
func sftpUploadTargetsTheCurrentOpenDirectoryAcrossPlatforms() throws {
let desktop = try String(
contentsOf: sourceRoot.appending(path: "Features/SFTP/SFTPSessionModel.swift"),
encoding: .utf8
)
let mobile = try String(
contentsOf: sourceRoot.appending(path: "../TFI/Features/Workspaces/MobileWorkspace.swift"),
encoding: .utf8
)
let desktopUpload = try #require(
desktop.components(separatedBy: "func prepareUpload").last?
.components(separatedBy: "func prepareDownload").first
)
let mobileDestination = try #require(
mobile.components(separatedBy: "var uploadDestination").last?
.components(separatedBy: "var uploadTargetProblem").first
)
#expect(desktopUpload.contains("destination: path"))
#expect(mobileDestination.contains("return sftpSession.path"))
}
@Test
func swiftDataModelsHaveOneSharedOwner() throws {
for directory in [
"", "../TFI", "../Frameworks/TermindDomain", "../Frameworks/TermindApplication",
"../Frameworks/TermindInfrastructure",
] {
for file in try swiftFiles(in: directory) {
let source = try String(contentsOf: file, encoding: .utf8)
#expect(
source.range(of: #"(?m)^\s*@Model\b"#, options: .regularExpression) == nil,
"\(file.path) declares a model outside TermindPersistence")
}
}
let models = try swiftFiles(in: "../Frameworks/TermindPersistence")
#expect(!models.isEmpty)
}
private func swiftFiles(in directory: String) throws -> [URL] {
let root = sourceRoot.appending(path: directory, directoryHint: .isDirectory)
let keys: [URLResourceKey] = [.isRegularFileKey]
-83
View File
@@ -68,74 +68,6 @@ struct ColorSystemTests {
#expect(colorDistance(light, dark) > 0.5)
}
@Test
func featureUIHasNoLiteralDisplayColorsOrDecorativeBlue() throws {
let sourceRoot = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM", directoryHint: .isDirectory)
let exemptPaths = ["DesignSystem/TagColor+Presentation.swift"]
let forbidden = [
"Color.white", "Color.black", "NSColor.white", "NSColor.gray",
"foregroundStyle(.white)", "AnyShapeStyle(.white)",
".shadow(color: .black", "Color(white:", "Color(red:", "NSColor(red:",
".blue", "systemBlue",
]
for file in try swiftFiles(in: sourceRoot) {
let relative = file.path.replacingOccurrences(
of: sourceRoot.path + "/",
with: ""
)
if exemptPaths.contains(relative) { continue }
let lines = try String(contentsOf: file, encoding: .utf8)
.split(separator: "\n", omittingEmptySubsequences: false)
for (offset, line) in lines.enumerated() {
// Black and white are alpha values here, not visible UI hues.
let isMask =
relative == "Features/AI/TranscriptNativeRows.swift"
&& line.contains("mask.colors")
if isMask { continue }
// A `TagColor` case a user picked for a host or key, not a hue
// this code chose to draw. Its presentation is resolved through
// the exempt `TagColor+Presentation.swift`, which is the file
// this scan exists to funnel such choices into.
if line.contains("colorTag:") { continue }
for token in forbidden {
#expect(
!line.contains(token),
"\(relative):\(offset + 1) bypasses TermindColor with \(token)"
)
}
}
}
}
@Test
func nativeHostingListsReloadRowsWhenTheirEnvironmentChanges() throws {
let sourceRoot = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM", directoryHint: .isDirectory)
for file in try swiftFiles(in: sourceRoot) {
let text = try String(contentsOf: file, encoding: .utf8)
let environmentChangeCount =
text.components(
separatedBy: "let environmentChanged"
).count - 1
guard environmentChangeCount > 0 else { continue }
let forcedReloadCount =
text.components(
separatedBy: "if environmentChanged { listView.reloadData() }"
).count - 1
#expect(
forcedReloadCount == environmentChangeCount,
"\(file.path) can leave recycled NSHostingView rows in the old appearance"
)
}
}
private func resolved(
_ color: Color,
appearance name: NSAppearance.Name
@@ -171,19 +103,4 @@ struct ColorSystemTests {
+ 0.7152 * linear(color.greenComponent)
+ 0.0722 * linear(color.blueComponent)
}
private func swiftFiles(in root: URL) throws -> [URL] {
let keys: Set<URLResourceKey> = [.isRegularFileKey]
guard
let enumerator = FileManager.default.enumerator(
at: root,
includingPropertiesForKeys: Array(keys)
)
else { return [] }
return try enumerator.compactMap { value in
guard let url = value as? URL, url.pathExtension == "swift" else { return nil }
let values = try url.resourceValues(forKeys: keys)
return values.isRegularFile == true ? url : nil
}
}
}
-23
View File
@@ -10,29 +10,6 @@ import Testing
@testable import Termind
struct CommerceConfigurationTests {
@Test
func normalDebugLaunchUsesLiveCommerce() throws {
let appFile = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM/App/TermindApp.swift")
let app = try String(contentsOf: appFile, encoding: .utf8)
#expect(!app.contains(".developmentDefault()"))
#expect(app.contains(": .live()"))
}
@Test
func appTargetDeclaresInAppPurchaseCapability() throws {
let projectFile = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "Termind.xcodeproj/project.pbxproj")
let project = try String(contentsOf: projectFile, encoding: .utf8)
#expect(project.contains("com.apple.InAppPurchase = {"))
}
@Test
func localStoreKitProductMatchesPurchaseRequest() throws {
let configurationFile = URL(fileURLWithPath: #filePath)
-2
View File
@@ -48,7 +48,6 @@ struct ConnectionJourneyTests {
#expect(journey.mode == .reconnection)
#expect(journey.phase == .connecting)
#expect(journey.isPresented)
#expect(journey.plainTextLog.contains("Reconnecting SSH session"))
}
@Test
@@ -114,7 +113,6 @@ struct ConnectionJourneyTests {
journey.waitForLocalPassphrase(at: destination.id)
#expect(journey.waitsForLocalPassphrase)
#expect(!journey.waitsForLocalIdentity)
#expect(journey.plainTextLog.contains("Waiting for a Passphrase"))
journey.waitForLocalIdentity(at: destination.id)
#expect(journey.waitsForLocalIdentity)
-27
View File
@@ -13,33 +13,6 @@ import Testing
@Suite
@MainActor
struct KeychainOrderTests {
private func storagePrecedesColor(in source: String, occurrences: Int) -> Bool {
var searchRange = source.startIndex..<source.endIndex
for _ in 0..<occurrences {
guard let storage = source.range(of: "Picker(\"Store in\"", range: searchRange),
let color = source.range(of: "ColorTagPicker", range: storage.upperBound..<source.endIndex)
else {
return false
}
searchRange = color.upperBound..<source.endIndex
}
return true
}
@Test
func keyFormsPlaceStorageBeforeColor() throws {
let sourceRoot = URL(fileURLWithPath: #filePath).deletingLastPathComponent().deletingLastPathComponent()
let desktop = try String(
contentsOf: sourceRoot.appendingPathComponent("TFM/Features/Keychain/KeychainPageView.swift"),
encoding: .utf8)
let mobile = try String(
contentsOf: sourceRoot.appendingPathComponent("TFI/Features/Keychain/MobileKeyEditor.swift"),
encoding: .utf8)
#expect(storagePrecedesColor(in: desktop, occurrences: 2))
#expect(storagePrecedesColor(in: mobile, occurrences: 1))
}
@Test
func unsortedInputsStartAlphabeticallyAndCanBeReordered() throws {
let zebra = SSHKeyRef(label: "Zebra")
-1
View File
@@ -156,7 +156,6 @@ struct ListViewMigrationTests {
#expect(normal.id == naming.id)
#expect(normal != naming)
#expect(normal.height == Metrics.Sidebar.historyCardHeight)
#expect(normal.height == 52)
#expect(naming.height == Metrics.Sidebar.historyCardEditingHeight)
#expect(naming.height > normal.height)
}
-27
View File
@@ -12,13 +12,6 @@ import Testing
@Suite
struct MenuSymbolTests {
private var vocabularySource: URL {
URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appending(path: "TFM/DesignSystem/MenuSymbol.swift")
}
/// A misspelled SF Symbol draws nothing and reports nothing, so the menu
/// simply loses one glyph and no one finds out. This is the only place that
/// notices.
@@ -32,26 +25,6 @@ struct MenuSymbolTests {
}
}
/// `all` is hand-written, so a new verb can be added and left out of it —
/// which would quietly exempt the new glyph from the check above.
@Test
func theCheckedListCoversEveryDeclaredGlyph() throws {
let text = try String(contentsOf: vocabularySource, encoding: .utf8)
let declarations = text.split(separator: "\n").compactMap { line -> String? in
let trimmed = line.trimmingCharacters(in: .whitespaces)
guard trimmed.hasPrefix("static let "), trimmed.contains("= \"") else { return nil }
let name = trimmed.dropFirst("static let ".count).prefix { $0 != " " }
return String(name)
}
#expect(!declarations.isEmpty)
let listMarker = "static let all: [String] = ["
let listed = text.components(separatedBy: listMarker).last ?? ""
for name in declarations {
#expect(listed.contains(name), "MenuSymbol.\(name) is missing from `all`")
}
}
@Test
@MainActor
func menuBarBrandAssetLoadsAsATransparentTemplate() throws {
-12
View File
@@ -34,18 +34,6 @@ struct MetricsInteractionTests {
#expect(window.isToolbarFindFocused)
}
@Test
func processColumnsSupportAscendingAndDescendingSort() {
let rows = [
MetricsProcess(pid: 20, started: 1, name: "zeta", cpu: 30, memory: 200),
MetricsProcess(pid: 2, started: 1, name: "alpha", cpu: 70, memory: 100),
]
#expect(rows.sorted(using: KeyPathComparator(\.pid)).map(\.pid) == [2, 20])
#expect(rows.sorted(using: KeyPathComparator(\.name)).map(\.pid) == [2, 20])
#expect(rows.sorted(using: KeyPathComparator(\.cpuSortValue, order: .reverse)).map(\.pid) == [2, 20])
#expect(rows.sorted(using: KeyPathComparator(\.memorySortValue, order: .reverse)).map(\.pid) == [20, 2])
}
@Test(arguments: [HostChooserPurpose.connect, .batchStartup, .metrics])
func hostChoosersRenderWithTheirRequiredEnvironment(
purpose: HostChooserPurpose
-103
View File
@@ -39,69 +39,6 @@ struct MetricsPresentationTests {
#expect(try height() == connecting)
}
@Test
func diskColumnsRenderAcrossTheFullAvailableWidth() throws {
let io = MetricsDevicePoint(
id: "8:1", read: 0, write: 0, readTotal: 438.4 * 1_073_741_824,
writeTotal: 625.2 * 1_073_741_824, readIOPS: 0, writeIOPS: 0
)
for width in [246.0, 300.0] {
let renderer = ImageRenderer(
content: MetricsDiskTable(io: io).frame(width: width)
.environment(\.locale, Locale(identifier: "zh-Hans")))
renderer.scale = 2
let image = try #require(renderer.nsImage)
#expect(image.size.width == CGFloat(width))
#expect(image.size.height == 52)
let bitmap = try #require(image.tiffRepresentation.flatMap { NSBitmapImageRep(data: $0) })
let png = try #require(bitmap.representation(using: .png, properties: [:]))
try png.write(
to: FileManager.default.temporaryDirectory.appending(path: "termind-disk-table-\(Int(width)).png"))
}
}
@Test
func nvidiaDetailsRenderWithTwoSimulatedDevicesWithoutConnecting() throws {
let gib = 1_073_741_824.0
let server = ServerMetric(selection: MetricsSelection(id: UUID()), name: "GPU Preview")
server.isConnecting = false
server.gpuState = .available
server.gpuSnapshot = NvidiaSnapshot(
cudaVersion: "12.4",
devices: [
NvidiaGPU(
id: "GPU-00000000-0000-0000-0000-000000000001", name: "NVIDIA GPU 0",
utilization: 74, memoryUsed: 17.3 * gib, memoryTotal: 24 * gib, memoryFree: 6.7 * gib,
memoryUtilization: 51, encoder: 12, decoder: 0, fan: 45, vbios: "95.02.3C.00.01"
),
NvidiaGPU(
id: "GPU-00000000-0000-0000-0000-000000000002", name: "NVIDIA GPU 1",
utilization: 18, memoryUsed: 4.1 * gib, memoryTotal: 24 * gib, memoryFree: 19.9 * gib,
memoryUtilization: 9, encoder: 0, decoder: 0, fan: nil, vbios: "95.02.3C.00.01"
),
])
for language in ["en", "zh-Hans", "zh-Hant"] {
for expanded in [false, true] {
let content = MetricsGPUSection(server: server, initiallyExpanded: expanded)
.frame(width: 324, alignment: .leading)
.padding(12).background(TermindColor.windowSurface)
.environment(\.locale, Locale(identifier: language))
.environment(\.colorScheme, .light)
let renderer = ImageRenderer(content: content)
renderer.scale = 2
var image: NSImage?
NSAppearance(named: .aqua)?.performAsCurrentDrawingAppearance { image = renderer.nsImage }
let bitmap = try #require(image?.tiffRepresentation.flatMap { NSBitmapImageRep(data: $0) })
let png = try #require(bitmap.representation(using: .png, properties: [:]))
#expect(bitmap.pixelsWide == 696)
#expect(bitmap.pixelsHigh > 600)
try png.write(
to: FileManager.default.temporaryDirectory.appending(
path: "termind-gpu-preview-\(language)\(expanded ? "-expanded" : "").png"))
}
}
}
@Test
func swapRendersAsASeparatePanelBelowMemoryAndHidesAtZeroCapacity() throws {
let withSwap = ServerMetric(selection: MetricsSelection(id: UUID()), name: "Swap Preview")
@@ -138,46 +75,6 @@ struct MetricsPresentationTests {
}
}
}
@Test
func compactCardsRenderInEveryLanguageAndAppearance() throws {
let hosts = HostLibraryModel()
let model = ServerMetricsModel(
hosts: hosts, preferences: PreviewMetricsPreferences(),
makeSampler: { SSHMetricsSampler(session: RemoteConnectionCoordinator().makeExecSession()) }
)
let server = ServerMetric(selection: MetricsSelection(id: UUID()), name: "ElasticSearch")
server.isConnecting = false
server.status = ""
server.point = MetricsPoint(
date: Date(), cpu: 94, memory: 65, memoryUsed: 2_400_000_000, memoryTotal: 4_000_000_000,
diskRead: 89_000_000, diskWrite: 161_000, networkReceive: 32_000, networkSend: 18_000
)
server.gpuState = .unavailable
for language in ["en", "zh-Hans", "zh-Hant"] {
for dark in [false, true] {
let content = ServerMetricsCard(
server: server, model: model, compact: true, inspect: {}, openTerminal: {}
)
.frame(width: 350).padding(14)
.background(TermindColor.windowSurface)
.environment(\.locale, Locale(identifier: language))
.environment(\.colorScheme, dark ? .dark : .light)
let renderer = ImageRenderer(content: content)
renderer.scale = 2
var image: NSImage?
NSAppearance(named: dark ? .darkAqua : .aqua)?.performAsCurrentDrawingAppearance {
image = renderer.nsImage
}
let bitmap = try #require(image?.tiffRepresentation.flatMap { NSBitmapImageRep(data: $0) })
let png = try #require(bitmap.representation(using: .png, properties: [:]))
#expect(bitmap.pixelsWide >= 700)
try png.write(
to: FileManager.default.temporaryDirectory.appending(
path: "termind-metrics-\(language)-\(dark ? "dark" : "light").png"))
}
}
}
}
private final class PreviewMetricsPreferences: MetricsConfigurationStoring {
+1 -3
View File
@@ -98,15 +98,13 @@ struct OnboardingControllerTests {
controller.preview(.commandGenerator)
controller.consider(window: window, context: OnboardingContext())
guard
case .waitingForContext(let reason) = controller.developerStatus(
case .waitingForContext = controller.developerStatus(
for: .commandGenerator
)
else {
Issue.record("Expected Preview to wait for a shell context")
return
}
#expect(reason.contains("supported SSH shell"))
controller.consider(
window: window,
context: OnboardingContext(canGenerateCommand: true)
-24
View File
@@ -171,30 +171,6 @@ struct SSHImportTests {
}
}
@Test
func importPreviewKeepsItemsAsDirectFormRows() throws {
let sourceRoot = URL(fileURLWithPath: #filePath).deletingLastPathComponent().deletingLastPathComponent()
let source = try String(
contentsOf: sourceRoot.appendingPathComponent("TFM/Features/SSHImport/SSHImportView.swift"),
encoding: .utf8)
#expect(source.contains("Form {"))
#expect(source.contains(".formStyle(.grouped)"))
#expect(source.contains("ForEach(model.items.filter"))
let tags = try #require(source.range(of: "TagField(tags: $model.hostTags"))
let storage = try #require(source.range(of: "Picker(\"Store in\", selection: $model.storage)"))
let color = try #require(source.range(of: "ColorTagPicker(selection: $model.importColor"))
let preview = try #require(source.range(of: "if !model.items.isEmpty"))
#expect(storage.lowerBound < color.lowerBound)
#expect(color.lowerBound < tags.lowerBound)
#expect(tags.lowerBound < preview.lowerBound)
#expect(!source.contains("hostColor"))
#expect(!source.contains("keyColor"))
#expect(!source.contains("identityColor"))
#expect(!source.contains("Store password in"))
#expect(!source.contains("private func categorySection"))
}
@Test
func droppedSourcesUseTheSameTypeValidationAsTheFilePicker() async throws {
let url = try root()
-1
View File
@@ -119,7 +119,6 @@ struct SerialFeatureTests {
window.select(workspace.id)
#expect(pane.kind == .serialSession)
#expect(pane.symbol == "cable.connector")
#expect(pane.serialSession?.title == "USB UART")
#expect(window.sessionPanes.map(\.pane.id) == [pane.id])
#expect(window.serialSessionPanes.map(\.pane.id) == [pane.id])
-6
View File
@@ -9,12 +9,6 @@ import Testing
@testable import Termind
struct TerminalThemeTests {
@Test
func defaultThemeBackgroundsMatchMacOSWindowBackgrounds() {
#expect(TermindTerminalPalette.termindLight.background.hex == "FFFFFF")
#expect(TermindTerminalPalette.termindDark.background.hex == "1E1E1E")
}
@Test
func unavailableThemesFallBackForBothAppearances() {
let light = TermindTerminalThemeCatalog.background(