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
+60 -41
View File
@@ -22,8 +22,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testChineseTypingDoesNotLoadEnglishLexicon() {
EnglishLexicon.shared.unload()
let typing = TypingSessionController()
_ = typing.setLanguage(.chinese)
let typing = makeTypingSession(language: .chinese)
typing.enterTypingMode()
XCTAssertFalse(EnglishLexicon.shared.isLoaded)
_ = typing.setLanguage(.english)
@@ -124,10 +123,10 @@ final class EnglishTypingTests: XCTestCase {
func testEnglishShiftArmsAfterReturnLikeNotes() {
// Simulates Notes: proxy preceding text gains a trailing newline after Return.
var preceding = "Hello"
let typing = TypingSessionController()
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.autocapitalizationModeProvider = { .sentences }
_ = typing.setLanguage(.english)
typing.syncAutocapitalization()
XCTAssertFalse(typing.shiftActive, "mid-word should not arm Shift")
_ = typing.handleReturn()
@@ -144,10 +143,10 @@ final class EnglishTypingTests: XCTestCase {
func testEnglishShiftArmsWhenProxyLagsAfterReturn() {
// Notes often still reports pre-Return context right after insertText("\n").
var preceding = "Hello"
let typing = TypingSessionController()
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.autocapitalizationModeProvider = { .sentences }
_ = typing.setLanguage(.english)
typing.syncAutocapitalization()
_ = typing.handleReturn()
// Proxy intentionally stale still "Hello" without "\n".
@@ -159,10 +158,10 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testEnglishShiftArmsWhenProxyLagsAfterPeriod() {
var preceding = "Hello"
let typing = TypingSessionController()
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.autocapitalizationModeProvider = { .sentences }
_ = typing.setLanguage(.english)
typing.syncAutocapitalization()
_ = typing.handleKey(".")
typing.syncAutocapitalization(accountingForInsert: ".")
@@ -171,9 +170,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testEnglishIdleShowsNoCandidatesUntilLetterTyped() {
let typing = TypingSessionController()
typing.suggestionsEnabled = true
_ = typing.setLanguage(.english)
let typing = makeTypingSession()
typing.enterTypingMode()
XCTAssertTrue(typing.composition.candidates.isEmpty)
@@ -202,9 +199,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testEnglishTypingEmitsCompletionsIntoComposition() {
let typing = TypingSessionController()
typing.suggestionsEnabled = true
_ = typing.setLanguage(.english)
let typing = makeTypingSession()
typing.enterTypingMode()
_ = typing.handleKey("h")
@@ -219,11 +214,9 @@ final class EnglishTypingTests: XCTestCase {
func testOldWordBackspaceRehydratesSuggestionsFromDocumentContext() {
var preceding = "board"
let following = "\n"
let typing = TypingSessionController()
typing.suggestionsEnabled = true
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.followingTextProvider = { following }
_ = typing.setLanguage(.english)
typing.enterTypingMode()
typing.synchronizeEnglishDocumentContext(caretMoved: true)
@@ -259,11 +252,9 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testCandidateReplacementRejectsStaleDocumentAnchor() {
var preceding = ""
let typing = TypingSessionController()
typing.suggestionsEnabled = true
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.followingTextProvider = { "" }
_ = typing.setLanguage(.english)
typing.enterTypingMode()
for key in ["b", "o", "a"] {
@@ -286,11 +277,9 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testMidWordCaretSuppressesUnsafeBackwardOnlyReplacement() {
let typing = TypingSessionController()
typing.suggestionsEnabled = true
let typing = makeTypingSession()
typing.precedingTextProvider = { "boa" }
typing.followingTextProvider = { "rd" }
_ = typing.setLanguage(.english)
typing.enterTypingMode()
typing.synchronizeEnglishDocumentContext(caretMoved: true)
@@ -302,11 +291,9 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testStaleHostCallbackDoesNotDiscardLocalEnglishWord() {
var preceding = ""
let typing = TypingSessionController()
typing.suggestionsEnabled = true
let typing = makeTypingSession()
typing.precedingTextProvider = { preceding }
typing.followingTextProvider = { "" }
_ = typing.setLanguage(.english)
typing.enterTypingMode()
let output = typing.handleKey("h")
@@ -337,7 +324,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testPeriodShortcutReplacesDoubleSpace() {
let typing = TypingSessionController()
let typing = makeTypingSession()
_ = typing.setLanguage(.english)
typing.enterTypingMode()
@@ -356,7 +343,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testPeriodShortcutDoesNotFireAfterAnotherLetter() {
let typing = TypingSessionController()
let typing = makeTypingSession()
_ = typing.setLanguage(.english)
typing.enterTypingMode()
@@ -369,8 +356,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testPeriodShortcutDoesNotFireAfterSentenceTerminator() {
let typing = TypingSessionController()
_ = typing.setLanguage(.english)
let typing = makeTypingSession()
typing.precedingTextProvider = { "Hello." }
typing.enterTypingMode()
typing.syncAutocapitalization()
@@ -382,8 +368,7 @@ final class EnglishTypingTests: XCTestCase {
@MainActor
func testChineseSpaceDoesNotUsePeriodShortcut() {
let typing = TypingSessionController()
_ = typing.setLanguage(.chinese)
let typing = makeTypingSession(language: .chinese)
let first = typing.handleSpace()
let second = typing.handleSpace()
XCTAssertEqual(first.text, " ")
@@ -526,9 +511,7 @@ final class EnglishTypingTests: XCTestCase {
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let store = EnglishLearningStore(defaults: defaults)
let typing = TypingSessionController(learningStore: store)
typing.suggestionsEnabled = true
_ = typing.setLanguage(.english)
let typing = makeTypingSession(learningStore: store)
typing.enterTypingMode()
for character in ["t", "e", "h"] {
@@ -545,9 +528,7 @@ final class EnglishTypingTests: XCTestCase {
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let store = EnglishLearningStore(defaults: defaults)
let typing = TypingSessionController(learningStore: store)
typing.suggestionsEnabled = true
_ = typing.setLanguage(.english)
let typing = makeTypingSession(learningStore: store)
typing.enterTypingMode()
for character in ["t", "e", "h"] {
@@ -581,13 +562,28 @@ final class EnglishTypingTests: XCTestCase {
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let store = EnglishLearningStore(defaults: defaults)
let typing = TypingSessionController(learningStore: store)
typing.suggestionsEnabled = true
_ = typing.setLanguage(.english)
let typing = makeTypingSession(learningStore: store)
typing.enterTypingMode()
return typing
}
@MainActor
private func makeTypingSession(
learningStore: EnglishLearningStore? = nil,
language: TypingInputLanguage = .english
) -> TypingSessionController {
let store = learningStore ?? EnglishLearningStore(
defaults: UserDefaults(suiteName: "english.tests.\(UUID().uuidString)")!
)
let typing = TypingSessionController(
engine: { NoopRimeEngine() },
learningStore: store
)
typing.suggestionsEnabled = true
_ = typing.setLanguage(language)
return typing
}
@MainActor
private func apply(_ typing: TypingSessionController, _ output: TypingOutput) {
typing.syncAutocapitalization(
@@ -596,3 +592,26 @@ final class EnglishTypingTests: XCTestCase {
)
}
}
@MainActor
private final class NoopRimeEngine: RimeEngineBridging {
var composition: TypingComposition = .empty
var isReady = true
var schema: TypingInputSchema = .fullPinyin
func prepare() async throws {}
func teardown() { composition = .empty }
func setLanguage(_ language: TypingInputLanguage) {}
@discardableResult
func setSchema(_ schema: TypingInputSchema) -> Bool {
self.schema = schema
return true
}
func processCharacter(_ character: Character) -> String? { nil }
func processBackspace() -> String? { nil }
func processSpace() -> String? { " " }
func processReturn() -> String? { "\n" }
func selectCandidate(at index: Int) -> String { "" }
func flushPreedit() -> String { "" }
func clearComposition() { composition = .empty }
}
@@ -97,7 +97,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testKeyRowsFollowTypingLanguageOnNumberPage() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
typing.setPage(.numbers)
XCTAssertEqual(typing.keyRows[1], ["-", "/", "", "", "", "", "", "@", "", ""])
@@ -325,7 +325,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testResourceRetryIsSkippedWhenNoErrorIsPending() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
XCTAssertNil(typing.lastError)
XCTAssertFalse(typing.lastErrorNeedsHostDeployment)
@@ -338,7 +338,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testSharedCapsuleCanSelectSpecificTypingLanguage() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
XCTAssertEqual(typing.language, .chinese)
XCTAssertEqual(typing.setLanguage(.english), .none)
@@ -349,7 +349,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testShiftStateProducesUppercaseKeyRows() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
XCTAssertFalse(typing.shiftActive)
_ = typing.handleKey("")
@@ -360,7 +360,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testManualShiftSurvivesAutocapitalizationSync() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
// Providers must be set before language switch (which syncs autocap).
typing.precedingTextProvider = { "hello " } // mid-sentence: auto stays off
typing.autocapitalizationModeProvider = { .sentences }
@@ -376,7 +376,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testShiftHoldTypesUppercaseWithoutEnteringCapsLock() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
_ = typing.setLanguage(.english)
typing.precedingTextProvider = { "hello " }
typing.autocapitalizationModeProvider = { .sentences }
@@ -396,7 +396,7 @@ final class KeyboardSurfaceStateTests: XCTestCase {
}
func testShiftHoldWithoutTypingActsAsTap() {
let typing = TypingSessionController()
let typing = TypingSessionController(engine: { TrackingStubRimeEngine() })
typing.beginShiftHold()
typing.endShiftHold()
XCTAssertTrue(typing.shiftActive)
@@ -51,6 +51,7 @@ final class LibrimeIntegrationTests: XCTestCase {
distributionVersion: "tests"
)
try bridge.start()
defer { bridge.finalizeRuntime() }
let vectors: [(TypingInputSchema, String)] = [
(.fullPinyin, "nihao"),
@@ -141,40 +142,34 @@ final class LibrimeIntegrationTests: XCTestCase {
let userFiles = fileManager.enumerator(atPath: user.path)?
.compactMap { $0 as? String } ?? []
XCTAssertTrue(userFiles.contains(where: { $0.contains("userdb") }))
}
// Redeploy with one fuzzy pair and verify it affects actual Rime
// candidates rather than just generated YAML.
for schema in TypingInputSchema.allCases {
try RimeSchemaGenerator.schema(for: schema, fuzzyPairs: [.nL]).write(
to: shared.appendingPathComponent("\(schema.rawValue).schema.yaml"),
atomically: true,
encoding: .utf8
)
}
let fuzzyDeployer = OSGRimeBridge(
sharedDataDirectory: shared.path,
userDataDirectory: user.path,
distributionVersion: "tests-fuzzy"
)
try fuzzyDeployer.deploy(withFullCheck: true)
fuzzyDeployer.finalizeRuntime()
func testNLFuzzyMapsLihaoToNihao() throws {
let env = try stagedRimeEnvironment(fuzzyPairs: [.nL])
defer { try? env.fileManager.removeItem(at: env.root) }
let fuzzyBridge = OSGRimeBridge(
sharedDataDirectory: shared.path,
userDataDirectory: user.path,
distributionVersion: "tests-fuzzy"
let deployer = OSGRimeBridge(
sharedDataDirectory: env.shared.path,
userDataDirectory: env.user.path,
distributionVersion: "tests-fuzzy-nl"
)
try fuzzyBridge.start()
XCTAssertTrue(fuzzyBridge.selectSchema(TypingInputSchema.fullPinyin.rawValue))
for scalar in "lihao".utf8 {
XCTAssertTrue(fuzzyBridge.processKeyCode(Int32(scalar), modifiers: 0))
}
let fuzzySnapshot = fuzzyBridge.snapshot(withCandidateLimit: 100)
try deployer.deploy(withFullCheck: true)
deployer.finalizeRuntime()
let bridge = OSGRimeBridge(
sharedDataDirectory: env.shared.path,
userDataDirectory: env.user.path,
distributionVersion: "tests-fuzzy-nl"
)
try bridge.start()
defer { bridge.finalizeRuntime() }
XCTAssertTrue(bridge.selectSchema(TypingInputSchema.fullPinyin.rawValue))
type("lihao", on: bridge)
let snapshot = bridge.snapshot(withCandidateLimit: 100)
XCTAssertTrue(
fuzzySnapshot.candidates.contains(where: { $0.text == "你好" }),
"n/l fuzzy candidates: \(fuzzySnapshot.candidates.map(\.text).prefix(20))"
snapshot.candidates.contains(where: { $0.text == "你好" }),
"n/l fuzzy candidates: \(snapshot.candidates.map(\.text).prefix(20))"
)
fuzzyBridge.finalizeRuntime()
}
func testPersonalDictionarySidecarPinsSameCodeCandidates() throws {
@@ -541,7 +536,9 @@ final class LibrimeIntegrationTests: XCTestCase {
)
}
private func stagedRimeEnvironment() throws -> (
private func stagedRimeEnvironment(
fuzzyPairs: Set<PinyinFuzzyPair> = []
) throws -> (
root: URL,
shared: URL,
user: URL,
@@ -569,7 +566,7 @@ final class LibrimeIntegrationTests: XCTestCase {
encoding: .utf8
)
for schema in TypingInputSchema.allCases {
try RimeSchemaGenerator.schema(for: schema, fuzzyPairs: []).write(
try RimeSchemaGenerator.schema(for: schema, fuzzyPairs: fuzzyPairs).write(
to: shared.appendingPathComponent("\(schema.rawValue).schema.yaml"),
atomically: true,
encoding: .utf8