Adds test cases.

This commit is contained in:
zonble 2022-01-18 17:05:51 +08:00
parent fb043b9308
commit 29813f93e5
6 changed files with 359 additions and 6 deletions

View File

@ -3,7 +3,7 @@ on: [push]
jobs:
build:
name: Build
name: Build and Test
runs-on: macOS-latest
env:
DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer
@ -17,6 +17,8 @@ jobs:
run: xcodebuild -scheme McBopomofo -configuration Release build
- name: Build
run: xcodebuild -scheme McBopomofoInstaller -configuration Release build
- name: Test
run: xcodebuild -scheme McBopomofo -configuration Debug test
- name: Test CandidateUI
run: swift test
working-directory: Packages/CandidateUI

View File

@ -55,6 +55,7 @@
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
D485D3B92796A8A000657FF3 /* PreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D485D3B82796A8A000657FF3 /* PreferencesTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -72,6 +73,13 @@
remoteGlobalIDString = 6A0D4EA115FC0D2D00ABF4B3;
remoteInfo = McBopomofo;
};
D485D3BA2796A8A000657FF3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6A0D4E9415FC0CFA00ABF4B3 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 6A0D4EA115FC0D2D00ABF4B3;
remoteInfo = McBopomofo;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@ -191,6 +199,8 @@
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserOverrideModel.cpp; sourceTree = "<group>"; };
D485D3B62796A8A000657FF3 /* McBopomofoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = McBopomofoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D485D3B82796A8A000657FF3 /* PreferencesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -218,6 +228,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D485D3B32796A8A000657FF3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@ -226,6 +243,7 @@
children = (
D427F766278C9CBD004A2160 /* Packages */,
6A0D4EC215FC0D3C00ABF4B3 /* Source */,
D485D3B72796A8A000657FF3 /* McBopomofoTests */,
6A0D4EA515FC0D2D00ABF4B3 /* Frameworks */,
6A0D4EA315FC0D2D00ABF4B3 /* Products */,
);
@ -236,6 +254,7 @@
children = (
6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */,
6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */,
D485D3B62796A8A000657FF3 /* McBopomofoTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -431,6 +450,14 @@
name = Packages;
sourceTree = "<group>";
};
D485D3B72796A8A000657FF3 /* McBopomofoTests */ = {
isa = PBXGroup;
children = (
D485D3B82796A8A000657FF3 /* PreferencesTests.swift */,
);
path = McBopomofoTests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
@ -499,17 +526,40 @@
productReference = 6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */;
productType = "com.apple.product-type.application";
};
D485D3B52796A8A000657FF3 /* McBopomofoTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D485D3BE2796A8A000657FF3 /* Build configuration list for PBXNativeTarget "McBopomofoTests" */;
buildPhases = (
D485D3B22796A8A000657FF3 /* Sources */,
D485D3B32796A8A000657FF3 /* Frameworks */,
D485D3B42796A8A000657FF3 /* Resources */,
);
buildRules = (
);
dependencies = (
D485D3BB2796A8A000657FF3 /* PBXTargetDependency */,
);
name = McBopomofoTests;
productName = McBopomofoTests;
productReference = D485D3B62796A8A000657FF3 /* McBopomofoTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
6A0D4E9415FC0CFA00ABF4B3 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1320;
LastUpgradeCheck = 1310;
TargetAttributes = {
6A0D4EA115FC0D2D00ABF4B3 = {
LastSwiftMigration = 1240;
};
D485D3B52796A8A000657FF3 = {
CreatedOnToolsVersion = 13.2.1;
TestTargetID = 6A0D4EA115FC0D2D00ABF4B3;
};
};
};
buildConfigurationList = 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "McBopomofo" */;
@ -531,6 +581,7 @@
6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */,
6ACA41CA15FC1D7500935EF6 /* McBopomofoInstaller */,
6A38BC2115FC12FD00A8A51F /* Data */,
D485D3B52796A8A000657FF3 /* McBopomofoTests */,
);
};
/* End PBXProject section */
@ -569,6 +620,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D485D3B42796A8A000657FF3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@ -625,6 +683,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D485D3B22796A8A000657FF3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D485D3B92796A8A000657FF3 /* PreferencesTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@ -638,6 +704,11 @@
target = 6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */;
targetProxy = 6ACA420015FC1DCC00935EF6 /* PBXContainerItemProxy */;
};
D485D3BB2796A8A000657FF3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */;
targetProxy = D485D3BA2796A8A000657FF3 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@ -1044,6 +1115,88 @@
};
name = Release;
};
D485D3BC2796A8A000657FF3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.1;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.cerence.McBopomofoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/McBopomofo.app/Contents/MacOS/McBopomofo";
};
name = Debug;
};
D485D3BD2796A8A000657FF3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 12.1;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.cerence.McBopomofoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/McBopomofo.app/Contents/MacOS/McBopomofo";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -1083,6 +1236,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D485D3BE2796A8A000657FF3 /* Build configuration list for PBXNativeTarget "McBopomofoTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D485D3BC2796A8A000657FF3 /* Debug */,
D485D3BD2796A8A000657FF3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */

View File

@ -28,6 +28,16 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D485D3B52796A8A000657FF3"
BuildableName = "McBopomofoTests.xctest"
BlueprintName = "McBopomofoTests"
ReferencedContainer = "container:McBopomofo.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction

View File

@ -0,0 +1,158 @@
import XCTest
@testable import McBopomofo
class PreferencesTests: XCTestCase {
override func setUpWithError() throws {
Preferences.reset()
}
override func tearDownWithError() throws {
Preferences.reset()
}
func testKeyboardLayout() {
XCTAssert(Preferences.keyboardLayout == 0)
Preferences.keyboardLayout = 1
XCTAssert(Preferences.keyboardLayout == 1)
}
func testKeyboardLayoutName() {
XCTAssert(Preferences.keyboardLayoutName == "Standard")
Preferences.keyboardLayout = 1
XCTAssert(Preferences.keyboardLayoutName == "ETen")
}
func testBasisKeyboardLayoutPreferenceKey() {
XCTAssert(Preferences.basisKeyboardLayout == "com.apple.keylayout.US")
Preferences.basisKeyboardLayout = "com.apple.keylayout.ABC"
XCTAssert(Preferences.basisKeyboardLayout == "com.apple.keylayout.ABC")
}
func testFunctionKeyboardLayout() {
XCTAssert(Preferences.functionKeyboardLayout == "com.apple.keylayout.US")
Preferences.functionKeyboardLayout = "com.apple.keylayout.ABC"
XCTAssert(Preferences.functionKeyboardLayout == "com.apple.keylayout.ABC")
}
func testFunctionKeyKeyboardLayoutOverrideIncludeShiftKey() {
XCTAssert(Preferences.functionKeyKeyboardLayoutOverrideIncludeShiftKey == false)
Preferences.functionKeyKeyboardLayoutOverrideIncludeShiftKey = true
XCTAssert(Preferences.functionKeyKeyboardLayoutOverrideIncludeShiftKey == true)
}
func testCandidateTextSize() {
XCTAssert(Preferences.candidateListTextSize == 16)
Preferences.candidateListTextSize = 18
XCTAssert(Preferences.candidateListTextSize == 18)
Preferences.candidateListTextSize = 11
XCTAssert(Preferences.candidateListTextSize == 12)
Preferences.candidateListTextSize = 197
XCTAssert(Preferences.candidateListTextSize == 196)
Preferences.candidateListTextSize = 12
XCTAssert(Preferences.candidateListTextSize == 12)
Preferences.candidateListTextSize = 196
XCTAssert(Preferences.candidateListTextSize == 196)
Preferences.candidateListTextSize = 13
XCTAssert(Preferences.candidateListTextSize == 13)
Preferences.candidateListTextSize = 195
XCTAssert(Preferences.candidateListTextSize == 195)
}
func testSelectPhraseAfterCursorAsCandidate() {
XCTAssert(Preferences.selectPhraseAfterCursorAsCandidate == false)
Preferences.selectPhraseAfterCursorAsCandidate = true
XCTAssert(Preferences.selectPhraseAfterCursorAsCandidate == true)
}
func testUseHorizontalCandidateList() {
XCTAssert(Preferences.useHorizontalCandidateList == false)
Preferences.useHorizontalCandidateList = true
XCTAssert(Preferences.useHorizontalCandidateList == true)
}
func testComposingBufferSize() {
XCTAssert(Preferences.composingBufferSize == 10)
Preferences.composingBufferSize = 4
XCTAssert(Preferences.composingBufferSize == 4)
Preferences.composingBufferSize = 20
XCTAssert(Preferences.composingBufferSize == 20)
Preferences.composingBufferSize = 3
XCTAssert(Preferences.composingBufferSize == 4)
Preferences.composingBufferSize = 21
XCTAssert(Preferences.composingBufferSize == 20)
Preferences.composingBufferSize = 5
XCTAssert(Preferences.composingBufferSize == 5)
Preferences.composingBufferSize = 19
XCTAssert(Preferences.composingBufferSize == 19)
}
func testChooseCandidateUsingSpace() {
XCTAssert(Preferences.chooseCandidateUsingSpace == true)
Preferences.chooseCandidateUsingSpace = false
XCTAssert(Preferences.chooseCandidateUsingSpace == false)
}
func testChineseConversionEnabled() {
XCTAssert(Preferences.chineseConversionEnabled == false)
Preferences.chineseConversionEnabled = true
XCTAssert(Preferences.chineseConversionEnabled == true)
_ = Preferences.toggleChineseConversionEnabled()
XCTAssert(Preferences.chineseConversionEnabled == false)
}
func testHalfWidthPunctuationEnabled() {
XCTAssert(Preferences.halfWidthPunctuationEnabled == false)
Preferences.halfWidthPunctuationEnabled = true
XCTAssert(Preferences.halfWidthPunctuationEnabled == true)
_ = Preferences.toggleHalfWidthPunctuationEnabled()
XCTAssert(Preferences.halfWidthPunctuationEnabled == false)
}
func testEscToCleanInputBuffer() {
XCTAssert(Preferences.escToCleanInputBuffer == false)
Preferences.escToCleanInputBuffer = true
XCTAssert(Preferences.escToCleanInputBuffer == true)
}
func testCandidateTextFontName() {
XCTAssert(Preferences.candidateTextFontName == nil)
Preferences.candidateTextFontName = "Helvetica"
XCTAssert(Preferences.candidateTextFontName == "Helvetica")
}
func testCandidateKeyLabelFontName() {
XCTAssert(Preferences.candidateKeyLabelFontName == nil)
Preferences.candidateKeyLabelFontName = "Helvetica"
XCTAssert(Preferences.candidateKeyLabelFontName == "Helvetica")
}
func testCandidateKeys() {
XCTAssert(Preferences.candidateKeys == Preferences.defaultCandidateKeys)
Preferences.candidateKeys = "abcd"
XCTAssert(Preferences.candidateKeys == "abcd")
}
func testPhraseReplacementEnabledKey() {
XCTAssert(Preferences.phraseReplacementEnabled == false)
Preferences.phraseReplacementEnabled = true
XCTAssert(Preferences.phraseReplacementEnabled == true)
}
func testChineneConversionEngine() {
XCTAssert(Preferences.chineneConversionEngine == 0)
Preferences.chineneConversionEngine = 1
XCTAssert(Preferences.chineneConversionEngine == 1)
}
func testChineseConversionStyle() {
XCTAssert(Preferences.chineseConversionStyle == 0)
Preferences.chineseConversionStyle = 1
XCTAssert(Preferences.chineseConversionStyle == 1)
}
}

View File

@ -1518,13 +1518,13 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
[Preferences toogleHalfWidthPunctuationEnabled];
[Preferences toggleHalfWidthPunctuationEnabled];
#pragma GCC diagnostic pop
}
- (void)togglePhraseReplacementEnabled:(id)sender
{
BOOL enabled = [Preferences tooglePhraseReplacementEnabled];
BOOL enabled = [Preferences togglePhraseReplacementEnabled];
McBopomofoLM *lm = [LanguageModelManager languageModelMcBopomofo];
lm->setPhraseReplacementEnabled(enabled);
}

View File

@ -55,7 +55,6 @@ private let kChineseConversionEngineKey = "ChineseConversionEngine"
private let kChineseConversionStyle = "ChineseConversionStyle"
private let kDefaultCandidateListTextSize: CGFloat = 16
private let kMinKeyLabelSize: CGFloat = 10
private let kMinCandidateListTextSize: CGFloat = 12
private let kMaxCandidateListTextSize: CGFloat = 196
@ -205,6 +204,28 @@ struct ComposingBufferSize {
// MARK: -
class Preferences: NSObject {
static func reset() {
let defaults = UserDefaults.standard
defaults.removeObject(forKey: kKeyboardLayoutPreferenceKey)
defaults.removeObject(forKey: kBasisKeyboardLayoutPreferenceKey)
defaults.removeObject(forKey: kFunctionKeyKeyboardLayoutPreferenceKey)
defaults.removeObject(forKey: kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey)
defaults.removeObject(forKey: kCandidateListTextSizeKey)
defaults.removeObject(forKey: kSelectPhraseAfterCursorAsCandidatePreferenceKey)
defaults.removeObject(forKey: kUseHorizontalCandidateListPreferenceKey)
defaults.removeObject(forKey: kComposingBufferSizePreferenceKey)
defaults.removeObject(forKey: kChooseCandidateUsingSpaceKey)
defaults.removeObject(forKey: kChineseConversionEnabledKey)
defaults.removeObject(forKey: kHalfWidthPunctuationEnabledKey)
defaults.removeObject(forKey: kEscToCleanInputBufferKey)
defaults.removeObject(forKey: kCandidateTextFontName)
defaults.removeObject(forKey: kCandidateKeyLabelFontName)
defaults.removeObject(forKey: kCandidateKeys)
defaults.removeObject(forKey: kPhraseReplacementEnabledKey)
defaults.removeObject(forKey: kChineseConversionEngineKey)
defaults.removeObject(forKey: kChineseConversionStyle)
}
@UserDefault(key: kKeyboardLayoutPreferenceKey, defaultValue: 0)
@objc static var keyboardLayout: Int
@ -247,7 +268,7 @@ class Preferences: NSObject {
@UserDefault(key: kHalfWidthPunctuationEnabledKey, defaultValue: false)
@objc static var halfWidthPunctuationEnabled: Bool
@objc static func toogleHalfWidthPunctuationEnabled() -> Bool {
@objc static func toggleHalfWidthPunctuationEnabled() -> Bool {
halfWidthPunctuationEnabled = !halfWidthPunctuationEnabled
return halfWidthPunctuationEnabled;
}
@ -326,7 +347,7 @@ class Preferences: NSObject {
@UserDefault(key: kPhraseReplacementEnabledKey, defaultValue: false)
@objc static var phraseReplacementEnabled: Bool
@objc static func tooglePhraseReplacementEnabled() -> Bool {
@objc static func togglePhraseReplacementEnabled() -> Bool {
phraseReplacementEnabled = !phraseReplacementEnabled
return phraseReplacementEnabled;
}