0a60006d2d
Ship user-defined Shortcut skills, companion Events/Navigate recipes, shared skill/style card chrome, and bump the build to 69.
269 lines
9.4 KiB
Swift
269 lines
9.4 KiB
Swift
// AIHintKeywordExtractorTests.swift
|
|
// OSGKeyboardTests
|
|
|
|
import XCTest
|
|
@testable import OSGKeyboardShared
|
|
|
|
final class AIHintKeywordExtractorTests: XCTestCase {
|
|
func testTrendingPrefersMetadataTitleOverHotPrefix() throws {
|
|
let json = """
|
|
{"id":"hot-1","text":"全网热点:朱镕基同志逝世","prompt":"请概括","category":"society","source":"tophub-open-hot","locale":"zh","metadata":{"title":"朱镕基同志逝世"}}
|
|
"""
|
|
let card = try JSONDecoder().decode(AIHintCard.self, from: Data(json.utf8))
|
|
XCTAssertEqual(card.visualKind, .trending)
|
|
XCTAssertEqual(card.visualKind.systemImage, "flame.fill")
|
|
XCTAssertEqual(card.resolvedDisplayText, "朱镕基同志逝世")
|
|
}
|
|
|
|
func testWeatherUsesCityAndTemperature() {
|
|
let card = AIHintCard(
|
|
id: "weather-zh-上海",
|
|
displayText: "上海天气速览",
|
|
prompt: "请说明天气",
|
|
category: "weather",
|
|
source: "open-meteo",
|
|
locale: "zh",
|
|
metadata: AIHintMetadata(city: "上海", tempC: 25.6)
|
|
)
|
|
XCTAssertEqual(card.visualKind, .weather)
|
|
XCTAssertEqual(card.resolvedDisplayText, "上海 26°")
|
|
}
|
|
|
|
func testHolidayStripsPrefixAndUsesChineseName() {
|
|
let card = AIHintCard(
|
|
id: "holiday-next-cn",
|
|
displayText: "临近节日:中秋节",
|
|
prompt: "介绍中秋",
|
|
category: "holiday",
|
|
source: "nager-holidays",
|
|
locale: "zh",
|
|
conditions: ["date"],
|
|
metadata: AIHintMetadata(name: "Mid-Autumn Festival")
|
|
)
|
|
XCTAssertEqual(card.visualKind, .calendar)
|
|
XCTAssertEqual(card.resolvedDisplayText, "中秋节")
|
|
}
|
|
|
|
func testEnglishHolidayUsesMetadataName() {
|
|
let card = AIHintCard(
|
|
id: "holiday-next-us",
|
|
displayText: "Upcoming: Labour Day",
|
|
prompt: "Explain Labour Day",
|
|
category: "holiday",
|
|
source: "nager-holidays",
|
|
locale: "en",
|
|
metadata: AIHintMetadata(name: "Labour Day")
|
|
)
|
|
XCTAssertEqual(card.resolvedDisplayText, "Labour Day")
|
|
}
|
|
|
|
func testLongOrgTitleFallsBackToLastChunk() {
|
|
let text = "中共中央 全国人大常委会 国务院 全国政协讣告 朱镕基同志逝世"
|
|
XCTAssertEqual(
|
|
AIHintKeywordExtractor.finalize(text, locale: "zh"),
|
|
"朱镕基同志逝世"
|
|
)
|
|
}
|
|
|
|
func testMixedTitlePrefersLeadingLatin() {
|
|
XCTAssertEqual(
|
|
AIHintKeywordExtractor.finalize(
|
|
"DeepSeek Pro 正式版已经发布,如何评价该模型?",
|
|
locale: "zh"
|
|
),
|
|
"DeepSeek"
|
|
)
|
|
}
|
|
|
|
func testDailyBriefIsNewsAndSoulQuoteIsSearch() {
|
|
let brief = AIHintCard(
|
|
id: "tophub-daily-brief-1",
|
|
displayText: "看看今日早报",
|
|
prompt: "写早报",
|
|
category: "daily",
|
|
source: "tophub-daily",
|
|
locale: "zh"
|
|
)
|
|
XCTAssertEqual(brief.visualKind, .news)
|
|
XCTAssertEqual(brief.resolvedDisplayText, "今日早报")
|
|
|
|
let soul = AIHintCard(
|
|
id: "tophub-daily-soul-1",
|
|
displayText: "今日一句:展开聊聊",
|
|
prompt: "解释这句话",
|
|
category: "daily",
|
|
source: "tophub-daily",
|
|
locale: "zh",
|
|
metadata: AIHintMetadata(soul: "为了防止我这个月又乱花钱")
|
|
)
|
|
XCTAssertEqual(soul.visualKind, .search)
|
|
XCTAssertEqual(soul.resolvedDisplayText, "今日金句")
|
|
}
|
|
|
|
func testCapabilityMapsToSearch() {
|
|
let card = AIHintLocalCatalog.cards(locale: "zh")
|
|
.first { $0.id == "local-zh-encyclopedia" }!
|
|
XCTAssertEqual(card.visualKind, .search)
|
|
XCTAssertEqual(card.resolvedDisplayText, "有趣概念")
|
|
}
|
|
|
|
func testStocksMapsToChartIcon() {
|
|
let card = AIHintLocalCatalog.cards(locale: "zh")
|
|
.first { $0.id == "local-zh-stocks" }!
|
|
XCTAssertEqual(card.visualKind, .stocks)
|
|
XCTAssertEqual(card.resolvedDisplayText, "今日大盘")
|
|
}
|
|
}
|
|
|
|
final class AIClipboardSkillTests: XCTestCase {
|
|
func testVisibleDefaultsAreReplySummarizeTranslate() {
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.visible().map(\.id),
|
|
["reply", "summarize", "translate"]
|
|
)
|
|
}
|
|
|
|
func testVisibleRespectsEnabledIDsForFutureSettings() {
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.visible(enabledIDs: ["translate", "reply"]).map(\.id),
|
|
["translate", "reply"]
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.visible(enabledIDs: ["unknown"]).map(\.id),
|
|
[]
|
|
)
|
|
}
|
|
|
|
func testTranslateFollowsUserTargetLanguage() {
|
|
let ja = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.translateID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: "ja"
|
|
)
|
|
XCTAssertTrue(ja.contains("Japanese"))
|
|
XCTAssertFalse(ja.contains("互译"))
|
|
}
|
|
|
|
func testTranslateFallsBackToChineseEnglishWhenUnset() {
|
|
let zh = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.translateID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(zh.contains("中文与英文"))
|
|
let en = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.translateID,
|
|
locale: "en",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(en.lowercased().contains("chinese"))
|
|
XCTAssertTrue(en.lowercased().contains("english"))
|
|
}
|
|
|
|
func testTranslateButtonTitleUsesDirectionPairsAndTargetShortNames() {
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId,
|
|
uiLanguage: .chinese
|
|
),
|
|
"中↔英"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId,
|
|
uiLanguage: .english
|
|
),
|
|
"CN↔EN"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "en",
|
|
uiLanguage: .chinese
|
|
),
|
|
"中译英"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "de",
|
|
uiLanguage: .chinese
|
|
),
|
|
"中译德"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "ja",
|
|
uiLanguage: .english
|
|
),
|
|
"To JP"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "zh-Hans",
|
|
uiLanguage: .english
|
|
),
|
|
"To CN"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "zh-Hant",
|
|
uiLanguage: .english
|
|
),
|
|
"To TW"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "zh-Hans",
|
|
uiLanguage: .chinese
|
|
),
|
|
"简↔繁"
|
|
)
|
|
XCTAssertEqual(
|
|
AIClipboardSkillCatalog.translateButtonTitle(
|
|
translationTargetLocaleId: "zh-Hant",
|
|
uiLanguage: .chinese
|
|
),
|
|
"简↔繁"
|
|
)
|
|
}
|
|
|
|
func testSummarizeAsksForOverviewNotShortening() {
|
|
let prompt = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.summarizeID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(prompt.contains("概括"))
|
|
XCTAssertTrue(prompt.contains("不要改写成可发送的短消息"))
|
|
}
|
|
|
|
func testExtractTodosAsksForNONEWhenEmpty() {
|
|
let prompt = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.extractTodosID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(prompt.contains("NONE"))
|
|
XCTAssertTrue(prompt.contains("不要把整段原文当成一条待办"))
|
|
}
|
|
|
|
func testExtractEventsAsksForNONEWhenEmpty() {
|
|
let prompt = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.extractEventsID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(prompt.contains("NONE"))
|
|
XCTAssertTrue(prompt.contains("开始|结束|标题|地点"))
|
|
}
|
|
|
|
func testNavigateAsksForNONEWhenEmpty() {
|
|
let prompt = AIClipboardSkillCatalog.instruction(
|
|
skillID: AIClipboardSkillCatalog.navigateID,
|
|
locale: "zh",
|
|
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId
|
|
)
|
|
XCTAssertTrue(prompt.contains("NONE"))
|
|
XCTAssertTrue(prompt.contains("起点|终点"))
|
|
}
|
|
}
|