diff --git a/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj b/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj index e668183de..8a055aeaa 100644 --- a/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj +++ b/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ B6273DE11C13A2E500738558 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B6273DE01C13A2E500738558 /* Assets.xcassets */; }; B6273DE41C13A2E500738558 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6273DE21C13A2E500738558 /* LaunchScreen.storyboard */; }; D2AECE731DE8C3360068CE15 /* ContactSortingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D2AECE721DE8C3360068CE15 /* ContactSortingTest.m */; }; + E95668321E0964F9002418B1 /* PhoneNumberUtilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E95668311E0964F9002418B1 /* PhoneNumberUtilTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -117,6 +118,7 @@ C0DC1A83C39CBC09FB2405A3 /* libPods-TSKitiOSTestAppTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TSKitiOSTestAppTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; D2AECE721DE8C3360068CE15 /* ContactSortingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactSortingTest.m; path = ../../../tests/Contacts/ContactSortingTest.m; sourceTree = ""; }; D3737F7A041D7147015C02C2 /* Pods-TSKitiOSTestAppTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSKitiOSTestAppTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-TSKitiOSTestAppTests/Pods-TSKitiOSTestAppTests.release.xcconfig"; sourceTree = ""; }; + E95668311E0964F9002418B1 /* PhoneNumberUtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneNumberUtilTest.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -192,6 +194,7 @@ 45458B721CC342B600A02153 /* Util */ = { isa = PBXGroup; children = ( + E95668311E0964F9002418B1 /* PhoneNumberUtilTest.m */, 45458B731CC342B600A02153 /* CryptographyTests.m */, 45458B741CC342B600A02153 /* MessagePaddingTests.m */, ); @@ -569,6 +572,7 @@ 4516E3EA1DD1542300DC4206 /* TSContactThreadTest.m in Sources */, 45458B771CC342B600A02153 /* TSMessageStorageTests.m in Sources */, 45046FE01D95A6130015EFF2 /* TSMessagesManagerTest.m in Sources */, + E95668321E0964F9002418B1 /* PhoneNumberUtilTest.m in Sources */, 45458B7C1CC342B600A02153 /* MessagePaddingTests.m in Sources */, 45A856AC1D220BFF0056CD4D /* TSAttributesTest.m in Sources */, 45731A6C1DA87AA1007E22AA /* TSOutgoingMessageTest.m in Sources */, diff --git a/src/Contacts/PhoneNumberUtil.h b/src/Contacts/PhoneNumberUtil.h index ff0e24275..ebcb0615a 100644 --- a/src/Contacts/PhoneNumberUtil.h +++ b/src/Contacts/PhoneNumberUtil.h @@ -10,6 +10,8 @@ @property (nonatomic, retain) NBPhoneNumberUtil *nbPhoneNumberUtil; ++ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString; + + (NSString *)callingCodeFromCountryCode:(NSString *)countryCode; + (NSString *)countryNameFromCountryCode:(NSString *)countryCode; + (NSArray *)countryCodesForSearchTerm:(NSString *)searchTerm; diff --git a/src/Contacts/PhoneNumberUtil.m b/src/Contacts/PhoneNumberUtil.m index 773c71fb2..eabc512f4 100644 --- a/src/Contacts/PhoneNumberUtil.m +++ b/src/Contacts/PhoneNumberUtil.m @@ -5,7 +5,6 @@ #import "PhoneNumberUtil.h" #import "ContactsManagerProtocol.h" #import "FunctionalUtil.h" -#import "TextSecureKitEnv.h" #import "Util.h" @implementation PhoneNumberUtil @@ -97,6 +96,21 @@ return countryCodes; } ++ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString { + NSCharacterSet *whitespaceSet = NSCharacterSet.whitespaceCharacterSet; + NSArray *queryStrings = [queryString componentsSeparatedByCharactersInSet:whitespaceSet]; + NSArray *nameStrings = [nameString componentsSeparatedByCharactersInSet:whitespaceSet]; + + return [queryStrings all:^int(NSString *query) { + if (query.length == 0) + return YES; + return [nameStrings any:^int(NSString *nameWord) { + NSStringCompareOptions searchOpts = NSCaseInsensitiveSearch | NSAnchoredSearch; + return [nameWord rangeOfString:query options:searchOpts].location != NSNotFound; + }]; + }]; +} + // search term -> country codes + (NSArray *)countryCodesForSearchTerm:(NSString *)searchTerm { searchTerm = [searchTerm stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; @@ -113,10 +127,11 @@ return NO; } - if ([[[TextSecureKitEnv sharedEnv].contactsManager class] name:countryName matchesQuery:searchTerm]) { + if ([self name:countryName matchesQuery:searchTerm]) { return YES; } - if ([[[TextSecureKitEnv sharedEnv].contactsManager class] name:countryCode matchesQuery:searchTerm]) { + + if ([self name:countryCode matchesQuery:searchTerm]) { return YES; } diff --git a/src/Protocols/ContactsManagerProtocol.h b/src/Protocols/ContactsManagerProtocol.h index e55cf9137..64317fa58 100644 --- a/src/Protocols/ContactsManagerProtocol.h +++ b/src/Protocols/ContactsManagerProtocol.h @@ -9,7 +9,6 @@ - (NSString * _Nonnull)displayNameForPhoneIdentifier:(NSString * _Nullable)phoneNumber; - (NSArray * _Nonnull)signalContacts; -+ (BOOL)name:(NSString * _Nonnull)nameString matchesQuery:(NSString * _Nonnull)queryString; #if TARGET_OS_IPHONE - (UIImage * _Nullable)imageForPhoneIdentifier:(NSString * _Nullable)phoneNumber; diff --git a/tests/Util/PhoneNumberUtilTest.m b/tests/Util/PhoneNumberUtilTest.m new file mode 100644 index 000000000..419d6fa25 --- /dev/null +++ b/tests/Util/PhoneNumberUtilTest.m @@ -0,0 +1,36 @@ +// +// PhoneNumberTest.m +// Signal +// +// Created by Michael Kirk on 6/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. +// + +#import +#import "PhoneNumberUtil.h" + +@interface PhoneNumberUtilTest : XCTestCase + +@end + +@implementation PhoneNumberUtilTest + +- (void)testQueryMatching { + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"big dave"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"dave big"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"dave"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"big"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"big "]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@" big "]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"dav"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"bi dav"]); + XCTAssertTrue([PhoneNumberUtil name:@"big dave" matchesQuery:@"big big big big big big big big big big dave dave dave dave dave"]); + + XCTAssertFalse([PhoneNumberUtil name:@"big dave" matchesQuery:@"ave"]); + XCTAssertFalse([PhoneNumberUtil name:@"big dave" matchesQuery:@"dare"]); + XCTAssertFalse([PhoneNumberUtil name:@"big dave" matchesQuery:@"mike"]); + XCTAssertFalse([PhoneNumberUtil name:@"big dave" matchesQuery:@"mike"]); + XCTAssertFalse([PhoneNumberUtil name:@"dave" matchesQuery:@"big"]); +} + +@end