aboutsummaryrefslogtreecommitdiff
path: root/UnitTesting
diff options
context:
space:
mode:
authorGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2008-10-22 19:16:19 +0000
committerGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2008-10-22 19:16:19 +0000
commit11938e47355bfbf3b81f1ff5b15f1222b83d4f47 (patch)
tree3794c78559472e4b2efe5eabc0e094d7c14a9743 /UnitTesting
parent90eba8f973c0b77f36dc7084163ff0d43675a1a8 (diff)
- GTM_INLINE will make sure a function gets inlined, and provides a consistent
way for all GTM code to do it. - Added GTMDebugThreadValidation to allow you to enforce the fact that your code must run in the main thread in DEBUG builds. - Updated some internals of the iPhone unittesting so it doesn't double print the test descriptions, file names, or lines numbers of a test failure line. Also includes the test names in the error output. - Changed the xcconfigs so that know it's easier to set different settings at the different levels and not accidentally overwrite settings set at lower levels in the "settings collapse". Also tightened up warnings significantly. - Changed how gtm_unitTestExposedBindingsTestValues works. If you have an implementation of gtm_unitTestExposedBindingsTestValues in your own code you will need to update to the new way of calling. See implementations in GTMNSObject+BindingUnitTesting.m for details. - Added support for grabbing the build number for a particular OS in GTMSystemVersion and easily comparing it to known build numbers, and switched some types from in GTMSystemVersion from "int" to SInt32 to make 64 bit work better. - Added support for SnowLeopard (10A96). We build cleanly with the 10.6 SDKs and all radar checks were updated accordingly. Build All script was also updated to build on SnowLeopard if you have the SDK available. - Turned off building ppc64 GTM because the SnowLeopard SDK currently doesn't have ppc64 support, so SenTestCase isn't defined. This makes it impossible to build the ppc64 10.5 config on SnowLeopard. We have left the setting in the xcconfig for those of you who need it, but have disabled it in the GTM project settings. - Turned on stack smashing protection on the debug builds for all Leopard and above. - Added ability to easily do leak checking by defining the GTM_ENABLE_LEAKS environment variable. It isn't on by default because several of Apple's frameworks leak. You can work around these false positives by using the GTM_LEAKS_SYMBOLS_TO_IGNORE environment variable. Also if you turn on leaks make sure to turn off zombies by defining the GTM_DISABLE_ZOMBIES variable, otherwise every memory allocation you do will look like a leak.
Diffstat (limited to 'UnitTesting')
-rw-r--r--UnitTesting/GTMAppKit+UnitTesting.m2
-rw-r--r--UnitTesting/GTMIPhoneUnitTestDelegate.m44
-rw-r--r--UnitTesting/GTMNSObject+BindingUnitTesting.h32
-rw-r--r--UnitTesting/GTMNSObject+BindingUnitTesting.m347
-rw-r--r--UnitTesting/GTMNSObject+UnitTesting.m90
-rw-r--r--UnitTesting/GTMSenTestCase.h7
-rw-r--r--UnitTesting/GTMSenTestCase.m308
-rw-r--r--UnitTesting/GTMTestTimer.h22
-rw-r--r--UnitTesting/GTMUnitTestingBindingTest.m9
-rw-r--r--UnitTesting/GTMUnitTestingUtilities.m2
-rwxr-xr-xUnitTesting/RunIPhoneUnitTest.sh28
-rwxr-xr-xUnitTesting/RunMacOSUnitTests.sh173
-rw-r--r--UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiffbin0 -> 21014 bytes
-rw-r--r--UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiffbin0 -> 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
new file mode 100644
index 0000000..2bbdb9c
--- /dev/null
+++ b/UnitTesting/TestData/GTMUnitTestingImage.10.6.0.tiff
Binary files differ
diff --git a/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff b/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff
new file mode 100644
index 0000000..60c362a
--- /dev/null
+++ b/UnitTesting/TestData/GTMUnitTestingWindow.10.6.0.tiff
Binary files differ