diff options
Diffstat (limited to 'UnitTesting')
-rw-r--r-- | UnitTesting/GTMAppKit+UnitTesting.m | 2 | ||||
-rw-r--r-- | UnitTesting/GTMIPhoneUnitTestDelegate.m | 44 | ||||
-rw-r--r-- | UnitTesting/GTMNSObject+BindingUnitTesting.h | 32 | ||||
-rw-r--r-- | UnitTesting/GTMNSObject+BindingUnitTesting.m | 347 | ||||
-rw-r--r-- | UnitTesting/GTMNSObject+UnitTesting.m | 90 | ||||
-rw-r--r-- | UnitTesting/GTMSenTestCase.h | 7 | ||||
-rw-r--r-- | UnitTesting/GTMSenTestCase.m | 308 | ||||
-rw-r--r-- | UnitTesting/GTMTestTimer.h | 22 | ||||
-rw-r--r-- | UnitTesting/GTMUnitTestingBindingTest.m | 9 | ||||
-rw-r--r-- | UnitTesting/GTMUnitTestingUtilities.m | 2 | ||||
-rwxr-xr-x | UnitTesting/RunIPhoneUnitTest.sh | 28 | ||||
-rwxr-xr-x | UnitTesting/RunMacOSUnitTests.sh | 173 | ||||
-rw-r--r-- | UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiff | bin | 0 -> 21014 bytes | |||
-rw-r--r-- | UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff | bin | 0 -> 21380 bytes |
14 files changed, 709 insertions, 355 deletions
diff --git a/UnitTesting/GTMAppKit+UnitTesting.m b/UnitTesting/GTMAppKit+UnitTesting.m index 6cb5a8b..0e21491 100644 --- a/UnitTesting/GTMAppKit+UnitTesting.m +++ b/UnitTesting/GTMAppKit+UnitTesting.m @@ -30,7 +30,7 @@ #endif @implementation NSApplication (GMUnitTestingAdditions) -GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:); // COV_NF_LINE +GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:); - (void)gtm_unitTestEncodeState:(NSCoder*)inCoder { [super gtm_unitTestEncodeState:inCoder]; diff --git a/UnitTesting/GTMIPhoneUnitTestDelegate.m b/UnitTesting/GTMIPhoneUnitTestDelegate.m index a793ff4..7ef46fc 100644 --- a/UnitTesting/GTMIPhoneUnitTestDelegate.m +++ b/UnitTesting/GTMIPhoneUnitTestDelegate.m @@ -34,36 +34,9 @@ static int MethodSort(const void *a, const void *b) { return strcmp(nameA, nameB); } -static void RunLeaks(void) { - // This is an atexit handler. It runs leaks for us to check if we are - // leaking anything in our tests. Note that leaks and NSZombieEnabled - // don't play well together, so we attempt to filter out the zombies from - // our leaks when NSZombieEnabled is on. - BOOL zombiesOn = getenv("NSZombieEnabled") != NULL; - NSString *filterZombies = @"| grep -v _NSZombie"; - NSString *zombieExplanation = @"echo 'Leaks:0: note: NSZombies being " - @"filtered from leaks. If zombies are on, ignore the \"x leaks for y total " - @"leaked bytes.\" line above unless actual leaks are reported. " - @"Set the 'GTM_DISABLE_ZOMBIES' environment variable to turn off " - @"zombies, and to get more information about the leaks.'"; - NSString *string - = [NSString stringWithFormat:@"/usr/bin/leaks %@ %d %@" - @"| /usr/bin/sed \"s/Leak: /Leaks:0: warning: Leak /\"; %@", - zombiesOn ? @"-nocontext -nostacks" : @"", - getpid(), - zombiesOn ? filterZombies : @"", - zombiesOn ? zombieExplanation : @""]; - int ret = system([string UTF8String]); - if (ret) { - fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d", - __FILE__, __LINE__, ret); - fflush(stderr); - } -} - @interface UIApplication (iPhoneUnitTestAdditions) // "Private" method that we need -- (void)terminate; +- (void)terminateWithSuccess; @end @implementation GTMIPhoneUnitTestDelegate @@ -85,19 +58,14 @@ static void RunLeaks(void) { // that are subclasses of SenTestCase. Terminate the application upon // test completion. - (void)applicationDidFinishLaunching:(UIApplication *)application { - // Don't want to get leaks on the device as the device doesn't - // have 'leaks'. We check for this by looking for the - // IPHONEOS_DEPLOYMENT_TARGET env var. If it isn't there, we are running - // on the simulator. - if (!getenv("IPHONEOS_DEPLOYMENT_TARGET")) { - if (!getenv("GTM_DISABLE_LEAKS")) { - atexit(&RunLeaks); - } - } [self runTests]; + // Using private call to end our tests if (!getenv("GTM_DISABLE_TERMINATION")) { - [[UIApplication sharedApplication] terminate]; + // I call this delayed just to make sure that the stack is clean + [application performSelector:@selector(terminateWithSuccess) + withObject:nil + afterDelay:0.00]; } } diff --git a/UnitTesting/GTMNSObject+BindingUnitTesting.h b/UnitTesting/GTMNSObject+BindingUnitTesting.h index 947221a..462bb9b 100644 --- a/UnitTesting/GTMNSObject+BindingUnitTesting.h +++ b/UnitTesting/GTMNSObject+BindingUnitTesting.h @@ -58,6 +58,23 @@ do { \ } \ } while(0) +// Utility class for setting up Binding Tests. Basically a pair of a value to +// set a binding to, followed by the expected return value. +// See description of gtm_unitTestExposedBindingsTestValues: below +// for example of usage. +@interface GTMBindingUnitTestData : NSObject { + @private + id valueToSet_; + id expectedValue_; +} + ++ (id)testWithIdentityValue:(id)value; ++ (id)testWithValue:(id)value expecting:(id)expecting; +- (id)initWithValue:(id)value expecting:(id)expecting; +- (id)valueToSet; +- (id)expectedValue; +@end + @interface NSObject (GTMBindingUnitTestingAdditions) // Allows you to ignore certain bindings when running GTMTestExposedBindings // If you have bindings you want to ignore, add them to the array returned @@ -76,14 +93,15 @@ do { \ // Allows you to set up test values for your different bindings. // if you have certain values you want to test against your bindings, add -// them to the dictionary returned by this method. The dictionary is a "value" key -// and an "expected return" object. +// them to the array returned by this method. The array is an array of +// GTMBindingUnitTestData. // The standard way to implement this would be: -// - (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { -// NSMutableDictionary *dict = [super unitTestExposedBindingsTestValues:binding]; +// - (NSMutableArray*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { +// NSMutableArray *dict = [super unitTestExposedBindingsTestValues:binding]; // if ([binding isEqualToString:@"myBinding"]) { -// [dict setObject:[[[MySpecialBindingValueSet alloc] init] autorelease] -// forKey:[[[MySpecialBindingValueGet alloc] init] autorelease]]; +// MySpecialBindingValueSet *value +// = [[[MySpecialBindingValueSet alloc] init] autorelease]; +// [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // ... // else if ([binding isEqualToString:@"myBinding2"]) { // ... @@ -94,7 +112,7 @@ do { \ // gives you a reasonable set of test values to start. // See the implementation for the current list of bindings, and values that we // set for those bindings. -- (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding; +- (NSMutableArray*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding; // A special version of isEqualTo to test whether two binding values are equal // by default it calls directly to isEqualTo: but can be overridden for special diff --git a/UnitTesting/GTMNSObject+BindingUnitTesting.m b/UnitTesting/GTMNSObject+BindingUnitTesting.m index 7773542..1ce1c88 100644 --- a/UnitTesting/GTMNSObject+BindingUnitTesting.m +++ b/UnitTesting/GTMNSObject+BindingUnitTesting.m @@ -20,6 +20,7 @@ #import "GTMDefines.h" #import "GTMNSObject+BindingUnitTesting.h" +#import "GTMSystemVersion.h" BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, NSArray **errors) { @@ -36,8 +37,10 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, if (![bindingsToIgnore containsObject:bindingKey]) { Class theClass = [object valueClassForBinding:bindingKey]; if (!theClass) { - [errorArray addObject:[NSString stringWithFormat:@"%@ should have valueClassForBinding '%@'", - object, bindingKey]]; + NSString *error + = [NSString stringWithFormat:@"%@ should have valueClassForBinding '%@'", + object, bindingKey]; + [errorArray addObject:error]; continue; } @try { @@ -45,32 +48,41 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, [object valueForKey:bindingKey]; } @catch (NSException *e) { - _GTMDevLog(@"%@ is not key value coding compliant for key %@", object, bindingKey); + _GTMDevLog(@"%@ is not key value coding compliant for key %@", + object, bindingKey); continue; } // COV_NF_LINE - compiler bug - NSDictionary *testValues = [object gtm_unitTestExposedBindingsTestValues:bindingKey]; - NSEnumerator *testEnum = [testValues keyEnumerator]; - id testValue; - while ((testValue = [testEnum nextObject])) { - [object setValue:testValue forKey:bindingKey]; - id value = [object valueForKey:bindingKey]; - id desiredValue = [testValues objectForKey:testValue]; - if (![desiredValue gtm_unitTestIsEqualTo:value]) { - [errorArray addObject:[NSString stringWithFormat:@"%@ unequal to %@ for binding '%@'", - value, desiredValue, bindingKey]]; + NSArray *testValues + = [object gtm_unitTestExposedBindingsTestValues:bindingKey]; + NSEnumerator *testEnum = [testValues objectEnumerator]; + GTMBindingUnitTestData *testData; + while ((testData = [testEnum nextObject])) { + id valueToSet = [testData valueToSet]; + [object setValue:valueToSet forKey:bindingKey]; + id valueReceived = [object valueForKey:bindingKey]; + id desiredValue = [testData expectedValue]; + if (![desiredValue gtm_unitTestIsEqualTo:valueReceived]) { + NSString *error + = [NSString stringWithFormat:@"%@ unequal to expected %@ for binding '%@'", + valueReceived, desiredValue, bindingKey]; + [errorArray addObject:error]; continue; } } } @catch(NSException *e) { - [errorArray addObject:[NSString stringWithFormat:@"%@:%@-> Binding %@", - [e name], [e reason], bindingKey]]; + NSString *error + = [NSString stringWithFormat:@"%@:%@-> Binding %@", + [e name], [e reason], bindingKey]; + [errorArray addObject:error]; } // COV_NF_LINE - compiler bug } } } else { - [errorArray addObject:[NSString stringWithFormat:@"%@ does not have any exposed bindings", - object]]; + NSString *error = + [NSString stringWithFormat:@"%@ does not have any exposed bindings", + object]; + [errorArray addObject:error]; } if (errors) { *errors = errorArray; @@ -78,10 +90,51 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, return [errorArray count] == 0; } -// Utility for simplifying unitTestExposedBindingsTestValues implementations -@interface NSMutableDictionary (GTMUnitTestingAdditions) -// Sets an object and a key to the same value in a dictionary. -- (void)gtm_setObjectAndKey:(id)objectAndKey; +@implementation GTMBindingUnitTestData ++ (id)testWithIdentityValue:(id)value { + return [self testWithValue:value expecting:value]; +} + ++ (id)testWithValue:(id)value expecting:(id)expecting { + return [[[self alloc] initWithValue:value expecting:expecting] autorelease]; +} + +- (id)initWithValue:(id)value expecting:(id)expecting { + if ((self = [super init])) { + valueToSet_ = [value retain]; + expectedValue_ = [expecting retain]; + } + return self; +} + +- (BOOL)isEqual:(id)object { + BOOL isEqual = [object isMemberOfClass:[self class]]; + if (isEqual) { + id objValue = [object valueToSet]; + id objExpect = [object expectedValue]; + isEqual = (((valueToSet_ == objValue) || ([valueToSet_ isEqual:objValue])) + && ((expectedValue_ == objExpect) || ([expectedValue_ isEqual:objExpect]))); + } + return isEqual; +} + +- (NSUInteger)hash { + return [valueToSet_ hash] + [expectedValue_ hash]; +} + +- (void)dealloc { + [valueToSet_ release]; + [expectedValue_ release]; + [super dealloc]; +} + +- (id)valueToSet { + return valueToSet_; +} + +- (id)expectedValue { + return expectedValue_; +} @end @implementation NSObject (GTMBindingUnitTestingAdditions) @@ -98,14 +151,14 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, return array; } -- (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { +- (NSMutableArray*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + NSMutableArray *array = [NSMutableArray array]; id value = [self valueForKey:binding]; // Always test identity if possible if (value) { - [dict gtm_setObjectAndKey:value]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } // Now some default test values for a variety of bindings to make @@ -114,21 +167,30 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, // If anybody can think of more to add, please go nuts. if ([binding isEqualToString:NSAlignmentBinding]) { - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:NSLeftTextAlignment]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:NSRightTextAlignment]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:NSCenterTextAlignment]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:NSJustifiedTextAlignment]]; - NSNumber *natural = [NSNumber numberWithInt:NSNaturalTextAlignment]; - [dict gtm_setObjectAndKey:natural]; - [dict setObject:natural forKey:[NSNumber numberWithInt:500]]; - [dict setObject:natural forKey:[NSNumber numberWithInt:-1]]; + value = [NSNumber numberWithInt:NSLeftTextAlignment]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:NSRightTextAlignment]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:NSCenterTextAlignment]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:NSJustifiedTextAlignment]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:NSNaturalTextAlignment]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + NSNumber *valueToSet = [NSNumber numberWithInt:500]; + [array addObject:[GTMBindingUnitTestData testWithValue:valueToSet + expecting:value]]; + valueToSet = [NSNumber numberWithInt:-1]; + [array addObject:[GTMBindingUnitTestData testWithValue:valueToSet + expecting:value]]; } else if ([binding isEqualToString:NSAlternateImageBinding] || [binding isEqualToString:NSImageBinding] || [binding isEqualToString:NSMixedStateImageBinding] || [binding isEqualToString:NSOffStateImageBinding] || [binding isEqualToString:NSOnStateImageBinding]) { // This handles all image bindings - [dict gtm_setObjectAndKey:[NSImage imageNamed:@"NSApplicationIcon"]]; + value = [NSImage imageNamed:@"NSApplicationIcon"]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSAnimateBinding] || [binding isEqualToString:NSDocumentEditedBinding] || [binding isEqualToString:NSEditableBinding] || @@ -139,57 +201,88 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, // NSTranparentBinding 10.5 only [binding isEqualToString:@"transparent"]) { // This handles all bool value bindings - [dict gtm_setObjectAndKey:[NSNumber numberWithBool:YES]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithBool:NO]]; + value = [NSNumber numberWithBool:YES]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithBool:NO]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSAlternateTitleBinding] || [binding isEqualToString:NSHeaderTitleBinding] || [binding isEqualToString:NSLabelBinding] || [binding isEqualToString:NSTitleBinding] || [binding isEqualToString:NSToolTipBinding]) { // This handles all string value bindings - [dict gtm_setObjectAndKey:@"happy"]; - [dict gtm_setObjectAndKey:@""]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:@"happy"]]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:@""]]; // Test some non-ascii roman text char a_not_alpha[] = { 'A', 0xE2, 0x89, 0xA2, 0xCE, 0x91, '.', 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:a_not_alpha]]; + value = [NSString stringWithUTF8String:a_not_alpha]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some korean char hangugo[] = { 0xED, 0x95, 0x9C, 0xEA, 0xB5, - 0xAD, 0xEC, 0x96, 0xB4, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:hangugo]]; + 0xAD, 0xEC, 0x96, 0xB4, 0x00 }; + value = [NSString stringWithUTF8String:hangugo]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some japanese char nihongo[] = { 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:nihongo]]; + value = [NSString stringWithUTF8String:nihongo]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some arabic char arabic[] = { 0xd9, 0x83, 0xd8, 0xa7, 0xd9, 0x83, 0xd8, 0xa7, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:arabic]]; + value = [NSString stringWithUTF8String:arabic]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSRepresentedFilenameBinding]) { // This handles all path bindings - [dict gtm_setObjectAndKey:@"/happy"]; - [dict gtm_setObjectAndKey:@"/"]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:@"/happy"]]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:@"/"]]; // Test some non-ascii roman text char a_not_alpha[] = { '/', 'A', 0xE2, 0x89, 0xA2, 0xCE, 0x91, '.', 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:a_not_alpha]]; + value = [NSString stringWithUTF8String:a_not_alpha]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some korean char hangugo[] = { '/', 0xED, 0x95, 0x9C, 0xEA, 0xB5, - 0xAD, 0xEC, 0x96, 0xB4, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:hangugo]]; + 0xAD, 0xEC, 0x96, 0xB4, 0x00 }; + value = [NSString stringWithUTF8String:hangugo]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some japanese char nihongo[] = { '/', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, - 0xAC, 0xE8, 0xAA, 0x9E, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:nihongo]]; + 0xAC, 0xE8, 0xAA, 0x9E, 0x00 }; + value = [NSString stringWithUTF8String:nihongo]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; // Test some arabic char arabic[] = { '/', 0xd9, 0x83, 0xd8, 0xa7, 0xd9, 0x83, 0xd8, 0xa7, 0x00 }; - [dict gtm_setObjectAndKey:[NSString stringWithUTF8String:arabic]]; - } else if ([binding isEqualToString:NSMaximumRecentsBinding] || - [binding isEqualToString:NSRowHeightBinding]) { - // This handles all int value bindings - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:0]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:-1]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:INT16_MAX]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithInt:INT16_MIN]]; + value = [NSString stringWithUTF8String:arabic]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + } else if ([binding isEqualToString:NSMaximumRecentsBinding]) { + value = [NSNumber numberWithInt:0]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:-1]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:INT16_MAX]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithInt:INT16_MIN]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + } else if ([binding isEqualToString:NSRowHeightBinding]) { + NSNumber *valueOne = [NSNumber numberWithInt:1]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:valueOne]]; + value = [NSNumber numberWithInt:0]; + id value2 = [NSNumber numberWithInt:INT16_MIN]; + // Row height no longer accepts <= 0 values on SnowLeopard + // which is a good thing. + if ([GTMSystemVersion isSnowLeopardOrGreater]) { + [array addObject:[GTMBindingUnitTestData testWithValue:value + expecting:valueOne]]; + + [array addObject:[GTMBindingUnitTestData testWithValue:value2 + expecting:valueOne]]; + } else { + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value2]]; + } + value = [NSNumber numberWithInt:INT16_MAX]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSMaxValueBinding] || [binding isEqualToString:NSMaxWidthBinding] || [binding isEqualToString:NSMinValueBinding] || @@ -198,39 +291,57 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, [binding isEqualToString:NSContentHeightBinding] || [binding isEqualToString:NSWidthBinding] || [binding isEqualToString:NSAnimationDelayBinding]) { + // NSAnimationDelay is deprecated on SnowLeopard. We continue to test it + // to make sure it doesn't get broken. + // This handles all float value bindings - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:0]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:FLT_MAX]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:-FLT_MAX]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:FLT_MIN]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:-FLT_MIN]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:FLT_EPSILON]]; - [dict gtm_setObjectAndKey:[NSNumber numberWithFloat:-FLT_EPSILON]]; + value = [NSNumber numberWithFloat:0]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:FLT_MAX]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:-FLT_MAX]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:FLT_MIN]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:-FLT_MIN]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:FLT_EPSILON]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSNumber numberWithFloat:-FLT_EPSILON]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSTextColorBinding]) { // This handles all color value bindings - [dict gtm_setObjectAndKey:[NSColor colorWithCalibratedWhite:1.0 alpha:1.0]]; - [dict gtm_setObjectAndKey:[NSColor colorWithCalibratedWhite:1.0 alpha:0.0]]; - [dict gtm_setObjectAndKey:[NSColor colorWithCalibratedWhite:1.0 alpha:0.5]]; - [dict gtm_setObjectAndKey:[NSColor colorWithCalibratedRed:0.5 green:0.5 - blue:0.5 alpha:0.5]]; - [dict gtm_setObjectAndKey:[NSColor colorWithDeviceCyan:0.25 magenta:0.25 - yellow:0.25 black:0.25 - alpha:0.25]]; + value = [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSColor colorWithCalibratedWhite:1.0 alpha:0.0]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:0.5]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSColor colorWithDeviceCyan:0.25 magenta:0.25 yellow:0.25 + black:0.25 alpha:0.25]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSFontBinding]) { // This handles all font value bindings - [dict gtm_setObjectAndKey:[NSFont boldSystemFontOfSize:[NSFont systemFontSize]]]; - [dict gtm_setObjectAndKey:[NSFont toolTipsFontOfSize:[NSFont smallSystemFontSize]]]; - [dict gtm_setObjectAndKey:[NSFont labelFontOfSize:144.0]]; + value = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSFont toolTipsFontOfSize:[NSFont smallSystemFontSize]]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; + value = [NSFont labelFontOfSize:144.0]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSRecentSearchesBinding] || [binding isEqualToString:NSSortDescriptorsBinding]) { // This handles all array value bindings - [dict gtm_setObjectAndKey:[NSArray array]]; + value = [NSArray array]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else if ([binding isEqualToString:NSTargetBinding]) { - [dict gtm_setObjectAndKey:[NSNull null]]; + value = [NSNull null]; + [array addObject:[GTMBindingUnitTestData testWithIdentityValue:value]]; } else { _GTMDevLog(@"Skipped Binding: %@ for %@", binding, self); // COV_NF_LINE } - return dict; + return array; } - (BOOL)gtm_unitTestIsEqualTo:(id)value { @@ -239,13 +350,6 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, @end -@implementation NSMutableDictionary (GTMUnitTestingAdditions) -// Sets an object and a key to the same value in a dictionary. -- (void)gtm_setObjectAndKey:(id)objectAndKey { - [self setObject:objectAndKey forKey:objectAndKey]; -} -@end - #pragma mark - #pragma mark All the special AppKit Bindings issues below @@ -267,10 +371,17 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, @implementation NSScroller (GTMBindingUnitTestingAdditions) - (NSMutableArray*)gtm_unitTestExposedBindingsToIgnore { NSMutableArray *array = [super gtm_unitTestExposedBindingsToIgnore]; - // rdar://5849154 - NSScroller exposes binding with no value class for NSValueBinding - [array addObject:NSValueBinding]; - // rdar://5849236 - NSScroller exposes binding for NSFontBinding - [array addObject:NSFontBinding]; + SInt32 major, minor, bugFix; + [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix]; + if (major <= 10 && minor <= 5 && bugFix <= 5) { + // rdar://5849154 - NSScroller exposes binding with no value class for NSValueBinding + [array addObject:NSValueBinding]; + } + if ([GTMSystemVersion isBuildLessThanOrEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // Broken on SnowLeopard WWDC and below + // rdar://5849236 - NSScroller exposes binding for NSFontBinding + [array addObject:NSFontBinding]; + } return array; } @end @@ -289,13 +400,22 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, return array; } -- (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { - NSMutableDictionary *dict = [super gtm_unitTestExposedBindingsTestValues:binding]; +- (NSMutableArray *)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { + NSMutableArray *array = [super gtm_unitTestExposedBindingsTestValues:binding]; if ([binding isEqualToString:NSAlignmentBinding]) { - // rdar://5851487 - If NSAlignmentBinding for a NSTextField is set to -1 and then got it returns 7 - [dict setObject:[NSNumber numberWithInt:7] forKey:[NSNumber numberWithInt:-1]]; + if ([GTMSystemVersion isBuildLessThanOrEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // rdar://5851487 - If NSAlignmentBinding for a NSTextField is set to -1 and then got it returns 7 + GTMBindingUnitTestData *dataToRemove = + [GTMBindingUnitTestData testWithValue:[NSNumber numberWithInt:-1] + expecting:[NSNumber numberWithInt:NSNaturalTextAlignment]]; + [array removeObject:dataToRemove]; + GTMBindingUnitTestData *dataToAdd = + [GTMBindingUnitTestData testWithValue:[NSNumber numberWithInt:-1] + expecting:[NSNumber numberWithInt:7]]; + [array addObject:dataToAdd]; + } } - return dict; + return array; } @end @@ -304,21 +424,15 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, @implementation NSSearchField (GTMBindingUnitTestingAdditions) -- (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { - NSMutableDictionary *dict = [super gtm_unitTestExposedBindingsTestValues:binding]; -#if !__LP64__ - if ([binding isEqualToString:NSAlignmentBinding]) { - // rdar://5851491 - Setting NSAlignmentBinding of search field to NSCenterTextAlignment broken - // This appears to not be a bug in 64 bit. Strange. - [dict setObject:[NSNumber numberWithInt:NSNaturalTextAlignment] - forKey:[NSNumber numberWithInt:NSCenterTextAlignment]]; - } -#endif - return dict; -} - - (NSMutableArray*)gtm_unitTestExposedBindingsToIgnore { NSMutableArray *array = [super gtm_unitTestExposedBindingsToIgnore]; + SInt32 major, minor, bugFix; + [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix]; + if (major <= 10 && minor <= 5 && bugFix <= 5) { + // rdar://5851491 - Setting NSAlignmentBinding of search field to NSCenterTextAlignment broken + // Broken on 10.5.5 and below. + [array addObject:NSAlignmentBinding]; + } // Not KVC Compliant [array addObject:NSPredicateBinding]; return array; @@ -367,8 +481,11 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, - (NSMutableArray*)gtm_unitTestExposedBindingsToIgnore { NSMutableArray *array = [super gtm_unitTestExposedBindingsToIgnore]; - // rdar://5849684 - NSTableView should throw exception when attempting to set NSFontBinding - [array addObject:NSFontBinding]; + if ([GTMSystemVersion isBuildLessThanOrEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // rdar://6288332 - NSTableView does not respond to NSFontBinding + // Broken on 10.5, and SnowLeopard WWDC + [array addObject:NSFontBinding]; + } // Not KVC Compliant [array addObject:NSContentBinding]; [array addObject:NSDoubleClickTargetBinding]; @@ -386,8 +503,10 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, - (NSMutableArray*)gtm_unitTestExposedBindingsToIgnore { NSMutableArray *array = [super gtm_unitTestExposedBindingsToIgnore]; - //rdar://5849335 - NSTextView only partially KVC compliant for key NSAttributedStringBinding - [array addObject:NSAttributedStringBinding]; + if ([GTMSystemVersion isBuildLessThanOrEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + //rdar://5849335 - NSTextView only partially KVC compliant for key NSAttributedStringBinding + [array addObject:NSAttributedStringBinding]; + } // Not KVC Compliant [array addObject:NSDataBinding]; [array addObject:NSValueURLBinding]; @@ -404,8 +523,10 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object, - (NSMutableArray*)gtm_unitTestExposedBindingsToIgnore { NSMutableArray *array = [super gtm_unitTestExposedBindingsToIgnore]; - // rdar://5849248 - NSTabView exposes binding with no value class for NSSelectedIdentifierBinding - [array addObject:NSSelectedIdentifierBinding]; + if ([GTMSystemVersion isBuildLessThanOrEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // rdar://5849248 - NSTabView exposes binding with no value class for NSSelectedIdentifierBinding + [array addObject:NSSelectedIdentifierBinding]; + } // Not KVC Compliant [array addObject:NSSelectedIndexBinding]; [array addObject:NSSelectedLabelBinding]; diff --git a/UnitTesting/GTMNSObject+UnitTesting.m b/UnitTesting/GTMNSObject+UnitTesting.m index a722b9e..bc94729 100644 --- a/UnitTesting/GTMNSObject+UnitTesting.m +++ b/UnitTesting/GTMNSObject+UnitTesting.m @@ -18,8 +18,6 @@ // the License. // -#import <mach-o/arch.h> - #import "GTMNSObject+UnitTesting.h" #import "GTMSystemVersion.h" #import "GTMGarbageCollection.h" @@ -68,9 +66,7 @@ BOOL GTMIsObjectImageEqualToImageNamed(id object, if (isGood) { isGood = [object gtm_compareWithImageAt:aPath diffImage:&diff]; } - if (isGood) { - CGImageRelease(diff); - } else { + if (!isGood) { if (aPath) { filename = [filename stringByAppendingString:@"_Failed"]; } @@ -98,7 +94,6 @@ BOOL GTMIsObjectImageEqualToImageNamed(id object, NSData *data = nil; if (diff) { data = [object gtm_imageDataForImage:diff]; - CFRelease(diff); } if ([data writeToFile:diffPath atomically:YES]) { failString = [NSString stringWithFormat:@"Object image different " @@ -114,6 +109,7 @@ BOOL GTMIsObjectImageEqualToImageNamed(id object, } } } + CGImageRelease(diff); } else { failString = @"systemSettings not valid for taking image"; // COV_NF_LINE } @@ -225,7 +221,7 @@ BOOL GTMIsObjectStateEqualToStateNamed(id object, @end // Small utility function for checking to see if a is b +/- 1. -static inline BOOL almostEqual(unsigned char a, unsigned char b) { +GTM_INLINE BOOL almostEqual(unsigned char a, unsigned char b) { unsigned char diff = a > b ? a - b : b - a; BOOL notEqual = diff < 2; return notEqual; @@ -468,7 +464,7 @@ static NSString *gGTMUnitTestSaveToDirectory = nil; _GTMDevAssert(myBundle, @"Couldn't find bundle for class: %@ searching for file:%@.%@", NSStringFromClass(bundleClass), name, extension); // System Version - long major, minor, bugFix; + SInt32 major, minor, bugFix; [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix]; NSString *systemVersions[4]; systemVersions[0] = [NSString stringWithFormat:@".%d.%d.%d", @@ -477,33 +473,8 @@ static NSString *gGTMUnitTestSaveToDirectory = nil; systemVersions[2] = [NSString stringWithFormat:@".%d", major]; systemVersions[3] = @""; NSString *extensions[2]; -#if GTM_IPHONE_SDK - extensions[0] = @".iPhone"; -#else // !GTM_IPHONE_SDK - // In reading arch(3) you'd thing this would work: - // - // const NXArchInfo *localInfo = NXGetLocalArchInfo(); - // _GTMDevAssert(localInfo && localInfo->name, @"Couldn't get NXArchInfo"); - // const NXArchInfo *genericInfo = NXGetArchInfoFromCpuType(localInfo->cputype, 0); - // _GTMDevAssert(genericInfo && genericInfo->name, @"Couldn't get generic NXArchInfo"); - // extensions[0] = [NSString stringWithFormat:@".%s", genericInfo->name]; - // - // but on 64bit it returns the same things as on 32bit, so... -#if __POWERPC__ - #if __LP64__ - extensions[0] = @".ppc64"; - #else // !__LP64__ - extensions[0] = @".ppc"; - #endif // __LP64__ -#else // !__POWERPC__ - #if __LP64__ - extensions[0] = @".x86_64"; - #else // !__LP64__ - extensions[0] = @".i386"; - #endif // __LP64__ -#endif // !__POWERPC__ - -#endif // GTM_IPHONE_SDK + extensions[0] + = [NSString stringWithFormat:@".%@", [GTMSystemVersion runtimeArchitecture]]; extensions[1] = @""; size_t i, j; @@ -529,38 +500,12 @@ static NSString *gGTMUnitTestSaveToDirectory = nil; - (NSString *)gtm_saveToPathForFileNamed:(NSString*)name extension:(NSString*)extension { - char const *systemArchitecture; -#if GTM_IPHONE_SDK - systemArchitecture = "iPhone"; -#else - // In reading arch(3) you'd thing this would work: - // - // const NXArchInfo *localInfo = NXGetLocalArchInfo(); - // _GTMDevAssert(localInfo && localInfo->name, @"Couldn't get NXArchInfo"); - // const NXArchInfo *genericInfo = NXGetArchInfoFromCpuType(localInfo->cputype, 0); - // _GTMDevAssert(genericInfo && genericInfo->name, @"Couldn't get generic NXArchInfo"); - // system = genericInfo->name; - // - // but on 64bit it returns the same things as on 32bit, so... -#if __POWERPC__ - #if __LP64__ - systemArchitecture = "ppc64"; - #else // !__LP64__ - systemArchitecture = "ppc"; - #endif // __LP64__ -#else // !__POWERPC__ - #if __LP64__ - systemArchitecture = "x86_64"; - #else // !__LP64__ - systemArchitecture = "i386"; - #endif // __LP64__ -#endif // !__POWERPC__ + NSString *systemArchitecture = [GTMSystemVersion runtimeArchitecture]; -#endif - long major, minor, bugFix; + SInt32 major, minor, bugFix; [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix]; - NSString *fullName = [NSString stringWithFormat:@"%@.%s.%d.%d.%d", + NSString *fullName = [NSString stringWithFormat:@"%@.%@.%d.%d.%d", name, systemArchitecture, major, minor, bugFix]; NSString *basePath = [[self class] gtm_getUnitTestSaveToDirectory]; @@ -869,17 +814,14 @@ static NSString *gGTMUnitTestSaveToDirectory = nil; *diff = CGBitmapContextCreateImage(diffContext); free(diffData); CFRelease(diffContext); - free(fileData); - CFRelease(fileContext); - free(imageData); - CFRelease(imageContext); - } else { - CFRelease(fileContext); - CFRelease(imageContext); - } - CFRelease(imageRep); - CFRelease(fileRep); + } + free(fileData); + CFRelease(fileContext); + free(imageData); + CFRelease(imageContext); } + CGImageRelease(imageRep); + CGImageRelease(fileRep); return answer; } diff --git a/UnitTesting/GTMSenTestCase.h b/UnitTesting/GTMSenTestCase.h index 4a2bc9f..99f520a 100644 --- a/UnitTesting/GTMSenTestCase.h +++ b/UnitTesting/GTMSenTestCase.h @@ -112,7 +112,7 @@ do { \ } \ }\ @catch (id anException) {\ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s) fails", #a1, #a2] \ exception:anException \ inFile:[NSString stringWithUTF8String:__FILE__] \ atLine:__LINE__ \ @@ -990,7 +990,10 @@ do { \ - (void)failWithException:(NSException*)exception; @end -CF_EXPORT NSString * const SenTestFailureException; +extern NSString *const SenTestFailureException; + +extern NSString *const SenTestFilenameKey; +extern NSString *const SenTestLineNumberKey; #endif // GTM_IPHONE_SDK diff --git a/UnitTesting/GTMSenTestCase.m b/UnitTesting/GTMSenTestCase.m index 856516c..8d45dab 100644 --- a/UnitTesting/GTMSenTestCase.m +++ b/UnitTesting/GTMSenTestCase.m @@ -6,9 +6,9 @@ // 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 @@ -17,38 +17,76 @@ // #import "GTMSenTestCase.h" +#import <unistd.h> -#if GTM_IPHONE_SDK +#if !GTM_IPHONE_SDK +#import "GTMGarbageCollection.h" +#endif // !GTM_IPHONE_SDK +#if GTM_IPHONE_SDK #import <stdarg.h> +@interface NSException (GTMSenTestPrivateAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + reason:(NSString *)reason; +@end + +@implementation NSException (GTMSenTestPrivateAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + reason:(NSString *)reason { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey, + filename, SenTestFilenameKey, + nil]; + + return [self exceptionWithName:SenTestFailureException + reason:reason + userInfo:userInfo]; +} +@end + @implementation NSException (GTMSenTestAdditions) -+ (NSException *)failureInFile:(NSString *)filename - atLine:(int)lineNumber ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"%@:%d: error: %@", filename, lineNumber, reason]; - return [NSException exceptionWithName:SenTestFailureException - reason:reason - userInfo:nil]; -} - -+ (NSException *)failureInCondition:(NSString *)condition - isTrue:(BOOL)isTrue - inFile:(NSString *)filename - atLine:(int)lineNumber + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = testDescription; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInCondition:(NSString *)condition + isTrue:(BOOL)isTrue + inFile:(NSString *)filename + atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"condition '%@' is %s : %@", - condition, isTrue ? "TRUE" : "FALSE", reason]; - return [self failureInFile:filename atLine:lineNumber withDescription:reason]; + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@", + condition, isTrue ? "TRUE" : "FALSE", testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; } + (NSException *)failureInEqualityBetweenObject:(id)left @@ -56,55 +94,99 @@ inFile:(NSString *)filename atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"%@ != %@ : %@", - left, right, reason]; - return [self failureInFile:filename atLine:lineNumber withDescription:reason]; -} - -+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left - andValue:(NSValue *)right - withAccuracy:(NSValue *)accuracy - inFile:(NSString *)filename + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", + [left description], [right description], testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInEqualityBetweenValue:(NSValue *)left + andValue:(NSValue *)right + withAccuracy:(NSValue *)accuracy + inFile:(NSString *)filename atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"%@ != %@ with accuracy %@ : %@", - left, right, accuracy, reason]; - return [self failureInFile:filename atLine:lineNumber withDescription:reason]; + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason; + if (accuracy) { + reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", + left, right, testDescription]; + } else { + reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@", + left, right, accuracy, testDescription]; + } + + return [self failureInFile:filename atLine:lineNumber reason:reason]; } -+ (NSException *)failureInRaise:(NSString *)expression - inFile:(NSString *)filename ++ (NSException *)failureInRaise:(NSString *)expression + inFile:(NSString *)filename atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"failure in raise %@ : %@", - expression, reason]; - return [self failureInFile:filename atLine:lineNumber withDescription:reason]; -} - -+ (NSException *)failureInRaise:(NSString *)expression - exception:(NSException *)exception - inFile:(NSString *)filename - atLine:(int)lineNumber + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@", + expression, testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInRaise:(NSString *)expression + exception:(NSException *)exception + inFile:(NSString *)filename + atLine:(int)lineNumber withDescription:(NSString *)formatString, ... { - va_list vl; - va_start(vl, formatString); - NSString *reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - reason = [NSString stringWithFormat:@"failure in raise %@ (%@) : %@", - expression, exception, reason]; - return [self failureInFile:filename atLine:lineNumber withDescription:reason]; + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason; + if ([[exception name] isEqualToString:SenTestFailureException]) { + // it's our exception, assume it has the right description on it. + reason = [exception reason]; + } else { + // not one of our exception, use the exceptions reason and our description + reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@", + expression, [exception reason], testDescription]; + } + + return [self failureInFile:filename atLine:lineNumber reason:reason]; } @end @@ -114,17 +196,20 @@ NSString *STComposeString(NSString *formatString, ...) { if (formatString) { va_list vl; va_start(vl, formatString); - reason = [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + reason = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; va_end(vl); } return reason; } -NSString * const SenTestFailureException = @"SenTestFailureException"; +NSString *const SenTestFailureException = @"SenTestFailureException"; +NSString *const SenTestFilenameKey = @"SenTestFilenameKey"; +NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey"; -@interface SenTestCase (SenTestCasePrivate) +@interface SenTestCase (SenTestCasePrivate) // our method of logging errors -- (void)printError:(NSString *)error; ++ (void)printException:(NSException *)exception fromTestName:(NSString *)name; @end @implementation SenTestCase @@ -140,17 +225,26 @@ NSString * const SenTestFailureException = @"SenTestFailureException"; @try { [self invokeTest]; } @catch (NSException *exception) { - [self printError:[exception reason]]; + [[self class] printException:exception + fromTestName:NSStringFromSelector(sel)]; [exception raise]; } } -- (void)printError:(NSString *)error { - if ([error rangeOfString:@"error:"].location == NSNotFound) { - fprintf(stderr, "error: %s\n", [error UTF8String]); - } else { - fprintf(stderr, "%s\n", [error UTF8String]); ++ (void)printException:(NSException *)exception fromTestName:(NSString *)name { + NSDictionary *userInfo = [exception userInfo]; + NSString *filename = [userInfo objectForKey:SenTestFilenameKey]; + NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey]; + NSString *className = NSStringFromClass([self class]); + if ([filename length] == 0) { + filename = @"Unknown.m"; } + fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n", + [filename UTF8String], + (long)[lineNumber integerValue], + [className UTF8String], + [name UTF8String], + [[exception reason] UTF8String]); fflush(stderr); } @@ -189,7 +283,7 @@ NSString * const SenTestFailureException = @"SenTestFailureException"; } @end -#endif // GTM_IPHONE_SDK +#endif // GTM_IPHONE_SDK @implementation GTMTestCase : SenTestCase - (void)invokeTest { @@ -197,7 +291,7 @@ NSString * const SenTestFailureException = @"SenTestFailureException"; if (devLogClass) { [devLogClass performSelector:@selector(enableTracking)]; [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; - + } [super invokeTest]; if (devLogClass) { @@ -206,3 +300,57 @@ NSString * const SenTestFailureException = @"SenTestFailureException"; } } @end + +// Leak detection +#if !GTM_IPHONE_DEVICE +// Don't want to get leaks on the iPhone Device as the device doesn't +// have 'leaks'. The simulator does though. + +static void _GTMRunLeaks(void) { + // This is an atexit handler. It runs leaks for us to check if we are + // leaking anything in our tests. + const char* cExclusionsEnv = getenv("GTM_LEAKS_SYMBOLS_TO_IGNORE"); + NSMutableString *exclusions = [NSMutableString string]; + if (cExclusionsEnv) { + NSString *exclusionsEnv = [NSString stringWithUTF8String:cExclusionsEnv]; + NSArray *exclusionsArray = [exclusionsEnv componentsSeparatedByString:@","]; + NSEnumerator *exclusionsEnum = [exclusionsArray objectEnumerator]; + NSString *exclusion; + NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet]; + while ((exclusion = [exclusionsEnum nextObject])) { + exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet]; + [exclusions appendFormat:@"-exclude \"%@\" ", exclusion]; + } + } + NSString *string + = [NSString stringWithFormat:@"/usr/bin/leaks %@%d" + @"| /usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'", + exclusions, getpid()]; + int ret = system([string UTF8String]); + if (ret) { + fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d", + __FILE__, __LINE__, ret); + fflush(stderr); + } +} + +static __attribute__((constructor)) void _GTMInstallLeaks(void) { + BOOL checkLeaks = YES; +#if !GTM_IPHONE_SDK + checkLeaks = GTMIsGarbageCollectionEnabled() ? NO : YES; +#endif // !GTM_IPHONE_SDK + if (checkLeaks) { + checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO; + if (checkLeaks) { + if (checkLeaks) { + fprintf(stderr, "Leak Checking Enabled\n"); + fflush(stderr); + _GTMDevAssert(atexit(&_GTMRunLeaks) == 0, + @"Unable to install _GTMRunLeaks as an atexit handler (%d)", + errno); + } + } + } +} + +#endif // !GTM_IPHONE_DEVICE diff --git a/UnitTesting/GTMTestTimer.h b/UnitTesting/GTMTestTimer.h index 200f9b1..6c5fc55 100644 --- a/UnitTesting/GTMTestTimer.h +++ b/UnitTesting/GTMTestTimer.h @@ -37,7 +37,7 @@ typedef struct { } GTMTestTimer; // Create a test timer -FOUNDATION_STATIC_INLINE GTMTestTimer *GTMTestTimerCreate(void) { +GTM_INLINE GTMTestTimer *GTMTestTimerCreate(void) { GTMTestTimer *t = calloc(sizeof(GTMTestTimer), 1); if (t) { if (mach_timebase_info(&t->time_base_info_) == KERN_SUCCESS) { @@ -53,12 +53,12 @@ FOUNDATION_STATIC_INLINE GTMTestTimer *GTMTestTimerCreate(void) { } // Retain a timer -FOUNDATION_STATIC_INLINE void GTMTestTimerRetain(GTMTestTimer *t) { +GTM_INLINE void GTMTestTimerRetain(GTMTestTimer *t) { t->retainCount_ += 1; } // Release a timer. When release count hits zero, we free it. -FOUNDATION_STATIC_INLINE void GTMTestTimerRelease(GTMTestTimer *t) { +GTM_INLINE void GTMTestTimerRelease(GTMTestTimer *t) { t->retainCount_ -= 1; if (t->retainCount_ == 0) { free(t); @@ -67,13 +67,13 @@ FOUNDATION_STATIC_INLINE void GTMTestTimerRelease(GTMTestTimer *t) { // Starts a timer timing. Specifically starts a new split. If the timer is // currently running, it resets the start time of the current split. -FOUNDATION_STATIC_INLINE void GTMTestTimerStart(GTMTestTimer *t) { +GTM_INLINE void GTMTestTimerStart(GTMTestTimer *t) { t->start_ = mach_absolute_time(); t->running_ = true; } // Stops a timer and returns split time (time from last start) in nanoseconds. -FOUNDATION_STATIC_INLINE uint64_t GTMTestTimerStop(GTMTestTimer *t) { +GTM_INLINE uint64_t GTMTestTimerStop(GTMTestTimer *t) { uint64_t now = mach_absolute_time(); t->running_ = false; ++t->iterations_; @@ -85,7 +85,7 @@ FOUNDATION_STATIC_INLINE uint64_t GTMTestTimerStop(GTMTestTimer *t) { // returns the current timer elapsed time (combined value of all splits, plus // current split if the timer is running) in nanoseconds. -FOUNDATION_STATIC_INLINE double GTMTestTimerGetNanoseconds(GTMTestTimer *t) { +GTM_INLINE double GTMTestTimerGetNanoseconds(GTMTestTimer *t) { uint64_t total = t->elapsed_; if (t->running_) { total += mach_absolute_time() - t->start_; @@ -96,30 +96,30 @@ FOUNDATION_STATIC_INLINE double GTMTestTimerGetNanoseconds(GTMTestTimer *t) { // Returns the current timer elapsed time (combined value of all splits, plus // current split if the timer is running) in seconds. -FOUNDATION_STATIC_INLINE double GTMTestTimerGetSeconds(GTMTestTimer *t) { +GTM_INLINE double GTMTestTimerGetSeconds(GTMTestTimer *t) { return GTMTestTimerGetNanoseconds(t) * 0.000000001; } // Returns the current timer elapsed time (combined value of all splits, plus // current split if the timer is running) in milliseconds. -FOUNDATION_STATIC_INLINE double GTMTestTimerGetMilliseconds(GTMTestTimer *t) { +GTM_INLINE double GTMTestTimerGetMilliseconds(GTMTestTimer *t) { return GTMTestTimerGetNanoseconds(t) * 0.000001; } // Returns the current timer elapsed time (combined value of all splits, plus // current split if the timer is running) in microseconds. -FOUNDATION_STATIC_INLINE double GTMTestTimerGetMicroseconds(GTMTestTimer *t) { +GTM_INLINE double GTMTestTimerGetMicroseconds(GTMTestTimer *t) { return GTMTestTimerGetNanoseconds(t) * 0.001; } // Returns the number of splits (start-stop) cycles recorded. // GTMTestTimerGetSeconds()/GTMTestTimerGetIterations() gives you an average // of all your splits. -FOUNDATION_STATIC_INLINE NSUInteger GTMTestTimerGetIterations(GTMTestTimer *t) { +GTM_INLINE NSUInteger GTMTestTimerGetIterations(GTMTestTimer *t) { return t->iterations_; } // Returns true if the timer is running. -FOUNDATION_STATIC_INLINE bool GTMTestTimerIsRunning(GTMTestTimer *t) { +GTM_INLINE bool GTMTestTimerIsRunning(GTMTestTimer *t) { return t->running_; } diff --git a/UnitTesting/GTMUnitTestingBindingTest.m b/UnitTesting/GTMUnitTestingBindingTest.m index 78e48b1..aabac43 100644 --- a/UnitTesting/GTMUnitTestingBindingTest.m +++ b/UnitTesting/GTMUnitTestingBindingTest.m @@ -91,11 +91,10 @@ NSString *const kGTMKeyThatIsntEqual = @"keyThatIsntEqual"; nil]; } -- (NSMutableDictionary*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { - - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - [dict setObject:kGTMKeyThatIsntEqual forKey:kGTMKeyThatIsntEqual]; - return dict; +- (NSArray*)gtm_unitTestExposedBindingsTestValues:(NSString*)binding { + GTMBindingUnitTestData *data + = [GTMBindingUnitTestData testWithIdentityValue:kGTMKeyThatIsntEqual]; + return [NSArray arrayWithObject:data]; } - (Class)valueClassForBinding:(NSString*)binding { diff --git a/UnitTesting/GTMUnitTestingUtilities.m b/UnitTesting/GTMUnitTestingUtilities.m index a20023f..39534f7 100644 --- a/UnitTesting/GTMUnitTestingUtilities.m +++ b/UnitTesting/GTMUnitTestingUtilities.m @@ -112,6 +112,7 @@ static void RestoreColorProfile(void) { if (gCurrentColorProfile) { CGDirectDisplayID displayID = CGMainDisplayID(); CMError error = CMSetProfileByAVID((UInt32)displayID, gCurrentColorProfile); + CMCloseProfile(gCurrentColorProfile); if (error) { // COV_NF_START // No way to force this case in a unittest. @@ -143,6 +144,7 @@ void SetColorProfileToGenericRGB(void) { // COV_NF_END } if (AreCMProfilesEqual(genericProfile, previousProfile)) { + CMCloseProfile(previousProfile); return; } CFStringRef previousProfileName; diff --git a/UnitTesting/RunIPhoneUnitTest.sh b/UnitTesting/RunIPhoneUnitTest.sh index 1718bda..0b6fe69 100755 --- a/UnitTesting/RunIPhoneUnitTest.sh +++ b/UnitTesting/RunIPhoneUnitTest.sh @@ -16,20 +16,28 @@ # # Runs all unittests through the iPhone simulator. We don't handle running them # on the device. To run on the device just choose "run". - # Controlling environment variables: # # GTM_DISABLE_ZOMBIES - -# Set to a non-zero value to turn off zombie checks that can interfere with -# leak checking. +# Set to a non-zero value to turn on zombie checks. You will probably +# want to turn this off if you enable leaks. # -# GTM_DISABLE_LEAKS - -# Set to a non-zero value to turn off the leaks check. +# GTM_ENABLE_LEAKS - +# Set to a non-zero value to turn on the leaks check. You will probably want +# to disable zombies, otherwise you will get a lot of false positives. # # GTM_DISABLE_TERMINATION # Set to a non-zero value so that the app doesn't terminate when it's finished # running tests. This is useful when using it with external tools such # as Instruments. +# +# GTM_LEAKS_SYMBOLS_TO_IGNORE +# List of comma separated symbols that leaks should ignore. Mainly to control +# leaks in frameworks you don't have control over. +# Search this file for GTM_LEAKS_SYMBOLS_TO_IGNORE to see examples. +# Please feel free to add other symbols as you find them but make sure to +# reference Radars or other bug systems so we can track them. +# ScriptDir=$(dirname $(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")) ScriptName=$(basename "$0") @@ -39,7 +47,7 @@ GTMXcodeNote() { echo ${ThisScript}:${1}: note: GTM ${2} } -if [ "$IPHONEOS_DEPLOYMENT_TARGET" == "" ]; then +if [ "$PLATFORM_NAME" == "iphonesimulator" ]; then # We kill the iPhone simulator because otherwise we run into issues where # the unittests fail becuase the simulator is currently running, and # at this time the iPhone SDK won't allow two simulators running at the same @@ -49,7 +57,7 @@ if [ "$IPHONEOS_DEPLOYMENT_TARGET" == "" ]; then export DYLD_ROOT_PATH="$SDKROOT" export DYLD_FRAMEWORK_PATH="$CONFIGURATION_BUILD_DIR" export IPHONE_SIMULATOR_ROOT="$SDKROOT" - export CFFIXED_USER_HOME="$USER_LIBRARY_DIR/Application Support/iPhone Simulator/User" + export CFFIXED_USER_HOME="$TEMP_FILES_DIR/iPhone Simulator User Dir" # See http://developer.apple.com/technotes/tn2004/tn2124.html for an # explanation of these environment variables. @@ -60,13 +68,17 @@ if [ "$IPHONEOS_DEPLOYMENT_TARGET" == "" ]; then export MallocStackLogging=YES export NSAutoreleaseFreedObjectCheckEnabled=YES export OBJC_DEBUG_FRAGILE_SUPERCLASSES=YES - + if [ ! $GTM_DISABLE_ZOMBIES ]; then GTMXcodeNote ${LINENO} "Enabling zombies" export CFZombieLevel=3 export NSZombieEnabled=YES fi + # 6251475 iPhone simulator leaks @ CFHTTPCookieStore shutdown if + # CFFIXED_USER_HOME empty + GTM_LEAKS_SYMBOLS_TO_IGNORE="CFHTTPCookieStore" + "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents else GTMXcodeNote ${LINENO} "Skipping running of unittests for device build." diff --git a/UnitTesting/RunMacOSUnitTests.sh b/UnitTesting/RunMacOSUnitTests.sh index 5c36a79..f35092b 100755 --- a/UnitTesting/RunMacOSUnitTests.sh +++ b/UnitTesting/RunMacOSUnitTests.sh @@ -21,37 +21,172 @@ # Controlling environment variables: # -# GTM_NO_MEMORY_STRESS - -# Set to zero to prevent the setting of system library/framework debugging -# environment variables that help find problems in code. See -# http://developer.apple.com/technotes/tn2004/tn2124.html -# for details. +# GTM_DISABLE_ZOMBIES - +# Set to a non-zero value to turn on zombie checks. You will probably +# want to turn this off if you enable leaks. +# +# GTM_ENABLE_LEAKS - +# Set to a non-zero value to turn on the leaks check. You will probably want +# to disable zombies, otherwise you will get a lot of false positives. +# # GTM_NO_DEBUG_FRAMEWORKS - # Set to zero to prevent the use of the debug versions of system -# libraries/frameworks if you have them installed on your system. The frameworks -# can be found at http://connect.apple.com > Downloads > Developer Tools +# libraries/frameworks if you have them installed on your system. The +# frameworks can be found at +# http://connect.apple.com > Downloads > Developer Tools # (https://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?bundleID=19915) +# +# GTM_LEAKS_SYMBOLS_TO_IGNORE +# List of comma separated symbols that leaks should ignore. Mainly to control +# leaks in frameworks you don't have control over. +# Search this file for GTM_LEAKS_SYMBOLS_TO_IGNORE to see examples. +# Please feel free to add other symbols as you find them but make sure to +# reference Radars or other bug systems so we can track them. +# ScriptDir=$(dirname $(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")) ScriptName=$(basename "$0") ThisScript="${ScriptDir}/${ScriptName}" GTMXcodeNote() { - echo ${ThisScript}:${1}: note: GTM ${2} + echo ${ThisScript}:${1}: note: GTM ${2} +} + +# The workaround below is due to +# Radar 6248062 otest won't run with MallocHistory enabled under rosetta +# Basically we go through and check what architecture we are running on +# and which architectures we can support +AppendToSymbolsLeaksShouldIgnore() { + if [ "${GTM_LEAKS_SYMBOLS_TO_IGNORE}" = "" ]; then + GTM_LEAKS_SYMBOLS_TO_IGNORE="${1}" + else + GTM_LEAKS_SYMBOLS_TO_IGNORE="${GTM_LEAKS_SYMBOLS_TO_IGNORE}, ${1}" + fi +} + +AppendToLeakTestArchs() { + if [ "${LEAK_TEST_ARCHS}" = "" ]; then + LEAK_TEST_ARCHS="${1}" + else + LEAK_TEST_ARCHS="${LEAK_TEST_ARCHS} ${1}" + fi +} + +AppendToNoLeakTestArchs() { + if [ "${NO_LEAK_TEST_ARCHS}" = "" ]; then + NO_LEAK_TEST_ARCHS="${1}" + else + NO_LEAK_TEST_ARCHS="${NO_LEAK_TEST_ARCHS} ${1}" + fi +} + +UpdateArchitecturesToTest() { + case "${NATIVE_ARCH_ACTUAL}" in + ppc) + if [ "${1}" = "ppc" ]; then + AppendToLeakTestArchs "${1}" + fi + ;; + + ppc64) + if [ "${1}" = "ppc" -o "${1}" = "ppc64" ]; then + AppendToLeakTestArchs "${1}" + fi + ;; + + i386) + if [ "${1}" = "i386" ]; then + AppendToLeakTestArchs "${1}" + elif [ "${1}" = "ppc" ]; then + AppendToNoLeakTestArchs "${1}" + fi + ;; + + x86_64) + if [ "${1}" = "i386" -o "${1}" = "x86_64" ]; then + AppendToLeakTestArchs "${1}" + elif [ "${1}" = "ppc" -o "${1}" = "ppc64" ]; then + AppendToNoLeakTestArchs "${1}" + fi + ;; + + *) + echo "RunMacOSUnitTests.sh Unknown native architecture: ${NATIVE_ARCH_ACTUAL}" + exit 1 + ;; + esac +} + +RunTests() { + if [ "${CURRENT_ARCH}" = "" ]; then + CURRENT_ARCH=`arch` + fi + + if [ "${ONLY_ACTIVE_ARCH}" = "YES" ]; then + ARCHS="${CURRENT_ARCH}" + fi + + if [ "${ARCHS}" = "" ]; then + ARCHS=`arch` + fi + + if [ "${VALID_ARCHS}" = "" ]; then + VALID_ARCHS=`arch` + fi + + if [ "${NATIVE_ARCH_ACTUAL}" = "" ]; then + NATIVE_ARCH_ACTUAL=`arch` + fi + + LEAK_TEST_ARCHS="" + NO_LEAK_TEST_ARCHS="" + + for TEST_ARCH in ${ARCHS}; do + for TEST_VALID_ARCH in ${VALID_ARCHS}; do + if [ "${TEST_VALID_ARCH}" = "${TEST_ARCH}" ]; then + UpdateArchitecturesToTest "${TEST_ARCH}" + fi + done + done + + # These are symbols that leak on OS 10.5.5 + # radar 6247293 NSCollatorElement leaks in +initialize. + AppendToSymbolsLeaksShouldIgnore "+[NSCollatorElement initialize]" + # radar 6247911 The first call to udat_open leaks only on x86_64 + AppendToSymbolsLeaksShouldIgnore "icu::TimeZone::initDefault()" + # radar 6263983 +[IMService allServices] leaks + AppendToSymbolsLeaksShouldIgnore "-[IMServiceAgentImpl allServices]" + # radar 6264034 +[IKSFEffectDescription initialize] Leaks + AppendToSymbolsLeaksShouldIgnore "+[IKSFEffectDescription initialize]" + + # Running leaks on architectures that support leaks. + export GTM_LEAKS_SYMBOLS_TO_IGNORE="${GTM_LEAKS_SYMBOLS_TO_IGNORE}" + ARCHS="${LEAK_TEST_ARCHS}" + VALID_ARCHS="${LEAK_TEST_ARCHS}" + "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" + + # Running leaks on architectures that don't support leaks. + unset MallocStackLogging + unset GTM_ENABLE_LEAKS + ARCHS="${NO_LEAK_TEST_ARCHS}" + VALID_ARCHS="${NO_LEAK_TEST_ARCHS}" + "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" } # Jack up some memory stress so we can catch more bugs. -if [ ! $GTM_NO_MEMORY_STRESS ]; then - GTMXcodeNote ${LINENO} "Enabling memory stressing" - export MallocScribble=YES - export MallocPreScribble=YES - export MallocGuardEdges=YES +export MallocScribble=YES +export MallocPreScribble=YES +export MallocGuardEdges=YES +export MallocStackLogging=YES +export NSAutoreleaseFreedObjectCheckEnabled=YES +export OBJC_DEBUG_FRAGILE_SUPERCLASSES=YES + +if [ ! $GTM_DISABLE_ZOMBIES ]; then + GTMXcodeNote ${LINENO} "Enabling zombies" # CFZombieLevel disabled because it doesn't play well with the # security framework # export CFZombieLevel=3 - export NSAutoreleaseFreedObjectCheckEnabled=YES export NSZombieEnabled=YES - export OBJC_DEBUG_FRAGILE_SUPERCLASSES=YES fi # If we have debug libraries on the machine, we'll use them @@ -63,4 +198,10 @@ if [ ! $GTM_NO_DEBUG_FRAMEWORKS ]; then fi fi -"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" +# If leaks testing is enabled, we have to go through our convoluted path +# to handle architectures that don't allow us to do leak testing. +if [ GTM_ENABLE_LEAKS ]; then + RunTests +else + "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" +fi diff --git a/UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiff b/UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiff Binary files differnew file mode 100644 index 0000000..2bbdb9c --- /dev/null +++ b/UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiff diff --git a/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff b/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff Binary files differnew file mode 100644 index 0000000..60c362a --- /dev/null +++ b/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff |