feat(keyboard): improve typing, voice flow, and polish reliability
Reduce extension memory pressure and delivery races while adding richer candidates, tactile feedback, and safer two-level creative polishing.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
// AlibabaVocabularySyncTests.swift
|
||||
// OSGKeyboardTests
|
||||
|
||||
import XCTest
|
||||
@testable import OSGKeyboardShared
|
||||
@testable import OSGKeyboardHostSupport
|
||||
|
||||
final class AlibabaVocabularySyncTests: XCTestCase {
|
||||
|
||||
private var suiteName: String!
|
||||
private var defaults: UserDefaults!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
suiteName = "group.com.osgkeyboard.tests.alibaba-vocab.\(UUID().uuidString)"
|
||||
defaults = UserDefaults(suiteName: suiteName)!
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
StubURLProtocol.reset()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
StubURLProtocol.reset()
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
defaults = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testEnsureVocabularyIDUsesCacheWhenFingerprintMatches() async throws {
|
||||
let dict = PersonalDictionary(entries: [
|
||||
PersonalDictionary.Entry(term: "热词", category: .custom, source: .manual),
|
||||
])
|
||||
defaults.set("vocab-cached", forKey: AlibabaVocabularySync.Keys.vocabularyId)
|
||||
defaults.set(
|
||||
dict.vocabularySyncFingerprint(),
|
||||
forKey: AlibabaVocabularySync.Keys.fingerprint
|
||||
)
|
||||
|
||||
let id = try await AlibabaVocabularySync.ensureVocabularyID(
|
||||
dictionary: dict,
|
||||
apiKey: "sk-test",
|
||||
defaults: defaults,
|
||||
session: StubURLProtocol.makeEphemeralSession()
|
||||
)
|
||||
XCTAssertEqual(id, "vocab-cached")
|
||||
XCTAssertNil(StubURLProtocolStorage.lastRequest, "cache hit must not hit network")
|
||||
}
|
||||
|
||||
func testEnsureVocabularyIDCreatesAndCachesOnMiss() async throws {
|
||||
StubURLProtocolStorage.config = (
|
||||
200,
|
||||
Data(#"{"output":{"vocabulary_id":"vocab-abc123"}}"#.utf8)
|
||||
)
|
||||
let dict = PersonalDictionary(entries: [
|
||||
PersonalDictionary.Entry(term: "新词", category: .custom, source: .manual),
|
||||
])
|
||||
let id = try await AlibabaVocabularySync.ensureVocabularyID(
|
||||
dictionary: dict,
|
||||
apiKey: "sk-test",
|
||||
defaults: defaults,
|
||||
session: StubURLProtocol.makeEphemeralSession()
|
||||
)
|
||||
XCTAssertEqual(id, "vocab-abc123")
|
||||
XCTAssertEqual(
|
||||
defaults.string(forKey: AlibabaVocabularySync.Keys.vocabularyId),
|
||||
"vocab-abc123"
|
||||
)
|
||||
XCTAssertEqual(
|
||||
defaults.string(forKey: AlibabaVocabularySync.Keys.fingerprint),
|
||||
dict.vocabularySyncFingerprint()
|
||||
)
|
||||
XCTAssertNotNil(StubURLProtocolStorage.lastRequest)
|
||||
}
|
||||
|
||||
func testEnsureVocabularyIDReturnsNilOnlyWhenNoHotwordEntries() async throws {
|
||||
// `effectiveEntries` always includes system term "OSGKeyboard", so a
|
||||
// user-empty dictionary still syncs. Clear-cache is for truly empty
|
||||
// hotword lists after filtering — exercise `clearCache` directly.
|
||||
defaults.set("stale-id", forKey: AlibabaVocabularySync.Keys.vocabularyId)
|
||||
defaults.set("stale-fp", forKey: AlibabaVocabularySync.Keys.fingerprint)
|
||||
AlibabaVocabularySync.clearCache(defaults: defaults)
|
||||
XCTAssertNil(defaults.string(forKey: AlibabaVocabularySync.Keys.vocabularyId))
|
||||
XCTAssertNil(defaults.string(forKey: AlibabaVocabularySync.Keys.fingerprint))
|
||||
}
|
||||
|
||||
func testEnsureVocabularyIDCreatesForSystemEntriesWhenUserDictionaryEmpty() async throws {
|
||||
StubURLProtocolStorage.config = (
|
||||
200,
|
||||
Data(#"{"output":{"vocabulary_id":"vocab-system"}}"#.utf8)
|
||||
)
|
||||
let id = try await AlibabaVocabularySync.ensureVocabularyID(
|
||||
dictionary: PersonalDictionary(),
|
||||
apiKey: "sk-test",
|
||||
defaults: defaults,
|
||||
session: StubURLProtocol.makeEphemeralSession()
|
||||
)
|
||||
XCTAssertEqual(id, "vocab-system")
|
||||
XCTAssertNotNil(StubURLProtocolStorage.lastRequest)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user