SignalServiceKit/tests/Contacts/ContactSortingTest.m
Russ Shanahan 34ffce89f5 Only calculate fullName once, & sortable fullnames (#67)
1. Adds caching of the calculated fullName value
   (which will slightly improve performance)
2. Incorporates fullNames that respect the first-name-first
   rules of the currently unmerged PR #22
3. Adds two new fullName properties that can be used
   for sorting comparators
4. Move the comparator into the model object for easy testing

Includes tests to ensure that the first name first and last name
first sorts are behaving as expected.

// FREEBIE
2016-11-29 10:02:46 -05:00

120 lines
5.6 KiB
Objective-C

// Created by Russ Shanahan on 11/25/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "Contact.h"
#import <XCTest/XCTest.h>
NS_ASSUME_NONNULL_BEGIN
@interface ContactSortingTest : XCTestCase
@end
@implementation ContactSortingTest
- (void)setUp
{
srandom((unsigned int)time(NULL));
}
- (void)testSortingNamesByFirstLast
{
NSComparator comparator = [Contact comparatorSortingNamesByFirstThenLast:YES];
NSArray<Contact *>*sortedContacts = [self.class contactArrayForNames:@[@[@"Adam", @"Smith"],
@[@"Adam", @"West"],
@[@"", @"Daisy"],
@[@"Daisy", @"Chain"],
@[@"Daisy", @"Duke"],
@[@"James", @"Smith"],
@[@"James", @"Van"],
@[@"James", @"Van Der Beek"],
@[@"Kevin", @"Smith"],
@[@"Mae", @"West"],
@[@"Mary", @"Oliver"],
@[@"Mary Jo", @"Catlett"],
]];
NSUInteger numContacts = sortedContacts.count;
for (NSUInteger i = 0; i < 20; i++) {
NSArray *shuffledContacts = [self.class shuffleArray:sortedContacts];
NSArray *resortedContacts = [shuffledContacts sortedArrayUsingComparator:comparator];
for (NSUInteger j = 0; j < numContacts; j++) {
Contact *a = sortedContacts[j];
Contact *b = resortedContacts[j];
BOOL correct = ([a.firstName isEqualToString:b.firstName] && [a.lastName isEqualToString:b.lastName]);
if (!correct) {
XCTAssert(@"Contacts failed to sort names by first, last");
break;
}
}
}
}
- (void)testSortingNamesByLastFirst
{
NSComparator comparator = [Contact comparatorSortingNamesByFirstThenLast:NO];
NSArray<Contact *>*sortedContacts = [self.class contactArrayForNames:@[@[@"Mary Jo", @"Catlett"],
@[@"Daisy", @"Chain"],
@[@"", @"Daisy"],
@[@"Daisy", @"Duke"],
@[@"Mary", @"Oliver"],
@[@"Adam", @"Smith"],
@[@"James", @"Smith"],
@[@"Kevin", @"Smith"],
@[@"James", @"Van"],
@[@"James", @"Van Der Beek"],
@[@"Adam", @"West"],
@[@"Mae", @"West"],
]];
NSUInteger numContacts = sortedContacts.count;
for (NSUInteger i = 0; i < 20; i++) {
NSArray *shuffledContacts = [self.class shuffleArray:sortedContacts];
NSArray *resortedContacts = [shuffledContacts sortedArrayUsingComparator:comparator];
for (NSUInteger j = 0; j < numContacts; j++) {
Contact *a = sortedContacts[j];
Contact *b = resortedContacts[j];
BOOL correct = ([a.firstName isEqualToString:b.firstName] && [a.lastName isEqualToString:b.lastName]);
if (!correct) {
XCTAssert(@"Contacts failed to sort names by last, first");
break;
}
}
}
}
+ (NSArray<Contact *> *)contactArrayForNames:(NSArray<NSArray<NSString *>*>*)namePairs
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
ABRecordID fakeRecordId = 0;
#pragma clang diagnostic pop
NSMutableArray<Contact *>*contacts = [[NSMutableArray alloc] initWithCapacity:namePairs.count];
for (NSArray<NSString *>*namePair in namePairs) {
Contact *c = [[Contact alloc] initWithContactWithFirstName:namePair[0]
andLastName:namePair[1]
andUserTextPhoneNumbers:@[]
andImage:nil
andContactID:fakeRecordId++];
[contacts addObject:c];
}
return [contacts copy]; // Return an immutable for good hygene
}
+ (NSArray*)shuffleArray:(NSArray *)array
{
NSMutableArray *shuffled = [[NSMutableArray alloc] initWithArray:array];
for(NSUInteger i = [array count]; i > 1; i--) {
NSUInteger j = arc4random_uniform((uint32_t)i);
[shuffled exchangeObjectAtIndex:(i - 1) withObjectAtIndex:j];
}
return [shuffled copy]; // Return an immutable for good hygene
}
@end
NS_ASSUME_NONNULL_END