31f5937a7f
Reduce extension memory pressure and delivery races while adding richer candidates, tactile feedback, and safer two-level creative polishing.
158 lines
6.0 KiB
Swift
158 lines
6.0 KiB
Swift
// KeyboardSurfaceStateTests.swift
|
||
// OSGKeyboard · Ext unit tests
|
||
|
||
import XCTest
|
||
@testable import OSGKeyboardShared
|
||
|
||
@MainActor
|
||
final class KeyboardSurfaceStateTests: XCTestCase {
|
||
func testRecordingLocksTyping() {
|
||
let state = KeyboardState()
|
||
state.phase = .idle
|
||
XCTAssertTrue(state.canEnterTypingSurface)
|
||
state.phase = .recording
|
||
XCTAssertTrue(state.locksTypingSurface)
|
||
XCTAssertFalse(state.canEnterTypingSurface)
|
||
}
|
||
|
||
func testStandardLayoutHasQwertyTopRow() {
|
||
let layout = StandardTypingLayout()
|
||
let rows = layout.rows(for: .letters, language: .english, shiftActive: false)
|
||
XCTAssertEqual(rows.first, ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"])
|
||
let shifted = layout.rows(for: .letters, language: .english, shiftActive: true)
|
||
XCTAssertEqual(shifted.first?.first, "Q")
|
||
}
|
||
|
||
func testEnglishNumberAndSymbolPagesMatchIOSUS() {
|
||
let layout = StandardTypingLayout()
|
||
XCTAssertEqual(
|
||
layout.rows(for: .numbers, language: .english, shiftActive: false),
|
||
[
|
||
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
|
||
["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""],
|
||
["#+=", ".", ",", "?", "!", "'", "⌫"]
|
||
]
|
||
)
|
||
XCTAssertEqual(
|
||
layout.rows(for: .symbols, language: .english, shiftActive: false),
|
||
[
|
||
["[", "]", "{", "}", "#", "%", "^", "*", "+", "="],
|
||
["_", "\\", "|", "~", "<", ">", "€", "£", "¥", "·"],
|
||
["123", ".", ",", "?", "!", "'", "⌫"]
|
||
]
|
||
)
|
||
}
|
||
|
||
func testChineseNumberAndSymbolPagesMatchIOSSimplified() {
|
||
let layout = StandardTypingLayout()
|
||
XCTAssertEqual(
|
||
layout.rows(for: .numbers, language: .chinese, shiftActive: false),
|
||
[
|
||
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
|
||
["-", "/", ":", ";", "(", ")", "¥", "@", "“", "”"],
|
||
["#+=", "。", ",", "、", "?", "!", ".", "⌫"]
|
||
]
|
||
)
|
||
XCTAssertEqual(
|
||
layout.rows(for: .symbols, language: .chinese, shiftActive: false),
|
||
[
|
||
["【", "】", "「", "」", "#", "%", "^", "*", "+", "="],
|
||
["_", "\\", "|", "~", "《", "》", "€", "£", "¥", "·"],
|
||
["123", "。", ",", "、", "?", "!", ".", "⌫"]
|
||
]
|
||
)
|
||
}
|
||
|
||
func testKeyRowsFollowTypingLanguageOnNumberPage() {
|
||
let typing = TypingSessionController()
|
||
typing.setPage(.numbers)
|
||
XCTAssertEqual(typing.keyRows[1], ["-", "/", ":", ";", "(", ")", "¥", "@", "“", "”"])
|
||
|
||
_ = typing.setLanguage(.english)
|
||
typing.setPage(.numbers)
|
||
XCTAssertEqual(typing.keyRows[1], ["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""])
|
||
}
|
||
|
||
func testVoiceAndTypingChromeShareStableDimensions() {
|
||
XCTAssertEqual(KeyboardChromeLayout.totalHeight, 281)
|
||
XCTAssertEqual(KeyboardChromeLayout.actionKeyHeight, 50)
|
||
XCTAssertEqual(KeyboardChromeLayout.actionKeyCornerRadius, 10)
|
||
XCTAssertEqual(KeyboardChromeLayout.actionKeySpacing, 8)
|
||
XCTAssertEqual(KeyboardChromeLayout.sideActionKeyFraction, 0.2)
|
||
XCTAssertEqual(KeyboardChromeLayout.centerActionKeyFraction, 0.6)
|
||
XCTAssertEqual(KeyboardChromeLayout.horizontalInset, 8)
|
||
XCTAssertEqual(KeyboardChromeLayout.contentMaxWidth, 700)
|
||
|
||
let widths = KeyboardChromeLayout.actionKeyWidths(availableWidth: 374)
|
||
XCTAssertEqual(widths.side, 71.6, accuracy: 0.001)
|
||
XCTAssertEqual(widths.center, 214.8, accuracy: 0.001)
|
||
}
|
||
|
||
func testSharedCapsuleCanSelectSpecificTypingLanguage() {
|
||
let typing = TypingSessionController()
|
||
XCTAssertEqual(typing.language, .chinese)
|
||
|
||
XCTAssertEqual(typing.setLanguage(.english), .none)
|
||
XCTAssertEqual(typing.language, .english)
|
||
|
||
XCTAssertEqual(typing.setLanguage(.chinese), .none)
|
||
XCTAssertEqual(typing.language, .chinese)
|
||
}
|
||
|
||
func testShiftStateProducesUppercaseKeyRows() {
|
||
let typing = TypingSessionController()
|
||
XCTAssertFalse(typing.shiftActive)
|
||
|
||
_ = typing.handleKey("⇧")
|
||
|
||
XCTAssertTrue(typing.shiftActive)
|
||
XCTAssertTrue(typing.isShiftEnabled)
|
||
XCTAssertEqual(typing.keyRows.first?.first, "Q")
|
||
}
|
||
|
||
func testManualShiftSurvivesAutocapitalizationSync() {
|
||
let typing = TypingSessionController()
|
||
// Providers must be set before language switch (which syncs autocap).
|
||
typing.precedingTextProvider = { "hello " } // mid-sentence: auto stays off
|
||
typing.autocapitalizationModeProvider = { .sentences }
|
||
_ = typing.setLanguage(.english)
|
||
XCTAssertFalse(typing.shiftActive)
|
||
|
||
_ = typing.handleKey("⇧")
|
||
XCTAssertTrue(typing.shiftActive)
|
||
|
||
typing.syncAutocapitalization()
|
||
XCTAssertTrue(typing.shiftActive, "manual one-shot must outrank autocap sync")
|
||
XCTAssertEqual(typing.keyRows.first?.first, "Q")
|
||
}
|
||
|
||
func testShiftHoldTypesUppercaseWithoutEnteringCapsLock() {
|
||
let typing = TypingSessionController()
|
||
_ = typing.setLanguage(.english)
|
||
typing.precedingTextProvider = { "hello " }
|
||
typing.autocapitalizationModeProvider = { .sentences }
|
||
|
||
typing.beginShiftHold()
|
||
XCTAssertTrue(typing.shiftHeld)
|
||
XCTAssertEqual(typing.keyRows.first?.first, "Q")
|
||
|
||
_ = typing.handleKey("S")
|
||
_ = typing.handleKey("m")
|
||
XCTAssertFalse(typing.capsLock)
|
||
|
||
typing.endShiftHold()
|
||
XCTAssertFalse(typing.shiftHeld)
|
||
XCTAssertFalse(typing.capsLock)
|
||
XCTAssertFalse(typing.shiftActive)
|
||
}
|
||
|
||
func testShiftHoldWithoutTypingActsAsTap() {
|
||
let typing = TypingSessionController()
|
||
typing.beginShiftHold()
|
||
typing.endShiftHold()
|
||
XCTAssertTrue(typing.shiftActive)
|
||
XCTAssertFalse(typing.shiftHeld)
|
||
XCTAssertFalse(typing.capsLock)
|
||
}
|
||
}
|