blob: 9037369fce64cce7ad42853e00641ef92b0233ca [file] [log] [blame]
//
// GTMABAddressBookTest.m
//
// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import "GTMSenTestCase.h"
#import "GTMABAddressBook.h"
#if GTM_IPHONE_SDK
#import "UIKit/UIKit.h"
#else
#import <AppKit/AppKit.h>
#endif // GTM_IPHONE_SDK
static NSString *const kGTMABTestFirstName = @"GTMABAddressBookTestFirstName";
static NSString *const kGTMABTestLastName = @"GTMABAddressBookTestLastName";
static NSString *const kGTMABTestGroupName = @"GTMABAddressBookTestGroupName";
@interface GTMABAddressBookTest : GTMTestCase {
@private
GTMABAddressBook *book_;
}
@end
@implementation GTMABAddressBookTest
#if GTM_IPHONE_SDK
// On iOS we need to check if we have access to the Address Book before running any tests.
// See
// third_party/objective_c/google_toolbox_for_mac/UnitTesting/GTMIPhoneUnitTestMain.m
// for a way this can be provided via entitlements.
+ (void)setUp {
[super setUp];
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if(status != kABAuthorizationStatusAuthorized) {
[NSException raise:NSInternalInconsistencyException format:@"Don't have Address Book Access"];
}
}
#endif // GTM_IPHONE_SDK
- (void)setUp {
// Create a book forcing it out of it's autorelease pool.
// I force it out of the release pool, so that we will see any errors
// for it immediately at teardown, and it will be clear which release
// caused us problems.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
book_ = [[GTMABAddressBook addressBook] retain];
[pool release];
XCTAssertNotNil(book_);
NSArray *people
= [book_ peopleWithCompositeNameWithPrefix:kGTMABTestFirstName];
GTMABPerson *person;
for (person in people) {
[book_ removeRecord:person];
}
NSArray *groups
= [book_ groupsWithCompositeNameWithPrefix:kGTMABTestGroupName];
GTMABGroup *group;
for (group in groups) {
[book_ removeRecord:group];
}
[book_ save];
}
- (void)tearDown {
[book_ release];
}
- (void)testGenericAddressBook {
XCTAssertEqualObjects([GTMABAddressBook localizedLabel:(NSString *)kABHomeLabel],
@"home");
XCTAssertThrows([GTMABRecord recordWithRecord:nil]);
}
- (void)testAddingAndRemovingPerson {
// Create a person
GTMABPerson *person = [GTMABPerson personWithFirstName:kGTMABTestFirstName
lastName:kGTMABTestLastName];
XCTAssertNotNil(person);
// Add person
NSArray *people = [book_ people];
XCTAssertFalse([people containsObject:person]);
XCTAssertTrue([book_ addRecord:person]);
#if GTM_IPHONE_SDK && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2)
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
// We will check to make sure it stays broken ;-)
XCTAssertFalse([book_ hasUnsavedChanges]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([book_ hasUnsavedChanges]);
#endif // GTM_IPHONE_SDK
people = [book_ people];
XCTAssertNotNil(people);
#if GTM_IPHONE_SDK
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200703: ABAddressBookAddRecord doesn't add an item to the people
// array until it's saved
// We will check to make sure it stays broken ;-)
XCTAssertFalse([people containsObject:person]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([people containsObject:person]);
#endif // GTM_IPHONE_SDK
// Save book_
XCTAssertTrue([book_ save]);
people = [book_ people];
XCTAssertNotNil(people);
XCTAssertTrue([people containsObject:person]);
people = [book_ peopleWithCompositeNameWithPrefix:kGTMABTestFirstName];
XCTAssertEqualObjects([people objectAtIndex:0], person);
GTMABRecordID recordID = [person recordID];
XCTAssertNotEqual(recordID, kGTMABRecordInvalidID);
GTMABRecord *record = [book_ personForId:recordID];
XCTAssertEqualObjects(record, person);
// Remove person
XCTAssertTrue([book_ removeRecord:person]);
people = [book_ peopleWithCompositeNameWithPrefix:kGTMABTestFirstName];
XCTAssertEqual([people count], (NSUInteger)0);
#if GTM_IPHONE_SDK && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2)
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
// We will check to make sure it stays broken ;-)
XCTAssertFalse([book_ hasUnsavedChanges]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([book_ hasUnsavedChanges]);
#endif // GTM_IPHONE_SDK
people = [book_ people];
XCTAssertFalse([people containsObject:person]);
// Save Book
XCTAssertTrue([book_ save]);
people = [book_ people];
XCTAssertFalse([book_ hasUnsavedChanges]);
XCTAssertFalse([people containsObject:person]);
record = [book_ personForId:recordID];
XCTAssertNil(record);
// Bogus data
XCTAssertFalse([book_ addRecord:nil]);
XCTAssertFalse([book_ removeRecord:nil]);
XCTAssertNotNULL([book_ addressBookRef]);
}
- (void)testAddingAndRemovingGroup {
// Create a group
GTMABGroup *group = [GTMABGroup groupNamed:kGTMABTestGroupName];
XCTAssertNotNil(group);
// Add group
NSArray *groups = [book_ groups];
XCTAssertFalse([groups containsObject:group]);
XCTAssertTrue([book_ addRecord:group]);
#if GTM_IPHONE_SDK && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2)
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
// We will check to make sure it stays broken ;-)
XCTAssertFalse([book_ hasUnsavedChanges]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([book_ hasUnsavedChanges]);
#endif // GTM_IPHONE_SDK
groups = [book_ groups];
XCTAssertNotNil(groups);
#if GTM_IPHONE_SDK
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200703: ABAddressBookAddRecord doesn't add an item to the groups
// array until it's saved
// We will check to make sure it stays broken ;-)
XCTAssertFalse([groups containsObject:group]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([groups containsObject:group]);
#endif // GTM_IPHONE_SDK
// Save book_
XCTAssertTrue([book_ save]);
groups = [book_ groups];
XCTAssertNotNil(groups);
XCTAssertTrue([groups containsObject:group]);
groups = [book_ groupsWithCompositeNameWithPrefix:kGTMABTestGroupName];
XCTAssertEqualObjects([groups objectAtIndex:0], group);
GTMABRecordID recordID = [group recordID];
XCTAssertNotEqual(recordID, kGTMABRecordInvalidID);
GTMABRecord *record = [book_ groupForId:recordID];
XCTAssertEqualObjects(record, group);
// Remove group
XCTAssertTrue([book_ removeRecord:group]);
#if GTM_IPHONE_SDK && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2)
// Normally this next line would be XCTAssertTrue, however due to
// Radar 6200638: ABAddressBookHasUnsavedChanges doesn't work
// We will check to make sure it stays broken ;-)
XCTAssertFalse([book_ hasUnsavedChanges]);
#else // GTM_IPHONE_SDK
XCTAssertTrue([book_ hasUnsavedChanges]);
#endif // GTM_IPHONE_SDK
groups = [book_ groups];
XCTAssertFalse([groups containsObject:group]);
// Save Book
XCTAssertTrue([book_ save]);
groups = [book_ groups];
XCTAssertFalse([book_ hasUnsavedChanges]);
XCTAssertFalse([groups containsObject:group]);
groups = [book_ groupsWithCompositeNameWithPrefix:kGTMABTestGroupName];
XCTAssertEqual([groups count], (NSUInteger)0);
record = [book_ groupForId:recordID];
XCTAssertNil(record);
}
- (void)testPerson {
GTMABPerson *person = [[[GTMABPerson alloc] initWithRecord:nil] autorelease];
XCTAssertNil(person);
person = [GTMABPerson personWithFirstName:kGTMABTestFirstName
lastName:nil];
XCTAssertNotNil(person);
XCTAssertEqualObjects([person compositeName], kGTMABTestFirstName);
NSString *firstName = [person valueForProperty:kGTMABPersonFirstNameProperty];
XCTAssertEqualObjects(firstName, kGTMABTestFirstName);
NSString *lastName = [person valueForProperty:kGTMABPersonLastNameProperty];
XCTAssertNil(lastName);
XCTAssertTrue([person removeValueForProperty:kGTMABPersonFirstNameProperty]);
XCTAssertFalse([person removeValueForProperty:kGTMABPersonFirstNameProperty]);
XCTAssertFalse([person removeValueForProperty:kGTMABPersonLastNameProperty]);
XCTAssertFalse([person setValue:nil forProperty:kGTMABPersonFirstNameProperty]);
XCTAssertFalse([person setValue:[NSNumber numberWithInt:1]
forProperty:kGTMABPersonFirstNameProperty]);
XCTAssertFalse([person setValue:@"Bart"
forProperty:kGTMABPersonBirthdayProperty]);
GTMABPropertyType property
= [GTMABPerson typeOfProperty:kGTMABPersonLastNameProperty];
XCTAssertEqual(property, (GTMABPropertyType)kGTMABStringPropertyType);
NSString *string
= [GTMABPerson localizedPropertyName:kGTMABPersonLastNameProperty];
XCTAssertEqualObjects(string, @"Last");
string = [GTMABPerson localizedPropertyName:kGTMABRecordInvalidID];
#if GTM_IPHONE_SDK
XCTAssertEqualObjects(string, kGTMABUnknownPropertyName);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(string, kGTMABRecordInvalidID);
#endif // GTM_IPHONE_SDK
string = [person description];
XCTAssertNotNil(string);
GTMABPersonCompositeNameFormat format = [GTMABPerson compositeNameFormat];
XCTAssertTrue(format == kABPersonCompositeNameFormatFirstNameFirst ||
format == kABPersonCompositeNameFormatLastNameFirst);
NSData *data = [person imageData];
XCTAssertNil(data);
XCTAssertTrue([person setImageData:nil]);
data = [person imageData];
XCTAssertNil(data);
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *phonePath = [bundle pathForResource:@"phone" ofType:@"png"];
XCTAssertNotNil(phonePath);
GTMABImage *image
= [[[GTMABImage alloc] initWithContentsOfFile:phonePath] autorelease];
XCTAssertNotNil(image);
#if GTM_IPHONE_SDK
data = UIImagePNGRepresentation(image);
#else // GTM_IPHONE_SDK
data = [image TIFFRepresentation];
#endif // GTM_IPHONE_SDK
XCTAssertTrue([person setImageData:data]);
NSData *data2 = [person imageData];
XCTAssertEqualObjects(data, data2);
XCTAssertTrue([person setImageData:nil]);
data = [person imageData];
XCTAssertNil(data);
XCTAssertTrue([person setImage:image]);
GTMABImage *image2 = [person image];
XCTAssertNotNil(image2);
#if GTM_IPHONE_SDK
XCTAssertEqualObjects(UIImagePNGRepresentation(image),
UIImagePNGRepresentation(image2));
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects([image TIFFRepresentation],
[image2 TIFFRepresentation]);
#endif // GTM_IPHONE_SDK
person = [GTMABPerson personWithFirstName:kGTMABTestFirstName
lastName:kGTMABTestLastName];
data = [NSData dataWithBytes:"a" length:1];
XCTAssertFalse([person setImageData:data]);
GTMABMutableMultiValue *value
= [GTMABMutableMultiValue valueWithPropertyType:kGTMABStringPropertyType];
XCTAssertNotNil(value);
XCTAssertNotEqual([value addValue:@"222-222-2222"
withLabel:(CFStringRef)kABHomeLabel],
kGTMABMultiValueInvalidIdentifier);
XCTAssertNotEqual([value addValue:@"333-333-3333"
withLabel:(CFStringRef)kABWorkLabel],
kGTMABMultiValueInvalidIdentifier);
XCTAssertTrue([person setValue:value
forProperty:kGTMABPersonPhoneProperty]);
id value2 = [person valueForProperty:kGTMABPersonPhoneProperty];
XCTAssertNotNil(value2);
XCTAssertEqualObjects(value, value2);
XCTAssertEqual([value hash], [value2 hash]);
XCTAssertNotEqual([person hash], (NSUInteger)0);
}
- (void)testGroup {
GTMABGroup *group = [[[GTMABGroup alloc] initWithRecord:nil] autorelease];
XCTAssertNil(group);
group = [GTMABGroup groupNamed:kGTMABTestGroupName];
XCTAssertNotNil(group);
XCTAssertEqualObjects([group compositeName], kGTMABTestGroupName);
NSString *name = [group valueForProperty:kABGroupNameProperty];
XCTAssertEqualObjects(name, kGTMABTestGroupName);
NSString *lastName = [group valueForProperty:kGTMABPersonLastNameProperty];
XCTAssertNil(lastName);
XCTAssertTrue([group removeValueForProperty:kABGroupNameProperty]);
XCTAssertFalse([group removeValueForProperty:kABGroupNameProperty]);
XCTAssertFalse([group removeValueForProperty:kGTMABPersonLastNameProperty]);
XCTAssertFalse([group setValue:nil forProperty:kABGroupNameProperty]);
XCTAssertFalse([group setValue:[NSNumber numberWithInt:1]
forProperty:kABGroupNameProperty]);
XCTAssertFalse([group setValue:@"Bart"
forProperty:kGTMABPersonBirthdayProperty]);
ABPropertyType property = [GTMABGroup typeOfProperty:kABGroupNameProperty];
XCTAssertEqual(property, (ABPropertyType)kGTMABStringPropertyType);
property = [GTMABGroup typeOfProperty:kGTMABPersonLastNameProperty];
XCTAssertEqual(property, (ABPropertyType)kGTMABInvalidPropertyType);
NSString *string = [GTMABGroup localizedPropertyName:kABGroupNameProperty];
XCTAssertEqualObjects(string, @"Name");
string = [GTMABGroup localizedPropertyName:kGTMABPersonLastNameProperty];
XCTAssertEqualObjects(string, kGTMABUnknownPropertyName);
string = [GTMABGroup localizedPropertyName:kGTMABRecordInvalidID];
XCTAssertEqualObjects(string, kGTMABUnknownPropertyName);
string = [group description];
XCTAssertNotNil(string);
// Adding and removing members
group = [GTMABGroup groupNamed:kGTMABTestGroupName];
NSArray *members = [group members];
XCTAssertEqual([members count], (NSUInteger)0, @"Members: %@", members);
XCTAssertFalse([group addMember:nil]);
members = [group members];
XCTAssertEqual([members count], (NSUInteger)0, @"Members: %@", members);
GTMABPerson *person = [GTMABPerson personWithFirstName:kGTMABTestFirstName
lastName:kGTMABTestLastName];
XCTAssertNotNil(person);
XCTAssertTrue([book_ addRecord:person]);
XCTAssertTrue([book_ save]);
XCTAssertTrue([book_ addRecord:group]);
XCTAssertTrue([book_ save]);
XCTAssertTrue([group addMember:person]);
XCTAssertTrue([book_ save]);
members = [group members];
XCTAssertEqual([members count], (NSUInteger)1, @"Members: %@", members);
XCTAssertTrue([group removeMember:person]);
XCTAssertFalse([group removeMember:person]);
XCTAssertFalse([group removeMember:nil]);
XCTAssertTrue([book_ removeRecord:group]);
XCTAssertTrue([book_ removeRecord:person]);
XCTAssertTrue([book_ save]);
}
- (void)testMultiValues {
XCTAssertThrows([[GTMABMultiValue alloc] init]);
XCTAssertThrows([[GTMABMutableMultiValue alloc] init]);
GTMABMultiValue *value = [[GTMABMultiValue alloc] initWithMultiValue:nil];
XCTAssertNil(value);
GTMABMutableMultiValue *mutValue
= [GTMABMutableMultiValue valueWithPropertyType:kGTMABInvalidPropertyType];
XCTAssertNil(mutValue);
mutValue
= [[[GTMABMutableMultiValue alloc]
initWithMutableMultiValue:nil] autorelease];
XCTAssertNil(mutValue);
mutValue
= [[[GTMABMutableMultiValue alloc]
initWithMultiValue:nil] autorelease];
XCTAssertNil(mutValue);
#if GTM_IPHONE_SDK
// Only the IPhone version actually allows you to check types of a multivalue
// before you stick anything in it
const GTMABPropertyType types[] = {
kGTMABStringPropertyType,
kGTMABIntegerPropertyType,
kGTMABRealPropertyType,
kGTMABDateTimePropertyType,
kGTMABDictionaryPropertyType,
kGTMABMultiStringPropertyType,
kGTMABMultiIntegerPropertyType,
kGTMABMultiRealPropertyType,
kGTMABMultiDateTimePropertyType,
kGTMABMultiDictionaryPropertyType
};
for (size_t i = 0; i < sizeof(types) / sizeof(GTMABPropertyType); ++i) {
mutValue = [GTMABMutableMultiValue valueWithPropertyType:types[i]];
XCTAssertNotNil(mutValue);
// Oddly the Apple APIs allow you to create a mutable multi value with
// either a property type of kABFooPropertyType or kABMultiFooPropertyType
// and apparently you get back basically the same thing. However if you
// ask a type that you created with kABMultiFooPropertyType for it's type
// it returns just kABFooPropertyType.
XCTAssertEqual([mutValue propertyType],
(GTMABPropertyType)(types[i] & ~kABMultiValueMask));
}
#endif // GTM_IPHONE_SDK
mutValue
= [GTMABMutableMultiValue valueWithPropertyType:kGTMABStringPropertyType];
XCTAssertNotNil(mutValue);
value = [[mutValue copy] autorelease];
XCTAssertEqualObjects([value class], [GTMABMultiValue class]);
mutValue = [[value mutableCopy] autorelease];
XCTAssertEqualObjects([mutValue class], [GTMABMutableMultiValue class]);
XCTAssertEqual([mutValue count], (NSUInteger)0);
XCTAssertNil([mutValue valueAtIndex:0]);
XCTAssertNil([mutValue labelAtIndex:0]);
#if GTM_IPHONE_SDK
XCTAssertEqual([mutValue identifierAtIndex:0],
kGTMABMultiValueInvalidIdentifier);
XCTAssertEqual([mutValue propertyType],
(GTMABPropertyType)kGTMABStringPropertyType);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects([mutValue identifierAtIndex:0],
kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
GTMABMultiValueIdentifier ident
= [mutValue addValue:nil withLabel:(CFStringRef)kABHomeLabel];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
ident = [mutValue addValue:@"val1"
withLabel:nil];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
ident = [mutValue insertValue:@"val1"
withLabel:nil
atIndex:0];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
ident = [mutValue insertValue:nil
withLabel:(CFStringRef)kABHomeLabel
atIndex:0];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
ident = [mutValue addValue:@"val1"
withLabel:(CFStringRef)kABHomeLabel];
#if GTM_IPHONE_SDK
XCTAssertNotEqual(ident, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertNotEqualObjects(ident, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
GTMABMultiValueIdentifier identCheck = [mutValue identifierAtIndex:0];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident, identCheck);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident, identCheck);
#endif // GTM_IPHONE_SDK
NSUInteger idx = [mutValue indexForIdentifier:ident];
XCTAssertEqual(idx, (NSUInteger)0);
XCTAssertTrue([mutValue replaceLabelAtIndex:0
withLabel:(CFStringRef)kABWorkLabel]);
XCTAssertFalse([mutValue replaceLabelAtIndex:10
withLabel:(CFStringRef)kABWorkLabel]);
XCTAssertTrue([mutValue replaceValueAtIndex:0
withValue:@"newVal1"]);
XCTAssertFalse([mutValue replaceValueAtIndex:10
withValue:@"newVal1"]);
XCTAssertEqualObjects([mutValue valueForIdentifier:ident], @"newVal1");
XCTAssertEqualObjects([mutValue labelForIdentifier:ident],
(NSString *)kABWorkLabel);
GTMABMultiValueIdentifier ident2
= [mutValue insertValue:@"val2"
withLabel:(CFStringRef)kABOtherLabel
atIndex:0];
XCTAssertNotEqual(ident2, kGTMABMultiValueInvalidIdentifier);
XCTAssertNotEqual(ident2, ident);
GTMABMultiValueIdentifier ident3
= [mutValue insertValue:@"val3"
withLabel:(CFStringRef)kGTMABPersonPhoneMainLabel
atIndex:10];
#if GTM_IPHONE_SDK
XCTAssertEqual(ident3, kGTMABMultiValueInvalidIdentifier);
#else // GTM_IPHONE_SDK
XCTAssertEqualObjects(ident3, kGTMABMultiValueInvalidIdentifier);
#endif // GTM_IPHONE_SDK
NSUInteger idx3 = [mutValue indexForIdentifier:ident3];
XCTAssertEqual(idx3, (NSUInteger)NSNotFound);
XCTAssertTrue([mutValue removeValueAndLabelAtIndex:1]);
XCTAssertFalse([mutValue removeValueAndLabelAtIndex:1]);
NSUInteger idx4
= [mutValue indexForIdentifier:kGTMABMultiValueInvalidIdentifier];
XCTAssertEqual(idx4, (NSUInteger)NSNotFound);
XCTAssertNotNULL([mutValue multiValueRef]);
// Enumerator test
mutValue
= [GTMABMutableMultiValue valueWithPropertyType:kGTMABIntegerPropertyType];
XCTAssertNotNil(mutValue);
for (int i = 0; i < 100; i++) {
NSString *label = [NSString stringWithFormat:@"label %d", i];
NSNumber *val = [NSNumber numberWithInt:i];
XCTAssertNotEqual([mutValue addValue:val
withLabel:(CFStringRef)label],
kGTMABMultiValueInvalidIdentifier);
}
int count = 0;
NSString *label;
for (label in [mutValue labelEnumerator]) {
NSString *testLabel = [NSString stringWithFormat:@"label %d", count++];
XCTAssertEqualObjects(label, testLabel);
}
count = 0;
value = [[mutValue copy] autorelease];
NSNumber *val;
for (val in [value valueEnumerator]) {
XCTAssertEqualObjects(val, [NSNumber numberWithInt:count++]);
}
// Test messing with the values while we're enumerating them
NSEnumerator *labelEnum = [mutValue labelEnumerator];
NSEnumerator *valueEnum = [mutValue valueEnumerator];
XCTAssertNotNil(labelEnum);
XCTAssertNotNil(valueEnum);
XCTAssertNotNil([labelEnum nextObject]);
XCTAssertNotNil([valueEnum nextObject]);
XCTAssertTrue([mutValue removeValueAndLabelAtIndex:0]);
XCTAssertThrows([labelEnum nextObject]);
XCTAssertThrows([valueEnum nextObject]);
// Test messing with the values while we're fast enumerating them
// Should throw an exception on the second access.
BOOL exceptionThrown = NO;
// Start at one because we removed index 0 above.
count = 1;
@try {
for (label in [mutValue labelEnumerator]) {
NSString *testLabel = [NSString stringWithFormat:@"label %d", count++];
XCTAssertEqualObjects(label, testLabel);
XCTAssertTrue([mutValue removeValueAndLabelAtIndex:50]);
}
} @catch(NSException *e) {
XCTAssertEqualObjects([e name], NSGenericException, @"Got %@ instead", e);
XCTAssertEqual(count, 2,
@"Should have caught it on the second access");
exceptionThrown = YES;
} // COV_NF_LINE - because we always catch, this brace doesn't get exec'd
XCTAssertTrue(exceptionThrown, @"We should have thrown an exception"
@" because the values under the enumerator were modified");
}
#if GTM_IPHONE_SDK
#if (!defined(__LP64__) || !__LP64__)
// This test does not work on LP64 because refcounts are magic and don't work the
// same as on i386.
- (void)testRadar6208390 {
GTMABPropertyType types[] = {
kGTMABStringPropertyType,
kGTMABIntegerPropertyType,
kGTMABRealPropertyType,
kGTMABDateTimePropertyType,
kGTMABDictionaryPropertyType
};
for (size_t j = 0; j < sizeof(types) / sizeof(ABPropertyType); ++j) {
ABPropertyType type = types[j];
ABMultiValueRef ref = ABMultiValueCreateMutable(type);
XCTAssertNotNULL(ref);
NSString *label = [[NSString alloc] initWithString:@"label"];
XCTAssertNotNil(label);
id val = nil;
if (type == kGTMABDictionaryPropertyType) {
val = [[NSDictionary alloc] initWithObjectsAndKeys:@"1", @"1", nil];
} else if (type == kGTMABStringPropertyType) {
val = [[NSString alloc] initWithFormat:@"value %zu", j];
} else if (type == kGTMABIntegerPropertyType
|| type == kGTMABRealPropertyType ) {
val = [[NSNumber alloc] initWithInt:143];
} else if (type == kGTMABDateTimePropertyType) {
val = [[NSDate alloc] init];
}
XCTAssertNotNil(val, @"Testing type %d, %@", type, val);
NSUInteger firstRetainCount = [val retainCount];
XCTAssertNotEqual(firstRetainCount,
(NSUInteger)0,
@"Testing type %d, %@", type, val);
GTMABMultiValueIdentifier identifier;
XCTAssertTrue(ABMultiValueAddValueAndLabel(ref,
val,
(CFStringRef)label,
&identifier),
@"Testing type %d, %@", type, val);
NSUInteger secondRetainCount = [val retainCount];
XCTAssertEqual(firstRetainCount + 1,
secondRetainCount,
@"Testing type %d, %@", type, val);
[label release];
[val release];
NSUInteger thirdRetainCount = [val retainCount];
XCTAssertEqual(firstRetainCount,
thirdRetainCount,
@"Testing type %d, %@", type, val);
id oldVal = val;
val = (id)ABMultiValueCopyValueAtIndex(ref, 0);
NSUInteger fourthRetainCount = [val retainCount];
// kABDictionaryPropertyTypes appear to do an actual copy, so the retain
// count checking trick won't work. We only check the retain count if
// we didn't get a new version.
if (val == oldVal) {
if (type == kGTMABIntegerPropertyType
|| type == kGTMABRealPropertyType) {
// We are verifying that yes indeed 6208390 is still broken
XCTAssertEqual(fourthRetainCount,
thirdRetainCount,
@"Testing type %d, %@. If you see this error it may "
@"be time to update the code to change retain behaviors"
@"with this os version", type, val);
} else {
XCTAssertEqual(fourthRetainCount,
thirdRetainCount + 1,
@"Testing type %d, %@", type, val);
[val release];
}
} else {
[val release];
}
CFRelease(ref);
}
}
#endif // (!defined(__LP64__) || !__LP64__)
// Globals used by testRadar6240394.
static GTMABPropertyID gGTMTestID;
static const GTMABPropertyID *gGTMTestIDPtr;
void __attribute__((constructor))SetUpIDForTestRadar6240394(void) {
// These must be set up BEFORE ABAddressBookCreate is called.
gGTMTestID = kGTMABPersonLastNameProperty;
gGTMTestIDPtr = &kGTMABPersonLastNameProperty;
}
- (void)testRadar6240394 {
// As of iPhone SDK 2.1, the property IDs aren't initialized until
// ABAddressBookCreate is actually called. They will return zero until
// then. Logged as radar 6240394.
XCTAssertEqual(gGTMTestID, 0, @"If this isn't zero, Apple has fixed 6240394");
(void)ABAddressBookCreate();
XCTAssertEqual(*gGTMTestIDPtr, kGTMABPersonLastNameProperty,
@"If this doesn't work, something else has broken");
}
#endif // GTM_IPHONE_SDK
@end