fix(release): prepare 1.8 disclosures and licensed resources

Replace the unclear CLM source, align release and privacy disclosures, complete third-party notices, and keep the expanded test suites deterministic for release validation.
This commit is contained in:
Rocky
2026-08-14 23:28:11 +08:00
parent 7364659027
commit f42a812256
36 changed files with 3950 additions and 10851 deletions
@@ -0,0 +1,77 @@
// AIUserSkillStoreTests.swift
// OSGKeyboardTests
import XCTest
@testable import OSGKeyboardShared
@MainActor
final class AIUserSkillStoreTests: XCTestCase {
private func makeDefaults() -> UserDefaults {
let suite = "group.com.osgkeyboard.shared.tests.userSkills.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
return defaults
}
func testChangingShortcutLinkDropsConfirmation() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
let firstURL = URL(string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44")!
let secondURL = URL(string: "https://www.icloud.com/shortcuts/1f4afcf7ee22400cbf84e319d969aadf")!
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it",
shortcutICloudURL: firstURL,
shortcutName: "One"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.confirmShortcutAndEnable(skill.id), .enabled)
XCTAssertTrue(store.layout.isEnabled(skill.id))
skill.shortcutICloudURL = secondURL
skill.shortcutName = "Two"
try store.saveUserSkill(skill)
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertFalse(store.layout.isEnabled(skill.id))
}
func testRemovingShortcutLinkKeepsEnabledTextSkill() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it",
shortcutICloudURL: URL(
string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44"
),
shortcutName: "Run Me"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.confirmShortcutAndEnable(skill.id), .enabled)
skill.shortcutICloudURL = nil
try store.saveUserSkill(skill)
XCTAssertTrue(store.layout.isEnabled(skill.id))
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertEqual(store.userSkill(id: skill.id)?.asClipboardSkill().kind, .transform)
}
func testAddingShortcutLinkDisablesTextSkillUntilConfirmed() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.enable(skill.id), .enabled)
skill.shortcutICloudURL = URL(
string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44"
)
skill.shortcutName = "Run Me"
try store.saveUserSkill(skill)
XCTAssertFalse(store.layout.isEnabled(skill.id))
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertEqual(store.enable(skill.id), .needsShortcut)
}
}
-72
View File
@@ -236,75 +236,3 @@ final class AIUserSkillTests: XCTestCase {
XCTAssertEqual(catalog.entries.count, 12)
}
}
@MainActor
final class AIUserSkillStoreTests: XCTestCase {
private func makeDefaults() -> UserDefaults {
let suite = "group.com.osgkeyboard.shared.tests.userSkills.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
return defaults
}
func testChangingShortcutLinkDropsConfirmation() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
let firstURL = URL(string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44")!
let secondURL = URL(string: "https://www.icloud.com/shortcuts/1f4afcf7ee22400cbf84e319d969aadf")!
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it",
shortcutICloudURL: firstURL,
shortcutName: "One"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.confirmShortcutAndEnable(skill.id), .enabled)
XCTAssertTrue(store.layout.isEnabled(skill.id))
skill.shortcutICloudURL = secondURL
skill.shortcutName = "Two"
try store.saveUserSkill(skill)
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertFalse(store.layout.isEnabled(skill.id))
}
func testRemovingShortcutLinkKeepsEnabledTextSkill() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it",
shortcutICloudURL: URL(
string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44"
),
shortcutName: "Run Me"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.confirmShortcutAndEnable(skill.id), .enabled)
skill.shortcutICloudURL = nil
try store.saveUserSkill(skill)
XCTAssertTrue(store.layout.isEnabled(skill.id))
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertEqual(store.userSkill(id: skill.id)?.asClipboardSkill().kind, .transform)
}
func testAddingShortcutLinkDisablesTextSkillUntilConfirmed() throws {
let store = AIAgentSkillLayoutStore(defaults: makeDefaults())
var skill = AIUserSkill(
name: "Custom",
prompt: "Do it"
)
try store.saveUserSkill(skill)
XCTAssertEqual(store.enable(skill.id), .enabled)
skill.shortcutICloudURL = URL(
string: "https://www.icloud.com/shortcuts/65bf33ba4206484ba78d582eaf1e9c44"
)
skill.shortcutName = "Run Me"
try store.saveUserSkill(skill)
XCTAssertFalse(store.layout.isEnabled(skill.id))
XCTAssertFalse(store.layout.hasConfirmedShortcut(skill.id))
XCTAssertEqual(store.enable(skill.id), .needsShortcut)
}
}
+7
View File
@@ -20,6 +20,9 @@ final class LLMClientTests: XCTestCase {
try? Keychain.deleteAPIKey(for: "qwen")
try? Keychain.deleteAPIKey(for: "openai")
try? Keychain.deleteAPIKey(for: "deepseek")
try? Keychain.deleteAPIKey(for: "qwen", useICloudSync: true)
try? Keychain.deleteAPIKey(for: "openai", useICloudSync: true)
try? Keychain.deleteAPIKey(for: "deepseek", useICloudSync: true)
StubURLProtocolStorage.config = nil
StubURLProtocolStorage.delaySeconds = 0
StubURLProtocolStorage.lastRequest = nil
@@ -31,6 +34,9 @@ final class LLMClientTests: XCTestCase {
try? Keychain.deleteAPIKey(for: "qwen")
try? Keychain.deleteAPIKey(for: "openai")
try? Keychain.deleteAPIKey(for: "deepseek")
try? Keychain.deleteAPIKey(for: "qwen", useICloudSync: true)
try? Keychain.deleteAPIKey(for: "openai", useICloudSync: true)
try? Keychain.deleteAPIKey(for: "deepseek", useICloudSync: true)
Keychain.resetTestMemoryStore()
StubURLProtocolStorage.config = nil
StubURLProtocolStorage.delaySeconds = 0
@@ -65,6 +71,7 @@ final class LLMClientTests: XCTestCase {
defer { defaults.removePersistentDomain(forName: suiteName) }
let config = ProviderConfig(defaults: defaults)
config.apiKey = ""
config.engineMode = "cloud"
XCTAssertFalse(config.isConfigured)
config.engineMode = "local"
@@ -13,9 +13,9 @@ final class LocalASRBiasAdapterTests: XCTestCase {
let url = dir.appendingPathComponent("phrases.tsv")
let tsv = """
word\tpinyin\tsource\tweight
SwiftUI\tswift ui\tcomputer_terms\t5
Kubernetes\tku bo ne si\tcomputer_terms\t5
一致性\tyi zhi xing\tcomputer_terms\t5
SwiftUI\tswift ui\tai_tech_seed\t90
Kubernetes\tku bo ne si\tai_tech_seed\t90
一致性\tyi zhi xing\tai_tech_seed\t80
"""
try tsv.write(to: url, atomically: true, encoding: .utf8)
addTeardownBlock {
@@ -103,11 +103,12 @@ final class LocalASRBiasAdapterTests: XCTestCase {
func testBuiltinLexiconParsesTSV() {
let terms = BuiltinLexiconIndex.parseTSV(
"word\tpinyin\tsource\tweight\nFoo\tfoo\tcomputer_terms\t5\n"
"word\tpinyin\tsource\tweight\nFoo\tfoo\tai_tech_seed\t80\n"
)
XCTAssertEqual(terms.count, 1)
XCTAssertEqual(terms[0].word, "Foo")
XCTAssertEqual(terms[0].weight, 5)
XCTAssertEqual(terms[0].source, "ai_tech_seed")
XCTAssertEqual(terms[0].weight, 80)
}
func testPolishingServiceMergesDictionarySupplement() {
@@ -106,7 +106,7 @@ final class LocalASRModelCatalogTests: XCTestCase {
func testMLXAdapterProducesPromptBiasNotHardHotwords() throws {
let fixtureURL = FileManager.default.temporaryDirectory
.appendingPathComponent("phrases-\(UUID().uuidString).tsv")
try "word\tpinyin\tsource\tweight\nSwiftUI\tswift ui\tcomputer_terms\t5\n"
try "word\tpinyin\tsource\tweight\nSwiftUI\tswift ui\tai_tech_seed\t90\n"
.write(to: fixtureURL, atomically: true, encoding: .utf8)
defer { try? FileManager.default.removeItem(at: fixtureURL) }
@@ -5,16 +5,18 @@ import XCTest
@testable import OSGKeyboard
final class OpenSourceLicenseCatalogTests: XCTestCase {
func testIOSCatalogIncludesRimeAndDictionaryDataOnly() {
func testIOSCatalogIncludesRimeDictionariesIconsAndCuratedSpeechData() {
let entries = OpenSourceLicenseCatalog.entries(for: .iOS)
let ids = Set(entries.map(\.id))
XCTAssertTrue(ids.contains("material-icons"))
XCTAssertTrue(ids.contains("librime-static"))
XCTAssertTrue(ids.contains("rime-pinyin-simp"))
XCTAssertTrue(ids.contains("jieba"))
XCTAssertTrue(ids.contains("phrase-pinyin-data"))
XCTAssertTrue(ids.contains("pinyin-data"))
XCTAssertTrue(ids.contains("english-typing-lexicon"))
XCTAssertTrue(ids.contains("osg-ai-tech-lexicon"))
XCTAssertFalse(ids.contains("mlx-audio-swift"))
}
@@ -22,7 +24,15 @@ final class OpenSourceLicenseCatalogTests: XCTestCase {
let entries = OpenSourceLicenseCatalog.entries(for: .macOS)
let ids = Set(entries.map(\.id))
XCTAssertEqual(ids, ["mlx-audio-swift"])
XCTAssertEqual(ids, [
"mlx-audio-swift",
"mlx-swift",
"mlx-swift-lm",
"osg-ai-tech-lexicon",
"qwen3-asr-mlx",
"swift-huggingface",
"swift-transformers",
])
}
func testBundledDictionaryLicensesKeepCopyrightNotices() throws {
@@ -46,4 +56,39 @@ final class OpenSourceLicenseCatalogTests: XCTestCase {
XCTAssertTrue(entry.licenseText.contains("leveldb.txt"))
XCTAssertTrue(entry.licenseText.contains("yaml-cpp.txt"))
}
func testMaterialIconsUseGoogleAttributionAndFullApacheLicense() throws {
let entry = try XCTUnwrap(
OpenSourceLicenseCatalog.entries(for: .iOS)
.first { $0.id == "material-icons" }
)
XCTAssertTrue(entry.licenseText.contains("Copyright 2014 Google LLC"))
XCTAssertTrue(entry.licenseText.contains("TERMS AND CONDITIONS FOR USE"))
}
func testMacMLXAndQwenNoticesContainUpstreamAttribution() throws {
let entries = OpenSourceLicenseCatalog.entries(for: .macOS)
let mlxAudio = try XCTUnwrap(entries.first { $0.id == "mlx-audio-swift" })
let mlxSwift = try XCTUnwrap(entries.first { $0.id == "mlx-swift" })
let transformers = try XCTUnwrap(entries.first { $0.id == "swift-transformers" })
let qwen = try XCTUnwrap(entries.first { $0.id == "qwen3-asr-mlx" })
XCTAssertTrue(mlxAudio.licenseText.contains("Copyright (c) 2025 Prince Canuma"))
XCTAssertTrue(mlxSwift.licenseText.contains("Copyright (c) 2023 ml-explore"))
XCTAssertTrue(transformers.licenseText.contains("Copyright 2022 Hugging Face SAS."))
XCTAssertTrue(qwen.licenseText.contains("Qwen3-ASR-0.6B-4bit"))
XCTAssertTrue(qwen.licenseText.contains("Apache License"))
}
func testCuratedLexiconNoticeDoesNotRelicenseApplication() throws {
let entry = try XCTUnwrap(
OpenSourceLicenseCatalog.entries(for: .iOS)
.first { $0.id == "osg-ai-tech-lexicon" }
)
XCTAssertTrue(entry.licenseText.contains("data subset"))
XCTAssertTrue(entry.licenseText.contains("source-available"))
XCTAssertTrue(entry.licenseText.contains("not distributed under the MIT License"))
}
}