test: merge near-identical cases into parameterized tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
27a1e51660
commit
7a6d0e6e80
7 files changed
+62
-197
No files matched your search
@@ -33,30 +33,26 @@ struct CloudSyncSafetyTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(arguments: SyncSafetyCategory.allCases)
|
||||
func olderFetchedRecordCannotAcknowledgeTheCurrentLocalWinner(category: SyncSafetyCategory) async throws {
|
||||
let fixture = try CloudSyncSafetyFixture(category: category)
|
||||
defer { fixture.stop() }
|
||||
try await fixture.start()
|
||||
let id = fixture.recordIDs[0]
|
||||
|
||||
try fixture.receive([try fixture.olderRecord(id)], [])
|
||||
|
||||
#expect(try fixture.pendingNames().contains(id.recordName))
|
||||
#expect(fixture.network.nextEngine.queued.contains(id.recordName))
|
||||
#expect(fixture.record(id) != nil)
|
||||
enum StaleFetchedRecord: CaseIterable {
|
||||
case older
|
||||
case sameVersionDifferentPayload
|
||||
}
|
||||
|
||||
@Test(arguments: SyncSafetyCategory.allCases)
|
||||
func sameVersionDifferentPayloadCannotAcknowledgeTheCurrentLocalWinner(
|
||||
category: SyncSafetyCategory
|
||||
@Test(arguments: SyncSafetyCategory.allCases, StaleFetchedRecord.allCases)
|
||||
func staleFetchedRecordCannotAcknowledgeTheCurrentLocalWinner(
|
||||
category: SyncSafetyCategory, stale: StaleFetchedRecord
|
||||
) async throws {
|
||||
let fixture = try CloudSyncSafetyFixture(category: category)
|
||||
defer { fixture.stop() }
|
||||
try await fixture.start()
|
||||
let id = fixture.recordIDs[0]
|
||||
let fetched =
|
||||
switch stale {
|
||||
case .older: try fixture.olderRecord(id)
|
||||
case .sameVersionDifferentPayload: try fixture.sameVersionLosingRecord(id)
|
||||
}
|
||||
|
||||
try fixture.receive([try fixture.sameVersionLosingRecord(id)], [])
|
||||
try fixture.receive([fetched], [])
|
||||
|
||||
#expect(try fixture.pendingNames().contains(id.recordName))
|
||||
#expect(fixture.network.nextEngine.queued.contains(id.recordName))
|
||||
|
||||
@@ -144,59 +144,27 @@ struct AgentPersistenceTests {
|
||||
|
||||
@Test
|
||||
func schemaV2MigratesToV3WithEmptyAttachmentBacking() throws {
|
||||
let directory = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("TermindAgentV3Migration-\(UUID().uuidString)")
|
||||
try FileManager.default.createDirectory(
|
||||
at: directory, withIntermediateDirectories: true
|
||||
)
|
||||
defer { try? FileManager.default.removeItem(at: directory) }
|
||||
let storeURL = directory.appendingPathComponent("Termind.store")
|
||||
let legacySchema = Schema(versionedSchema: TermindSchemaV2.self)
|
||||
let conversationID = UUID()
|
||||
|
||||
var legacyContainer: ModelContainer? = try ModelContainer(
|
||||
for: legacySchema,
|
||||
configurations: [
|
||||
localModelConfiguration("Migration", schema: legacySchema, url: storeURL)
|
||||
]
|
||||
)
|
||||
legacyContainer?.mainContext.insert(
|
||||
PersistentAgentConversation(
|
||||
id: conversationID, title: "Existing"
|
||||
))
|
||||
try legacyContainer?.mainContext.save()
|
||||
legacyContainer = nil
|
||||
|
||||
let migrated = try ModelContainer(
|
||||
for: HostPersistence.schema,
|
||||
migrationPlan: TermindMigrationPlan.self,
|
||||
configurations: [
|
||||
localModelConfiguration(
|
||||
"Migration", schema: HostPersistence.schema, url: storeURL
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
#expect(
|
||||
try migrated.mainContext.fetch(
|
||||
FetchDescriptor<PersistentAgentConversation>()
|
||||
).map(\.id) == [conversationID])
|
||||
#expect(
|
||||
try migrated.mainContext.fetch(
|
||||
FetchDescriptor<PersistentAgentContextAttachments>()
|
||||
).isEmpty)
|
||||
try expectMigrationKeepsConversationAndLeavesEmptyBacking(
|
||||
from: TermindSchemaV2.self, backing: PersistentAgentContextAttachments.self)
|
||||
}
|
||||
|
||||
@Test
|
||||
func schemaV8MigratesToV9WithEmptyCompactionBacking() throws {
|
||||
try expectMigrationKeepsConversationAndLeavesEmptyBacking(
|
||||
from: TermindSchemaV8.self, backing: PersistentAgentCompaction.self)
|
||||
}
|
||||
|
||||
private func expectMigrationKeepsConversationAndLeavesEmptyBacking<Backing: PersistentModel>(
|
||||
from legacy: any VersionedSchema.Type, backing: Backing.Type
|
||||
) throws {
|
||||
let directory = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("TermindAgentV9Migration-\(UUID().uuidString)")
|
||||
.appendingPathComponent("TermindAgentMigration-\(UUID().uuidString)")
|
||||
try FileManager.default.createDirectory(
|
||||
at: directory, withIntermediateDirectories: true
|
||||
)
|
||||
defer { try? FileManager.default.removeItem(at: directory) }
|
||||
let storeURL = directory.appendingPathComponent("Termind.store")
|
||||
let legacySchema = Schema(versionedSchema: TermindSchemaV8.self)
|
||||
let legacySchema = Schema(versionedSchema: legacy)
|
||||
let conversationID = UUID()
|
||||
|
||||
var legacyContainer: ModelContainer? = try ModelContainer(
|
||||
@@ -226,10 +194,7 @@ struct AgentPersistenceTests {
|
||||
try migrated.mainContext.fetch(
|
||||
FetchDescriptor<PersistentAgentConversation>()
|
||||
).map(\.id) == [conversationID])
|
||||
#expect(
|
||||
try migrated.mainContext.fetch(
|
||||
FetchDescriptor<PersistentAgentCompaction>()
|
||||
).isEmpty)
|
||||
#expect(try migrated.mainContext.fetch(FetchDescriptor<Backing>()).isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -521,50 +521,11 @@ struct AgentRuntimeTests {
|
||||
#expect(await executions.value == 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
func emptyCompatibleToolArgumentsBecomeAnEmptyObject() async {
|
||||
@Test(arguments: ["", "null{}provider-duplicate"])
|
||||
func zeroParameterToolReceivesAnEmptyObjectForCompatibleArguments(arguments: String) async {
|
||||
let model = ScriptedAgentModel(turns: [
|
||||
[
|
||||
.toolCallDelta(id: "1", name: "list_hosts", arguments: ""),
|
||||
.finished(.toolCalls),
|
||||
],
|
||||
[.textDelta("done"), .finished(.completed)],
|
||||
])
|
||||
let executions = Counter()
|
||||
let tool = AnyAgentTool(
|
||||
descriptor: AgentToolDescriptor(
|
||||
name: "list_hosts", summary: "list",
|
||||
inputSchema: .object([
|
||||
"type": .string("object"), "properties": .object([:]),
|
||||
"required": .array([]), "additionalProperties": .bool(false),
|
||||
]),
|
||||
target: .host, approvalPolicy: .approve
|
||||
)
|
||||
) { invocation, _ in
|
||||
#expect(invocation.call.arguments == .object([:]))
|
||||
await executions.increment()
|
||||
return AgentToolResult(callID: invocation.call.id, content: "[]")
|
||||
}
|
||||
let runtime = AgentRuntime(
|
||||
model: model, tools: [tool],
|
||||
approval: AgentApprovalBroker(reviewer: nil, manualApproval: { _ in .allow })
|
||||
)
|
||||
for await _ in await runtime.start(
|
||||
AgentRunRequest(
|
||||
conversationID: UUID(), prompt: "list", permissionMode: .askForApproval
|
||||
))
|
||||
{}
|
||||
#expect(await executions.value == 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
func zeroParameterToolIgnoresMalformedCompatibleArguments() async {
|
||||
let model = ScriptedAgentModel(turns: [
|
||||
[
|
||||
.toolCallDelta(
|
||||
id: "1", name: "list_hosts",
|
||||
arguments: "null{}provider-duplicate"
|
||||
),
|
||||
.toolCallDelta(id: "1", name: "list_hosts", arguments: arguments),
|
||||
.finished(.toolCalls),
|
||||
],
|
||||
[.textDelta("done"), .finished(.completed)],
|
||||
|
||||
@@ -7,30 +7,22 @@ import Testing
|
||||
@testable import TermindRemoteInfrastructure
|
||||
|
||||
struct AuthorizedKeyExportTests {
|
||||
@Test
|
||||
func exportPlacesTheKeyNameCommentAboveThePublicKey() throws {
|
||||
let input = try SSHConnectionOpener.authorizedKeyInstallInput(
|
||||
publicKey: "ssh-ed25519 AAAAC3Nza test@example.com",
|
||||
keyName: "Production"
|
||||
)
|
||||
@Test(arguments: [
|
||||
(
|
||||
"ssh-ed25519 AAAAC3Nza test@example.com", "Production",
|
||||
"# Production Key by Termind\nssh-ed25519 AAAAC3Nza test@example.com\n"
|
||||
),
|
||||
(
|
||||
"ssh-ed25519 AAAAC3Nza", " Production\n\tServer ",
|
||||
"# Production Server Key by Termind\nssh-ed25519 AAAAC3Nza\n"
|
||||
),
|
||||
])
|
||||
func exportPlacesTheKeyNameCommentAboveThePublicKeyOnOneLine(
|
||||
publicKey: String, keyName: String, expected: String
|
||||
) throws {
|
||||
let input = try SSHConnectionOpener.authorizedKeyInstallInput(publicKey: publicKey, keyName: keyName)
|
||||
|
||||
#expect(
|
||||
String(decoding: input, as: UTF8.self)
|
||||
== "# Production Key by Termind\nssh-ed25519 AAAAC3Nza test@example.com\n"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
func exportKeepsTheGeneratedCommentOnOneLine() throws {
|
||||
let input = try SSHConnectionOpener.authorizedKeyInstallInput(
|
||||
publicKey: "ssh-ed25519 AAAAC3Nza",
|
||||
keyName: " Production\n\tServer "
|
||||
)
|
||||
|
||||
#expect(
|
||||
String(decoding: input, as: UTF8.self)
|
||||
== "# Production Server Key by Termind\nssh-ed25519 AAAAC3Nza\n"
|
||||
)
|
||||
#expect(String(decoding: input, as: UTF8.self) == expected)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -600,11 +600,11 @@ struct BroadcastInputTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func commandQFallsThroughToAppKitQuitCommand() throws {
|
||||
@Test(arguments: [("q", UInt16(12)), ("i", UInt16(34))])
|
||||
func commandShortcutFallsThroughToAppKit(character: String, keyCode: UInt16) throws {
|
||||
let host = Host(name: "host", host: "host.example")
|
||||
let sshSession = Workspace.sshSession(host: host).focusedPane.sshSession!
|
||||
AppShortcutRegistry.shared.register(AppShortcutRegistration("q"))
|
||||
AppShortcutRegistry.shared.register(AppShortcutRegistration(.character(Character(character))))
|
||||
let event = try #require(
|
||||
NSEvent.keyEvent(
|
||||
with: .keyDown,
|
||||
@@ -613,32 +613,10 @@ struct BroadcastInputTests {
|
||||
timestamp: ProcessInfo.processInfo.systemUptime,
|
||||
windowNumber: 0,
|
||||
context: nil,
|
||||
characters: "q",
|
||||
charactersIgnoringModifiers: "q",
|
||||
characters: character,
|
||||
charactersIgnoringModifiers: character,
|
||||
isARepeat: false,
|
||||
keyCode: 12
|
||||
))
|
||||
|
||||
#expect(!sshSession.terminalViewOwner.performKeyEquivalentForTesting(event))
|
||||
}
|
||||
|
||||
@Test
|
||||
func commandIFallsThroughToAppKitGenerateCommand() throws {
|
||||
let host = Host(name: "host", host: "host.example")
|
||||
let sshSession = Workspace.sshSession(host: host).focusedPane.sshSession!
|
||||
AppShortcutRegistry.shared.register(AppShortcutRegistration("i"))
|
||||
let event = try #require(
|
||||
NSEvent.keyEvent(
|
||||
with: .keyDown,
|
||||
location: .zero,
|
||||
modifierFlags: .command,
|
||||
timestamp: ProcessInfo.processInfo.systemUptime,
|
||||
windowNumber: 0,
|
||||
context: nil,
|
||||
characters: "i",
|
||||
charactersIgnoringModifiers: "i",
|
||||
isARepeat: false,
|
||||
keyCode: 34
|
||||
keyCode: keyCode
|
||||
))
|
||||
|
||||
#expect(!sshSession.terminalViewOwner.performKeyEquivalentForTesting(event))
|
||||
|
||||
@@ -395,30 +395,8 @@ struct ExternalAuthCoordinatorTests {
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct ExternalToolCallHistoryTests {
|
||||
@Test
|
||||
func clearingHistoryInvalidatesObservedEntriesImmediately() {
|
||||
let entry = ExternalToolCall(
|
||||
runID: UUID(), clientName: "Codex", toolName: "list_hosts",
|
||||
summary: "List saved hosts", risk: .readOnly,
|
||||
startedAt: Date(timeIntervalSince1970: 1)
|
||||
)
|
||||
let store = ToolAuditModel(entries: [entry])
|
||||
let invalidated = ObservationInvalidationFlag()
|
||||
|
||||
withObservationTracking {
|
||||
#expect(store.entries().map(\.id) == [entry.id])
|
||||
} onChange: {
|
||||
invalidated.value = true
|
||||
}
|
||||
|
||||
store.clear()
|
||||
|
||||
#expect(invalidated.value)
|
||||
#expect(store.entries().isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
func clearingHistoryInvalidatesObservedFilteredEntriesImmediately() {
|
||||
@Test(arguments: [nil, "uname"])
|
||||
func clearingHistoryInvalidatesObservedEntriesImmediately(filter: String?) {
|
||||
let entry = ExternalToolCall(
|
||||
runID: UUID(), clientName: "Claude Code", toolName: "ssh_exec",
|
||||
summary: "uname -a", risk: .readOnly,
|
||||
@@ -426,9 +404,12 @@ struct ExternalToolCallHistoryTests {
|
||||
)
|
||||
let store = ToolAuditModel(entries: [entry])
|
||||
let invalidated = ObservationInvalidationFlag()
|
||||
func observedEntries() -> [ExternalToolCall] {
|
||||
filter.map { store.entries(matching: $0) } ?? store.entries()
|
||||
}
|
||||
|
||||
withObservationTracking {
|
||||
#expect(store.entries(matching: "uname").map(\.id) == [entry.id])
|
||||
#expect(observedEntries().map(\.id) == [entry.id])
|
||||
} onChange: {
|
||||
invalidated.value = true
|
||||
}
|
||||
@@ -436,7 +417,7 @@ struct ExternalToolCallHistoryTests {
|
||||
store.clear()
|
||||
|
||||
#expect(invalidated.value)
|
||||
#expect(store.entries(matching: "uname").isEmpty)
|
||||
#expect(observedEntries().isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -72,26 +72,18 @@ struct MarkdownParsingTests {
|
||||
#expect(paragraphText(items[1].children.first) == "todo")
|
||||
}
|
||||
|
||||
@Test
|
||||
func fencedCodeKeepsItsLanguageAndNewlines() {
|
||||
let blocks = TermindMarkdownParser.parse("```bash\nls -la\ncd /tmp\n```")
|
||||
@Test(arguments: [
|
||||
("```bash\nls -la\ncd /tmp\n```", "ls -la\ncd /tmp"),
|
||||
("```bash\nls -la", "ls -la"),
|
||||
])
|
||||
func fencedCodeKeepsItsLanguageAndNewlines(markdown: String, expectedCode: String) {
|
||||
let blocks = TermindMarkdownParser.parse(markdown)
|
||||
guard case .codeBlock(let language, let code)? = blocks.first else {
|
||||
Issue.record("expected a code block, got \(blocks)")
|
||||
return
|
||||
}
|
||||
#expect(language == "bash")
|
||||
#expect(code.trimmingCharacters(in: .newlines) == "ls -la\ncd /tmp")
|
||||
}
|
||||
|
||||
@Test
|
||||
func unterminatedFenceStillProducesACodeBlock() {
|
||||
let blocks = TermindMarkdownParser.parse("```bash\nls -la")
|
||||
guard case .codeBlock(let language, let code)? = blocks.first else {
|
||||
Issue.record("expected a code block, got \(blocks)")
|
||||
return
|
||||
}
|
||||
#expect(language == "bash")
|
||||
#expect(code.trimmingCharacters(in: .newlines) == "ls -la")
|
||||
#expect(code.trimmingCharacters(in: .newlines) == expectedCode)
|
||||
}
|
||||
|
||||
@Test(arguments: ["https://example.com", "file:///tmp/example.txt", "ssh://example.com", "custom:document"])
|
||||
|
||||
Reference in new issue
Block a user