Files
OSGKeyboard/OSGKeyboardExtTests/PinyinNextKeyResolverTests.swift
T
Rocky 2ed16e1fbf feat(typing): improve key hit accuracy and bump to 1.6.1
Add gap-filling hit regions, release-to-commit with slide-to-reselect,
touch intent offset, and full-pinyin next-key bias; cut release 1.6.1 (build 45).
2026-08-05 22:47:20 +08:00

182 lines
5.5 KiB
Swift

// PinyinNextKeyResolverTests.swift
// OSGKeyboard · Ext unit tests
//
// Phase 4: legal next-key sets and weighted ambiguous hit resolution.
import XCTest
@testable import OSGKeyboardShared
final class PinyinNextKeyResolverTests: XCTestCase {
func testZhongPrefixAllowsG() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "zhon",
schema: .fullPinyin,
language: .chinese,
page: .letters
)
XCTAssertEqual(keys, ["g"])
}
func testCompleteZhongAllowsNewSyllableInitials() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "zhong",
schema: .fullPinyin,
language: .chinese,
page: .letters
)
XCTAssertNotNil(keys)
XCTAssertTrue(keys?.contains("g") == true) // zhongguo
XCTAssertTrue(keys?.contains("w") == true)
}
func testMultiSyllableTrailingGAllowsU() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "zhongg",
schema: .fullPinyin,
language: .chinese,
page: .letters
)
XCTAssertTrue(keys?.contains("u") == true) // gu / guo
}
func testNiAllowsExtensionAndNewInitial() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "ni",
schema: .fullPinyin,
language: .chinese,
page: .letters
)
XCTAssertTrue(keys?.contains("a") == true) // nia…
XCTAssertTrue(keys?.contains("h") == true) // nihao
}
func testEmptyRawDisablesBias() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "",
schema: .fullPinyin,
language: .chinese,
page: .letters
)
XCTAssertNil(keys)
}
func testEnglishDisablesBias() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "ni",
schema: .fullPinyin,
language: .english,
page: .letters
)
XCTAssertNil(keys)
}
func testDoublePinyinDisablesBias() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "nihk",
schema: .microsoftDoublePinyin,
language: .chinese,
page: .letters
)
XCTAssertNil(keys)
}
func testNumbersPageDisablesBias() {
let keys = PinyinNextKeyResolver.validNextKeys(
rawInput: "ni",
schema: .fullPinyin,
language: .chinese,
page: .numbers
)
XCTAssertNil(keys)
}
func testHitWeightsBoostLegalLetters() {
let keys = [
TypingKeyHitTarget(
id: "grid.0.0",
label: "G",
visualFrame: .zero,
behavior: .commitOnRelease
),
TypingKeyHitTarget(
id: "grid.0.1",
label: "H",
visualFrame: .zero,
behavior: .commitOnRelease
),
TypingKeyHitTarget(
id: "grid.0.2",
label: "⌫",
visualFrame: .zero,
behavior: .deleteRepeat
)
]
let weights = PinyinNextKeyResolver.hitWeights(for: keys, validNext: ["g"])
XCTAssertEqual(weights["grid.0.0"], KeyHitBiasMetrics.legalBoost)
XCTAssertEqual(weights["grid.0.1"], KeyHitBiasMetrics.illegalShrink)
XCTAssertNil(weights["grid.0.2"])
}
func testWeightedNearestPrefersLegalKeyInGap() {
let left = TypingKeyHitTarget(
id: "L",
label: "F",
visualFrame: CGRect(x: 0, y: 0, width: 40, height: 50),
behavior: .commitOnRelease
)
let right = TypingKeyHitTarget(
id: "R",
label: "G",
visualFrame: CGRect(x: 46, y: 0, width: 40, height: 50),
behavior: .commitOnRelease
)
let plane = left.visualFrame.union(right.visualFrame)
// Shared expanded edge (half of 6pt gap) — both frames contain x=43.
let point = CGPoint(x: 43, y: 25)
let weighted = KeyHitTesting.hitTarget(
at: point,
targets: [left, right],
keyPlaneBounds: plane,
horizontalGap: 6,
verticalGap: 7,
edgeExpansion: 0,
hitWeights: [
"L": KeyHitBiasMetrics.illegalShrink,
"R": KeyHitBiasMetrics.legalBoost
]
)
XCTAssertEqual(weighted?.id, "R")
}
func testClearSingleHitIgnoresBias() {
// Point clearly inside F — must not jump to boosted G.
let left = TypingKeyHitTarget(
id: "L",
label: "F",
visualFrame: CGRect(x: 0, y: 0, width: 40, height: 50),
behavior: .commitOnRelease
)
let right = TypingKeyHitTarget(
id: "R",
label: "G",
visualFrame: CGRect(x: 46, y: 0, width: 40, height: 50),
behavior: .commitOnRelease
)
let plane = left.visualFrame.union(right.visualFrame)
let point = CGPoint(x: 20, y: 25)
let hit = KeyHitTesting.hitTarget(
at: point,
targets: [left, right],
keyPlaneBounds: plane,
horizontalGap: 6,
verticalGap: 7,
edgeExpansion: 0,
hitWeights: [
"L": KeyHitBiasMetrics.illegalShrink,
"R": KeyHitBiasMetrics.legalBoost
]
)
XCTAssertEqual(hit?.id, "L")
}
}