From 49f998ad5d37ae20ddbc380791e559021eda958b Mon Sep 17 00:00:00 2001 From: zonble Date: Wed, 2 Feb 2022 07:23:39 +0800 Subject: [PATCH] Adds tests. --- McBopomofoTests/KeyHandlerBopomofoTests.swift | 221 +++++++++++++++++- .../KeyHandlerPlainBopomofoTests.swift | 15 ++ Source/KeyHandler.mm | 95 ++++---- 3 files changed, 284 insertions(+), 47 deletions(-) diff --git a/McBopomofoTests/KeyHandlerBopomofoTests.swift b/McBopomofoTests/KeyHandlerBopomofoTests.swift index e1ec55a8..5a9e8b70 100644 --- a/McBopomofoTests/KeyHandlerBopomofoTests.swift +++ b/McBopomofoTests/KeyHandlerBopomofoTests.swift @@ -18,7 +18,167 @@ class KeyHandlerBopomofoTests: XCTestCase { override func tearDownWithError() throws { } + func testIgnoreEmpty() { + let input = KeyHandlerInput(inputText: "", keyCode: 0, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreEnter() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.enter.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreUp() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.up.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result, "\(state)") + } + + func testIgnoreDown() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.down.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result, "\(state)") + } + + func testIgnoreLeft() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.left.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreRight() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.right.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnorePageUp() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.pageUp.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnorePageDown() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.pageDown.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreHome() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.home.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreEnd() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.end.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testIgnoreDelete() { + let input = KeyHandlerInput(inputText: " ", keyCode: KeyCode.delete.rawValue, charCode: 0, flags: [], isVerticalMode: false) + var state: InputState = InputState.Empty() + let result = handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + XCTAssertFalse(result) + } + + func testPunctuationTable() { + let enabled = Preferences.halfWidthPunctuationEnabled + Preferences.halfWidthPunctuationEnabled = false + let input = KeyHandlerInput(inputText: "`", keyCode: 0, charCode: charCode("`"), flags: .shift, isVerticalMode: false) + var state: InputState = InputState.Empty() + handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + + XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)") + if let state = state as? InputState.ChoosingCandidate { + XCTAssertTrue(state.candidates.contains(",")) + } + Preferences.halfWidthPunctuationEnabled = enabled + } + + func testHalfPunctuationComma() { + let enabled = Preferences.halfWidthPunctuationEnabled + Preferences.halfWidthPunctuationEnabled = true + let input = KeyHandlerInput(inputText: "<", keyCode: 0, charCode: charCode("<"), flags: .shift, isVerticalMode: false) + var state: InputState = InputState.Empty() + handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + + XCTAssertTrue(state is InputState.Inputting, "\(state)") + if let state = state as? InputState.Inputting { + XCTAssertEqual(state.composingBuffer, ",") + } + Preferences.halfWidthPunctuationEnabled = enabled + } + + func testPunctuationComma() { + let enabled = Preferences.halfWidthPunctuationEnabled + Preferences.halfWidthPunctuationEnabled = false let input = KeyHandlerInput(inputText: "<", keyCode: 0, charCode: charCode("<"), flags: .shift, isVerticalMode: false) var state: InputState = InputState.Empty() handler.handle(input, state: state) { newState in @@ -31,9 +191,31 @@ class KeyHandlerBopomofoTests: XCTestCase { if let state = state as? InputState.Inputting { XCTAssertEqual(state.composingBuffer, ",") } + Preferences.halfWidthPunctuationEnabled = enabled + } + + func testHalfPunctuationPeriod() { + let enabled = Preferences.halfWidthPunctuationEnabled + Preferences.halfWidthPunctuationEnabled = true + let input = KeyHandlerInput(inputText: ">", keyCode: 0, charCode: charCode(">"), flags: .shift, isVerticalMode: false) + var state: InputState = InputState.Empty() + handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + + XCTAssertTrue(state is InputState.Inputting, "\(state)") + if let state = state as? InputState.Inputting { + XCTAssertEqual(state.composingBuffer, ".") + } + Preferences.halfWidthPunctuationEnabled = enabled } func testPunctuationPeriod() { + let enabled = Preferences.halfWidthPunctuationEnabled + Preferences.halfWidthPunctuationEnabled = false + let input = KeyHandlerInput(inputText: ">", keyCode: 0, charCode: charCode(">"), flags: .shift, isVerticalMode: false) var state: InputState = InputState.Empty() handler.handle(input, state: state) { newState in @@ -46,6 +228,7 @@ class KeyHandlerBopomofoTests: XCTestCase { if let state = state as? InputState.Inputting { XCTAssertEqual(state.composingBuffer, "。") } + Preferences.halfWidthPunctuationEnabled = enabled } func testInputting() { @@ -374,7 +557,42 @@ class KeyHandlerBopomofoTests: XCTestCase { XCTAssertEqual(state.cursorIndex, 1) } - let space = KeyHandlerInput(inputText: " ", keyCode: KeyCode.down.rawValue, charCode: 0, flags: [], isVerticalMode: false) + let down = KeyHandlerInput(inputText: " ", keyCode: KeyCode.down.rawValue, charCode: 0, flags: [], isVerticalMode: false) + handler.handle(down, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + + XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)") + if let state = state as? InputState.ChoosingCandidate { + XCTAssertEqual(state.composingBuffer, "你") + XCTAssertEqual(state.cursorIndex, 1) + let candidates = state.candidates + XCTAssertTrue(candidates.contains("你")) + } + } + + func testCandidateWithSpace() { + let enabled = Preferences.chooseCandidateUsingSpace + Preferences.chooseCandidateUsingSpace = true + var state: InputState = InputState.Empty() + let keys = Array("su3").map { String($0) } + for key in keys { + let input = KeyHandlerInput(inputText: key, keyCode: 0, charCode: charCode(key), flags: [], isVerticalMode: false) + handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + } + XCTAssertTrue(state is InputState.Inputting, "\(state)") + if let state = state as? InputState.Inputting { + XCTAssertEqual(state.composingBuffer, "你") + XCTAssertEqual(state.cursorIndex, 1) + } + + let space = KeyHandlerInput(inputText: " ", keyCode: 0, charCode: 32, flags: [], isVerticalMode: false) handler.handle(space, state: state) { newState in state = newState } candidateSelectionCallback: { @@ -388,6 +606,7 @@ class KeyHandlerBopomofoTests: XCTestCase { let candidates = state.candidates XCTAssertTrue(candidates.contains("你")) } + Preferences.chooseCandidateUsingSpace = enabled } func testHomeAndEnd() { diff --git a/McBopomofoTests/KeyHandlerPlainBopomofoTests.swift b/McBopomofoTests/KeyHandlerPlainBopomofoTests.swift index 7eaecfc2..621f68f2 100644 --- a/McBopomofoTests/KeyHandlerPlainBopomofoTests.swift +++ b/McBopomofoTests/KeyHandlerPlainBopomofoTests.swift @@ -13,6 +13,21 @@ class KeyHandlerPlainBopomofoTests: XCTestCase { override func tearDownWithError() throws { } + func testPunctuationTable() { + let input = KeyHandlerInput(inputText: "`", keyCode: 0, charCode: charCode("`"), flags: .shift, isVerticalMode: false) + var state: InputState = InputState.Empty() + handler.handle(input, state: state) { newState in + state = newState + } candidateSelectionCallback: { + } errorCallback: { + } + + XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)") + if let state = state as? InputState.ChoosingCandidate { + XCTAssertTrue(state.candidates.contains(",")) + } + } + func testPunctuationComma() { let input = KeyHandlerInput(inputText: "<", keyCode: 0, charCode: charCode("<"), flags: .shift, isVerticalMode: false) var state: InputState = InputState.Empty() diff --git a/Source/KeyHandler.mm b/Source/KeyHandler.mm index 569eca31..8d32facf 100644 --- a/Source/KeyHandler.mm +++ b/Source/KeyHandler.mm @@ -532,6 +532,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleEscWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + BOOL escToClearInputBufferEnabled = Preferences.escToCleanInputBuffer; if (escToClearInputBufferEnabled) { @@ -547,12 +551,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot // Bopomofo reading, in odds with the expectation of users from // other platforms - if (_bpmfReadingBuffer->isEmpty()) { - // no need to beep since the event is deliberately triggered by user - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } - } else { + if (!_bpmfReadingBuffer->isEmpty()) { _bpmfReadingBuffer->clear(); InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; stateCallback(inputting); @@ -563,16 +562,16 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleBackwardWithState:(InputState *)state input:(KeyHandlerInput *)input stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (!_bpmfReadingBuffer->isEmpty()) { errorCallback(); stateCallback(state); return YES; } - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } - InputStateInputting *currentState = (InputStateInputting *) state; if ([input isShiftHold]) { @@ -601,16 +600,16 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleForwardWithState:(InputState *)state input:(KeyHandlerInput *)input stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (!_bpmfReadingBuffer->isEmpty()) { errorCallback(); stateCallback(state); return YES; } - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } - InputStateInputting *currentState = (InputStateInputting *) state; if ([input isShiftHold]) { @@ -640,16 +639,16 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleHomeWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (!_bpmfReadingBuffer->isEmpty()) { errorCallback(); stateCallback(state); return YES; } - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } - if (_builder->cursorIndex()) { _builder->setCursorIndex(0); InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; @@ -664,16 +663,16 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleEndWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (!_bpmfReadingBuffer->isEmpty()) { errorCallback(); stateCallback(state); return YES; } - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } - if (_builder->cursorIndex() != _builder->length()) { _builder->setCursorIndex(_builder->length()); InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; @@ -688,6 +687,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleAbsorbedArrowKeyWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (!_bpmfReadingBuffer->isEmpty()) { errorCallback(); } @@ -697,11 +700,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleBackspaceWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { - if (_bpmfReadingBuffer->isEmpty()) { - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (_bpmfReadingBuffer->isEmpty()) { if (_builder->cursorIndex()) { _builder->deleteReadingBeforeCursor(); [self _walk]; @@ -726,11 +729,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleDeleteWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { - if (_bpmfReadingBuffer->isEmpty()) { - if (![state isKindOfClass:[InputStateInputting class]]) { - return NO; - } + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + if (_bpmfReadingBuffer->isEmpty()) { if (_builder->cursorIndex() != _builder->length()) { _builder->deleteReadingAfterCursor(); [self _walk]; @@ -755,26 +758,26 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot - (BOOL)_handleEnterWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { - if ([state isKindOfClass:[InputStateInputting class]]) { - if (_inputMode == InputModePlainBopomofo) { - if (!_bpmfReadingBuffer->isEmpty()) { - errorCallback(); - } - return YES; + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (_inputMode == InputModePlainBopomofo) { + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); } - - [self clear]; - - InputStateInputting *current = (InputStateInputting *) state; - NSString *composingBuffer = current.composingBuffer; - InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; - stateCallback(committing); - InputStateEmpty *empty = [[InputStateEmpty alloc] init]; - stateCallback(empty); return YES; } - return NO; + [self clear]; + + InputStateInputting *current = (InputStateInputting *) state; + NSString *composingBuffer = current.composingBuffer; + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; + stateCallback(committing); + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + return YES; } - (BOOL)_handlePunctuation:(string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback