Files
OSGKeyboard/OSGKeyboardTests/ClipboardSemanticAnalyzerTests.swift
T
Rocky 2cc81c4628 feat(keyboard): expand contextual skills and managed flows
Add local clipboard intent recommendations, webpage and phone actions, and safer host handoffs. Refine managed gateway, catalog refresh, onboarding, and adaptive polish behavior.
2026-08-23 14:02:33 +08:00

139 lines
4.9 KiB
Swift

// ClipboardSemanticAnalyzerTests.swift
// OSGKeyboardTests
@testable import OSGKeyboardShared
import XCTest
final class ClipboardSemanticAnalyzerTests: XCTestCase {
func testEmptyTextReturnsNoLabels() async {
let analysis = await ClipboardSemanticAnalyzer().analyze(" \n ")
XCTAssertNil(analysis.language)
XCTAssertEqual(analysis.sentiment, .unknown)
XCTAssertFalse(analysis.task.isDetected)
XCTAssertFalse(analysis.question.isDetected)
XCTAssertFalse(analysis.invitation.isDetected)
XCTAssertFalse(analysis.complaint.isDetected)
XCTAssertFalse(analysis.replyableMessage.isDetected)
}
func testDetectsLanguageAndStructuredDataLocally() async {
let text = """
Meet on August 28, 2026 at 3:00 PM at 1 Apple Park Way, Cupertino, CA 95014.
Call +1 408-996-1010 or visit https://www.apple.com.
"""
let analysis = await ClipboardSemanticAnalyzer().analyze(text)
XCTAssertEqual(analysis.language?.identifier, "en")
XCTAssertTrue(analysis.hasDateOrTime)
XCTAssertTrue(analysis.hasAddress)
XCTAssertTrue(analysis.hasPhoneNumber)
XCTAssertTrue(analysis.hasURL)
}
func testStandaloneHTTPSLinkBecomesSingleWebURL() async {
let analysis = await ClipboardSemanticAnalyzer().analyze(
"https://www.apple.com/newsroom/"
)
XCTAssertEqual(
analysis.singleWebURL?.absoluteString,
"https://www.apple.com/newsroom/"
)
}
func testBareDomainIsNormalizedToHTTPS() {
let url = ClipboardWebLinkResolver.singleWebURL(
in: "详情见 www.apple.com/newsroom/"
)
XCTAssertEqual(
url?.absoluteString,
"https://www.apple.com/newsroom/"
)
}
func testMultipleLinksHaveNoSingleActionTarget() {
XCTAssertNil(
ClipboardWebLinkResolver.singleWebURL(
in: "https://example.com/a 和 https://example.com/b"
)
)
}
func testStandalonePhoneNumberBecomesSingleActionTarget() async throws {
let analysis = await ClipboardSemanticAnalyzer().analyze(
"请拨打 +1 (408) 996-1010"
)
XCTAssertEqual(analysis.singlePhoneNumber, "+14089961010")
XCTAssertEqual(
AIPhoneNumberResolver.telephoneURL(
for: try XCTUnwrap(analysis.singlePhoneNumber)
)?.absoluteString,
"tel:+14089961010"
)
}
func testMultiplePhoneNumbersHaveNoSingleActionTarget() {
let labels = [
ClipboardTextLabel(sourceText: "+1 408-996-1010"),
ClipboardTextLabel(sourceText: "400-666-8800")
]
XCTAssertNil(AIPhoneNumberResolver.singlePhoneNumber(from: labels))
}
func testApprovedModelsDetectHighConfidenceIntents() async {
let analyzer = ClipboardSemanticAnalyzer()
let task = await analyzer.analyze(
"请今天下班前发送会议纪要,完成后发给项目群。"
)
let question = await analyzer.analyze(
"退款流程具体是怎么安排的?"
)
let invitation = await analyzer.analyze(
"今晚七点在老地方吃饭,你能来吗?"
)
let complaint = await analyzer.analyze(
"应用一直闪退,数据还丢了,你们能尽快处理吗?"
)
XCTAssertTrue(task.task.isApprovedForAutomaticRouting)
XCTAssertTrue(task.task.isDetected)
XCTAssertTrue(question.question.isApprovedForAutomaticRouting)
XCTAssertTrue(question.question.isDetected)
XCTAssertTrue(invitation.invitation.isApprovedForAutomaticRouting)
XCTAssertTrue(invitation.invitation.isDetected)
XCTAssertTrue(complaint.complaint.isApprovedForAutomaticRouting)
XCTAssertTrue(complaint.complaint.isDetected)
}
func testReplyableModelDistinguishesConversationFromAcknowledgment() async {
let analyzer = ClipboardSemanticAnalyzer()
let conversation = await analyzer.analyze(
"我刚到家,今天真是累坏了。"
)
let acknowledgment = await analyzer.analyze(
"收到,谢谢。"
)
XCTAssertTrue(conversation.replyableMessage.isApprovedForAutomaticRouting)
XCTAssertTrue(conversation.replyableMessage.isDetected)
XCTAssertTrue(acknowledgment.replyableMessage.isApprovedForAutomaticRouting)
XCTAssertFalse(acknowledgment.replyableMessage.isDetected)
}
func testPersonalPlanDoesNotBecomeAutomaticTask() async {
let analysis = await ClipboardSemanticAnalyzer().analyze(
"私人备忘:我准备周五自己整理完这份报告。"
)
XCTAssertTrue(analysis.task.isApprovedForAutomaticRouting)
XCTAssertFalse(analysis.task.isDetected)
XCTAssertFalse(analysis.replyableMessage.isDetected)
}
}