Skip to content

Commit

Permalink
refactor for better testability; add more unit tests to cover the bas…
Browse files Browse the repository at this point in the history
…ic/core logic
  • Loading branch information
dongyuwei committed Jul 16, 2019
1 parent b8dd956 commit 4b8aca3
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 280 deletions.
110 changes: 110 additions & 0 deletions Tests/TestConversionEngine.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

#import "ConversionEngine.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import <XCTest/XCTest.h>

@interface TestConversionEngine : XCTestCase
@property ConversionEngine *engine;
@end

@implementation TestConversionEngine

- (void)setUp {
self.engine = [ConversionEngine sharedEngine];
}

- (void)testWordsWithFrequencyAndTranslation {
NSDictionary *dict = self.engine.wordsWithFrequencyAndTranslation;
NSArray *allKeys = [dict allKeys];
XCTAssert([allKeys count] == 140402);
NSDictionary *word = [dict objectForKey:@"test"];
int frequency = [[word objectForKey:@"frequency"] intValue];
XCTAssert(frequency == 154999587);
NSArray *translation = [word objectForKey:@"translation"];
XCTAssert(translation.count == 2);
}
- (void)testWordsStartsWith {
NSArray *words = [self.engine wordsStartsWith:@"tes"];
XCTAssert(words.count == 95);
NSArray *words5 = [words subarrayWithRange:NSMakeRange(0, 5)];
XCTAssertTrue([[words objectAtIndex:0] isEqualToString:@"test"]);
XCTAssertTrue([[words5 componentsJoinedByString:@";"] isEqualToString:@"test;testing;testings;testim;testimonial"]);
}

- (void)testSortWordsByFrequency {
NSArray *words = [self.engine wordsStartsWith:@"tes"];
NSArray *sorted = [self.engine sortWordsByFrequency:words];
NSArray *words10 = [sorted subarrayWithRange:NSMakeRange(0, 10)];
XCTAssertTrue([[words10 objectAtIndex:0] isEqualToString:@"test"]);
XCTAssertTrue([[words10 componentsJoinedByString:@";"]
isEqualToString:@"test;testing;tests;tested;testimonials;testimony;testament;tester;testified;testers"]);
}

- (void)testPhonexEncode {
JSValue *phonexFunc = self.engine.phonexEncoder;
XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"test" ]] toString] isEqualToString:@"T23"]);

XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"courage" ]] toString]
isEqualToString:[[phonexFunc callWithArguments:@[ @"cerrage" ]] toString]]);

XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"kerrage" ]] toString]
isEqualToString:[[phonexFunc callWithArguments:@[ @"cerrage" ]] toString]]);

XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"inderpendent" ]] toString]
isEqualToString:[[phonexFunc callWithArguments:@[ @"independent" ]] toString]]);

XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"aosome" ]] toString]
isEqualToString:[[phonexFunc callWithArguments:@[ @"awesome" ]] toString]]);

XCTAssertTrue([[[phonexFunc callWithArguments:@[ @"ausome" ]] toString]
isEqualToString:[[phonexFunc callWithArguments:@[ @"awesome" ]] toString]]);
}

- (void)testGetTranslations {
NSArray *translations = [self.engine getTranslations:@"test"];
XCTAssertTrue([[translations objectAtIndex:0] isEqualToString:@"n. 考验;试验;测试"]);
XCTAssertTrue([[translations objectAtIndex:1] isEqualToString:@"vt. 试验;测试;接受测验"]);
}

- (void)testGetPhoneticSymbolOfWord {
NSString *ipa = [self.engine getPhoneticSymbolOfWord:@"test"];
XCTAssertTrue([ipa isEqualToString:@"tɛst"]);
}

- (void)testGetAnnotation {
NSString *annotation = [self.engine getAnnotation:@"test"];
NSArray *list = @[ @"[tɛst]", @"n. 考验;试验;测试", @"vt. 试验;测试;接受测验" ];
XCTAssertTrue([[list componentsJoinedByString:@"\n"] isEqualToString:annotation]);
}

- (void)testGetSuggestionOfSpellChecker {
NSArray *suggestions = [self.engine getSuggestionOfSpellChecker:@"aosome"];
XCTAssertTrue([[suggestions componentsJoinedByString:@";"] isEqualToString:@"Amos;assume;awesome;assumes"]);

NSArray *suggestions2 = [self.engine getSuggestionOfSpellChecker:@"ausome"];
XCTAssertTrue([[suggestions2 componentsJoinedByString:@";"] isEqualToString:@"assume;Amos;assume;awesome;assumes;outcome"]);

NSArray *suggestions3 = [self.engine getSuggestionOfSpellChecker:@"kerrage"];
XCTAssertTrue([[suggestions3 componentsJoinedByString:@";"] isEqualToString:@"Kerrie;kerne;courage;carriage"]);

NSArray *suggestions4 = [self.engine getSuggestionOfSpellChecker:@"cerrage"];
XCTAssertTrue([[suggestions4 componentsJoinedByString:@";"] isEqualToString:@"courage;courage;carriage"]);

NSArray *suggestions5 = [self.engine getSuggestionOfSpellChecker:@"awsome"];
XCTAssertTrue([[suggestions5 componentsJoinedByString:@";"] isEqualToString:@"awesome;awesome;assume;assumes"]);
}

- (void)testGetCandidates {
NSArray *candidates = [self.engine getCandidates:@"tes"];
XCTAssertTrue(candidates.count == 50);
NSArray *words5 = [candidates subarrayWithRange:NSMakeRange(0, 5)];
XCTAssertTrue([[words5 componentsJoinedByString:@";"] isEqualToString:@"tes;test;testing;tests;tested"]);

NSArray *candidates2 = [self.engine getCandidates:@"ceshi"];
XCTAssertTrue(candidates.count == 50);
NSArray *words10 = [candidates2 subarrayWithRange:NSMakeRange(0, 10)];
XCTAssertTrue([[words10 componentsJoinedByString:@","]
isEqualToString:@"ceshi,cash,cushy,case,cases,cisco,测试,to test (machinery etc),to test (students),test"]);
}

@end
58 changes: 0 additions & 58 deletions Tests/TestPhonex.m

This file was deleted.

3 changes: 3 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
xcodebuild -version
clang -v
rm -rf /tmp/hallelujah

xcodebuild clean -workspace hallelujah.xcworkspace/ -scheme hallelujah

xcodebuild -workspace hallelujah.xcworkspace/ -scheme hallelujah -configuration Release CONFIGURATION_BUILD_DIR=/tmp/hallelujah/build/release
26 changes: 22 additions & 4 deletions hallelujah.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@
0D2BFD8F194588F400DE18D9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D2BFD8E194588F400DE18D9 /* Images.xcassets */; };
0DE74BFE1978EC6A00040F3C /* him.png in Resources */ = {isa = PBXBuildFile; fileRef = 0DE74BFD1978EC6A00040F3C /* him.png */; };
0DE74C001978F18E00040F3C /* him.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0DE74BFF1978F18E00040F3C /* him.icns */; };
3802CD7C22CE034100A7E2F9 /* TestPhonex.m in Sources */ = {isa = PBXBuildFile; fileRef = 3802CD7B22CE034100A7E2F9 /* TestPhonex.m */; };
3802CD8622CEE7BB00A7E2F9 /* phonex.js in Resources */ = {isa = PBXBuildFile; fileRef = 3802CD8422CEE7BB00A7E2F9 /* phonex.js */; };
3802CD8C22CF43BD00A7E2F9 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3802CD8B22CF43BD00A7E2F9 /* JavaScriptCore.framework */; };
3802CD9A22CF591100A7E2F9 /* phonex_encoded_words.json in Resources */ = {isa = PBXBuildFile; fileRef = 3802CD9922CF591100A7E2F9 /* phonex_encoded_words.json */; };
3804D23720F2FC2A00CF1BD9 /* NSScreen+PointConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = 3804D23520F2FC2A00CF1BD9 /* NSScreen+PointConversion.m */; };
3817857B22D0E2240091268E /* phonex.js in Resources */ = {isa = PBXBuildFile; fileRef = 3817857A22D0E2240091268E /* phonex.js */; };
381CD8C622C60D610098764F /* WebServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 381CD8C522C60D610098764F /* WebServer.m */; };
3833665322DC8160004BA2D1 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3802CD8B22CF43BD00A7E2F9 /* JavaScriptCore.framework */; };
3833665922DD6F45004BA2D1 /* TestConversionEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3833665822DD6F45004BA2D1 /* TestConversionEngine.mm */; };
3843EC702283BE8E00F52003 /* words_with_frequency_and_translation_and_ipa.json in Resources */ = {isa = PBXBuildFile; fileRef = 3843EC6F2283BE8E00F52003 /* words_with_frequency_and_translation_and_ipa.json */; };
386E1C0022DC5E9C000C6DCF /* ConversionEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 386E1BFF22DC5E9B000C6DCF /* ConversionEngine.mm */; };
389468CB1F56A34A00EF1F5E /* web in Resources */ = {isa = PBXBuildFile; fileRef = 389468CA1F56A34A00EF1F5E /* web */; };
389468D61F57C8CE00EF1F5E /* InputApplicationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 389468D51F57C8CE00EF1F5E /* InputApplicationDelegate.m */; };
38A9EAC722CB424F003CCF52 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38A9EAC622CB424F003CCF52 /* Carbon.framework */; };
Expand Down Expand Up @@ -57,7 +59,6 @@
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
3802CD7922CE034100A7E2F9 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3802CD7B22CE034100A7E2F9 /* TestPhonex.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestPhonex.m; sourceTree = "<group>"; };
3802CD7D22CE034100A7E2F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3802CD8422CEE7BB00A7E2F9 /* phonex.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = phonex.js; sourceTree = "<group>"; };
3802CD8B22CF43BD00A7E2F9 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
Expand All @@ -67,7 +68,10 @@
3817857A22D0E2240091268E /* phonex.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = phonex.js; path = src/phonex.js; sourceTree = "<group>"; };
381CD8C422C60D610098764F /* WebServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebServer.h; path = src/WebServer.h; sourceTree = "<group>"; };
381CD8C522C60D610098764F /* WebServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WebServer.m; path = src/WebServer.m; sourceTree = "<group>"; };
3833665822DD6F45004BA2D1 /* TestConversionEngine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestConversionEngine.mm; sourceTree = "<group>"; };
3843EC6F2283BE8E00F52003 /* words_with_frequency_and_translation_and_ipa.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = words_with_frequency_and_translation_and_ipa.json; path = dictionary/words_with_frequency_and_translation_and_ipa.json; sourceTree = "<group>"; };
386E1BFC22DC5A54000C6DCF /* ConversionEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConversionEngine.h; path = src/ConversionEngine.h; sourceTree = "<group>"; };
386E1BFF22DC5E9B000C6DCF /* ConversionEngine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ConversionEngine.mm; path = src/ConversionEngine.mm; sourceTree = "<group>"; };
389468CA1F56A34A00EF1F5E /* web */ = {isa = PBXFileReference; lastKnownFileType = folder; path = web; sourceTree = "<group>"; };
389468D41F57C8CE00EF1F5E /* InputApplicationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputApplicationDelegate.h; path = src/InputApplicationDelegate.h; sourceTree = "<group>"; };
389468D51F57C8CE00EF1F5E /* InputApplicationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InputApplicationDelegate.m; path = src/InputApplicationDelegate.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -98,6 +102,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3833665322DC8160004BA2D1 /* JavaScriptCore.framework in Frameworks */,
8E90E6AE1DD558B60385D996 /* Pods_Tests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -122,6 +127,8 @@
080E96DDFE201D6D7F000001 /* Classes */ = {
isa = PBXGroup;
children = (
386E1BFC22DC5A54000C6DCF /* ConversionEngine.h */,
386E1BFF22DC5E9B000C6DCF /* ConversionEngine.mm */,
381CD8C422C60D610098764F /* WebServer.h */,
381CD8C522C60D610098764F /* WebServer.m */,
389468D41F57C8CE00EF1F5E /* InputApplicationDelegate.h */,
Expand Down Expand Up @@ -214,8 +221,8 @@
3802CD7A22CE034100A7E2F9 /* Tests */ = {
isa = PBXGroup;
children = (
3833665822DD6F45004BA2D1 /* TestConversionEngine.mm */,
3802CD8422CEE7BB00A7E2F9 /* phonex.js */,
3802CD7B22CE034100A7E2F9 /* TestPhonex.m */,
3802CD7D22CE034100A7E2F9 /* Info.plist */,
);
path = Tests;
Expand Down Expand Up @@ -434,7 +441,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3802CD7C22CE034100A7E2F9 /* TestPhonex.m in Sources */,
3833665922DD6F45004BA2D1 /* TestConversionEngine.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -448,6 +455,7 @@
F102C5AC1F4882D30005B03F /* InputController.mm in Sources */,
F109B4911E1A83AF00AA7A41 /* AnnotationWinController.m in Sources */,
381CD8C622C60D610098764F /* WebServer.m in Sources */,
386E1C0022DC5E9C000C6DCF /* ConversionEngine.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -513,6 +521,11 @@
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_CONFIGURATION_BUILD_DIR}/MDCDamerauLevenshtein/MDCDamerauLevenshtein.framework/Headers\"",
$SOURCE_ROOT/include,
);
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.14;
Expand Down Expand Up @@ -552,6 +565,11 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_CONFIGURATION_BUILD_DIR}/MDCDamerauLevenshtein/MDCDamerauLevenshtein.framework/Headers\"",
$SOURCE_ROOT/include,
);
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.14;
Expand Down
25 changes: 25 additions & 0 deletions src/ConversionEngine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#import "marisa.h"
#import <Cocoa/Cocoa.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import <MDCDamerauLevenshtein/MDCDamerauLevenshtein.h>

@interface ConversionEngine : NSObject

+ (instancetype)sharedEngine;
- (NSMutableArray *)wordsStartsWith:(NSString *)prefix;
- (NSArray *)sortWordsByFrequency:(NSArray *)filtered;
- (NSString *)phonexEncode:(NSString *)word;
- (NSArray *)getTranslations:(NSString *)word;
- (NSString *)getPhoneticSymbolOfWord:(NSString *)candidateString;
- (NSString *)getAnnotation:(NSString *)word;
- (NSArray *)sortByDamerauLevenshteinDistance:(NSArray *)original inputText:(NSString *)text;
- (NSArray *)getSuggestionOfSpellChecker:(NSString *)buffer;
- (NSArray *)getCandidates:(NSString *)originalInput;

@property NSDictionary *wordsWithFrequencyAndTranslation;
@property NSDictionary *substitutions;
@property NSDictionary *pinyinDict;
@property NSDictionary *phonexEncoded;
@property JSValue *phonexEncoder;

@end
Loading

0 comments on commit 4b8aca3

Please sign in to comment.