Files
OSGKeyboard/OSGKeyboardExtTests/KeyboardUsageTypingTests.swift
Rocky e5a83843db Expand onboarding and adaptive keyboard intelligence
Add resilient usage analytics, OOBE gateway flows, clipboard semantic ranking, purchase recovery, style learning, and managed current-information search.
2026-08-22 16:33:18 +08:00

87 lines
2.3 KiB
Swift

// KeyboardUsageTypingTests.swift
// OSGKeyboardExtTests
//
// Chinese preedit remains in the IME; only committed candidate text is counted.
@testable import OSGKeyboardShared
import XCTest
@MainActor
final class KeyboardUsageTypingTests: XCTestCase {
func testPinyinCompositionDoesNotCountLatinBeforeHanCommit() {
let engine = KeyboardUsageRimeStub()
let typing = TypingSessionController(engine: { engine })
let first = typing.handleKey("n")
let second = typing.handleKey("i")
XCTAssertEqual(first, .none)
XCTAssertEqual(second, .none)
XCTAssertEqual(engine.composition.rawInput, "ni")
let committed = typing.handleSpace()
XCTAssertEqual(committed, .insert("你好"))
let counts = KeyboardUsageCharacterClassifier.classify(committed.text)
XCTAssertEqual(counts.chinese, 2)
XCTAssertEqual(counts.english, 0)
XCTAssertEqual(counts.other, 0)
}
}
@MainActor
private final class KeyboardUsageRimeStub: RimeEngineBridging {
private(set) 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? {
composition.rawInput.append(character)
composition.preedit = composition.rawInput
return nil
}
func processBackspace() -> String? {
if !composition.rawInput.isEmpty {
composition.rawInput.removeLast()
}
composition.preedit = composition.rawInput
return nil
}
func processSpace() -> String? {
composition = .empty
return "你好"
}
func processReturn() -> String? {
processSpace()
}
func selectCandidate(at index: Int) -> String {
processSpace() ?? ""
}
func flushPreedit() -> String {
let raw = composition.rawInput
composition = .empty
return raw
}
func clearComposition() {
composition = .empty
}
}