e5a83843db
Add resilient usage analytics, OOBE gateway flows, clipboard semantic ranking, purchase recovery, style learning, and managed current-information search.
87 lines
2.3 KiB
Swift
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
|
|
}
|
|
}
|