Files
ggbond268--mactools/Plugins/Translator/Tests/SelectedTextCapturePipelineTests.swift
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

235 lines
8.9 KiB
Swift

import Foundation
import XCTest
@testable import TranslatorPlugin
@MainActor
final class SelectedTextCapturePipelineTests: XCTestCase {
func testFirstSuccessfulStrategyWins() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .accessibility,
isEditable: false,
sourceApplicationBundleID: "com.example.first",
failureReason: "失败"
)
),
StubSelectedTextCapture(
strategyID: .browserAppleScript,
result: SelectedTextCaptureResult(
text: "selected text",
strategyID: .browserAppleScript,
isEditable: true,
sourceApplicationBundleID: "com.example.second",
failureReason: "忽略"
)
),
StubSelectedTextCapture(
strategyID: .simulatedCopy,
result: SelectedTextCaptureResult(
text: "later text",
strategyID: .simulatedCopy,
isEditable: false,
sourceApplicationBundleID: "com.example.third",
failureReason: nil
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext())
XCTAssertEqual(result.text, "selected text")
XCTAssertEqual(result.strategyID, .browserAppleScript)
XCTAssertTrue(result.isEditable)
XCTAssertEqual(result.sourceApplicationBundleID, "com.example.second")
XCTAssertNil(result.failureReason)
}
func testBlankTextFallsThroughAfterTrimming() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: " \n\t ",
strategyID: .accessibility,
isEditable: true,
sourceApplicationBundleID: "com.example.blank",
failureReason: nil
)
),
StubSelectedTextCapture(
strategyID: .browserAppleScript,
result: SelectedTextCaptureResult(
text: "browser text",
strategyID: .browserAppleScript,
isEditable: false,
sourceApplicationBundleID: "com.apple.Safari",
failureReason: nil
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext())
XCTAssertEqual(result.text, "browser text")
XCTAssertEqual(result.strategyID, .browserAppleScript)
XCTAssertEqual(result.sourceApplicationBundleID, "com.apple.Safari")
}
func testBrowserContextPrefersAppleScriptOverAccessibilityText() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: "accessibility text",
strategyID: .accessibility,
isEditable: true,
sourceApplicationBundleID: "com.apple.Safari",
failureReason: nil
)
),
StubSelectedTextCapture(
strategyID: .browserAppleScript,
result: SelectedTextCaptureResult(
text: "browser selection",
strategyID: .browserAppleScript,
isEditable: false,
sourceApplicationBundleID: "com.apple.Safari",
failureReason: nil
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext(frontmostApplicationBundleID: "com.apple.Safari"))
XCTAssertEqual(result.text, "browser selection")
XCTAssertEqual(result.strategyID, .browserAppleScript)
}
func testBrowserContextFallsBackToAccessibilityWhenAppleScriptFails() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: "accessibility fallback",
strategyID: .accessibility,
isEditable: true,
sourceApplicationBundleID: "com.apple.Safari",
failureReason: nil
)
),
StubSelectedTextCapture(
strategyID: .browserAppleScript,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .browserAppleScript,
isEditable: false,
sourceApplicationBundleID: "com.apple.Safari",
failureReason: "自动化取词失败"
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext(frontmostApplicationBundleID: "com.apple.Safari"))
XCTAssertEqual(result.text, "accessibility fallback")
XCTAssertEqual(result.strategyID, .accessibility)
}
func testAllFailuresReturnsMissingSelection() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .accessibility,
isEditable: false,
sourceApplicationBundleID: nil,
failureReason: "失败"
)
),
StubSelectedTextCapture(
strategyID: .simulatedCopy,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .simulatedCopy,
isEditable: false,
sourceApplicationBundleID: nil,
failureReason: "复制失败"
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext())
XCTAssertEqual(result, .missing)
XCTAssertEqual(result.failureReason, "未找到选中文本")
}
func testPermissionRequiredFailureIsPreservedWhenNoStrategySucceeds() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .accessibility,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .accessibility,
isEditable: false,
sourceApplicationBundleID: "com.example.secure",
failureReason: "需要辅助功能授权"
)
),
StubSelectedTextCapture(
strategyID: .simulatedCopy,
result: SelectedTextCaptureResult(
text: nil,
strategyID: .simulatedCopy,
isEditable: false,
sourceApplicationBundleID: nil,
failureReason: "复制失败"
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext())
XCTAssertNil(result.text)
XCTAssertEqual(result.strategyID, .accessibility)
XCTAssertFalse(result.isEditable)
XCTAssertEqual(result.sourceApplicationBundleID, "com.example.secure")
XCTAssertEqual(result.failureReason, "需要辅助功能授权")
}
func testReturnedTextIsTrimmed() async {
let pipeline = SelectedTextCapturePipeline(strategies: [
StubSelectedTextCapture(
strategyID: .simulatedCopy,
result: SelectedTextCaptureResult(
text: "\n trimmed text \t",
strategyID: .simulatedCopy,
isEditable: false,
sourceApplicationBundleID: "com.example.app",
failureReason: nil
)
),
])
let result = await pipeline.capture(context: SelectedTextCaptureContext())
XCTAssertEqual(result.text, "trimmed text")
XCTAssertEqual(result.strategyID, .simulatedCopy)
XCTAssertEqual(result.sourceApplicationBundleID, "com.example.app")
XCTAssertNil(result.failureReason)
}
}
private struct StubSelectedTextCapture: SelectedTextCapturing {
let strategyID: SelectedTextCaptureStrategyID
let result: SelectedTextCaptureResult
func capture(context: SelectedTextCaptureContext) async -> SelectedTextCaptureResult {
result
}
}