mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 08:25:32 +00:00
also remove related debug mode code, debug logging is controlled solely by universal logging settings Fixes: #11525
609 lines
33 KiB
Objective-C
609 lines
33 KiB
Objective-C
//
|
||
// KMEngineTests.m
|
||
// KeymanEngine4MacTests
|
||
//
|
||
// Created by tom on 1/18/18.
|
||
// Copyright © 2018 SIL International. All rights reserved.
|
||
//
|
||
|
||
#import <XCTest/XCTest.h>
|
||
#import <Carbon/Carbon.h>
|
||
#import "KeymanEngineTestsStaticHelperMethods.h"
|
||
#import "KMEngine.h"
|
||
#import "CoreAction.h"
|
||
#import "KMELogs.h"
|
||
|
||
@interface KMEngineTests : XCTestCase
|
||
@end
|
||
|
||
@implementation KMEngineTests
|
||
const int nCombinations = 14;
|
||
NSEventModifierFlags modifiers[nCombinations];
|
||
NSString * names[nCombinations];
|
||
|
||
- (void)setUp {
|
||
[super setUp];
|
||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||
}
|
||
|
||
- (void)tearDown {
|
||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||
[super tearDown];
|
||
}
|
||
|
||
- (void)testinitWithKMX_NilKmx_ProcessEventReturnsNil {
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:nil context:@""];
|
||
NSEvent *event = [[NSEvent alloc] init];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output == nil, @"Expected processEvent to return nil for nil kmx");
|
||
}
|
||
|
||
- (void)testinitWithKMX_ValidKmxEmptyContext_InitializedWithEmptyContext {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
XCTAssert(engine != nil, @"Expected non-nil engine");
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([engine.getCoreContextDebug isEqualToString:@"|| (len: 0) [ ]"], @"Expected empty context buffer");
|
||
}
|
||
|
||
- (void)testinitWithKMX_ValidKmxNonEmptyContext_InitializedWithContext {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"abc"];
|
||
XCTAssert(engine != nil, @"Expected non-nil engine");
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([engine.getCoreContextDebug isEqualToString:@"|abc| (len: 3) [ U+0061 U+0062 U+0063 ]"], @"Expected 'abc' in context buffer");
|
||
}
|
||
|
||
- (void)testsetCoreContextIfNeeded_NonEmptyContext_InitialContextUpdated {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"a"];
|
||
[engine setCoreContextIfNeeded:@"xyz"];
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer");
|
||
}
|
||
|
||
// TODO: re-enable this one after the core API km_core_state_context_set_if_needed is fixed
|
||
/*
|
||
- (void)testsetCoreContextIfNeeded_EmptyContext_InitialContextUpdated {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
[engine setCoreContextIfNeeded:@"xyz"];
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer");
|
||
}
|
||
*/
|
||
|
||
- (void)testprocessEvent_eventForCommandKey_ReturnsNilOutput {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagCommand timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output == nil, @"expected nil output from core");
|
||
}
|
||
|
||
- (void)testprocessEvent_eventWithoutKeycode_ReturnsNilOutput {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:NSMakePoint(29, 21) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil eventNumber:23 clickCount:0 pressure:0];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output == nil, @"nil CoreKeyOutput");
|
||
}
|
||
|
||
// TODO: shouldn't this return emitKeystroke = YES?
|
||
- (void)testprocessEvent_eventForUnmappedKey_ReturnsNoActions {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"z" charactersIgnoringModifiers:@"z" isARepeat:NO keyCode:kVK_ANSI_Z];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output == nil, @"Expected nil array of actions");
|
||
}
|
||
|
||
- (void)testprocessEvent_eventForLowercaseA_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
os_log_debug([KMELogs testLog], "output = %{public}@", output);
|
||
XCTAssert(output.hasTextToInsert, @"output has text to insert");
|
||
XCTAssert([output.textToInsert isEqualToString:@"\u00C7"], @"Expected capital C cedille (U+00C7)");
|
||
}
|
||
|
||
// TODO: fails with core, investigate
|
||
/*
|
||
-(void)testprocessEvent_eventForCtrlShiftNumeralWithCipherMusicKmx_ReturnsQstrActionForCorrectUnicodeSurrogatePair {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""];
|
||
for (int i = 1; i <= 6; i++)
|
||
{
|
||
unsigned short ansiCode = kVK_ANSI_1 + i - 1;
|
||
NSString * chars = [NSString stringWithFormat:@"%d", i];
|
||
UTF32Char expectedUtf32Char;
|
||
switch (i) {
|
||
case 1: expectedUtf32Char = 0x1D100; break;
|
||
case 2: expectedUtf32Char = 0x1D101; break;
|
||
case 3: expectedUtf32Char = 0x1D103; break;
|
||
case 4: expectedUtf32Char = 0x1D102; break;
|
||
case 5:
|
||
expectedUtf32Char = 0x1D106;
|
||
ansiCode = kVK_ANSI_5; // 5 and 6 have codes swapped so they are not in sequential order
|
||
break;
|
||
case 6:
|
||
expectedUtf32Char = 0x1D107;
|
||
ansiCode = kVK_ANSI_6;
|
||
break;
|
||
}
|
||
NSString * expectedOutput = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift|NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:chars isARepeat:NO keyCode:ansiCode];
|
||
NSArray *actions = [engine processEvent:event];
|
||
XCTAssert(actions.count == 1, @"Expected 1 action");
|
||
NSDictionary *action = actions[0];
|
||
NSString *actionType = [[action allKeys] objectAtIndex:0];
|
||
XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action");
|
||
NSString *output = [action objectForKey:actionType];
|
||
XCTAssert([output isEqualToString:expectedOutput], @"Output incorrect");
|
||
[engine clearContext];
|
||
}
|
||
}
|
||
*/
|
||
|
||
- (void)testprocessEvent_eventsForOpenCurlyBraceWithCipherMusicKmx_ReturnsCharacterForStartSlide {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
UTF32Char expectedUtf32Char = 0x1D177;
|
||
NSString * expectedStartSlideSurrogatePair = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:@"{" charactersIgnoringModifiers:@"[" isARepeat:NO keyCode:kVK_ANSI_LeftBracket];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.hasTextToInsert, @"expected hasTextToInsert");
|
||
XCTAssert([output.textToInsert isEqualToString:expectedStartSlideSurrogatePair], @"output = %@", expectedStartSlideSurrogatePair);
|
||
}
|
||
|
||
/*
|
||
// TODO: fails with core, investigate
|
||
- (void)testprocessEvent_eventForUnshiftedNumeralWithCipherMusicKmx_ReturnsCharacterActionToInsertNumeral {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""];
|
||
for (int i = 1; i <= 9; i++)
|
||
{
|
||
unsigned short ansiCode = kVK_ANSI_1 + i - 1;
|
||
NSString * numeral = [NSString stringWithFormat:@"%d", i];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:numeral charactersIgnoringModifiers:numeral isARepeat:NO keyCode:ansiCode];
|
||
NSArray *actions = [engine processEvent:event];
|
||
os_log_debug([KMELogs testLog], "testprocessEvent, actions[0]: %{public}@, expected numeral: %{public}@", actions[0], numeral);
|
||
XCTAssert(actions.count == 1, @"Expected 1 action");
|
||
CoreAction *action = actions[0];
|
||
XCTAssert([action isCharacter], @"Expected CharacterAction");
|
||
XCTAssert([action.content isEqualToString:numeral], @"Output incorrect");
|
||
[engine clearContext];
|
||
}
|
||
}
|
||
*/
|
||
|
||
// TODO: fails with core, returns CharacterAction
|
||
- (void)testprocessEvent_eventForShiftNumeralsWithoutRulesInCipherMusicKmx_ReturnsNoAction {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
for (int i = 0; i <= 9; i++)
|
||
{
|
||
if (i == 6)
|
||
continue; // There is a rule in the keyboard for '^' (which is a SHIFT+6).
|
||
unsigned short ansiCode = kVK_ANSI_1 + i - 1; // This works for 1-4
|
||
NSString * unmodifiedChars = [NSString stringWithFormat:@"%d", i];
|
||
NSString * chars;
|
||
switch (i) {
|
||
case 0:
|
||
chars = @")";
|
||
ansiCode = kVK_ANSI_0;
|
||
break;
|
||
case 1: chars = @"!"; break;
|
||
case 2: chars = @"@"; break;
|
||
case 3: chars = @"#"; break;
|
||
case 4: chars = @"$"; break;
|
||
case 5:
|
||
chars = @"%";
|
||
ansiCode = kVK_ANSI_5;
|
||
break;
|
||
case 7:
|
||
chars = @"&";
|
||
ansiCode = kVK_ANSI_7;
|
||
break;
|
||
case 8:
|
||
chars = @"*";
|
||
ansiCode = kVK_ANSI_8;
|
||
break;
|
||
case 9:
|
||
chars = @"(%)";
|
||
ansiCode = kVK_ANSI_9;
|
||
break;
|
||
}
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:unmodifiedChars isARepeat:NO keyCode:ansiCode];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.emitKeystroke, @"expected emit keycode");
|
||
}
|
||
}
|
||
|
||
// TODO: fails with core, returns CharacterAction
|
||
- (void)testprocessEvent_eventForPeriodWithCipherMusicKmx_ReturnsNoAction {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"." charactersIgnoringModifiers:@"." isARepeat:NO keyCode:kVK_ANSI_Period];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(!output.hasTextToInsert, @"expected no text to insert");
|
||
}
|
||
|
||
- (void)testprocessEvent_eventForCtrl8WithCipherMusicKmx_ReturnsEmit {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:@"8" charactersIgnoringModifiers:@"8" isARepeat:NO keyCode:kVK_ANSI_8];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.emitKeystroke, @"emitKeystroke == YES");
|
||
}
|
||
|
||
+ (void)fillInNamesAndModifiersForAllChiralCombinations {
|
||
int i = 0;
|
||
modifiers[i] = LEFT_CTRL_FLAG;
|
||
names[i++] = @"LEFT CTRL";
|
||
modifiers[i] = LEFT_SHIFT_FLAG;
|
||
names[i++] = @"LEFT SHIFT";
|
||
modifiers[i] = RIGHT_SHIFT_FLAG;
|
||
names[i++] = @"RIGHT SHIFT";
|
||
modifiers[i] = RIGHT_CTRL_FLAG;
|
||
names[i++] = @"RIGHT CTRL";
|
||
modifiers[i] = LEFT_ALT_FLAG;
|
||
names[i++] = @"LEFT ALT";
|
||
modifiers[i] = RIGHT_ALT_FLAG;
|
||
names[i++] = @"RIGHT ALT";
|
||
modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG;
|
||
names[i++] = @"LEFT CTRL+ALT";
|
||
modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG;
|
||
names[i++] = @"RIGHT CTRL+ALT";
|
||
modifiers[i] = LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG;
|
||
names[i++] = @"LEFT CTRL+SHIFT";
|
||
modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG;
|
||
names[i++] = @"RIGHT CTRL+SHIFT";
|
||
modifiers[i] = LEFT_ALT_FLAG | LEFT_SHIFT_FLAG;
|
||
names[i++] = @"LEFT ALT+SHIFT";
|
||
modifiers[i] = RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG;
|
||
names[i++] = @"RIGHT ALT+SHIFT";
|
||
modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG;
|
||
names[i++] = @"LEFT CTRL+ALT+SHIFT";
|
||
modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG;
|
||
names[i++] = @"RIGHT CTRL+ALT+SHIFT";
|
||
}
|
||
|
||
- (void)testprocessEvent_eventForAWithModifiers_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx {
|
||
int i = 0;
|
||
[KMEngineTests fillInNamesAndModifiersForAllChiralCombinations];
|
||
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
|
||
for (i = 0; i < nCombinations; i++) {
|
||
[engine clearCoreContext];
|
||
NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"A" : @"a";
|
||
NSString * characters = charactersIgnoringModifiers;
|
||
if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG))
|
||
characters = [characters stringByAppendingString:@"\u030A"];
|
||
|
||
os_log_debug([KMELogs testLog], "Test case: %lu", (NSUInteger)modifiers[i]);
|
||
// NOTE: 'a' happens to be keyCode 0 (see initVirtualKeyMapping in CoreHelper)
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:0];
|
||
NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers];
|
||
CoreKeyOutput *coreKeyOutput = [engine processEvent:event];
|
||
XCTAssert(coreKeyOutput.hasTextToInsert, @"hasTextToInsert for %@", keyCombination);
|
||
NSString *output = coreKeyOutput.textToInsert;
|
||
os_log_debug([KMELogs testLog], "output = %{public}@", output);
|
||
switch (modifiers[i]) {
|
||
case LEFT_SHIFT_FLAG:
|
||
case RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00AE"], @"Expected Registered Sign (U+00AE) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A3"], @"Expected Pound Sign (U+00A3) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A4"], @"Expected Currency Sign (U+00A4) for %@", keyCombination);
|
||
break;
|
||
case LEFT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A1"], @"Expected Inverted Exclamation Mark (U+00A1) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A2"], @"Expected Cent Sign (U+00A2) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A6"], @"Expected Broken Bar (U+00A6) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A5"], @"Expected Yen Sign (U+00A5) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00DB"], @"Expected Capital U with Circumflex (U+00DB) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00DF"], @"Expected Small Letter Sharp S (U+00DF) for %@", keyCombination);
|
||
break;
|
||
case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00CB"], @"Expected Capital E with Diaresis (U+00CB) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00BD"], @"Expected Vulgar Fraction One Half (U+00BD) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00D8"], @"Expected Capital O with Stroke (U+00D8) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00B5"], @"Expected Micro Sign (U+00B5) for %@", keyCombination);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)testprocessEvent_eventForSWithModifiers_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx {
|
||
int i = 0;
|
||
[KMEngineTests fillInNamesAndModifiersForAllChiralCombinations];
|
||
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
|
||
for (i = 0; i < nCombinations; i++) {
|
||
[engine clearCoreContext];
|
||
NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"S" : @"s";
|
||
NSString * characters = charactersIgnoringModifiers;
|
||
if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG)) {
|
||
if (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG))
|
||
characters = @"Í";
|
||
else
|
||
characters = @"ß";
|
||
}
|
||
|
||
os_log_debug([KMELogs testLog], "Test case: %lu", (NSUInteger)modifiers[i]);
|
||
// NOTE: 's' happens to be keyCode 1 (see initVirtualKeyMapping in CoreHelper)
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:1];
|
||
NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers];
|
||
CoreKeyOutput *coreKeyOutput = [engine processEvent:event];
|
||
NSString *output = coreKeyOutput.textToInsert;
|
||
os_log_debug([KMELogs testLog], "output = %@", output);
|
||
switch (modifiers[i]) {
|
||
case LEFT_SHIFT_FLAG:
|
||
case RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E6"], @"Expected Small Letter ae (U+00E6) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00AA"], @"Expected Feminine Ordinal Indicator (U+00AA) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00AB"], @"Expected Left-Pointing Double Angle Quotation Mark (U+00AB) for %@", keyCombination);
|
||
break;
|
||
case LEFT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A8"], @"Expected Diaresis (U+00A8) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00A9"], @"Expected Copyright Sign (U+00A9) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00AD"], @"Expected Soft Hyphen (U+00AD) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00AC"], @"Expected Not Sign (U+00AC) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E1"], @"Expected Small A with Acute (U+00E1) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E0"], @"Expected Small A with Grave (U+00E0) for %@", keyCombination);
|
||
break;
|
||
case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E5"], @"Expected Small A with Ring Above (U+00E5) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E4"], @"Expected Small A with Diaresis (U+00E4) for %@", keyCombination);
|
||
break;
|
||
case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E2"], @"Expected Small A with Circumflex (U+00E2) for %@", keyCombination);
|
||
break;
|
||
case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG:
|
||
XCTAssert([output isEqualToString:@"\u00E3"], @"Expected Small A with Tilde (U+00E3) for %@", keyCombination);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// The following checkPlatform tests all use the PlatformTest KMX file based on PlatformTest.kmn
|
||
// (not included in the project itself, but available in the source repo for reference. This
|
||
// keyboard has been craefully crafted to check for all the "wrong" values first, for which checkPlatform
|
||
// should return NO, so while these tests are ostensibly testing for YES for the platform components that
|
||
// should match on a Mac, they are also testing for NO for all the other non-matching values.
|
||
|
||
- (NSString *)checkPlatform_getOutputForKeystroke: (NSString*) character modifierFlags: (NSEventModifierFlags) flag keyCode:(unsigned short)code {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForPlatformTest];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSString *lcChar = [character lowercaseString];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:flag timestamp:0 windowNumber:0 context:nil characters:character charactersIgnoringModifiers:lcChar isARepeat:NO keyCode:code];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
return output.textToInsert;
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_native_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"u" modifierFlags:0 keyCode:kVK_ANSI_U];
|
||
XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for native.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_NATIVE_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"U" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_U];
|
||
XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for NATIVE.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_hardware_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"p" modifierFlags:0 keyCode:kVK_ANSI_P];
|
||
XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for hardware.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_HARDWARE_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"P" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_P];
|
||
XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for HARDWARE.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_desktop_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:0 keyCode:kVK_ANSI_I];
|
||
XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for desktop.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_Desktop_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_I];
|
||
XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for Desktop.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_macosx_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"o" modifierFlags:0 keyCode:kVK_ANSI_O];
|
||
XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for macosx.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_MacOS_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"K" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_K];
|
||
XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for MacOS.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_MAC_ReturnsYes {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"L" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_L];
|
||
XCTAssert([output isEqualToString:@" mac"], @"Expected checkPlatform to return YES for MAC.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_Browsers_ReturnsNo {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"y" modifierFlags:0 keyCode:kVK_ANSI_Y];
|
||
XCTAssert([output isEqualToString:@" [Browser Undefined]"], @"Expected checkPlatform to return NO for all browsers (ie, chrome, firefox, safari, opera).");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testCheckPlatform_multipleTokens_MatchesCorrectOneForMac {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"m" modifierFlags:0 keyCode:kVK_ANSI_M];
|
||
XCTAssert([output isEqualToString:@" macOS native desktop hardware"], @"Expected checkPlatform to return YES for macOS native desktop hardware.");
|
||
}
|
||
|
||
// TODO: rewrite for combined character actions
|
||
- (void)testContextMatch_InvertedPlatformLogic_NotTouch {
|
||
NSString *output = [self checkPlatform_getOutputForKeystroke:@"x" modifierFlags:0 keyCode:kVK_ANSI_X];
|
||
XCTAssert([output isEqualToString:@" !Touch"], @"Expected !touch to be true.");
|
||
}
|
||
|
||
// This allows for easy debugging of the "manual" platformtest keyboard developed for filling in the test spreadsheet.
|
||
//- (void)testCheckPlatform_temp_UnknownPlatformX {
|
||
// KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:@"/Users/tom/Documents/keymanapp/keyman/windows/src/test/manual-tests/platform-rules/platformtest.kmx"];
|
||
//
|
||
// KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""];
|
||
// NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A];
|
||
// NSArray *actions = [engine processEvent:event];
|
||
// XCTAssert(actions.count == 1, @"Expected 1 action");
|
||
// NSDictionary *action = actions[0];
|
||
// NSString *actionType = [[action allKeys] objectAtIndex:0];
|
||
// XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action");
|
||
// NSString *output = [action objectForKey:actionType];
|
||
// XCTAssert([output isEqualToString:@"hardware macosx desktop native undefined !touch undefined macosx"], @"Expected !touch.");
|
||
//}
|
||
|
||
|
||
- (void)testEngine_ipaKeyboardAction_DoesNotCrash_Issue1892 {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForIndexOffsetTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"z"];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.hasCodePointsToDelete, @"output hasCodePointsToDelete == YES");
|
||
XCTAssert([output.textToInsert isEqualToString:@"Z"], @"Expected output to be 'Z'.");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_eventForFWithElNuerKmx_ReturnsCorrectCharacter {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"f" charactersIgnoringModifiers:@"f" isARepeat:NO keyCode:kVK_ANSI_F];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert([output.textToInsert isEqualToString:@"ɣ"], @"Expected output to be 'ɣ'.");
|
||
XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing");
|
||
XCTAssert(!output.emitKeystroke, @"expected to emit nothing");
|
||
}
|
||
|
||
- (void)testArmenianMnemonic_triggerPersistOptions_ReturnsOptions {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForArmenianMnemonicTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"√"];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"w" charactersIgnoringModifiers:@"w" isARepeat:NO keyCode:kVK_ANSI_W];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
NSString *key = @"option_ligature_ew";
|
||
NSDictionary *options = output.optionsToPersist;
|
||
NSString *value = options[key];
|
||
XCTAssertEqualObjects(value, @"1", @"expected 'option_ligature_ew' with value of '1'");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_backspaceElNuerEmptyContext_PassesThrough {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@""];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
os_log_debug([KMELogs testLog], "output = %{public}@", output);
|
||
XCTAssert(!output.hasTextToInsert, @"expected to insert nothing");
|
||
XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing");
|
||
XCTAssert(output.emitKeystroke, @"expected to emit key");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_backspaceElNuerWithContext_EmptiesContextReturnsDelete {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ"];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
os_log_debug([KMELogs testLog], "output = %{public}@", output);
|
||
XCTAssert(output.codePointsToDeleteBeforeInsert == 1, @"Expected output to delete one code point");
|
||
XCTAssert(!output.hasTextToInsert, @"expected to insert nothing");
|
||
NSString *context = engine.getCoreContextDebug;
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be empty.");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_eventReturnWithElNuerKmx_EmitWithContextEmpty {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ"];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\n" charactersIgnoringModifiers:@"\n" isARepeat:NO keyCode:kVK_Return];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES");
|
||
NSString *context = engine.getCoreContextDebug;
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared.");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_eventTabWithElNuerKmx_EmitWithContextEmpty {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ"];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\t" charactersIgnoringModifiers:@"\t" isARepeat:NO keyCode:kVK_Tab];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES");
|
||
NSString *context = engine.getCoreContextDebug;
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared.");
|
||
}
|
||
|
||
- (void)testCoreProcessEvent_eventSingleQuoteWithElNuerKmx_ReturnsDiacritic {
|
||
KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests];
|
||
NSString *context = @"ɛ";
|
||
KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:context];
|
||
NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"'" charactersIgnoringModifiers:@"'" isARepeat:NO keyCode:kVK_ANSI_Quote];
|
||
CoreKeyOutput *output = [engine processEvent:event];
|
||
XCTAssert(output.hasTextToInsert, @"returns text to insert");
|
||
context = engine.getCoreContextDebug;
|
||
// Note: relying on km_core_state_context_debug output format is just barely
|
||
// acceptable for a unit test
|
||
XCTAssert([context isEqualToString:@"|\u025B\u0308| (len: 2) [ U+025b U+0308 ]"], @"Context updated with diacritic.");
|
||
}
|
||
|
||
@end
|