MainAssembly // Implementing Unit Tests.
* Further unit tests will be implemented later according to other necessities.
This commit is contained in:
parent
f81e6837b8
commit
136e8088be
|
@ -0,0 +1,17 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import Foundation
|
||||
|
||||
let mapKeyCodesANSIForTests: [String: UInt16] = [
|
||||
"1": 18, "2": 19, "3": 20, "4": 21, "5": 23, "6": 22, "7": 26, "8": 28, "9": 25, "0": 29, "-": 27,
|
||||
"=": 24, "q": 12, "w": 13, "e": 14, "r": 15, "t": 17, "y": 16, "u": 32, "i": 34, "o": 31, "p": 35,
|
||||
"[": 33, "]": 30, "\\": 42, "a": 0, "s": 1, "d": 2, "f": 3, "g": 5, "h": 4, "j": 38, "k": 40,
|
||||
"l": 37, ";": 41, "'": 39, "z": 6, "x": 7, "c": 8, "v": 9, "b": 11, "n": 45, "m": 46, ",": 43,
|
||||
".": 47, "/": 44,
|
||||
]
|
|
@ -0,0 +1,65 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import LangModelAssembly
|
||||
import MainAssembly
|
||||
|
||||
// MARK: - Converting Sample String Data to LMCoreJSON Instance.
|
||||
|
||||
extension String {
|
||||
func toDictMap(swapKeyValue: Bool = false, encrypt: Bool = false) -> [String: [String]] {
|
||||
var theDict = [String: [String]]()
|
||||
enumerateLines { currentLine, _ in
|
||||
if currentLine.isEmpty || currentLine.hasPrefix("#") {
|
||||
return
|
||||
}
|
||||
let linestream = currentLine.split(separator: " ")
|
||||
let col0 = String(linestream[0])
|
||||
let col1 = String(linestream[1])
|
||||
let col2: Double? = Double(linestream[2])
|
||||
var key = swapKeyValue ? col1 : col0
|
||||
if encrypt {
|
||||
key = vChewingLM.LMCoreJSON.cnvPhonabetToASCII(key)
|
||||
}
|
||||
var storedValue = swapKeyValue ? col0 : col1
|
||||
if let col2 = col2 {
|
||||
storedValue.insert(contentsOf: "\(col2.description) ", at: storedValue.startIndex)
|
||||
}
|
||||
theDict[key, default: []].append(storedValue)
|
||||
}
|
||||
return theDict
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Allow LMInstantiator to Load Test Data.
|
||||
|
||||
extension vChewingLM.LMInstantiator {
|
||||
static func construct(
|
||||
isCHS: Bool = false, completionHandler: @escaping (_ this: vChewingLM.LMInstantiator) -> Void
|
||||
) -> vChewingLM.LMInstantiator {
|
||||
let this = vChewingLM.LMInstantiator(isCHS: isCHS)
|
||||
completionHandler(this)
|
||||
return this
|
||||
}
|
||||
|
||||
func loadTestData() {
|
||||
resetFactoryJSONModels()
|
||||
loadLanguageModel(
|
||||
json: (
|
||||
dict: strSampleDataFactoryCore.toDictMap(swapKeyValue: false, encrypt: true),
|
||||
path: "/dev/null"
|
||||
)
|
||||
)
|
||||
loadSymbolData(
|
||||
json: (
|
||||
dict: strSampleDataFactorySymbol.toDictMap(swapKeyValue: true, encrypt: true),
|
||||
path: "/dev/null"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import MainAssembly
|
||||
|
||||
public let strSampleDataFactorySymbol = #"""
|
||||
ㄈㄥ 🐝 -11
|
||||
ㄇㄧˋ-ㄈㄥ 🐝 -11
|
||||
"""#
|
||||
|
||||
public let strSampleDataFactoryCore = #"""
|
||||
#
|
||||
# 下述詞頻資料取自 libTaBE 資料庫 (http://sourceforge.net/projects/libtabe/)
|
||||
# (2002 最終版). 該專案於 1999 年由 Pai-Hsiang Hsiao 發起、以 BSD 授權發行。
|
||||
#
|
||||
ㄇㄧˋ-ㄈㄥ 蜜蜂 -3.6231
|
||||
ㄇㄧˋ 蜜 -4.6231
|
||||
ㄈㄥ 蜂 -4.6231
|
||||
ㄋㄧˇ 你 -6.000000 // Non-LibTaBE
|
||||
ㄓㄜˋ 這 -6.000000 // Non-LibTaBE
|
||||
ㄧㄤˋ 樣 -6.000000 // Non-LibTaBE
|
||||
ㄙ 絲 -9.495858
|
||||
ㄙ 思 -9.006414
|
||||
ㄙ 私 -99.000000
|
||||
ㄙ 斯 -8.091803
|
||||
ㄙ 司 -99.000000
|
||||
ㄙ 嘶 -13.513987
|
||||
ㄙ 撕 -12.259095
|
||||
ㄍㄠ 高 -7.171551
|
||||
ㄎㄜ 顆 -10.574273
|
||||
ㄎㄜ 棵 -11.504072
|
||||
ㄎㄜ 刻 -10.450457
|
||||
ㄎㄜ 科 -7.171052
|
||||
ㄎㄜ 柯 -99.000000
|
||||
ㄍㄠ 膏 -11.928720
|
||||
ㄍㄠ 篙 -13.624335
|
||||
ㄍㄠ 糕 -12.390804
|
||||
ㄉㄜ˙ 的 -3.516024
|
||||
ㄉㄧˊ 的 -3.516024
|
||||
ㄉㄧˋ 的 -3.516024
|
||||
ㄓㄨㄥ 中 -5.809297
|
||||
ㄉㄜ˙ 得 -7.427179
|
||||
ㄍㄨㄥ 共 -8.381971
|
||||
ㄍㄨㄥ 供 -8.501463
|
||||
ㄐㄧˋ 既 -99.000000
|
||||
ㄐㄧㄣ 今 -8.034095
|
||||
ㄍㄨㄥ 紅 -8.858181
|
||||
ㄐㄧˋ 際 -7.608341
|
||||
ㄐㄧˋ 季 -99.000000
|
||||
ㄐㄧㄣ 金 -7.290109
|
||||
ㄐㄧˋ 騎 -10.939895
|
||||
ㄓㄨㄥ 終 -99.000000
|
||||
ㄐㄧˋ 記 -99.000000
|
||||
ㄐㄧˋ 寄 -99.000000
|
||||
ㄐㄧㄣ 斤 -99.000000
|
||||
ㄐㄧˋ 繼 -9.715317
|
||||
ㄐㄧˋ 計 -7.926683
|
||||
ㄐㄧˋ 暨 -8.373022
|
||||
ㄓㄨㄥ 鐘 -9.877580
|
||||
ㄐㄧㄣ 禁 -10.711079
|
||||
ㄍㄨㄥ 公 -7.877973
|
||||
ㄍㄨㄥ 工 -7.822167
|
||||
ㄍㄨㄥ 攻 -99.000000
|
||||
ㄍㄨㄥ 功 -99.000000
|
||||
ㄍㄨㄥ 宮 -99.000000
|
||||
ㄓㄨㄥ 鍾 -9.685671
|
||||
ㄐㄧˋ 繫 -10.425662
|
||||
ㄍㄨㄥ 弓 -99.000000
|
||||
ㄍㄨㄥ 恭 -99.000000
|
||||
ㄐㄧˋ 劑 -8.888722
|
||||
ㄐㄧˋ 祭 -10.204425
|
||||
ㄐㄧㄣ 浸 -11.378321
|
||||
ㄓㄨㄥ 盅 -99.000000
|
||||
ㄐㄧˋ 忌 -99.000000
|
||||
ㄐㄧˋ 技 -8.450826
|
||||
ㄐㄧㄣ 筋 -11.074890
|
||||
ㄍㄨㄥ 躬 -99.000000
|
||||
ㄐㄧˋ 冀 -12.045357
|
||||
ㄓㄨㄥ 忠 -99.000000
|
||||
ㄐㄧˋ 妓 -99.000000
|
||||
ㄐㄧˋ 濟 -9.517568
|
||||
ㄐㄧˋ 薊 -12.021587
|
||||
ㄐㄧㄣ 巾 -99.000000
|
||||
ㄐㄧㄣ 襟 -12.784206
|
||||
ㄋㄧㄢˊ 年 -6.086515
|
||||
ㄐㄧㄤˇ 講 -9.164384
|
||||
ㄐㄧㄤˇ 獎 -8.690941
|
||||
ㄐㄧㄤˇ 蔣 -10.127828
|
||||
ㄋㄧㄢˊ 黏 -11.336864
|
||||
ㄋㄧㄢˊ 粘 -11.285740
|
||||
ㄐㄧㄤˇ 槳 -12.492933
|
||||
ㄍㄨㄥ-ㄙ 公司 -6.299461
|
||||
ㄎㄜ-ㄐㄧˋ 科技 -6.736613
|
||||
ㄐㄧˋ-ㄍㄨㄥ 濟公 -13.336653
|
||||
ㄐㄧㄤˇ-ㄐㄧㄣ 獎金 -10.344678
|
||||
ㄋㄧㄢˊ-ㄓㄨㄥ 年終 -11.668947
|
||||
ㄋㄧㄢˊ-ㄓㄨㄥ 年中 -11.373044
|
||||
ㄍㄠ-ㄎㄜ-ㄐㄧˋ 高科技 -9.842421
|
||||
ㄓㄜˋ-ㄧㄤˋ 這樣 -6.000000 // Non-LibTaBE
|
||||
ㄋㄧˇ-ㄓㄜˋ 你這 -9.000000 // Non-LibTaBE
|
||||
ㄎㄜ-ㄎㄜ 顆顆 -8.000000 // Non-LibTaBE
|
||||
ㄐㄧㄠˋ 教 -3.676169
|
||||
ㄐㄧㄠˋ 較 -3.24869962
|
||||
ㄐㄧㄠˋ-ㄩˋ 教育 -3.32220565
|
||||
ㄩˋ 育 -3.30192952
|
||||
|
||||
"""#
|
|
@ -0,0 +1,119 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import InputMethodKit
|
||||
|
||||
class FakeClient: NSObject, IMKTextInput {
|
||||
var attributedString: NSMutableAttributedString = .init(string: "")
|
||||
var cursor = 0 {
|
||||
didSet {
|
||||
cursor = max(0, min(cursor, attributedString.length))
|
||||
}
|
||||
}
|
||||
|
||||
var selectedRangeStored: NSRange = .notFound
|
||||
var markedRangeStored: NSRange = .notFound
|
||||
var markedText: NSAttributedString = .init(string: "")
|
||||
|
||||
func toString() -> String {
|
||||
attributedString.string
|
||||
}
|
||||
|
||||
func clear() {
|
||||
cursor = 0
|
||||
attributedString = .init()
|
||||
}
|
||||
|
||||
func insertText(_ string: Any!, replacementRange: NSRange) {
|
||||
guard let string = string as? String else { return }
|
||||
var insertionPoint = replacementRange.location
|
||||
if insertionPoint == NSNotFound {
|
||||
insertionPoint = cursor
|
||||
}
|
||||
cursor = insertionPoint
|
||||
attributedString.insert(.init(string: string), at: cursor)
|
||||
cursor += string.utf16.count
|
||||
}
|
||||
|
||||
func setMarkedText(_ string: Any!, selectionRange _: NSRange, replacementRange: NSRange) {
|
||||
markedText = string as? NSAttributedString ?? .init(string: string as? String ?? "")
|
||||
var insertionPoint = replacementRange.location
|
||||
if insertionPoint == NSNotFound {
|
||||
insertionPoint = cursor
|
||||
}
|
||||
cursor = insertionPoint
|
||||
}
|
||||
|
||||
func selectedRange() -> NSRange {
|
||||
NSIntersectionRange(selectedRangeStored, .init(location: 0, length: attributedString.length))
|
||||
}
|
||||
|
||||
func markedRange() -> NSRange {
|
||||
NSIntersectionRange(markedRangeStored, .init(location: 0, length: attributedString.length))
|
||||
}
|
||||
|
||||
func attributedSubstring(from range: NSRange) -> NSAttributedString! {
|
||||
let usableRange = NSIntersectionRange(range, .init(location: 0, length: attributedString.length))
|
||||
return attributedString.attributedSubstring(from: usableRange)
|
||||
}
|
||||
|
||||
func length() -> Int {
|
||||
attributedString.length
|
||||
}
|
||||
|
||||
func characterIndex(for _: NSPoint, tracking _: IMKLocationToOffsetMappingMode, inMarkedRange _: UnsafeMutablePointer<ObjCBool>!) -> Int {
|
||||
cursor
|
||||
}
|
||||
|
||||
func attributes(forCharacterIndex _: Int, lineHeightRectangle _: UnsafeMutablePointer<NSRect>!) -> [AnyHashable: Any]! {
|
||||
[:]
|
||||
}
|
||||
|
||||
func validAttributesForMarkedText() -> [Any]! {
|
||||
[]
|
||||
}
|
||||
|
||||
func overrideKeyboard(withKeyboardNamed keyboardUniqueName: String!) {
|
||||
_ = keyboardUniqueName
|
||||
}
|
||||
|
||||
func selectMode(_ modeIdentifier: String!) {
|
||||
_ = modeIdentifier
|
||||
}
|
||||
|
||||
func supportsUnicode() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
func bundleIdentifier() -> String {
|
||||
"org.atelierInmu.vChewing.MainAssembly.UnitTests.MockedClient"
|
||||
}
|
||||
|
||||
func windowLevel() -> CGWindowLevel {
|
||||
CGShieldingWindowLevel()
|
||||
}
|
||||
|
||||
func supportsProperty(_: TSMDocumentPropertyTag) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
func uniqueClientIdentifierString() -> String {
|
||||
bundleIdentifier()
|
||||
}
|
||||
|
||||
func string(from range: NSRange, actualRange: NSRangePointer!) -> String! {
|
||||
let actualNSRange = actualRange.move()
|
||||
var usableRange = NSIntersectionRange(actualNSRange, range)
|
||||
usableRange = NSIntersectionRange(usableRange, .init(location: 0, length: attributedString.length))
|
||||
return attributedString.attributedSubstring(from: usableRange).string
|
||||
}
|
||||
|
||||
func firstRect(forCharacterRange _: NSRange, actualRange _: NSRangePointer!) -> NSRect {
|
||||
.zero
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import AppKit
|
||||
|
||||
public extension NSEvent {
|
||||
struct KeyEventData {
|
||||
public var type: EventType = .keyDown
|
||||
public var flags: ModifierFlags
|
||||
public var chars: String
|
||||
public var charsSansModifiers: String
|
||||
public var keyCode: UInt16
|
||||
|
||||
public init(type: EventType = .keyDown, flags: ModifierFlags = [], chars: String, charsSansModifiers: String? = nil, keyCode: UInt16? = nil) {
|
||||
self.type = type
|
||||
self.flags = flags
|
||||
self.chars = chars
|
||||
self.charsSansModifiers = charsSansModifiers ?? chars
|
||||
self.keyCode = keyCode ?? mapKeyCodesANSIForTests[chars] ?? 65535
|
||||
}
|
||||
|
||||
public func toEvents(paired: Bool = false) -> [NSEvent] {
|
||||
NSEvent.keyEvents(data: self, paired: paired)
|
||||
}
|
||||
|
||||
public var asPairedEvents: [NSEvent] {
|
||||
NSEvent.keyEvents(data: self, paired: true)
|
||||
}
|
||||
|
||||
public var asEvent: NSEvent? {
|
||||
NSEvent.keyEvent(data: self)
|
||||
}
|
||||
}
|
||||
|
||||
static func keyEvents(data: KeyEventData, paired: Bool = false) -> [NSEvent] {
|
||||
var resultArray = [NSEvent]()
|
||||
if let eventA: NSEvent = Self.keyEvent(data: data) {
|
||||
resultArray.append(eventA)
|
||||
if paired, eventA.type == .keyDown,
|
||||
let eventB = eventA.reinitiate(with: .keyUp, characters: nil, charactersIgnoringModifiers: nil)
|
||||
{
|
||||
resultArray.append(eventB)
|
||||
}
|
||||
}
|
||||
return resultArray
|
||||
}
|
||||
|
||||
static func keyEvent(data: KeyEventData) -> NSEvent? {
|
||||
Self.keyEventSimple(type: data.type, flags: data.flags, chars: data.chars, charsSansModifiers: data.charsSansModifiers, keyCode: data.keyCode)
|
||||
}
|
||||
|
||||
static func keyEventSimple(type: EventType, flags: ModifierFlags, chars: String, charsSansModifiers: String? = nil, keyCode: UInt16) -> NSEvent? {
|
||||
Self.keyEvent(
|
||||
with: type, location: .zero, modifierFlags: flags, timestamp: .init(),
|
||||
windowNumber: 0, context: nil, characters: chars,
|
||||
charactersIgnoringModifiers: charsSansModifiers ?? chars, isARepeat: false, keyCode: keyCode
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
@testable import MainAssembly
|
||||
import XCTest
|
||||
|
||||
final class MainAssemblyTests: XCTestCase {
|
||||
override func setUpWithError() throws {
|
||||
UserDefaults.unitTests = .init(suiteName: "org.atelierInmu.vChewing.MainAssembly.UnitTests")
|
||||
UserDefaults.pendingUnitTests = true
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
UserDefaults.unitTests?.removeSuite(named: "org.atelierInmu.vChewing.MainAssembly.UnitTests")
|
||||
}
|
||||
|
||||
func testExample() throws {}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CocoaExtension
|
||||
import InputMethodKit
|
||||
import LangModelAssembly
|
||||
@testable import MainAssembly
|
||||
import Shared
|
||||
import XCTest
|
||||
|
||||
let testClient = FakeClient()
|
||||
|
||||
public extension SessionCtl {
|
||||
override func client() -> (IMKTextInput & NSObjectProtocol)! { testClient }
|
||||
}
|
||||
|
||||
func vCTestLog(_ str: String) {
|
||||
print("[VCLOG] \(str)")
|
||||
}
|
||||
|
||||
/// 威注音輸入法的控制模組單元測試。
|
||||
/// - Remark: 歡迎來到威注音輸入法的控制模組單元測試。
|
||||
///
|
||||
/// 不似其他同類產品的單元測試,威注音輸入法的單元測試
|
||||
/// 會盡量模擬使用者的日常打字擊鍵行為與使用方法。
|
||||
/// 單元測試的內容可能算不上豐富,但會隨著今後來自各位
|
||||
/// 使用者所提報的故障、而繼續逐漸擴大測試範圍。
|
||||
///
|
||||
/// 該單元測試使用獨立的語彙資料,因此會在選字時的候選字
|
||||
/// 順序等方面與威注音輸入法實際使用時的體驗有差異。
|
||||
class MainAssemblyTests: XCTestCase {
|
||||
let testUOM = vChewingLM.LMUserOverride(dataURL: .init(fileURLWithPath: "/dev/null"))
|
||||
var testLM = vChewingLM.LMInstantiator.construct { $0.loadTestData() }
|
||||
static let testServer = IMKServer(name: "org.atelierInmu.vChewing.MainAssembly.UnitTests_Connection", bundleIdentifier: "org.atelierInmu.vChewing.MainAssembly.UnitTests")
|
||||
|
||||
static var _testHandler: InputHandler?
|
||||
var testHandler: InputHandler {
|
||||
let result = Self._testHandler ?? InputHandler(lm: testLM, uom: testUOM, pref: PrefMgr.shared)
|
||||
if Self._testHandler == nil { Self._testHandler = result }
|
||||
return result
|
||||
}
|
||||
|
||||
static var _testSession: SessionCtl?
|
||||
var testSession: SessionCtl {
|
||||
guard let session = Self._testSession ?? SessionCtl(server: Self.testServer, delegate: testHandler, client: testClient) else {
|
||||
fatalError("Session failed from booting!")
|
||||
}
|
||||
if Self._testSession == nil { Self._testSession = session }
|
||||
return session
|
||||
}
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
let dataArrowLeft = NSEvent.KeyEventData(chars: NSEvent.SpecialKey.leftArrow.unicodeScalar.description, keyCode: KeyCode.kLeftArrow.rawValue)
|
||||
let dataArrowDown = NSEvent.KeyEventData(chars: NSEvent.SpecialKey.downArrow.unicodeScalar.description, keyCode: KeyCode.kDownArrow.rawValue)
|
||||
let dataEnterReturn = NSEvent.KeyEventData(chars: NSEvent.SpecialKey.carriageReturn.unicodeScalar.description, keyCode: KeyCode.kLineFeed.rawValue)
|
||||
let dataTab = NSEvent.KeyEventData(chars: NSEvent.SpecialKey.tab.unicodeScalar.description, keyCode: KeyCode.kTab.rawValue)
|
||||
|
||||
func clearTestUOM() {
|
||||
testUOM.clearData(withURL: URL(fileURLWithPath: "/dev/null"))
|
||||
}
|
||||
|
||||
func typeSentenceOrCandidates(_ sequence: String) {
|
||||
if !([.ofEmpty, .ofInputting].contains(testSession.state.type) || testSession.state.isCandidateContainer) { return }
|
||||
let typingSequence: [NSEvent] = sequence.compactMap { charRAW in
|
||||
var finalArray = [NSEvent]()
|
||||
let char = charRAW.description
|
||||
let keyEventData = NSEvent.KeyEventData(chars: char)
|
||||
finalArray.append(contentsOf: keyEventData.asPairedEvents)
|
||||
return finalArray
|
||||
}.flatMap { $0 }
|
||||
typingSequence.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preparing Unit Tests.
|
||||
|
||||
override func setUpWithError() throws {
|
||||
UserDefaults.unitTests = .init(suiteName: "org.atelierInmu.vChewing.MainAssembly.UnitTests")
|
||||
UserDef.resetAll()
|
||||
UserDefaults.pendingUnitTests = true
|
||||
testSession.activateServer(testClient)
|
||||
testSession.isActivated = true
|
||||
testSession.inputHandler = testHandler
|
||||
testHandler.delegate = testSession
|
||||
testSession.syncBaseLMPrefs()
|
||||
testClient.clear()
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
testSession.switchState(IMEState.ofAbortion())
|
||||
UserDefaults.unitTests?.removeSuite(named: "org.atelierInmu.vChewing.MainAssembly.UnitTests")
|
||||
UserDef.resetAll()
|
||||
testClient.clear()
|
||||
testSession.deactivateServer(testClient)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CocoaExtension
|
||||
import InputMethodKit
|
||||
import LangModelAssembly
|
||||
@testable import MainAssembly
|
||||
import Shared
|
||||
import XCTest
|
||||
|
||||
extension MainAssemblyTests {
|
||||
func test001_ClientTest_BundleIdentifier() throws {
|
||||
guard let identifier = testSession.client()?.bundleIdentifier() else {
|
||||
fatalError("致命錯誤:客體唯一標幟碼無效。")
|
||||
}
|
||||
vCTestLog("測試客體唯一標幟碼:\(identifier)")
|
||||
}
|
||||
|
||||
func test002_ClientTest_TextInsertion() throws {
|
||||
testClient.clear()
|
||||
let testString = UUID().uuidString
|
||||
testSession.client().insertText(testString, replacementRange: .notFound)
|
||||
XCTAssertEqual(testClient.attributedString.string, testString)
|
||||
testClient.clear()
|
||||
}
|
||||
|
||||
// MARK: - Input Handler Tests.
|
||||
|
||||
/// 測試基本的打字組句(不是ㄅ半注音)。
|
||||
func test101_InputHandler_BasicSentenceComposition() throws {
|
||||
PrefMgr.shared.useSCPCTypingMode = false
|
||||
clearTestUOM()
|
||||
vCTestLog("測試組句:高科技公司的年中獎金")
|
||||
testSession.resetInputHandler(forceComposerCleanup: true)
|
||||
typeSentenceOrCandidates("el dk ru4ej/ n 2k7su065j/ ru;3rup ")
|
||||
let resultText1 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText1)")
|
||||
XCTAssertEqual(resultText1, "高科技公司的年中獎金")
|
||||
}
|
||||
|
||||
/// 測試基本的逐字選字(ㄅ半注音)。
|
||||
func test102_InputHandler_BasicSCPCTyping() throws {
|
||||
PrefMgr.shared.useSCPCTypingMode = true
|
||||
clearTestUOM()
|
||||
vCTestLog("測試逐字選字:高科技公司的年中獎金")
|
||||
testSession.resetInputHandler(forceComposerCleanup: true)
|
||||
typeSentenceOrCandidates("el dk ru44ej/ 2n ")
|
||||
dataArrowDown.asPairedEvents.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
typeSentenceOrCandidates("12k7su065j/ ru;3rup ")
|
||||
XCTAssert(testSession.candidateUI?.visible ?? false)
|
||||
dataEnterReturn.asPairedEvents.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
let resultText1 = testClient.toString()
|
||||
vCTestLog("- // 組字結果:\(resultText1)")
|
||||
XCTAssertEqual(resultText1, "高科技公司的年中獎金")
|
||||
testClient.clear()
|
||||
}
|
||||
|
||||
/// 測試就地輪替候選字。
|
||||
func test103_InputHandler_RevolvingCandidates() throws {
|
||||
PrefMgr.shared.useSCPCTypingMode = false
|
||||
PrefMgr.shared.useRearCursorMode = false
|
||||
clearTestUOM()
|
||||
|
||||
testSession.resetInputHandler(forceComposerCleanup: true)
|
||||
typeSentenceOrCandidates("el dk ru4ej/ n 2k7su065j/ ru;3rup ")
|
||||
|
||||
// Testing Inline Candidate Revolver.
|
||||
|
||||
vCTestLog("測試就地輪替候選字:高科技公司的年中獎金 -> 高科技公司的年終獎金")
|
||||
|
||||
[dataArrowLeft, dataArrowLeft].map(\.asPairedEvents).flatMap { $0 }.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
|
||||
dataTab.asPairedEvents.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
let resultText2 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText2)")
|
||||
XCTAssertEqual(resultText2, "高科技公司的年終獎金")
|
||||
}
|
||||
|
||||
/// 測試藉由選字窗選字、且同時測試半衰記憶模組在此情況下的記憶資料生成與適用情況。
|
||||
/// - Remark: 這裡順便測試一下「在選字窗選字後自動推進游標」這個有被預設啟用的功能。
|
||||
func test104_InputHandler_ManualCandidateSelectionAndUOM() throws {
|
||||
PrefMgr.shared.useSCPCTypingMode = false
|
||||
PrefMgr.shared.useRearCursorMode = false
|
||||
PrefMgr.shared.moveCursorAfterSelectingCandidate = true
|
||||
clearTestUOM()
|
||||
|
||||
var sequenceChars = "el dk ru4ej/ n 2k7su065j/ ru;3rup "
|
||||
|
||||
testSession.resetInputHandler(forceComposerCleanup: true)
|
||||
typeSentenceOrCandidates(sequenceChars)
|
||||
|
||||
// Testing Manual Candidate Selection, UOM Observation, and Post-Candidate-Selection Cursor Jumping.
|
||||
|
||||
vCTestLog("測試選字窗選字:高科技公司的年終獎金 -> 高科技公司的年中獎金")
|
||||
let keyOne = NSEvent.KeyEventData(chars: "1")
|
||||
[dataArrowDown, keyOne].map(\.asPairedEvents).flatMap { $0 }.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
let resultText3 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText3)")
|
||||
XCTAssertEqual(resultText3, "高科技公司的年中獎金")
|
||||
XCTAssertEqual(testHandler.compositor.cursor, 10)
|
||||
|
||||
// Continuing UOM Tests (in the Current Context).
|
||||
|
||||
vCTestLog("測試半衰記憶的適用範圍:「年終」的記憶應僅對下述給定上下文情形生效。")
|
||||
vCTestLog("- 該給定上下文情形為「((ㄍㄨㄥ-ㄙ,公司),(ㄉㄜ˙,的),ㄋㄧㄢˊ-ㄓㄨㄥ)」。")
|
||||
clearTestUOM()
|
||||
let keyTwo = NSEvent.KeyEventData(chars: "2")
|
||||
[dataArrowLeft, dataArrowLeft, dataArrowDown, keyTwo].map(\.asPairedEvents).flatMap { $0 }.forEach { theEvent in
|
||||
let dismissed = !testSession.handle(theEvent, client: testClient)
|
||||
if theEvent.type == .keyDown { XCTAssertFalse(dismissed) }
|
||||
}
|
||||
let resultText4 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText4)")
|
||||
XCTAssertEqual(resultText4, "高科技公司的年終獎金")
|
||||
|
||||
vCTestLog("- 清空組字區,重新打剛才那句話來測試。")
|
||||
testSession.switchState(IMEState.ofAbortion())
|
||||
typeSentenceOrCandidates(sequenceChars)
|
||||
let resultText5 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText5)")
|
||||
XCTAssertEqual(resultText5, "高科技公司的年終獎金")
|
||||
vCTestLog("- 已成功證實「年終」的記憶對該給定上下文情形生效。")
|
||||
|
||||
vCTestLog("- 清空組字區,重新打另一句話來測試。")
|
||||
testSession.switchState(IMEState.ofAbortion())
|
||||
|
||||
sequenceChars = "ru4ej/ 2k7su065j/ ru;3rup "
|
||||
typeSentenceOrCandidates(sequenceChars)
|
||||
let resultText6 = testSession.state.displayedText
|
||||
vCTestLog("- // 組字結果:\(resultText6)")
|
||||
XCTAssertEqual(resultText6, "濟公的年中獎金")
|
||||
vCTestLog("- 已成功證實「年終」的記憶不會對除了給定上下文以外的情形生效。")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue