Cursor: Apply local changes for cloud agent

This commit is contained in:
Rocky
2026-08-27 18:01:46 +08:00
parent 39002336c0
commit 42e6252f01
148 changed files with 120105 additions and 8122 deletions
+146
View File
@@ -0,0 +1,146 @@
@testable import OSGKeyboardShared
import XCTest
final class AIReplyVariantTests: XCTestCase {
func testStrictParserReturnsThreeKindsInStableUIOrder() throws {
let raw = """
{"variants":[
{"kind":"playful","emotion":"celebratory","text":" 🎉"},
{"kind":"ordinary","emotion":"warm","text":""},
{"kind":"formal","emotion":"neutral","text":""}
]}
"""
let variants = try XCTUnwrap(AIReplyVariantParser.parse(raw))
XCTAssertEqual(variants.map(\.kind), [.ordinary, .formal, .playful])
XCTAssertEqual(variants.map(\.emotion), [.warm, .neutral, .celebratory])
XCTAssertEqual(variants.map(\.text), ["好呀,到时见。", "好的,届时见。", "好呀,走起 🎉"])
}
func testUnknownEmotionSafelyDowngradesToNeutral() throws {
let raw = """
{"variants":[
{"kind":"ordinary","emotion":"unsafe-symbol-name","text":"A"},
{"kind":"formal","emotion":"neutral","text":"B"},
{"kind":"playful","emotion":"playful","text":"C"}
]}
"""
let variants = try XCTUnwrap(AIReplyVariantParser.parse(raw))
XCTAssertEqual(variants[0].emotion, .neutral)
}
func testStrictParserRejectsUnknownFieldsAndMissingKinds() {
let extraField = """
{"variants":[
{"kind":"ordinary","emotion":"neutral","text":"A","icon":"star"},
{"kind":"formal","emotion":"neutral","text":"B"},
{"kind":"playful","emotion":"playful","text":"C"}
]}
"""
let duplicatedKind = """
{"variants":[
{"kind":"ordinary","emotion":"neutral","text":"A"},
{"kind":"ordinary","emotion":"warm","text":"B"},
{"kind":"playful","emotion":"playful","text":"C"}
]}
"""
XCTAssertNil(AIReplyVariantParser.parse(extraField))
XCTAssertNil(AIReplyVariantParser.parse(duplicatedKind))
}
func testFencedJSONFallsBackToOneCleanOrdinaryReply() throws {
let raw = """
```json
{"variants":[
{"kind":"ordinary","emotion":"warm","text":""},
{"kind":"formal","emotion":"neutral","text":""}
]}
```
"""
let result = try XCTUnwrap(AIReplyVariantParser.parseOrFallback(raw))
guard case .single(let fallback) = result else {
return XCTFail("Expected a safe single fallback")
}
XCTAssertEqual(fallback.kind, .ordinary)
XCTAssertEqual(fallback.emotion, .neutral)
XCTAssertEqual(fallback.text, "先确认一下具体时间,可以吗?")
XCTAssertFalse(fallback.text.contains("variants"))
XCTAssertFalse(fallback.text.contains("```"))
}
func testMalformedJSONExtractsReplyInsteadOfReturningStructure() throws {
let raw = #"{"kind":"ordinary","text":"","emotion":"warm",}"#
XCTAssertEqual(
AIReplyVariantParser.fallbackText(from: raw),
"可以,周五见。"
)
}
func testParserRejectsSourceRestatementAndKeepsConversationalReplies() throws {
let source = "630语音因为技术改造,能力回退😪"
let restatement = """
{"variants":[
{"kind":"ordinary","emotion":"neutral","text":"630退"},
{"kind":"formal","emotion":"neutral","text":"630退"},
{"kind":"playful","emotion":"playful","text":"630退 😅"}
]}
"""
let replies = """
{"variants":[
{"kind":"ordinary","emotion":"empathetic","text":""},
{"kind":"formal","emotion":"calm","text":""},
{"kind":"playful","emotion":"playful","text":"退 😅"}
]}
"""
XCTAssertNil(
AIReplyVariantParser.parseOrFallback(
restatement,
sourceText: source
)
)
XCTAssertEqual(
try XCTUnwrap(
AIReplyVariantParser.parse(replies, sourceText: source)
).count,
3
)
}
func testReplyKindOwnsLocalPresentationMetadata() {
XCTAssertEqual(
AIReplyVariant.Kind.allCases.map(\.systemImage),
["bubble.left.fill", "briefcase.fill", "theatermasks.fill"]
)
XCTAssertEqual(
AIReplyVariant.Kind.allCases.map(\.titleKey),
[
"keyboard.ai.replyVariant.ordinary",
"keyboard.ai.replyVariant.formal",
"keyboard.ai.replyVariant.playful"
]
)
}
func testEmotionMapsOnlyToLocalSFSymbolAllowlist() {
XCTAssertEqual(
AIReplyVariant.Emotion.celebratory.systemImage(fallback: .ordinary),
"party.popper.fill"
)
XCTAssertEqual(
AIReplyVariant.Emotion.empathetic.systemImage(fallback: .playful),
"heart.text.square.fill"
)
XCTAssertEqual(
AIReplyVariant.Emotion.neutral.systemImage(fallback: .formal),
"briefcase.fill"
)
}
}