Search SignalAccounts by profile name
...and fixup some tests
This commit is contained in:
parent
06f52deaf9
commit
71bafcc8f0
|
@ -279,7 +279,6 @@
|
|||
45E7A6A81E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E7A6A61E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift */; };
|
||||
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
||||
45F170AD1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
||||
45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */; };
|
||||
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||
45F170BC1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||
45F170CC1E310E22003FC1F2 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170CB1E310E22003FC1F2 /* WeakTimer.swift */; };
|
||||
|
@ -866,7 +865,6 @@
|
|||
45E615151E8C590B0018AD52 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableText.swift; sourceTree = "<group>"; };
|
||||
45E7A6A61E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableTextFilterTest.swift; sourceTree = "<group>"; };
|
||||
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; };
|
||||
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSessionTest.swift; sourceTree = "<group>"; };
|
||||
45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; };
|
||||
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = "<group>"; };
|
||||
45F170CB1E310E22003FC1F2 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
|
||||
|
@ -1837,7 +1835,6 @@
|
|||
B660F6731C29867F00687D6E /* call */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */,
|
||||
456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */,
|
||||
);
|
||||
path = call;
|
||||
|
@ -2928,7 +2925,6 @@
|
|||
458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */,
|
||||
452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */,
|
||||
451DE9FE1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */,
|
||||
45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */,
|
||||
456F6E231E24133500FD2210 /* Platform.swift in Sources */,
|
||||
4539B5871F79348F007141FF /* PushRegistrationManager.swift in Sources */,
|
||||
4504493A1F45EE7D002D1ADA /* NSString+OWS.m in Sources */,
|
||||
|
|
|
@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic) BOOL shouldNotifyDelegateOfUpdatedContacts;
|
||||
@property (nonatomic) BOOL hasUpdatedContactsAtLeastOnce;
|
||||
@property (nonatomic) OWSProfileManager *profileManager;
|
||||
@property (nonatomic, readonly) AnySearcher *signalAccountSearcher;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -59,6 +60,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self updateContacts];
|
||||
self.shouldNotifyDelegateOfUpdatedContacts = NO;
|
||||
|
||||
_signalAccountSearcher = [self buildAccountSearcher];
|
||||
|
||||
[self observeNotifications];
|
||||
|
||||
return self;
|
||||
|
@ -99,6 +102,24 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark - Contacts
|
||||
|
||||
- (AnySearcher *)buildAccountSearcher
|
||||
{
|
||||
return [[AnySearcher alloc] initWithIndexer:^NSString *_Nonnull(id _Nonnull obj) {
|
||||
if (![obj isKindOfClass:[SignalAccount class]]) {
|
||||
OWSFail(@"unexpected item in searcher");
|
||||
return @"";
|
||||
}
|
||||
|
||||
SignalAccount *signalAccount = (SignalAccount *)obj;
|
||||
|
||||
NSString *recipientId = signalAccount.recipientId;
|
||||
NSString *contactName = [self.contactsManager displayNameForPhoneIdentifier:recipientId];
|
||||
NSString *profileName = [self.contactsManager profileNameForRecipientId:recipientId];
|
||||
|
||||
return [NSString stringWithFormat:@"%@ %@ %@", recipientId, contactName, profileName];
|
||||
}];
|
||||
}
|
||||
|
||||
- (nullable SignalAccount *)signalAccountForRecipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
@ -173,37 +194,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)doesSignalAccount:(SignalAccount *)signalAccount matchSearchTerm:(NSString *)searchTerm
|
||||
{
|
||||
OWSAssert(signalAccount);
|
||||
OWSAssert(searchTerm.length > 0);
|
||||
|
||||
if ([signalAccount.contact.fullName.lowercaseString containsString:searchTerm.lowercaseString]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString *asPhoneNumber = [PhoneNumber removeFormattingCharacters:searchTerm];
|
||||
if (asPhoneNumber.length > 0 && [signalAccount.recipientId containsString:asPhoneNumber]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)doesSignalAccount:(SignalAccount *)signalAccount matchSearchTerms:(NSArray<NSString *> *)searchTerms
|
||||
{
|
||||
OWSAssert(signalAccount);
|
||||
OWSAssert(searchTerms.count > 0);
|
||||
|
||||
for (NSString *searchTerm in searchTerms) {
|
||||
if (![self doesSignalAccount:signalAccount matchSearchTerm:searchTerm]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)searchTermsForSearchString:(NSString *)searchText
|
||||
{
|
||||
return [[[searchText ows_stripped]
|
||||
|
@ -225,7 +215,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self.signalAccounts
|
||||
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(SignalAccount *signalAccount,
|
||||
NSDictionary<NSString *, id> *_Nullable bindings) {
|
||||
return [self doesSignalAccount:signalAccount matchSearchTerms:searchTerms];
|
||||
return [self.signalAccountSearcher item:signalAccount doesMatchQuery:searchText];
|
||||
}]];
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,16 @@ class Searcher<T> {
|
|||
}
|
||||
|
||||
private func stem(string: String) -> [String] {
|
||||
return normalize(string: string).components(separatedBy: .whitespaces)
|
||||
var normalized = normalize(string: string)
|
||||
|
||||
// Remove any phone number formatting from the search terms
|
||||
let nonformattingScalars = normalized.unicodeScalars.lazy.filter {
|
||||
!CharacterSet.punctuationCharacters.contains($0)
|
||||
}
|
||||
|
||||
normalized = String(String.UnicodeScalarView(nonformattingScalars))
|
||||
|
||||
return normalized.components(separatedBy: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
private func normalize(string: String) -> String {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import XCTest
|
||||
import PromiseKit
|
||||
import SignalServiceKit
|
||||
|
||||
struct VerificationFailedError: Error { }
|
||||
struct FailedToGetRPRegistrationTokenError: Error { }
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
import SignalServiceKit
|
||||
|
||||
/**
|
||||
* This is a brittle test, which will break if our layout changes.
|
||||
|
@ -23,7 +24,12 @@ class MesssagesBubblesSizeCalculatorTest: XCTestCase {
|
|||
func viewItemForText(_ text: String?) -> ConversationViewItem {
|
||||
let interaction = TSOutgoingMessage(timestamp: 0, in: thread, messageBody: text)
|
||||
interaction.save()
|
||||
let viewItem = ConversationViewItem(tsInteraction:interaction, isGroupThread:false)
|
||||
|
||||
var viewItem: ConversationViewItem!
|
||||
interaction.dbReadWriteConnection().readWrite { transaction in
|
||||
viewItem = ConversationViewItem(interaction: interaction, isGroupThread: false, transaction: transaction)
|
||||
}
|
||||
|
||||
viewItem.shouldShowDate = false
|
||||
viewItem.shouldHideRecipientStatus = true
|
||||
return viewItem
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#import <SignalServiceKit/TSAttachmentStream.h>
|
||||
#import <SignalServiceKit/TSOutgoingMessage.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
@interface ConversationViewItem (Testing)
|
||||
|
||||
|
@ -64,8 +65,10 @@
|
|||
|
||||
OWSAssert([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
|
||||
|
||||
TSAttachmentStream *attachment = [[TSAttachmentStream alloc] initWithContentType:mimeType sourceFilename:nil];
|
||||
DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
|
||||
TSAttachmentStream *attachment = [[TSAttachmentStream alloc] initWithContentType:mimeType
|
||||
byteCount:(UInt32)dataSource.dataLength
|
||||
sourceFilename:nil];
|
||||
BOOL success = [attachment writeDataSource:dataSource];
|
||||
OWSAssert(success);
|
||||
[attachment save];
|
||||
|
@ -75,7 +78,12 @@
|
|||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:nil attachmentIds:attachmentIds];
|
||||
[message save];
|
||||
ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithInteraction:message isGroupThread:NO];
|
||||
|
||||
__block ConversationViewItem *viewItem = nil;
|
||||
[TSYapDatabaseObject.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:message isGroupThread:NO transaction:transaction];
|
||||
}];
|
||||
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright © 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AVKit
|
||||
import WebRTC
|
||||
|
||||
/**
|
||||
* These tests are obtuse - they just assert the exact implementation of the methods. Normally I wouldn't include them,
|
||||
* but these methods make use of a header not included in the standard distribution of the WebRTC.framework. We've
|
||||
* included the header in our local project, and test the methods here to make sure that they are still available when
|
||||
* we upgrade the framework.
|
||||
*
|
||||
* If they are failing, it's possible the RTCAudioSession header, and our usage of it, need to be updated.
|
||||
*/
|
||||
class CallAudioSessionTest: XCTestCase {
|
||||
func testAudioSession() {
|
||||
|
||||
let rtcAudioSession = RTCAudioSession.sharedInstance()
|
||||
// Sanity Check
|
||||
XCTAssertFalse(rtcAudioSession.useManualAudio)
|
||||
|
||||
CallAudioSession().configure()
|
||||
XCTAssertTrue(rtcAudioSession.useManualAudio)
|
||||
XCTAssertFalse(rtcAudioSession.isAudioEnabled)
|
||||
|
||||
CallAudioSession().start()
|
||||
XCTAssertTrue(rtcAudioSession.useManualAudio)
|
||||
XCTAssertTrue(rtcAudioSession.isAudioEnabled)
|
||||
|
||||
CallAudioSession().stop()
|
||||
XCTAssertTrue(rtcAudioSession.useManualAudio)
|
||||
XCTAssertFalse(rtcAudioSession.isAudioEnabled)
|
||||
}
|
||||
}
|
|
@ -9,14 +9,15 @@ class SearcherTest: XCTestCase {
|
|||
struct TestCharacter {
|
||||
let name: String
|
||||
let description: String
|
||||
let phoneNumber: String?
|
||||
}
|
||||
|
||||
let smerdyakov = TestCharacter(name: "Pavel Fyodorovich Smerdyakov", description: "A rusty hue in the sky")
|
||||
let stinkingLizaveta = TestCharacter(name: "Stinking Lizaveta", description: "object of pity")
|
||||
let regularLizaveta = TestCharacter(name: "Lizaveta", description: "")
|
||||
let smerdyakov = TestCharacter(name: "Pavel Fyodorovich Smerdyakov", description: "A rusty hue in the sky", phoneNumber: nil)
|
||||
let stinkingLizaveta = TestCharacter(name: "Stinking Lizaveta", description: "object of pity", phoneNumber: "+13235555555")
|
||||
let regularLizaveta = TestCharacter(name: "Lizaveta", description: "", phoneNumber: "1 (415) 555-5555")
|
||||
|
||||
let indexer = { (character: TestCharacter) in
|
||||
return "\(character.name) \(character.description)"
|
||||
return "\(character.name) \(character.description) \(character.phoneNumber ?? "")"
|
||||
}
|
||||
|
||||
var searcher: Searcher<TestCharacter> {
|
||||
|
@ -57,4 +58,20 @@ class SearcherTest: XCTestCase {
|
|||
XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Lizaveta St"))
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query: " Lizaveta St "))
|
||||
}
|
||||
|
||||
func testFormattingChars() {
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"323"))
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"1-323-555-5555"))
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"13235555555"))
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"+1-323"))
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"Liza +1-323"))
|
||||
|
||||
// Sanity check, match both by names
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"Liza"))
|
||||
XCTAssert(searcher.matches(item: regularLizaveta, query:"Liza"))
|
||||
|
||||
// Disambiguate the two Liza's by area code
|
||||
XCTAssert(searcher.matches(item: stinkingLizaveta, query:"Liza 323"))
|
||||
XCTAssertFalse(searcher.matches(item: regularLizaveta, query:"Liza 323"))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue