diff options
81 files changed, 2319 insertions, 632 deletions
diff --git a/Foundation/GTMGetURLHandler.m b/AppKit/GTMGetURLHandler.m index 30d516f..a35dd95 100644 --- a/Foundation/GTMGetURLHandler.m +++ b/AppKit/GTMGetURLHandler.m @@ -55,7 +55,7 @@ // } // @end -#import <Foundation/Foundation.h> +#import <AppKit/AppKit.h> #import "GTMGarbageCollection.h" #import "GTMNSAppleEventDescriptor+Foundation.h" #import "GTMMethodCheck.h" @@ -93,6 +93,7 @@ withReplyEvent:(NSAppleEventDescriptor *)replyEvent; withDescription:(NSString*)string toDescriptor:(NSAppleEventDescriptor *)desc; + (id)handlerForBundle:(NSBundle *)bundle; ++ (void)appFinishedLaunchingHandler:(NSNotification*)notification; @end @implementation GTMGetURLHandler @@ -101,6 +102,15 @@ GTM_METHOD_CHECK(NSString, gtm_appleEventDescriptor); + (void)load { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(appFinishedLaunchingHandler:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; + [pool release]; +} + ++ (void)appFinishedLaunchingHandler:(NSNotification*)notification { NSBundle *bundle = [NSBundle mainBundle]; GTMGetURLHandler *handler = [GTMGetURLHandler handlerForBundle:bundle]; if (handler) { @@ -111,13 +121,17 @@ GTM_METHOD_CHECK(NSString, gtm_appleEventDescriptor); andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; - } - [pool release]; + } + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self + name:NSApplicationDidFinishLaunchingNotification + object:nil]; } + (id)handlerForBundle:(NSBundle *)bundle { GTMGetURLHandler *handler = nil; - NSArray *urlTypes = [bundle objectForInfoDictionaryKey:kGTMCFBundleURLTypesKey]; + NSArray *urlTypes + = [bundle objectForInfoDictionaryKey:kGTMCFBundleURLTypesKey]; if (urlTypes) { handler = [[[GTMGetURLHandler alloc] initWithTypes:urlTypes] autorelease]; } else { diff --git a/AppKit/GTMLargeTypeWindowTest.m b/AppKit/GTMLargeTypeWindowTest.m index 36e60c3..6e0577a 100644 --- a/AppKit/GTMLargeTypeWindowTest.m +++ b/AppKit/GTMLargeTypeWindowTest.m @@ -64,7 +64,7 @@ NSString *const kShortTextBlock = @"Short"; // bug. Please bump the system check as appropriate when new systems are // tested. Currently broken on 10.5.5 and below. // Radar 6137322 CIFilter crashing when run with GC enabled - long major, minor, bugfix; + SInt32 major, minor, bugfix; [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugfix]; if (!(GTMIsGarbageCollectionEnabled() && major <= 10 && minor <= 5 && bugfix <= 5)) { diff --git a/AppKit/GTMLinearRGBShading.m b/AppKit/GTMLinearRGBShading.m index ef13986..f0216bf 100644 --- a/AppKit/GTMLinearRGBShading.m +++ b/AppKit/GTMLinearRGBShading.m @@ -193,7 +193,7 @@ static void cShadeFunction(void *info, const CGFloat *inPos, CGFloat *outVals) { // lazily create the colorspace as necessary if (nil == colorSpace_) { if (isCalibrated_) { - colorSpace_ = CGColorSpaceCreateWithName(kCGColorSpaceUserRGB); + colorSpace_ = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); } else { colorSpace_ = CGColorSpaceCreateDeviceRGB(); } diff --git a/AppKit/GTMLinearRGBShadingTest.m b/AppKit/GTMLinearRGBShadingTest.m index d70b878..38802e6 100644 --- a/AppKit/GTMLinearRGBShadingTest.m +++ b/AppKit/GTMLinearRGBShadingTest.m @@ -44,7 +44,7 @@ - (void)testShadingWith { // Create a shading with kColorCount colors and make sure all the values are there. - const NSUInteger kColorCount = 100; + enum { kColorCount = 100 }; NSColor *theColors[kColorCount]; CGFloat thePositions[kColorCount]; const CGFloat kColorIncrement = 1.0 / kColorCount; diff --git a/AppKit/GTMNSBezierPath+Shading.m b/AppKit/GTMNSBezierPath+Shading.m index eff8dfb..f75876f 100644 --- a/AppKit/GTMNSBezierPath+Shading.m +++ b/AppKit/GTMNSBezierPath+Shading.m @@ -154,7 +154,7 @@ @implementation NSBezierPath (GTMBezierPathShadingAdditions) -GTM_METHOD_CHECK(NSBezierPath, gtm_createCGPath); // COV_NF_LINE +GTM_METHOD_CHECK(NSBezierPath, gtm_createCGPath); - (void)gtm_strokeAxiallyFrom:(NSPoint)fromPoint to:(NSPoint)toPoint extendingStart:(BOOL)extendingStart extendingEnd:(BOOL)extendingEnd diff --git a/AppKit/GTMNSImage+Scaling.h b/AppKit/GTMNSImage+Scaling.h index 297d18c..6bf2dd5 100644 --- a/AppKit/GTMNSImage+Scaling.h +++ b/AppKit/GTMNSImage+Scaling.h @@ -26,8 +26,12 @@ // Return an existing representation of a size - (NSImageRep *)gtm_representationOfSize:(NSSize)size; +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 // Return the exact or next largest representation for a size +// If you are on SnowLeopard use +// -[NSImage bestRepresentationForRect:context:hints:] - (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size; +#endif // Create a new represetation for a given size - (BOOL)gtm_createRepresentationOfSize:(NSSize)size; diff --git a/AppKit/GTMNSImage+Scaling.m b/AppKit/GTMNSImage+Scaling.m index 57687fd..5f31190 100644 --- a/AppKit/GTMNSImage+Scaling.m +++ b/AppKit/GTMNSImage+Scaling.m @@ -23,6 +23,9 @@ @implementation NSImage (GTMNSImageScaling) +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 +// If you are on SnowLeopard use +// -[NSImage bestRepresentationForRect:context:hints:] - (NSImageRep *)gtm_bestRepresentationForSize:(NSSize)size { NSImageRep *bestRep = [self gtm_representationOfSize:size]; if (bestRep) { @@ -37,7 +40,7 @@ while ((thisRep = [repEnum nextObject])) { CGFloat thisDistance; thisDistance = MIN(size.width - [thisRep size].width, - size.height-[thisRep size].height); + size.height - [thisRep size].height); if (repDistance < 0 && thisDistance > 0) continue; if (ABS(thisDistance) < ABS(repDistance) @@ -53,6 +56,7 @@ return bestRep; } +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 - (NSImageRep *)gtm_representationOfSize:(NSSize)size { NSArray *reps = [self representations]; @@ -80,8 +84,15 @@ return NO; } - NSBitmapImageRep *bestRep = - (NSBitmapImageRep *)[self gtm_bestRepresentationForSize:size]; + NSBitmapImageRep *bestRep; +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 + bestRep = (NSBitmapImageRep *)[self gtm_bestRepresentationForSize:size]; +#else + bestRep + = (NSBitmapImageRep *)[self bestRepresentationForRect:GTMNSRectOfSize(size) + context:nil + hints:nil]; +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 NSRect drawRect = GTMNSScaleRectToRect(GTMNSRectOfSize([bestRep size]), GTMNSRectOfSize(size), diff --git a/AppKit/GTMNSImage+ScalingTest.m b/AppKit/GTMNSImage+ScalingTest.m index ec17cc5..5679b7c 100644 --- a/AppKit/GTMNSImage+ScalingTest.m +++ b/AppKit/GTMNSImage+ScalingTest.m @@ -21,6 +21,7 @@ #import "GTMSenTestCase.h" #import "GTMNSImage+Scaling.h" +#import "GTMGeometryUtils.h" @interface GTMNSImage_ScalingTest : GTMTestCase @end @@ -31,7 +32,16 @@ NSImage *testImage = [NSImage imageNamed:@"NSApplicationIcon"]; NSImageRep *rep = nil; - rep = [testImage gtm_bestRepresentationForSize:NSMakeSize(99, 99)]; + NSRect bestRepRect = NSMakeRect(0, 0, 99, 99); + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 + rep = [testImage bestRepresentationForRect:bestRepRect + context:nil + hints:nil]; +#else + rep = [testImage gtm_bestRepresentationForSize:bestRepRect.size]; +#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 + STAssertTrue(NSEqualSizes([rep size], NSMakeSize(128, 128)), nil); [testImage gtm_createIconRepresentations]; @@ -39,7 +49,14 @@ STAssertNotNil([testImage gtm_representationOfSize:NSMakeSize(32, 32)], nil); NSImage *duplicate = [testImage gtm_duplicateOfSize: NSMakeSize(48, 48)]; - rep = [duplicate gtm_bestRepresentationForSize:NSMakeSize(50, 50)]; + bestRepRect = NSMakeRect(0, 0, 50, 50); +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 + rep = [duplicate bestRepresentationForRect:bestRepRect + context:nil + hints:nil]; +#else + rep = [duplicate gtm_bestRepresentationForSize:bestRepRect.size]; +#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 STAssertTrue(NSEqualSizes([rep size], NSMakeSize(48, 48)), nil); } diff --git a/AppKit/TestData/GTMNSBezierPath+ShadingTest.10.5.tiff b/AppKit/TestData/GTMNSBezierPath+ShadingTest.tiff Binary files differindex b44b5bf..b44b5bf 100644 --- a/AppKit/TestData/GTMNSBezierPath+ShadingTest.10.5.tiff +++ b/AppKit/TestData/GTMNSBezierPath+ShadingTest.tiff diff --git a/BuildScripts/BuildAllSDKs.sh b/BuildScripts/BuildAllSDKs.sh index 1e08940..32a867d 100755 --- a/BuildScripts/BuildAllSDKs.sh +++ b/BuildScripts/BuildAllSDKs.sh @@ -1,8 +1,8 @@ #!/bin/sh # BuildAllSDKs.sh # -# This script builds the Tiger, Leopard and iPhone versions of the requested -# target in the current basic config (debug, release, debug-gcov). +# This script builds the Tiger, Leopard, SnowLeopard and iPhone versions of the +# requested target in the current basic config (debug, release, debug-gcov). # # Copyright 2006-2008 Google Inc. # @@ -30,18 +30,30 @@ if [ "${ACTION}" == "clean" ]; then PROJECT_ACTION="clean" fi +# get available SDKs and PLATFORMS +AVAILABLE_MACOS_SDKS=`eval ls ${DEVELOPER_SDK_DIR}` +AVAILABLE_PLATFORMS=`eval ls ${DEVELOPER_DIR}/Platforms` + # build up our GTMiPhone parts GTMIPHONE_OPEN_EXTRAS="" GTMIPHONE_BUILD_EXTRAS="" if [ "${GTMIPHONE_PROJECT_TARGET}" != "" ]; then - GTMIPHONE_OPEN_EXTRAS="-- make sure both project files are open - open posix file \"${SRCROOT}/GTM.xcodeproj\" - open posix file \"${SRCROOT}/GTMiPhone.xcodeproj\"" - GTMIPHONE_BUILD_EXTRAS="tell project \"GTMiPhone\" - -- do the GTMiPhone build - ${PROJECT_ACTION} using build configuration \"${REQUESTED_BUILD_STYLE}\" - set active target to target \"${STARTING_TARGET}\" - end tell" + GTMIPHONE_OPEN_EXTRAS=" + if \"${AVAILABLE_PLATFORMS}\" contains \"iPhoneSimulator.platform\" then + -- make sure both project files are open + open posix file \"${SRCROOT}/GTM.xcodeproj\" + open posix file \"${SRCROOT}/GTMiPhone.xcodeproj\" + end if" + GTMIPHONE_BUILD_EXTRAS=" + if \"${AVAILABLE_PLATFORMS}\" contains \"iPhoneSimulator.platform\" then + with timeout of 9999 seconds + tell project \"GTMiPhone\" + -- do the GTMiPhone build + ${PROJECT_ACTION} using build configuration \"${REQUESTED_BUILD_STYLE}\" + set active target to target \"${STARTING_TARGET}\" + end tell + end timeout + end if" fi # build up our GTM AppleScript @@ -49,32 +61,47 @@ OUR_BUILD_SCRIPT="on run tell application \"Xcode\" activate ${GTMIPHONE_OPEN_EXTRAS} - tell project \"GTM\" - -- wait for build to finish - set x to 0 - repeat while currently building - delay 0.5 - set x to x + 1 - if x > 6 then - display alert \"GTM is still building, can't start.\" - return - end if - end repeat - -- do the GTM builds - with timeout of 9999 seconds - set active target to target \"${GTM_PROJECT_TARGET}\" - set buildResult to ${PROJECT_ACTION} using build configuration \"TigerOrLater-${REQUESTED_BUILD_STYLE}\" - if buildResult is not equal to \"Build succeeded\" then - set active target to target \"${STARTING_TARGET}\" - return - end if - set buildResult to ${PROJECT_ACTION} using build configuration \"LeopardOrLater-${REQUESTED_BUILD_STYLE}\" - set active target to target \"${STARTING_TARGET}\" - if buildResult is not equal to \"Build succeeded\" then - return - end if - end timeout - end tell + if \"${AVAILABLE_PLATFORMS}\" contains \"MacOSX.platform\" then + tell project \"GTM\" + -- wait for build to finish + set x to 0 + repeat while currently building + delay 0.5 + set x to x + 1 + if x > 6 then + display alert \"GTM is still building, can't start.\" + return + end if + end repeat + -- do the GTM builds + with timeout of 9999 seconds + if \"{$AVAILABLE_MACOS_SDKS}\" contains \"MacOSX10.4u.sdk\" then + set active target to target \"${GTM_PROJECT_TARGET}\" + set buildResult to ${PROJECT_ACTION} using build configuration \"TigerOrLater-${REQUESTED_BUILD_STYLE}\" + set active target to target \"${STARTING_TARGET}\" + if buildResult is not equal to \"Build succeeded\" then + return + end if + end if + if \"{$AVAILABLE_MACOS_SDKS}\" contains \"MacOSX10.5.sdk\" then + set active target to target \"${GTM_PROJECT_TARGET}\" + set buildResult to ${PROJECT_ACTION} using build configuration \"LeopardOrLater-${REQUESTED_BUILD_STYLE}\" + set active target to target \"${STARTING_TARGET}\" + if buildResult is not equal to \"Build succeeded\" then + return + end if + end if + if \"{$AVAILABLE_MACOS_SDKS}\" contains \"MacOSX10.6.sdk\" then + set active target to target \"${GTM_PROJECT_TARGET}\" + set buildResult to ${PROJECT_ACTION} using build configuration \"SnowLeopardOrLater-${REQUESTED_BUILD_STYLE}\" + set active target to target \"${STARTING_TARGET}\" + if buildResult is not equal to \"Build succeeded\" then + return + end if + end if + end timeout + end tell + end if ${GTMIPHONE_BUILD_EXTRAS} end tell end run" diff --git a/DebugUtils/GTMDebugThreadValidation.h b/DebugUtils/GTMDebugThreadValidation.h new file mode 100644 index 0000000..0636159 --- /dev/null +++ b/DebugUtils/GTMDebugThreadValidation.h @@ -0,0 +1,55 @@ +// +// GTMDebugThreadValidation.h +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#if DEBUG +#import "GTMDefines.h" +#import <Foundation/Foundation.h> + +// GTMAssertRunningOnMainThread will allow you to verify that you are +// currently running on the main thread. This can be useful for checking +// under DEBUG to make sure that code that requires being run on the main thread +// is doing so. Use the GTMAssertRunningOnMainThread macro, don't use +// the _GTMAssertRunningOnMainThread or _GTMIsRunningOnMainThread +// helper functions. + +// On Leopard and above we can just use NSThread functionality. +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 +BOOL _GTMIsRunningOnMainThread(void); +#else // MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 +#import <Foundation/Foundation.h> +GTM_INLINE BOOL _GTMIsRunningOnMainThread(void) { + return [NSThread isMainThread]; +} +#endif // MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 + +GTM_INLINE void _GTMAssertRunningOnMainThread(const char *func, + const char *file, + int lineNum) { + _GTMDevAssert(_GTMIsRunningOnMainThread(), + @"%s not being run on main thread (%s - %d)", + func, file, lineNum); +} + +#define GTMAssertRunningOnMainThread() \ + (_GTMAssertRunningOnMainThread(__func__, __FILE__, __LINE__)) + +#else // DEBUG + +#define GTMAssertRunningOnMainThread() do { } while (0) + +#endif // DEBUG diff --git a/DebugUtils/GTMDebugThreadValidation.m b/DebugUtils/GTMDebugThreadValidation.m new file mode 100644 index 0000000..5889cd8 --- /dev/null +++ b/DebugUtils/GTMDebugThreadValidation.m @@ -0,0 +1,38 @@ +// +// GTMDebugThreadValidation.m +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + + +#if DEBUG && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 + +#import "GTMDebugThreadValidation.h" + +static NSThread *gGTMMainThread = nil; + +static __attribute__((constructor)) void _GTMInitThread(void) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + gGTMMainThread = [NSThread currentThread]; + [gGTMMainThread retain]; + [pool release]; +} + + +BOOL _GTMIsRunningOnMainThread(void) { + return [[NSThread currentThread] isEqual:gGTMMainThread]; +} + +#endif // DEBUG && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 diff --git a/DebugUtils/GTMDebugThreadValidationTest.m b/DebugUtils/GTMDebugThreadValidationTest.m new file mode 100644 index 0000000..66bd51b --- /dev/null +++ b/DebugUtils/GTMDebugThreadValidationTest.m @@ -0,0 +1,110 @@ +// +// GTMDebugThreadValidationTest.m +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMSenTestCase.h" +#import "GTMDebugThreadValidation.h" + +// GTMDebugThreadValidation only happens on debug builds +#if DEBUG + +@interface GTMDebugThreadValidationTest : GTMTestCase +@end + +// A cheap flag for knowing when our thread has run + +static volatile BOOL gGTMDebugThreadValidationTestDone = NO; + +// This is an assertion handler that just records that an assertion has fired. +@interface GTMDebugThreadValidationCheckAssertionHandler : NSAssertionHandler { + @private + BOOL handledAssertion_; +} +- (void)handleFailureInMethod:(SEL)selector + object:(id)object + file:(NSString *)fileName + lineNumber:(NSInteger)line + description:(NSString *)format,...; + +- (void)handleFailureInFunction:(NSString *)functionName + file:(NSString *)fileName + lineNumber:(NSInteger)line + description:(NSString *)format,...; +- (BOOL)didHandleAssertion; +@end + +@implementation GTMDebugThreadValidationTest +- (void)testOnMainThread { + STAssertNoThrow(GTMAssertRunningOnMainThread(), nil); +} + +- (void)threadFunc:(NSMutableString *)result { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + // We'll insert our own assertion handler that will get called on the assert + // so that we don't have to worry about the log, and exception being thrown. + GTMDebugThreadValidationCheckAssertionHandler *handler = + [[[GTMDebugThreadValidationCheckAssertionHandler alloc] init] autorelease]; + NSMutableDictionary *threadDictionary + = [[NSThread currentThread] threadDictionary]; + [threadDictionary setObject:handler forKey:@"NSAssertionHandler"]; + GTMAssertRunningOnMainThread(); + if ([handler didHandleAssertion]) { + [result setString:@"ASSERTED"]; + } + [threadDictionary removeObjectForKey:@"NSAssertionHandler"]; + gGTMDebugThreadValidationTestDone = YES; + [pool release]; +} + +- (void)testOnOtherThread { + NSMutableString *result = [NSMutableString string]; + gGTMDebugThreadValidationTestDone = NO; + [NSThread detachNewThreadSelector:@selector(threadFunc:) + toTarget:self + withObject:result]; + NSRunLoop *loop = [NSRunLoop currentRunLoop]; + + while (!gGTMDebugThreadValidationTestDone) { + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0.01]; + [loop runUntilDate:date]; + } + STAssertEqualStrings(result, @"ASSERTED", @"GTMAssertRunningOnMainThread did " + @"not assert while running on another thread"); +} +@end + +@implementation GTMDebugThreadValidationCheckAssertionHandler + +- (void)handleFailureInMethod:(SEL)selector + object:(id)object + file:(NSString *)fileName + lineNumber:(NSInteger)line + description:(NSString *)format,... { + handledAssertion_ = YES; +} + +- (void)handleFailureInFunction:(NSString *)functionName + file:(NSString *)fileName + lineNumber:(NSInteger)line + description:(NSString *)format,... { + handledAssertion_ = YES; +} + +- (BOOL)didHandleAssertion { + return handledAssertion_; +} +@end +#endif // DEBUG diff --git a/DebugUtils/GTMMethodCheck.m b/DebugUtils/GTMMethodCheck.m index ef3ee4a..2f88dc3 100644 --- a/DebugUtils/GTMMethodCheck.m +++ b/DebugUtils/GTMMethodCheck.m @@ -76,6 +76,7 @@ void GTMMethodCheckMethodChecker(void) { // Run through all the classes looking for class methods that are // prefixed with xxGMMethodCheckMethod. If it finds one, it calls it. // See GTMMethodCheck.h to see what it does. + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int numClasses = 0; int newNumClasses = objc_getClassList(NULL, 0); int i; @@ -156,6 +157,7 @@ void GTMMethodCheckMethodChecker(void) { if (classes) { free(classes); } + [pool release]; } #endif // DEBUG diff --git a/DebugUtils/GTMMethodCheckTest.m b/DebugUtils/GTMMethodCheckTest.m index 7b9fa0c..974dfaf 100644 --- a/DebugUtils/GTMMethodCheckTest.m +++ b/DebugUtils/GTMMethodCheckTest.m @@ -25,8 +25,8 @@ static BOOL gTestCheckVar = NO; @end @implementation GTMMethodCheckTest -GTM_METHOD_CHECK(GTMMethodCheckTest, GTMMethodCheckTestMethod); // COV_NF_LINE -GTM_METHOD_CHECK(GTMMethodCheckTest, GTMMethodCheckTestClassMethod); // COV_NF_LINE +GTM_METHOD_CHECK(GTMMethodCheckTest, GTMMethodCheckTestMethod); +GTM_METHOD_CHECK(GTMMethodCheckTest, GTMMethodCheckTestClassMethod); - (void)GTMMethodCheckTestMethod { } diff --git a/Foundation/GTMBase64.m b/Foundation/GTMBase64.m index 03914fd..5cbcfa7 100644 --- a/Foundation/GTMBase64.m +++ b/Foundation/GTMBase64.m @@ -153,7 +153,7 @@ static const char kWebSafeBase64DecodeChars[] = { // YES if the character is a whitespace character. // NO if the character is not a whitespace character. // -FOUNDATION_STATIC_INLINE BOOL IsSpace(unsigned char c) { +GTM_INLINE BOOL IsSpace(unsigned char c) { // we use our own mapping here because we don't want anything w/ locale // support. static BOOL kSpaces[256] = { @@ -192,8 +192,7 @@ FOUNDATION_STATIC_INLINE BOOL IsSpace(unsigned char c) { // Returns: // The guessed encoded length for a source length // -FOUNDATION_STATIC_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, - BOOL padded) { +GTM_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, BOOL padded) { NSUInteger intermediate_result = 8 * srcLen + 5; NSUInteger len = intermediate_result / 6; if (padded) { @@ -209,7 +208,7 @@ FOUNDATION_STATIC_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, // Returns: // The guessed decoded length for a source length // -FOUNDATION_STATIC_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) { +GTM_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) { return (srcLen + 3) / 4 * 3; } diff --git a/Foundation/GTMCalculatedRange.m b/Foundation/GTMCalculatedRange.m index 218b811..ef49d83 100644 --- a/Foundation/GTMCalculatedRange.m +++ b/Foundation/GTMCalculatedRange.m @@ -30,7 +30,7 @@ - (CGFloat)position; @end -CG_INLINE BOOL FPEqual(CGFloat a, CGFloat b) { +GTM_INLINE BOOL FPEqual(CGFloat a, CGFloat b) { return (fpclassify(a - b) == FP_ZERO); } diff --git a/Foundation/GTMGarbageCollection.h b/Foundation/GTMGarbageCollection.h index 7f2873c..b29a13b 100644 --- a/Foundation/GTMGarbageCollection.h +++ b/Foundation/GTMGarbageCollection.h @@ -33,13 +33,13 @@ // but there may be a reason the you want to make something collectable // but not autoreleased, especially in pure GC code where you don't // want to bother with the nop autorelease. -FOUNDATION_STATIC_INLINE id GTMNSMakeCollectable(CFTypeRef cf) { +GTM_INLINE id GTMNSMakeCollectable(CFTypeRef cf) { return NSMakeCollectable(cf); } // GTMNSMakeUncollectable is for global maps, etc. that we don't // want released ever. You should still retain these in non-gc code. -FOUNDATION_STATIC_INLINE void GTMNSMakeUncollectable(id object) { +GTM_INLINE void GTMNSMakeUncollectable(id object) { [[NSGarbageCollector defaultCollector] disableCollectorForPointer:object]; } @@ -48,21 +48,21 @@ FOUNDATION_STATIC_INLINE void GTMNSMakeUncollectable(id object) { // There are some places where GC doesn't work w/ things w/in Apple's // frameworks, so this is here so GTM unittests and detect it, and not run // individual tests to work around bugs in Apple's frameworks. -FOUNDATION_STATIC_INLINE BOOL GTMIsGarbageCollectionEnabled(void) { +GTM_INLINE BOOL GTMIsGarbageCollectionEnabled(void) { return ([NSGarbageCollector defaultCollector] != nil); } #else -FOUNDATION_STATIC_INLINE id GTMNSMakeCollectable(CFTypeRef cf) { +GTM_INLINE id GTMNSMakeCollectable(CFTypeRef cf) { // NSMakeCollectable handles NULLs just fine and returns nil as expected. return (id)cf; } -FOUNDATION_STATIC_INLINE void GTMNSMakeUncollectable(id object) { +GTM_INLINE void GTMNSMakeUncollectable(id object) { } -FOUNDATION_STATIC_INLINE BOOL GTMIsGarbageCollectionEnabled(void) { +GTM_INLINE BOOL GTMIsGarbageCollectionEnabled(void) { return NO; } @@ -71,7 +71,7 @@ FOUNDATION_STATIC_INLINE BOOL GTMIsGarbageCollectionEnabled(void) { // GTMCFAutorelease makes a CF object collectable in GC mode, or adds it // to the autorelease pool in non-GC mode. Either way it is taken care // of. -FOUNDATION_STATIC_INLINE id GTMCFAutorelease(CFTypeRef cf) { +GTM_INLINE id GTMCFAutorelease(CFTypeRef cf) { return [GTMNSMakeCollectable(cf) autorelease]; } diff --git a/Foundation/GTMGeometryUtils.h b/Foundation/GTMGeometryUtils.h index 855b97f..c3d6b1a 100644 --- a/Foundation/GTMGeometryUtils.h +++ b/Foundation/GTMGeometryUtils.h @@ -52,7 +52,7 @@ typedef NSUInteger GTMRectAlignment; // // Returns: // point located in the middle of min X side of rect -CG_INLINE CGPoint GTMCGMidMinX(CGRect rect) { +GTM_INLINE CGPoint GTMCGMidMinX(CGRect rect) { return CGPointMake(CGRectGetMinX(rect), CGRectGetMidY(rect)); } @@ -63,7 +63,7 @@ CG_INLINE CGPoint GTMCGMidMinX(CGRect rect) { // // Returns: // point located in the middle of max X side of rect -CG_INLINE CGPoint GTMCGMidMaxX(CGRect rect) { +GTM_INLINE CGPoint GTMCGMidMaxX(CGRect rect) { return CGPointMake(CGRectGetMaxX(rect), CGRectGetMidY(rect)); } @@ -74,7 +74,7 @@ CG_INLINE CGPoint GTMCGMidMaxX(CGRect rect) { // // Returns: // point located in the middle of max Y side of rect -CG_INLINE CGPoint GTMCGMidMaxY(CGRect rect) { +GTM_INLINE CGPoint GTMCGMidMaxY(CGRect rect) { return CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); } @@ -85,7 +85,7 @@ CG_INLINE CGPoint GTMCGMidMaxY(CGRect rect) { // // Returns: // point located in the middle of min Y side of rect -CG_INLINE CGPoint GTMCGMidMinY(CGRect rect) { +GTM_INLINE CGPoint GTMCGMidMinY(CGRect rect) { return CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); } @@ -96,7 +96,7 @@ CG_INLINE CGPoint GTMCGMidMinY(CGRect rect) { // // Returns: // point located in the center of rect -CG_INLINE CGPoint GTMCGCenter(CGRect rect) { +GTM_INLINE CGPoint GTMCGCenter(CGRect rect) { return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); } @@ -110,7 +110,7 @@ CG_INLINE CGPoint GTMCGCenter(CGRect rect) { // // Returns: // size of rectangle -CG_INLINE CGSize GTMCGRectSize(CGRect rect) { +GTM_INLINE CGSize GTMCGRectSize(CGRect rect) { return CGSizeMake(CGRectGetWidth(rect), CGRectGetHeight(rect)); } @@ -121,7 +121,7 @@ CG_INLINE CGSize GTMCGRectSize(CGRect rect) { // // Returns: // rectangle of size (origin 0,0) -CG_INLINE CGRect GTMCGRectOfSize(CGSize size) { +GTM_INLINE CGRect GTMCGRectOfSize(CGSize size) { return CGRectMake(0.0f, 0.0f, size.width, size.height); } @@ -137,7 +137,7 @@ CG_INLINE CGRect GTMCGRectOfSize(CGSize size) { // // Returns: // Converted Rect -CG_INLINE CGRect GTMCGRectScale(CGRect inRect, CGFloat xScale, CGFloat yScale) { +GTM_INLINE CGRect GTMCGRectScale(CGRect inRect, CGFloat xScale, CGFloat yScale) { return CGRectMake(inRect.origin.x, inRect.origin.y, inRect.size.width * xScale, inRect.size.height * yScale); } @@ -171,7 +171,7 @@ CGRect GTMCGScaleRectangleToSize(CGRect scalee, CGSize size, // // Returns: // Distance -CG_INLINE CGFloat GTMCGDistanceBetweenPoints(CGPoint pt1, CGPoint pt2) { +GTM_INLINE CGFloat GTMCGDistanceBetweenPoints(CGPoint pt1, CGPoint pt2) { CGFloat dX = pt1.x - pt2.x; CGFloat dY = pt1.y - pt2.y; #if CGFLOAT_IS_DOUBLE @@ -200,7 +200,7 @@ CG_INLINE CGFloat GTMCGDistanceBetweenPoints(CGPoint pt1, CGPoint pt2) { // // Returns: // Converted NSPoint -CG_INLINE NSPoint GTMCGPointToNSPoint(CGPoint inPoint) { +GTM_INLINE NSPoint GTMCGPointToNSPoint(CGPoint inPoint) { _GTMCompileAssert(sizeof(NSPoint) == sizeof(CGPoint), NSPoint_and_CGPoint_must_be_the_same_size); union convertUnion {NSPoint ns; CGPoint cg;}; return ((union convertUnion *)&inPoint)->ns; @@ -216,7 +216,7 @@ CG_INLINE NSPoint GTMCGPointToNSPoint(CGPoint inPoint) { // // Returns: // Converted CGPoint -CG_INLINE CGPoint GTMNSPointToCGPoint(NSPoint inPoint) { +GTM_INLINE CGPoint GTMNSPointToCGPoint(NSPoint inPoint) { _GTMCompileAssert(sizeof(NSPoint) == sizeof(CGPoint), NSPoint_and_CGPoint_must_be_the_same_size); union convertUnion {NSPoint ns; CGPoint cg;}; return ((union convertUnion *)&inPoint)->cg; @@ -235,7 +235,7 @@ CG_INLINE CGPoint GTMNSPointToCGPoint(NSPoint inPoint) { // // Returns: // Converted NSRect -CG_INLINE NSRect GTMCGRectToNSRect(CGRect inRect) { +GTM_INLINE NSRect GTMCGRectToNSRect(CGRect inRect) { _GTMCompileAssert(sizeof(NSRect) == sizeof(CGRect), NSRect_and_CGRect_must_be_the_same_size); union convertUnion {NSRect ns; CGRect cg;}; return ((union convertUnion *)&inRect)->ns; @@ -251,7 +251,7 @@ CG_INLINE NSRect GTMCGRectToNSRect(CGRect inRect) { // // Returns: // Converted CGRect -CG_INLINE CGRect GTMNSRectToCGRect(NSRect inRect) { +GTM_INLINE CGRect GTMNSRectToCGRect(NSRect inRect) { _GTMCompileAssert(sizeof(NSRect) == sizeof(CGRect), NSRect_and_CGRect_must_be_the_same_size); union convertUnion {NSRect ns; CGRect cg;}; return ((union convertUnion *)&inRect)->cg; @@ -268,7 +268,7 @@ CG_INLINE CGRect GTMNSRectToCGRect(NSRect inRect) { // // Returns: // Converted NSSize -CG_INLINE NSSize GTMCGSizeToNSSize(CGSize inSize) { +GTM_INLINE NSSize GTMCGSizeToNSSize(CGSize inSize) { _GTMCompileAssert(sizeof(NSSize) == sizeof(CGSize), NSSize_and_CGSize_must_be_the_same_size); union convertUnion {NSSize ns; CGSize cg;}; return ((union convertUnion *)&inSize)->ns; @@ -281,7 +281,7 @@ CG_INLINE NSSize GTMCGSizeToNSSize(CGSize inSize) { // // Returns: // Converted CGSize -CG_INLINE CGSize GTMNSSizeToCGSize(NSSize inSize) { +GTM_INLINE CGSize GTMNSSizeToCGSize(NSSize inSize) { _GTMCompileAssert(sizeof(NSSize) == sizeof(CGSize), NSSize_and_CGSize_must_be_the_same_size); union convertUnion {NSSize ns; CGSize cg;}; return ((union convertUnion *)&inSize)->cg; @@ -297,7 +297,7 @@ CG_INLINE CGSize GTMNSSizeToCGSize(NSSize inSize) { // // Returns: // point located in the middle of min X side of rect -CG_INLINE NSPoint GTMNSMidMinX(NSRect rect) { +GTM_INLINE NSPoint GTMNSMidMinX(NSRect rect) { return NSMakePoint(NSMinX(rect), NSMidY(rect)); } @@ -308,7 +308,7 @@ CG_INLINE NSPoint GTMNSMidMinX(NSRect rect) { // // Returns: // point located in the middle of max X side of rect -CG_INLINE NSPoint GTMNSMidMaxX(NSRect rect) { +GTM_INLINE NSPoint GTMNSMidMaxX(NSRect rect) { return NSMakePoint(NSMaxX(rect), NSMidY(rect)); } @@ -319,7 +319,7 @@ CG_INLINE NSPoint GTMNSMidMaxX(NSRect rect) { // // Returns: // point located in the middle of max Y side of rect -CG_INLINE NSPoint GTMNSMidMaxY(NSRect rect) { +GTM_INLINE NSPoint GTMNSMidMaxY(NSRect rect) { return NSMakePoint(NSMidX(rect), NSMaxY(rect)); } @@ -330,7 +330,7 @@ CG_INLINE NSPoint GTMNSMidMaxY(NSRect rect) { // // Returns: // point located in the middle of min Y side of rect -CG_INLINE NSPoint GTMNSMidMinY(NSRect rect) { +GTM_INLINE NSPoint GTMNSMidMinY(NSRect rect) { return NSMakePoint(NSMidX(rect), NSMinY(rect)); } @@ -341,7 +341,7 @@ CG_INLINE NSPoint GTMNSMidMinY(NSRect rect) { // // Returns: // point located in the center of rect -CG_INLINE NSPoint GTMNSCenter(NSRect rect) { +GTM_INLINE NSPoint GTMNSCenter(NSRect rect) { return NSMakePoint(NSMidX(rect), NSMidY(rect)); } @@ -355,7 +355,7 @@ CG_INLINE NSPoint GTMNSCenter(NSRect rect) { // // Returns: // size of rectangle -CG_INLINE NSSize GTMNSRectSize(NSRect rect) { +GTM_INLINE NSSize GTMNSRectSize(NSRect rect) { return NSMakeSize(NSWidth(rect), NSHeight(rect)); } @@ -366,7 +366,7 @@ CG_INLINE NSSize GTMNSRectSize(NSRect rect) { // // Returns: // rectangle of size (origin 0,0) -CG_INLINE NSRect GTMNSRectOfSize(NSSize size) { +GTM_INLINE NSRect GTMNSRectOfSize(NSSize size) { return NSMakeRect(0.0f, 0.0f, size.width, size.height); } @@ -382,7 +382,7 @@ CG_INLINE NSRect GTMNSRectOfSize(NSSize size) { // // Returns: // Converted Rect -CG_INLINE NSRect GTMNSRectScale(NSRect inRect, CGFloat xScale, CGFloat yScale) { +GTM_INLINE NSRect GTMNSRectScale(NSRect inRect, CGFloat xScale, CGFloat yScale) { return NSMakeRect(inRect.origin.x, inRect.origin.y, inRect.size.width * xScale, inRect.size.height * yScale); } @@ -392,8 +392,8 @@ CG_INLINE NSRect GTMNSRectScale(NSRect inRect, CGFloat xScale, CGFloat yScale) { // Args: // alignee - rect to be aligned // aligner - rect to be aligned from -CG_INLINE NSRect GTMNSAlignRectangles(NSRect alignee, NSRect aligner, - GTMRectAlignment alignment) { +GTM_INLINE NSRect GTMNSAlignRectangles(NSRect alignee, NSRect aligner, + GTMRectAlignment alignment) { return GTMCGRectToNSRect(GTMCGAlignRectangles(GTMNSRectToCGRect(alignee), GTMNSRectToCGRect(aligner), alignment)); @@ -406,10 +406,10 @@ CG_INLINE NSRect GTMNSAlignRectangles(NSRect alignee, NSRect aligner, // scaler - rect to scale to // scaling - way to scale the rectangle // alignment - way to align the scaled rectangle -CG_INLINE NSRect GTMNSScaleRectToRect(NSRect scalee, - NSRect scaler, - GTMScaling scaling, - GTMRectAlignment alignment) { +GTM_INLINE NSRect GTMNSScaleRectToRect(NSRect scalee, + NSRect scaler, + GTMScaling scaling, + GTMRectAlignment alignment) { return GTMCGRectToNSRect( GTMCGAlignRectangles( @@ -426,8 +426,8 @@ CG_INLINE NSRect GTMNSScaleRectToRect(NSRect scalee, // scalee - rect to be scaled // size - size to scale to // scaling - way to scale the rectangle -CG_INLINE NSRect GTMNSScaleRectangleToSize(NSRect scalee, NSSize size, - GTMScaling scaling) { +GTM_INLINE NSRect GTMNSScaleRectangleToSize(NSRect scalee, NSSize size, + GTMScaling scaling) { return GTMCGRectToNSRect(GTMCGScaleRectangleToSize(GTMNSRectToCGRect(scalee), GTMNSSizeToCGSize(size), scaling)); @@ -444,7 +444,7 @@ CG_INLINE NSRect GTMNSScaleRectangleToSize(NSRect scalee, NSSize size, // // Returns: // Distance -CG_INLINE CGFloat GTMNSDistanceBetweenPoints(NSPoint pt1, NSPoint pt2) { +GTM_INLINE CGFloat GTMNSDistanceBetweenPoints(NSPoint pt1, NSPoint pt2) { return GTMCGDistanceBetweenPoints(GTMNSPointToCGPoint(pt1), GTMNSPointToCGPoint(pt2)); } diff --git a/Foundation/GTMHTTPFetcher.m b/Foundation/GTMHTTPFetcher.m index 614f3ad..bc93bab 100644 --- a/Foundation/GTMHTTPFetcher.m +++ b/Foundation/GTMHTTPFetcher.m @@ -21,6 +21,7 @@ #import "GTMHTTPFetcher.h" #import "GTMDebugSelectorValidation.h" #import "GTMGarbageCollection.h" +#import "GTMSystemVersion.h" @interface GTMHTTPFetcher (GTMHTTPFetcherLoggingInternal) - (void)logFetchWithError:(NSError *)error; @@ -1129,13 +1130,9 @@ CannotBeginFetch: NSString *scheme = [theURL scheme]; NSString *domain = nil; - if ([host isEqual:@"localhost"]) { - // the domain stored into NSHTTPCookies for localhost is "localhost.local" - domain = @"localhost.local"; - } else { - if (host) { - domain = [@"." stringByAppendingString:host]; - } + + if (host) { + domain = [[@"." stringByAppendingString:host] lowercaseString]; } NSUInteger numberOfCookies = [cookieStorageArray count]; @@ -1143,11 +1140,17 @@ CannotBeginFetch: NSHTTPCookie *storedCookie = [cookieStorageArray objectAtIndex:idx]; - NSString *cookieDomain = [storedCookie domain]; + NSString *cookieDomain = [[storedCookie domain] lowercaseString]; NSString *cookiePath = [storedCookie path]; BOOL cookieIsSecure = [storedCookie isSecure]; BOOL domainIsOK = [domain hasSuffix:cookieDomain]; + if (!domainIsOK && [domain hasSuffix:@"localhost"]) { + // On Leopard and below, localhost Cookies always come back + // with a domain of localhost.local. On SnowLeopard they come + // back as just localhost. + domainIsOK = [@".localhost.local" hasSuffix:cookieDomain]; + } BOOL pathIsOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; BOOL secureIsOK = (!cookieIsSecure) || [scheme isEqual:@"https"]; diff --git a/Foundation/GTMHTTPFetcherTest.m b/Foundation/GTMHTTPFetcherTest.m index 3c461e0..a541d1f 100644 --- a/Foundation/GTMHTTPFetcherTest.m +++ b/Foundation/GTMHTTPFetcherTest.m @@ -19,6 +19,7 @@ #import "GTMSenTestCase.h" #import "GTMHTTPFetcher.h" #import "GTMTestHTTPServer.h" +#import "GTMUnitTestDevLog.h" @interface GTMHTTPFetcherTest : GTMTestCase { // these ivars are checked after fetches, and are reset by resetFetchResponse @@ -97,7 +98,7 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; - (void)tearDown { [testServer_ release]; testServer_ = nil; - + [self resetFetchResponse]; [fetchHistory_ release]; @@ -136,24 +137,24 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; responseHeaders = [(NSHTTPURLResponse *)fetchedResponse_ allHeaderFields]; NSString *cookiesSetString = [responseHeaders objectForKey:@"Set-Cookie"]; NSString *cookieExpected = [NSString stringWithFormat:@"TestCookie=%@", - kValidFileName]; + kValidFileName]; STAssertEqualObjects(cookiesSetString, cookieExpected, @"Unexpected cookie"); // test properties NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: - @"val1", @"key1", @"val2", @"key2", nil]; + @"val1", @"key1", @"val2", @"key2", nil]; [fetcher setProperties:dict]; STAssertEqualObjects([fetcher properties], dict, @"properties as dictionary"); STAssertEqualObjects([fetcher propertyForKey:@"key2"], @"val2", - @"single property"); + @"single property"); NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys: - @"valx1", @"key1", @"val3", @"key3", nil]; + @"valx1", @"key1", @"val3", @"key3", nil]; [fetcher setProperty:@"valx1" forKey:@"key1"]; [fetcher setProperty:nil forKey:@"key2"]; [fetcher setProperty:@"val3" forKey:@"key3"]; STAssertEqualObjects([fetcher properties], dict2, @"property changes"); - + // make a copy of the fetched data to compare with our next fetch from the // cache NSData *originalFetchedData = [[fetchedData_ copy] autorelease]; @@ -161,7 +162,7 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; // Now fetch again so the "If modified since" header will be set (because // we're calling setFetchHistory: below) and caching ON, and verify that we // got a good data from the cache, along with a "Not modified" status - + [self resetFetchResponse]; [self doFetchWithURLString:urlString cachingDatedData:YES]; @@ -196,19 +197,19 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; [fetchHistory_ removeAllObjects]; [self doFetchWithURLString:urlString cachingDatedData:NO]; - + STAssertEqualObjects(fetchedData_, originalFetchedData, @"cache data mismatch"); - + [self resetFetchResponse]; [self doFetchWithURLString:urlString cachingDatedData:NO]; - + STAssertNotNil(fetchedData_, @""); STAssertEquals([fetchedData_ length], (NSUInteger)0, @"unexpected data"); STAssertEquals(fetchedStatus_, (NSInteger)kGTMHTTPFetcherStatusNotModified, @"fetching data expected status 304, instead got %d", fetchedStatus_); STAssertNil(fetcherError_, @"unexpected error: %@", fetcherError_); - + } - (void)testBogusFetch { @@ -221,29 +222,29 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; if (fetchedStatus_ == kServiceUnavailableStatus) { // some proxies give a "service unavailable" error for bogus fetches } else { - + if (fetchedData_) { NSString *str = [[[NSString alloc] initWithData:fetchedData_ encoding:NSUTF8StringEncoding] autorelease]; STAssertNil(fetchedData_, @"fetched unexpected data: %@", str); } - + STAssertNotNil(fetcherError_, @"failed to receive fetching error"); STAssertEquals(fetchedStatus_, (NSInteger)0, @"fetching data expected no status from no response, instead got %d", fetchedStatus_); } - + // fetch with a specific status code from our http server [self resetFetchResponse]; - + NSString *invalidWebPageFile = [kValidFileName stringByAppendingString:@"?status=400"]; NSString *statusUrlString = [self fileURLStringToTestFileName:invalidWebPageFile]; - + [self doFetchWithURLString:statusUrlString cachingDatedData:NO]; - + STAssertNotNil(fetchedData_, @"fetch lacked data with error info"); STAssertNil(fetcherError_, @"expected bad status but got an error"); STAssertEquals(fetchedStatus_, (NSInteger)400, @@ -258,7 +259,7 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; SEL countRetriesSel = @selector(countRetriesFetcher:willRetry:forError:); SEL fixRequestSel = @selector(fixRequestFetcher:willRetry:forError:); - + // // test: retry until timeout, then expect failure with status message // @@ -310,6 +311,44 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; STAssertEquals([fetcher retryCount], 1U, @"retry count unexpected"); } +- (void)testNilFetch { + GTMHTTPFetcher *fetcher = [[GTMHTTPFetcher alloc] init]; + [GTMUnitTestDevLog expectString:@"beginFetchWithDelegate requires a request"]; + BOOL wasGood = [fetcher beginFetchWithDelegate:nil + didFinishSelector:NULL + didFailSelector:NULL]; + STAssertFalse(wasGood, nil); +} + +- (void)testCookies { + // This is checking part one of + // rdar://6293862 NSHTTPCookie cookieWithProperties doesn't work with + // NSHTTPCookieOriginURL key + NSString *urlString = @"http://www.apple.com/index.html"; + NSURL *url = [NSURL URLWithString:@"http://www.apple.com/index.html"]; + + NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys: + url, NSHTTPCookieOriginURL, + @"testCookies", NSHTTPCookieName, + @"1", NSHTTPCookieValue, + nil]; + NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties]; + + STAssertNil(cookie, nil); + + // This is checking part two of + // rdar://6293862 NSHTTPCookie cookieWithProperties doesn't work with + // NSHTTPCookieOriginURL key + properties = [NSDictionary dictionaryWithObjectsAndKeys: + urlString, NSHTTPCookieOriginURL, + @"testCookies", NSHTTPCookieName, + @"1", NSHTTPCookieValue, + nil]; + cookie = [NSHTTPCookie cookieWithProperties:properties]; + + STAssertNil(cookie, nil); +} + #pragma mark - - (GTMHTTPFetcher *)doFetchWithURLString:(NSString *)urlString @@ -327,7 +366,7 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; retrySelector:(SEL)retrySel maxRetryInterval:(NSTimeInterval)maxRetryInterval userData:(id)userData { - + NSURL *url = [NSURL URLWithString:urlString]; NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData @@ -387,7 +426,7 @@ static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; // return a localhost:port URL for the test file NSString *urlString = [NSString stringWithFormat:@"http://localhost:%d/%@", - [testServer_ port], name]; + [testServer_ port], name]; // we exclude the "?status=" that would indicate that the URL // should cause a retryable error diff --git a/Foundation/GTMNSAppleEventDescriptor+Foundation.m b/Foundation/GTMNSAppleEventDescriptor+Foundation.m index deb375f..14f256d 100644 --- a/Foundation/GTMNSAppleEventDescriptor+Foundation.m +++ b/Foundation/GTMNSAppleEventDescriptor+Foundation.m @@ -507,13 +507,12 @@ static NSMutableDictionary *gTypeMap = nil; BOOL isGood = YES; AppleEvent replyEvent = { typeNull, NULL }; OSStatus err = AESendMessage([self aeDesc], &replyEvent, mode, timeout * 60); + NSAppleEventDescriptor *replyDesc + = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&replyEvent] autorelease]; if (err) { isGood = NO; _GTMDevLog(@"Unable to send message: %@ %d", self, err); - replyEvent.descriptorType = typeNull; - replyEvent.dataHandle = NULL; } - NSAppleEventDescriptor *replyDesc = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&replyEvent] autorelease]; if (isGood) { NSAppleEventDescriptor *errorDesc = [replyDesc descriptorForKeyword:keyErrorNumber]; if (errorDesc && [errorDesc int32Value]) { diff --git a/Foundation/GTMNSAppleEventDescriptor+Handler.m b/Foundation/GTMNSAppleEventDescriptor+Handler.m index da0197b..76b6e85 100644 --- a/Foundation/GTMNSAppleEventDescriptor+Handler.m +++ b/Foundation/GTMNSAppleEventDescriptor+Handler.m @@ -22,7 +22,7 @@ #import <Carbon/Carbon.h> @implementation NSAppleEventDescriptor (GTMAppleEventDescriptorHandlerAdditions) -GTM_METHOD_CHECK(NSProcessInfo, gtm_appleEventDescriptor); // COV_NF_LINE +GTM_METHOD_CHECK(NSProcessInfo, gtm_appleEventDescriptor); + (id)gtm_descriptorWithPositionalHandler:(NSString*)handler parametersArray:(NSArray*)params { diff --git a/Foundation/GTMNSAppleScript+Handler.h b/Foundation/GTMNSAppleScript+Handler.h index 2c38f36..e63eaee 100644 --- a/Foundation/GTMNSAppleScript+Handler.h +++ b/Foundation/GTMNSAppleScript+Handler.h @@ -21,7 +21,7 @@ // :::WARNING::: NSAppleScript and Garbage Collect (GC) // -// As of 10.5.4 (and below) Apple has bugs in NSAppleScript when running with +// As of 10.5.5 (and below) Apple has bugs in NSAppleScript when running with // GC; ie-things crash that have nothing to do w/ this or your code. See // http://rails.wincent.com/issues/640 for a good amount of detail about the // problems and simple cases that show it. diff --git a/Foundation/GTMNSAppleScript+Handler.m b/Foundation/GTMNSAppleScript+Handler.m index ec6f5d0..592aca6 100644 --- a/Foundation/GTMNSAppleScript+Handler.m +++ b/Foundation/GTMNSAppleScript+Handler.m @@ -22,6 +22,7 @@ #import "GTMNSAppleEventDescriptor+Handler.h" #import "GTMFourCharCode.h" #import "GTMMethodCheck.h" +#import "GTMDebugThreadValidation.h" // Some private methods that we need to call @interface NSAppleScript (NSPrivate) @@ -70,9 +71,9 @@ @end @implementation NSAppleScript(GTMAppleScriptHandlerAdditions) -GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_descriptorWithPositionalHandler:parametersArray:); // COV_NF_LINE -GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_descriptorWithLabeledHandler:labels:parameters:count:); // COV_NF_LINE -GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); // COV_NF_LINE +GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_descriptorWithPositionalHandler:parametersArray:); +GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_descriptorWithLabeledHandler:labels:parameters:count:); +GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); + (void)load { DescType types[] = { @@ -104,6 +105,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); - (NSAppleEventDescriptor *)gtm_executeAppleEvent:(NSAppleEventDescriptor *)event error:(NSDictionary **)error { + GTMAssertRunningOnMainThread(); if (![self isCompiled]) { if (![self compileAndReturnError:error]) { return nil; @@ -225,7 +227,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); desc = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&result] autorelease]; } else { - _GTMDevLog(@"Unable to coerce script %d", error); // COV_NF_LINE + _GTMDevLog(@"Unable to coerce script %d", error); } return desc; } @@ -247,7 +249,8 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); - (void)forwardInvocation:(NSInvocation *)invocation { SEL sel = [invocation selector]; - NSMutableString *handlerName = [NSStringFromSelector(sel) mutableCopy]; + NSMutableString *handlerName + = [[NSStringFromSelector(sel) mutableCopy] autorelease]; NSUInteger handlerOrigLength = [handlerName length]; [handlerName replaceOccurrencesOfString:@":" withString:@"" @@ -285,6 +288,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSAppleEventDescriptor*)gtm_valueDescriptorForProperty:(id)property { + GTMAssertRunningOnMainThread(); OSAError error = paramErr; NSAppleEventDescriptor *desc = nil; NSAppleEventDescriptor *propertyName @@ -335,6 +339,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSSet*)gtm_scriptHandlers { + GTMAssertRunningOnMainThread(); AEDescList names = { typeNull, NULL }; NSArray *array = nil; ComponentInstance component; @@ -353,6 +358,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSSet*)gtm_scriptProperties { + GTMAssertRunningOnMainThread(); AEDescList names = { typeNull, NULL }; NSArray *array = nil; ComponentInstance component; @@ -371,6 +377,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (OSAID)gtm_genericID:(OSAID)osaID forComponent:(ComponentInstance)component { + GTMAssertRunningOnMainThread(); ComponentInstance genericComponent = [NSAppleScript _defaultScriptingComponent]; OSAID exactID = osaID; OSAError error = OSARealToGenericID(genericComponent, &exactID, component); @@ -383,6 +390,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); - (NSAppleEventDescriptor*)descForScriptID:(OSAID)osaID component:(ComponentInstance)component { + GTMAssertRunningOnMainThread(); NSAppleEventDescriptor *desc = nil; // If we have a script, return a typeGTMOSAID, otherwise convert it to // it's default AEDesc using OSACoerceToDesc with typeWildCard. @@ -422,6 +430,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (OSAID)gtm_realIDAndComponent:(ComponentInstance*)component { + GTMAssertRunningOnMainThread(); if (![self isCompiled]) { NSDictionary *error; if (![self compileAndReturnError:&error]) { diff --git a/Foundation/GTMNSAppleScript+HandlerTest.m b/Foundation/GTMNSAppleScript+HandlerTest.m index d4bb9bc..102332e 100644 --- a/Foundation/GTMNSAppleScript+HandlerTest.m +++ b/Foundation/GTMNSAppleScript+HandlerTest.m @@ -36,11 +36,11 @@ // GTMNSAppleScript+Handler.h for more details, but we disable them to avoid // the tests failing (crashing) when it's Apple's bug. Please bump the system // check as appropriate when new systems are tested. Currently broken on - // 10.5.4 and below. Radar 6126682. - long major, minor, bugfix; + // 10.5.5 and below. Radar 6126682. + SInt32 major, minor, bugfix; [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugfix]; if (!(GTMIsGarbageCollectionEnabled() - && major <= 10 && minor <= 5 && bugfix <= 4)) { + && major <= 10 && minor <= 5 && bugfix <= 5)) { [super invokeTest]; } else { NSLog(@"--- %@ NOT run because of GC incompatibilites ---", [self name]); @@ -286,6 +286,12 @@ @"testadd", @"testgetscript", nil]; + if ([GTMSystemVersion isBuildEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // Workaround for bug in SnowLeopard + // rdar://66688601 OSAGetHandlersNames returns names in camelcase instead + // of smallcaps. + handlers = [handlers valueForKey:@"lowercaseString"]; + } STAssertEqualObjects(handlers, expected, @"Unexpected handlers?"); } @@ -345,13 +351,19 @@ [GTMFourCharCode fourCharCodeWithFourCharCode:pASWeeks], [GTMFourCharCode fourCharCodeWithFourCharCode:pTextItemDelimiters], // Applescript properties should be pASSeconds, but - // on 10.5.4 it is actually using cSeconds. + // on 10.5.4/10.5.5 it is actually using cSeconds. // Radar 6132696 Applescript root level property is cSeconds // instead of pASSeconds [GTMFourCharCode fourCharCodeWithFourCharCode:cSeconds], [GTMFourCharCode fourCharCodeWithFourCharCode:pASHours], [GTMFourCharCode fourCharCodeWithFourCharCode:pASTab], nil]; + if ([GTMSystemVersion isBuildEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // Workaround for bug in SnowLeopard + // rdar://6289077 OSAGetPropertyNames returns names in camelcase instead + // of lowercase. + properties = [properties valueForKey:@"lowercaseString"]; + } STAssertEqualObjects(properties, expected, @"Unexpected properties?"); id value = [script gtm_valueForProperty:@"testScriptProperty"]; STAssertEqualObjects(value, [NSNumber numberWithInt:5], @"bad property?"); diff --git a/Foundation/GTMNSDictionary+URLArguments.m b/Foundation/GTMNSDictionary+URLArguments.m index 9b3d67e..d67572c 100644 --- a/Foundation/GTMNSDictionary+URLArguments.m +++ b/Foundation/GTMNSDictionary+URLArguments.m @@ -22,7 +22,7 @@ @implementation NSDictionary (GTMNSDictionaryURLArgumentsAdditions) -GTM_METHOD_CHECK(NSString, gtm_stringByEscapingForURLArgument); // COV_NF_LINE +GTM_METHOD_CHECK(NSString, gtm_stringByEscapingForURLArgument); - (NSString *)gtm_httpArgumentsString { NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:[self count]]; diff --git a/Foundation/GTMNSString+XML.m b/Foundation/GTMNSString+XML.m index 909a8f1..0e16ddb 100644 --- a/Foundation/GTMNSString+XML.m +++ b/Foundation/GTMNSString+XML.m @@ -40,7 +40,7 @@ static NSString *gXMLEntityList[] = { @">", }; -FOUNDATION_STATIC_INLINE GTMXMLCharMode XMLModeForUnichar(UniChar c) { +GTM_INLINE GTMXMLCharMode XMLModeForUnichar(UniChar c) { // Per XML spec Section 2.2 Characters // ( http://www.w3.org/TR/REC-xml/#charsets ) diff --git a/Foundation/GTMObjC2Runtime.m b/Foundation/GTMObjC2Runtime.m index df3c9ca..ba0cb74 100644 --- a/Foundation/GTMObjC2Runtime.m +++ b/Foundation/GTMObjC2Runtime.m @@ -108,8 +108,16 @@ IMP method_setImplementation(Method method, IMP imp) { // because it seems odd that this API won't accept nil for method considering // all the other apis will accept nil args. // If this does get fixed, remember to enable the unit tests. - IMP oldImp = method->method_imp; - method->method_imp = imp; + // This method works differently on SnowLeopard than + // on Leopard. If you pass in a nil for IMP on SnowLeopard + // it doesn't change anything. On Leopard it will. Since + // attempting to change a sel to nil is probably an error + // we follow the SnowLeopard way of doing things. + IMP oldImp = NULL; + if (imp) { + oldImp = method->method_imp; + method->method_imp = imp; + } return oldImp; } diff --git a/Foundation/GTMObjC2RuntimeTest.m b/Foundation/GTMObjC2RuntimeTest.m index 6fb5bdf..1bc0ee3 100644 --- a/Foundation/GTMObjC2RuntimeTest.m +++ b/Foundation/GTMObjC2RuntimeTest.m @@ -18,6 +18,10 @@ #import "GTMObjC2Runtime.h" #import "GTMSenTestCase.h" +#import "GTMSystemVersion.h" + + + #import <string.h> @protocol GTMObjC2Runtime_TestProtocol @@ -270,11 +274,6 @@ AT_REQUIRED } - (void)test_method_setImplementation { - // Nil Checks - // This case intentionally not tested. Passing nil to method_setImplementation - // on Leopard crashes. It does on Tiger as well. - // STAssertNULL(method_setImplementation(nil, nil), nil); - // Standard use check GTMObjC2Runtime_TestClass *test = [[GTMObjC2Runtime_TestClass alloc] init]; Method *list = class_copyMethodList(cls_, nil); @@ -297,12 +296,45 @@ AT_REQUIRED STAssertNotEquals(oldImp, newImp, nil); // test nils - oldImp = method_setImplementation(list[0], nil); - STAssertNotNULL(oldImp, nil); - - newImp = method_setImplementation(list[0], oldImp); - STAssertNULL(newImp, nil); - + // Apparently it was a bug that we could call setImplementation with a nil + // so we now test to make sure that setting to nil works as expected on + // all systems. +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 + // Built for less then leopard gives us the behaviors we defined... + // (doesn't take nil) + IMP nullImp = method_setImplementation(list[0], nil); + STAssertNULL(nullImp, nil); + IMP testImp = method_setImplementation(list[0], newImp); + STAssertEquals(testImp, oldImp, nil); +#else + // Built for leopard or later means we get the os runtime behavior... + if ([GTMSystemVersion isLeopard]) { + // (takes nil) + oldImp = method_setImplementation(list[0], nil); + STAssertNotNULL(oldImp, nil); + newImp = method_setImplementation(list[0], oldImp); + STAssertNULL(newImp, nil); + } else { + // (doesn't take nil) + IMP nullImp = method_setImplementation(list[0], nil); + STAssertNULL(nullImp, nil); + IMP testImp = method_setImplementation(list[0], newImp); + STAssertEquals(testImp, oldImp, nil); + } +#endif + + // This case intentionally not tested. Passing nil to method_setImplementation + // on Leopard crashes. It does on Tiger as well. Half works on SnowLeopard. + // We made our Tiger implementation the same as the SnowLeopard + // implementation. + // Logged as radar 5572981. + if (![GTMSystemVersion isLeopard]) { + STAssertNULL(method_setImplementation(nil, nil), nil); + } + if ([GTMSystemVersion isBuildGreaterThan:kGTMSystemBuild10_6_0_WWDC]) { + STAssertNULL(method_setImplementation(nil, newImp), nil); + } + [test release]; free(list); } diff --git a/Foundation/GTMProgressMonitorInputStreamTest.m b/Foundation/GTMProgressMonitorInputStreamTest.m index 1d0d1aa..69d331a 100644 --- a/Foundation/GTMProgressMonitorInputStreamTest.m +++ b/Foundation/GTMProgressMonitorInputStreamTest.m @@ -19,7 +19,7 @@ #import "GTMSenTestCase.h" #import "GTMProgressMonitorInputStream.h" #import "GTMUnitTestDevLog.h" - +#import "GTMSystemVersion.h" @interface GTMProgressMonitorInputStreamTest : GTMTestCase @end @@ -111,10 +111,15 @@ static const unsigned long long kSourceDataByteCount = (10000*10); [monStream setDelegate:nil]; STAssertNil([monStream delegate], nil); - // error (we get unknown error before we open things) - - NSError *err = [monStream streamError]; - STAssertEqualObjects([err domain], @"NSUnknownErrorDomain", nil); + if (![GTMSystemVersion isBuildEqualTo:kGTMSystemBuild10_6_0_WWDC]) { + // error (we get unknown error before we open things) + // This was changed on SnowLeopard. + // rdar://689714 Calling streamError on unopened stream no longer returns + // error + // was filed to check this behaviour. + NSError *err = [monStream streamError]; + STAssertEqualObjects([err domain], @"NSUnknownErrorDomain", nil); + } // status and properties diff --git a/Foundation/GTMRegex.m b/Foundation/GTMRegex.m index 33c5b25..71d5050 100644 --- a/Foundation/GTMRegex.m +++ b/Foundation/GTMRegex.m @@ -444,13 +444,16 @@ static NSString *const kReplacementPattern = NSString *result = @"internal error"; // size the buffer we need - size_t len = regerror(errCode, ®exData_, nil, 0); - char buffer[len]; - // fetch the error - if (len == regerror(errCode, ®exData_, buffer, len)) { - NSString *generatedError = [NSString stringWithUTF8String:buffer]; - if (generatedError) - result = generatedError; + size_t len = regerror(errCode, ®exData_, NULL, 0); + char *buffer = (char*)malloc(sizeof(char) * len); + if (buffer) { + // fetch the error + if (len == regerror(errCode, ®exData_, buffer, len)) { + NSString *generatedError = [NSString stringWithUTF8String:buffer]; + if (generatedError) + result = generatedError; + } + free(buffer); } return result; } diff --git a/Foundation/GTMScriptRunner.m b/Foundation/GTMScriptRunner.m index 8a76c4a..fce6915 100644 --- a/Foundation/GTMScriptRunner.m +++ b/Foundation/GTMScriptRunner.m @@ -72,6 +72,7 @@ static BOOL LaunchNSTaskCatchingExceptions(NSTask *task); } - (void)dealloc { + [environment_ release]; [interpreter_ release]; [interpreterArgs_ release]; [super dealloc]; diff --git a/Foundation/GTMScriptRunnerTest.m b/Foundation/GTMScriptRunnerTest.m index 9545045..3d74b9e 100644 --- a/Foundation/GTMScriptRunnerTest.m +++ b/Foundation/GTMScriptRunnerTest.m @@ -183,12 +183,13 @@ GTMScriptRunner *sr = [GTMScriptRunner runner]; STAssertNotNil(sr, @"Script runner must not be nil"); NSString *output = nil; - + NSString *error = nil; STAssertNil([sr environment], @"should start w/ empty env"); - output = [sr run:@"/usr/bin/env | wc -l"]; + output = [sr run:@"/usr/bin/env | wc -l" standardError:&error]; int numVars = [output intValue]; - STAssertGreaterThan(numVars, 0, @"numVars should be positive"); + STAssertGreaterThan(numVars, 0, + @"numVars should be positive. StdErr %@", error); // By default the environment is wiped clean, however shells often add a few // of their own env vars after things have been wiped. For example, sh will // add about 3 env vars (PWD, _, and SHLVL). @@ -197,15 +198,14 @@ NSDictionary *newEnv = [NSDictionary dictionaryWithObject:@"bar" forKey:@"foo"]; [sr setEnvironment:newEnv]; - - output = [sr run:@"/usr/bin/env | wc -l"]; + output = [sr run:@"/usr/bin/env | wc -l" standardError:&error]; STAssertEquals([output intValue], numVars + 1, - @"should have one more env var now"); + @"should have one more env var now. StdErr %@", error); [sr setEnvironment:nil]; - output = [sr run:@"/usr/bin/env | wc -l"]; + output = [sr run:@"/usr/bin/env | wc -l" standardError:&error]; STAssertEquals([output intValue], numVars, - @"should be back down to %d vars", numVars); + @"should be back down to %d vars. StdErr:%@", numVars, error); NSMutableDictionary *currVars = [[[[NSProcessInfo processInfo] environment] mutableCopy] autorelease]; @@ -216,9 +216,11 @@ [currVars setObject:@"/usr/bin/env" forKey:@"_"]; [sr setEnvironment:currVars]; - output = [sr run:@"/usr/bin/env | wc -l"]; - STAssertEquals([output intValue], (int)[currVars count], - @"should be back down to %d vars", numVars); + output = [sr run:@"/usr/bin/env | /usr/bin/sort" standardError:&error]; + NSArray *lineArray = [output componentsSeparatedByString:@"\n"]; + STAssertEquals([lineArray count], [currVars count], + @"StdErr:%@\nCurrentEnvironment:\n%@\nExpected environment:\n%@", + error, output, currVars); } - (void)testDescription { diff --git a/Foundation/GTMStackTrace.h b/Foundation/GTMStackTrace.h index a77ca93..3b6965d 100644 --- a/Foundation/GTMStackTrace.h +++ b/Foundation/GTMStackTrace.h @@ -17,6 +17,7 @@ // #include <CoreFoundation/CoreFoundation.h> +#import "GTMDefines.h" #ifdef __cplusplus extern "C" { @@ -66,7 +67,7 @@ NSString *GTMStackTrace(void); // Returns: // The number of program counters actually added to outPcs. // -int GTMGetStackProgramCounters(void *outPcs[], int count); +NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count); // Returns an array of GTMAddressDescriptors from the current thread's stack. // *** You should probably use GTMStackTrace() instead of this function *** @@ -84,8 +85,8 @@ int GTMGetStackProgramCounters(void *outPcs[], int count); // Returns: // The number of program counters actually added to outPcs. // -int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], - int count); +NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], + NSUInteger count); #ifdef __cplusplus } #endif diff --git a/Foundation/GTMStackTrace.m b/Foundation/GTMStackTrace.m index a7198dc..8a14bcf 100644 --- a/Foundation/GTMStackTrace.m +++ b/Foundation/GTMStackTrace.m @@ -42,7 +42,7 @@ struct GTMClassDescription { #pragma mark Private utility functions -static struct GTMClassDescription *GTMClassDescriptions(int *total_count) { +static struct GTMClassDescription *GTMClassDescriptions(NSUInteger *total_count) { int class_count = objc_getClassList(nil, 0); struct GTMClassDescription *class_descs = calloc(class_count, sizeof(struct GTMClassDescription)); @@ -74,9 +74,9 @@ static struct GTMClassDescription *GTMClassDescriptions(int *total_count) { } static void GTMFreeClassDescriptions(struct GTMClassDescription *class_descs, - int count) { - if (!class_descs || count < 0) return; - for (int i = 0; i < count; ++i) { + NSUInteger count) { + if (!class_descs) return; + for (NSUInteger i = 0; i < count; ++i) { if (class_descs[i].instance_methods) { free(class_descs[i].instance_methods); } @@ -95,7 +95,7 @@ static void GTMFreeClassDescriptions(struct GTMClassDescription *class_descs, // great on i386, but PPC requires a little more work because the PC (or link // register) isn't always stored on the stack. // -int GTMGetStackProgramCounters(void *outPcs[], int count) { +NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count) { if (!outPcs || (count < 1)) return 0; struct GTMStackFrame *fp; @@ -108,7 +108,7 @@ int GTMGetStackProgramCounters(void *outPcs[], int count) { #error architecture not supported #endif - int level = 0; + NSUInteger level = 0; while (level < count) { if (fp == NULL) { level--; @@ -122,15 +122,15 @@ int GTMGetStackProgramCounters(void *outPcs[], int count) { return level; } -int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], - int count) { - if (count < 1) return 0; +NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], + NSUInteger count) { + if (count < 1 || !outDescs) return 0; void **pcs = calloc(count, sizeof(void*)); if (!pcs) return 0; - int newSize = GTMGetStackProgramCounters(pcs, count); - int class_desc_count; + NSUInteger newSize = GTMGetStackProgramCounters(pcs, count); + NSUInteger class_desc_count; // Get our obj-c class descriptions. This is expensive, so we do it once // at the top. We go through this because dladdr doesn't work with @@ -139,7 +139,7 @@ int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], = GTMClassDescriptions(&class_desc_count); // Iterate through the stack. - for (int i = 0; i < newSize; ++i) { + for (NSUInteger i = 0; i < newSize; ++i) { const char *class_name = NULL; Boolean is_class_method = FALSE; size_t smallest_diff = SIZE_MAX; @@ -147,9 +147,9 @@ int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], currDesc->address = pcs[i]; Method best_method = NULL; // Iterate through all the classes we know of. - for (int j = 0; j < class_desc_count; ++j) { + for (NSUInteger j = 0; j < class_desc_count; ++j) { // First check the class methods. - for (unsigned int k = 0; k < class_descs[j].class_method_count; ++k) { + for (NSUInteger k = 0; k < class_descs[j].class_method_count; ++k) { IMP imp = method_getImplementation(class_descs[j].class_methods[k]); if (imp <= (IMP)currDesc->address) { size_t diff = (size_t)currDesc->address - (size_t)imp; @@ -162,7 +162,7 @@ int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], } } // Then check the instance methods. - for (unsigned int k = 0; k < class_descs[j].instance_method_count; ++k) { + for (NSUInteger k = 0; k < class_descs[j].instance_method_count; ++k) { IMP imp = method_getImplementation(class_descs[j].instance_methods[k]); if (imp <= (IMP)currDesc->address) { size_t diff = (size_t)currDesc->address - (size_t)imp; @@ -194,6 +194,7 @@ int GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], currDesc->filename = info.dli_fname; } GTMFreeClassDescriptions(class_descs, class_desc_count); + free(pcs); return newSize; } @@ -201,17 +202,16 @@ NSString *GTMStackTrace(void) { // The maximum number of stack frames that we will walk. We limit this so // that super-duper recursive functions (or bugs) don't send us for an // infinite loop. - const int kMaxStackTraceDepth = 100; - struct GTMAddressDescriptor descs[kMaxStackTraceDepth]; - int depth = kMaxStackTraceDepth; + struct GTMAddressDescriptor descs[100]; + size_t depth = sizeof(descs) / sizeof(struct GTMAddressDescriptor); depth = GTMGetStackAddressDescriptors(descs, depth); NSMutableString *trace = [NSMutableString string]; // Start at the second item so that GTMStackTrace and it's utility calls (of // which there is currently 1) is not included in the output. - const int kTracesToStrip = 2; - for (int i = kTracesToStrip; i < depth; i++) { + const size_t kTracesToStrip = 2; + for (size_t i = kTracesToStrip; i < depth; i++) { if (descs[i].class_name) { [trace appendFormat:@"#%-2d 0x%08lx %s[%s %s] (%s)\n", i - kTracesToStrip, descs[i].address, diff --git a/Foundation/GTMStackTraceTest.m b/Foundation/GTMStackTraceTest.m index dd92fe9..dc5ea57 100644 --- a/Foundation/GTMStackTraceTest.m +++ b/Foundation/GTMStackTraceTest.m @@ -47,11 +47,12 @@ - (void)testProgramCountersBasic { void *pcs[10]; - int depth = 10; + NSUInteger depth = 10; depth = GTMGetStackProgramCounters(pcs, depth); - STAssertGreaterThan(depth, 3, @"stack trace must have > 3 lines"); - STAssertLessThanOrEqual(depth, 10, @"stack trace must have < 10 lines"); + STAssertGreaterThan(depth, (NSUInteger)3, @"stack trace must have > 3 lines"); + STAssertLessThanOrEqual(depth, (NSUInteger)10, + @"stack trace must have < 10 lines"); // pcs is an array of program counters from the stack. pcs[0] should match // the call into GTMGetStackProgramCounters, which is tough for us to check. @@ -63,19 +64,19 @@ - (void)testProgramCountersMore { void *pcs0[0]; - int depth0 = 0; + NSUInteger depth0 = 0; depth0 = GTMGetStackProgramCounters(pcs0, depth0); - STAssertEquals(depth0, 0, @"stack trace must have 0 lines"); + STAssertEquals(depth0, (NSUInteger)0, @"stack trace must have 0 lines"); void *pcs1[1]; - int depth1 = 1; + NSUInteger depth1 = 1; depth1 = GTMGetStackProgramCounters(pcs1, depth1); - STAssertEquals(depth1, 1, @"stack trace must have 1 lines"); + STAssertEquals(depth1, (NSUInteger)1, @"stack trace must have 1 lines"); void *pcs2[2]; - int depth2 = 2; + NSUInteger depth2 = 2; depth2 = GTMGetStackProgramCounters(pcs2, depth2); - STAssertEquals(depth2, 2, @"stack trace must have 2 lines"); + STAssertEquals(depth2, (NSUInteger)2, @"stack trace must have 2 lines"); void *current_pc = __builtin_return_address(0); STAssertEquals(pcs2[1], current_pc, @"pcs[1] should equal the current PC"); } diff --git a/Foundation/GTMSystemVersion.h b/Foundation/GTMSystemVersion.h index 0f19596..959d2af 100644 --- a/Foundation/GTMSystemVersion.h +++ b/Foundation/GTMSystemVersion.h @@ -23,7 +23,20 @@ @interface GTMSystemVersion : NSObject // Returns the current system version major.minor.bugFix -+ (void)getMajor:(long*)major minor:(long*)minor bugFix:(long*)bugFix; ++ (void)getMajor:(SInt32*)major minor:(SInt32*)minor bugFix:(SInt32*)bugFix; + +// Returns the build number of the OS. Useful when looking for bug fixes +// in new OSes which all have a set system version. +// eg 10.5.5's build number is 9F33. Easy way to check the build number +// is to choose "About this Mac" from the Apple menu and click on the version +// number. ++ (NSString*)build; + ++ (BOOL)isBuildLessThan:(NSString*)build; ++ (BOOL)isBuildLessThanOrEqualTo:(NSString*)build; ++ (BOOL)isBuildGreaterThan:(NSString*)build; ++ (BOOL)isBuildGreaterThanOrEqualTo:(NSString*)build; ++ (BOOL)isBuildEqualTo:(NSString *)build; #if GTM_MACOS_SDK // Returns YES if running on 10.3, NO otherwise. @@ -35,6 +48,9 @@ // Returns YES if running on 10.5, NO otherwise. + (BOOL)isLeopard; +// Returns YES if running on 10.6, NO otherwise. ++ (BOOL)isSnowLeopard; + // Returns a YES/NO if the system is 10.3 or better + (BOOL)isPantherOrGreater; @@ -43,6 +59,27 @@ // Returns a YES/NO if the system is 10.5 or better + (BOOL)isLeopardOrGreater; + +// Returns a YES/NO if the system is 10.6 or better ++ (BOOL)isSnowLeopardOrGreater; #endif // GTM_MACOS_SDK +// Returns one of the achitecture strings below. Note that this is the +// architecture that we are currently running as, not the hardware architecture. ++ (NSString *)runtimeArchitecture; @end + +// Architecture Strings +// TODO: Should probably break iPhone up into iPhone_ARM and iPhone_Simulator +// but haven't found a need yet. +extern NSString *const kGTMArch_iPhone; +extern NSString *const kGTMArch_ppc; +extern NSString *const kGTMArch_ppc64; +extern NSString *const kGTMArch_x86_64; +extern NSString *const kGTMArch_i386; + +// System Build Number constants +extern NSString *const kGTMSystemBuild10_5_5; +extern NSString *const kGTMSystemBuild10_6_0_WWDC; + + diff --git a/Foundation/GTMSystemVersion.m b/Foundation/GTMSystemVersion.m index da767ae..868f6b8 100644 --- a/Foundation/GTMSystemVersion.m +++ b/Foundation/GTMSystemVersion.m @@ -17,6 +17,7 @@ // #import "GTMSystemVersion.h" +#import "GTMGarbageCollection.h" #if GTM_MACOS_SDK #import <Carbon/Carbon.h> #endif @@ -24,6 +25,18 @@ static SInt32 sGTMSystemVersionMajor = 0; static SInt32 sGTMSystemVersionMinor = 0; static SInt32 sGTMSystemVersionBugFix = 0; +static NSString *sBuild = nil; + +NSString *const kGTMArch_iPhone = @"iPhone"; +NSString *const kGTMArch_ppc = @"ppc"; +NSString *const kGTMArch_ppc64 = @"ppc64"; +NSString *const kGTMArch_x86_64 = @"x86_64"; +NSString *const kGTMArch_i386 = @"i386"; + +static NSString *const kSystemVersionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist"; + +NSString *const kGTMSystemBuild10_5_5 = @"9F33"; +NSString *const kGTMSystemBuild10_6_0_WWDC = @"10A96"; @implementation GTMSystemVersion + (void)initialize { @@ -51,9 +64,9 @@ static SInt32 sGTMSystemVersionBugFix = 0; // Note that this code will return x.9.9 for any system rev parts that are // greater than 9 (i.e., 10.10.10 will be 10.9.9). This shouldn't ever be a // problem as the code above takes care of 10.4+. - int msb = (binaryCodedDec & 0x0000F000L) >> 12; + SInt32 msb = (binaryCodedDec & 0x0000F000L) >> 12; msb *= 10; - int lsb = (binaryCodedDec & 0x00000F00L) >> 8; + SInt32 lsb = (binaryCodedDec & 0x00000F00L) >> 8; sGTMSystemVersionMajor = msb + lsb; sGTMSystemVersionMinor = (binaryCodedDec & 0x000000F0L) >> 4; sGTMSystemVersionBugFix = (binaryCodedDec & 0x0000000FL); @@ -61,14 +74,17 @@ static SInt32 sGTMSystemVersionBugFix = 0; #else // GTM_MACOS_SDK NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSDictionary *systemVersionPlist = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; + NSDictionary *systemVersionPlist + = [NSDictionary dictionaryWithContentsOfFile:kSystemVersionPlistPath]; NSString *version = [systemVersionPlist objectForKey:@"ProductVersion"]; _GTMDevAssert(version, @"Unable to get version"); NSArray *versionInfo = [version componentsSeparatedByString:@"."]; NSUInteger length = [versionInfo count]; - _GTMDevAssert(length > 1 && length < 4, @"Unparseable version %@", version); + _GTMDevAssert(length > 1 && length < 4, + @"Unparseable version %@", version); sGTMSystemVersionMajor = [[versionInfo objectAtIndex:0] intValue]; - _GTMDevAssert(sGTMSystemVersionMajor != 0, @"Unknown version for %@", version); + _GTMDevAssert(sGTMSystemVersionMajor != 0, + @"Unknown version for %@", version); sGTMSystemVersionMinor = [[versionInfo objectAtIndex:1] intValue]; if (length == 3) { sGTMSystemVersionBugFix = [[versionInfo objectAtIndex:2] intValue]; @@ -78,7 +94,7 @@ static SInt32 sGTMSystemVersionBugFix = 0; } } -+ (void)getMajor:(long*)major minor:(long*)minor bugFix:(long*)bugFix { ++ (void)getMajor:(SInt32*)major minor:(SInt32*)minor bugFix:(SInt32*)bugFix { if (major) { *major = sGTMSystemVersionMajor; } @@ -90,6 +106,57 @@ static SInt32 sGTMSystemVersionBugFix = 0; } } ++ (NSString*)build { + @synchronized(self) { + // Not cached at initialization time because we don't expect "real" + // software to want this, and it costs a bit to get at startup. + // This will mainly be for unit test cases. + if (!sBuild) { + NSDictionary *systemVersionPlist + = [NSDictionary dictionaryWithContentsOfFile:kSystemVersionPlistPath]; + sBuild = [[systemVersionPlist objectForKey:@"ProductBuildVersion"] retain]; + GTMNSMakeUncollectable(sBuild); + _GTMDevAssert(sBuild, @"Unable to get build version"); + } + } + return sBuild; +} + ++ (BOOL)isBuildLessThan:(NSString*)build { + NSComparisonResult result + = [[self build] compare:build + options:NSNumericSearch | NSCaseInsensitiveSearch]; + return result == NSOrderedAscending; +} + ++ (BOOL)isBuildLessThanOrEqualTo:(NSString*)build { + NSComparisonResult result + = [[self build] compare:build + options:NSNumericSearch | NSCaseInsensitiveSearch]; + return result != NSOrderedDescending; +} + ++ (BOOL)isBuildGreaterThan:(NSString*)build { + NSComparisonResult result + = [[self build] compare:build + options:NSNumericSearch | NSCaseInsensitiveSearch]; + return result == NSOrderedDescending; +} + ++ (BOOL)isBuildGreaterThanOrEqualTo:(NSString*)build { + NSComparisonResult result + = [[self build] compare:build + options:NSNumericSearch | NSCaseInsensitiveSearch]; + return result != NSOrderedAscending; +} + ++ (BOOL)isBuildEqualTo:(NSString *)build { + NSComparisonResult result + = [[self build] compare:build + options:NSNumericSearch | NSCaseInsensitiveSearch]; + return result == NSOrderedSame; +} + #if GTM_MACOS_SDK + (BOOL)isPanther { return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 3; @@ -103,6 +170,10 @@ static SInt32 sGTMSystemVersionBugFix = 0; return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 5; } ++ (BOOL)isSnowLeopard { + return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 6; +} + + (BOOL)isPantherOrGreater { return (sGTMSystemVersionMajor > 10) || (sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 3); @@ -118,6 +189,43 @@ static SInt32 sGTMSystemVersionBugFix = 0; (sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 5); } ++ (BOOL)isSnowLeopardOrGreater { + return (sGTMSystemVersionMajor > 10) || + (sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 6); +} + #endif // GTM_MACOS_SDK ++ (NSString *)runtimeArchitecture { + NSString *architecture = nil; +#if GTM_IPHONE_SDK + architecture = kGTMArch_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__ + architecture = kGTMArch_ppc64; +#else // !__LP64__ + architecture = kGTMArch_ppc; +#endif // __LP64__ +#else // !__POWERPC__ +#if __LP64__ + architecture = kGTMArch_x86_64; +#else // !__LP64__ + architecture = kGTMArch_i386; +#endif // __LP64__ +#endif // !__POWERPC__ + +#endif // GTM_IPHONE_SDK + return architecture; +} + @end diff --git a/Foundation/GTMSystemVersionTest.m b/Foundation/GTMSystemVersionTest.m index e95a33d..b6952da 100644 --- a/Foundation/GTMSystemVersionTest.m +++ b/Foundation/GTMSystemVersionTest.m @@ -24,9 +24,9 @@ @implementation GTMSystemVersionTest - (void)testBasics { - long major; - long minor; - long bugFix; + SInt32 major; + SInt32 minor; + SInt32 bugFix; [GTMSystemVersion getMajor:nil minor:nil bugFix:nil]; [GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugFix]; @@ -37,17 +37,54 @@ BOOL isPanther = (major == 10) && (minor == 3); BOOL isTiger = (major == 10) && (minor == 4); BOOL isLeopard = (major == 10) && (minor == 5); - BOOL isLater = (major > 10) || ((major == 10) && (minor > 5)); + BOOL isSnowLeopard = (major == 10) && (minor == 6); + + BOOL isLater = (major > 10) || ((major == 10) && (minor > 6)); STAssertEquals([GTMSystemVersion isPanther], isPanther, nil); STAssertEquals([GTMSystemVersion isPantherOrGreater], - (BOOL)(isPanther || isTiger || isLeopard || isLater), nil); + (BOOL)(isPanther || isTiger + || isLeopard || isSnowLeopard || isLater), nil); STAssertEquals([GTMSystemVersion isTiger], isTiger, nil); STAssertEquals([GTMSystemVersion isTigerOrGreater], - (BOOL)(isTiger || isLeopard || isLater), nil); + (BOOL)(isTiger || isLeopard || isSnowLeopard || isLater), nil); STAssertEquals([GTMSystemVersion isLeopard], isLeopard, nil); STAssertEquals([GTMSystemVersion isLeopardOrGreater], - (BOOL)(isLeopard || isLater), nil); -#endif + (BOOL)(isLeopard || isSnowLeopard || isLater), nil); + STAssertEquals([GTMSystemVersion isSnowLeopard], isSnowLeopard, nil); + STAssertEquals([GTMSystemVersion isSnowLeopardOrGreater], + (BOOL)(isSnowLeopard || isLater), nil); +#endif +} + +- (void)testRuntimeArchitecture { + // Not sure how to test this short of recoding it and verifying. + // This at least executes the code for me. + STAssertNotNil([GTMSystemVersion runtimeArchitecture], nil); } +- (void)testBuild { + // Not sure how to test this short of coding up a large fragile table. + // This at least executes the code for me. + NSString *systemVersion = [GTMSystemVersion build]; + STAssertNotEquals([systemVersion length], (NSUInteger)0, nil); + + NSString *smallVersion = @"1A00"; + NSString *largeVersion = @"100Z100"; + STAssertTrue([GTMSystemVersion isBuildGreaterThan:smallVersion], nil); + STAssertFalse([GTMSystemVersion isBuildGreaterThan:systemVersion], nil); + STAssertFalse([GTMSystemVersion isBuildGreaterThan:largeVersion], nil); + STAssertTrue([GTMSystemVersion isBuildGreaterThanOrEqualTo:smallVersion], nil); + STAssertTrue([GTMSystemVersion isBuildGreaterThanOrEqualTo:systemVersion], nil); + STAssertFalse([GTMSystemVersion isBuildGreaterThanOrEqualTo:largeVersion], nil); + STAssertFalse([GTMSystemVersion isBuildEqualTo:smallVersion], nil); + STAssertTrue([GTMSystemVersion isBuildEqualTo:systemVersion], nil); + STAssertFalse([GTMSystemVersion isBuildEqualTo:largeVersion], nil); + STAssertFalse([GTMSystemVersion isBuildLessThanOrEqualTo:smallVersion], nil); + STAssertTrue([GTMSystemVersion isBuildLessThanOrEqualTo:systemVersion], nil); + STAssertTrue([GTMSystemVersion isBuildLessThanOrEqualTo:largeVersion], nil); + STAssertFalse([GTMSystemVersion isBuildLessThan:smallVersion], nil); + STAssertFalse([GTMSystemVersion isBuildLessThan:systemVersion], nil); + STAssertTrue([GTMSystemVersion isBuildLessThan:largeVersion], nil); + +} @end diff --git a/Foundation/GTMValidatingContainers.h b/Foundation/GTMValidatingContainers.h index 1b11f1b..e53b541 100644 --- a/Foundation/GTMValidatingContainers.h +++ b/Foundation/GTMValidatingContainers.h @@ -33,7 +33,7 @@ // GTMValidatingArray *array = [GTMValidatingArray validatingArrayWithTarget:target // selector:selector]; // [array addObject:@"foo"]; // Will be good -// [array addObject:[NSNumber numberWithInt:2]; // Will fail +// [array addObject:[NSNumber numberWithInt:2]]; // Will fail // // By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and // GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens @@ -84,18 +84,19 @@ void _GTMValidateContainerContainsMemberOfClass(id container, Class cls); void _GTMValidateContainerConformsToProtocol(id container, Protocol *prot); void _GTMValidateContainerItemsRespondToSelector(id container, SEL sel); #else -inline void _GTMValidateContainer(id container, id target, SEL selector) { +GTM_INLINE void _GTMValidateContainer(id container, id target, SEL selector) { } -inline void _GTMValidateContainerContainsKindOfClass(id container, Class cls) { +GTM_INLINE void _GTMValidateContainerContainsKindOfClass(id container, + Class cls) { } -inline void _GTMValidateContainerContainsMemberOfClass(id container, - Class cls) { +GTM_INLINE void _GTMValidateContainerContainsMemberOfClass(id container, + Class cls) { } -inline void _GTMValidateContainerConformsToProtocol(id container, - Protocol *prot) { +GTM_INLINE void _GTMValidateContainerConformsToProtocol(id container, + Protocol *prot) { } -inline void _GTMValidateContainerItemsRespondToSelector(id container, - SEL sel) { +GTM_INLINE void _GTMValidateContainerItemsRespondToSelector(id container, + SEL sel) { } #endif diff --git a/Foundation/GTMValidatingContainers.m b/Foundation/GTMValidatingContainers.m index f46ba3f..3b31356 100644 --- a/Foundation/GTMValidatingContainers.m +++ b/Foundation/GTMValidatingContainers.m @@ -34,10 +34,10 @@ #import <objc/objc-runtime.h> #endif // GTM_IPHONE_SDK -static inline BOOL VerifyObjectWithTargetAndSelectorForContainer(id anObject, - id target, - SEL selector, - id container) { +GTM_INLINE BOOL VerifyObjectWithTargetAndSelectorForContainer(id anObject, + id target, + SEL selector, + id container) { // We must take care here, since Intel leaves junk in high bytes of return // register for predicates that return BOOL. // For details see: @@ -59,7 +59,7 @@ static inline BOOL VerifyObjectWithTargetAndSelectorForContainer(id anObject, return isGood; } -static inline void VerifySelectorOnTarget(SEL sel, id target) { +GTM_INLINE void VerifySelectorOnTarget(SEL sel, id target) { GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, sel, @encode(BOOL), @@ -207,7 +207,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { - (id)initValidatingWithCapacity:(NSUInteger)capacity target:(id)target selector:(SEL)sel { - [self release]; + if ((self = [super init])) { + [self release]; + } return [[NSMutableArray alloc] initWithCapacity:capacity]; } #endif // GTM_CONTAINERS_VALIDATE @@ -282,7 +284,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { - (id)initValidatingWithCapacity:(NSUInteger)capacity target:(id)target selector:(SEL)sel { - [self release]; + if ((self = [super init])) { + [self release]; + } return [[NSMutableDictionary alloc] initWithCapacity:capacity]; } @@ -359,7 +363,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { - (id)initValidatingWithCapacity:(NSUInteger)capacity target:(id)target selector:(SEL)sel { - [self release]; + if ((self = [super init])) { + [self release]; + } return [[NSMutableSet alloc] initWithCapacity:capacity]; } #endif // GTM_CONTAINERS_VALIDATE @@ -384,7 +390,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { } return self; #else // GTM_CONTAINERS_VALIDATE - [self release]; + if ((self = [super init])) { + [self release]; + } return nil; #endif // GTM_CONTAINERS_VALIDATE } @@ -411,7 +419,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { } return self; #else // GTM_CONTAINERS_VALIDATE - [self release]; + if ((self = [super init])) { + [self release]; + } return nil; #endif // GTM_CONTAINERS_VALIDATE } @@ -438,7 +448,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { } return self; #else // GTM_CONTAINERS_VALIDATE - [self release]; + if ((self = [super init])) { + [self release]; + } return nil; #endif // GTM_CONTAINERS_VALIDATE } @@ -465,7 +477,9 @@ void _GTMValidateContainer(id container, id target, SEL selector) { } return self; #else // GTM_CONTAINERS_VALIDATE - [self release]; + if ((self = [super init])) { + [self release]; + } return nil; #endif // GTM_CONTAINERS_VALIDATE } diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj index 7f1a92c..017d952 100644 --- a/GTM.xcodeproj/project.pbxproj +++ b/GTM.xcodeproj/project.pbxproj @@ -47,6 +47,9 @@ 7F3EB3940E5E0A2100A7A75E /* GTMNSImage+ScalingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F3EB3930E5E0A2100A7A75E /* GTMNSImage+ScalingTest.m */; }; 7F3EB5540E5F0B0400A7A75E /* GTMUnitTestingImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8BEEA90A0DA7446300894774 /* GTMUnitTestingImage.tiff */; }; 7F3EB5870E5F0CBB00A7A75E /* GTMLargeTypeWindowTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B1801A40E2533DB00280961 /* GTMLargeTypeWindowTest.m */; }; + 84978FBC0EA6A67C00C5DC83 /* GTMSystemVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = F48FE2930D198D24009257D2 /* GTMSystemVersion.m */; }; + 84B91B8B0EA3CC2E0087500F /* GTMUnitTestingImage.10.6.0.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 84B91B890EA3CC2E0087500F /* GTMUnitTestingImage.10.6.0.tiff */; }; + 84B91B8C0EA3CC2E0087500F /* GTMUnitTestingWindow.10.6.0.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 84B91B8A0EA3CC2E0087500F /* GTMUnitTestingWindow.10.6.0.tiff */; }; 8B1801A20E2533D500280961 /* GTMLargeTypeWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B1801A00E2533D500280961 /* GTMLargeTypeWindow.m */; }; 8B1801A30E2533D500280961 /* GTMLargeTypeWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B1801A10E2533D500280961 /* GTMLargeTypeWindow.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8B1801AE0E25341B00280961 /* GTMLargeTypeWindowImageTest.gtmUTState in Resources */ = {isa = PBXBuildFile; fileRef = 8B1801A80E25341B00280961 /* GTMLargeTypeWindowImageTest.gtmUTState */; }; @@ -92,7 +95,9 @@ 8B61FDC00E4CDB8000FF9C21 /* GTMStackTrace.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B61FDBF0E4CDB8000FF9C21 /* GTMStackTrace.m */; }; 8B6F32080DA34A1B0052CA40 /* GTMObjC2RuntimeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6F32050DA34A1B0052CA40 /* GTMObjC2RuntimeTest.m */; }; 8B6F32160DA34C830052CA40 /* GTMMethodCheckTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6F31F10DA347720052CA40 /* GTMMethodCheckTest.m */; }; - 8B7AD49A0DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.10.5.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.10.5.tiff */; }; + 8B6F4B630E8856CA00425D9F /* GTMDebugThreadValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6F4B610E8856CA00425D9F /* GTMDebugThreadValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8B6F4B640E8856CA00425D9F /* GTMDebugThreadValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6F4B620E8856CA00425D9F /* GTMDebugThreadValidation.m */; }; + 8B7AD49A0DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.tiff */; }; 8B7AD49B0DABBB5800B84F4A /* GTMNSBezierPath+CGPathTest.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8B7AD4980DABBB5800B84F4A /* GTMNSBezierPath+CGPathTest.tiff */; }; 8B7AD49C0DABBB5800B84F4A /* GTMNSBezierPath+RoundRectTest.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8B7AD4990DABBB5800B84F4A /* GTMNSBezierPath+RoundRectTest.tiff */; }; 8B7AD4AE0DABBFEE00B84F4A /* GTMUnitTestingBindingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B7AD4AD0DABBFEE00B84F4A /* GTMUnitTestingBindingTest.m */; }; @@ -123,6 +128,7 @@ 8BE281B20DEC7E930035B3F8 /* GTMNSAppleEventDescriptor+Foundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B33441F0DBF7A36009FD32C /* GTMNSAppleEventDescriptor+Foundation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8BE2836F0DED0F130035B3F8 /* GTMFourCharCodeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE2836C0DED0F130035B3F8 /* GTMFourCharCodeTest.m */; }; 8BE283730DED13AB0035B3F8 /* GTMFourCharCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BE2836D0DED0F130035B3F8 /* GTMFourCharCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8BE839AA0E8AF72E00C611B0 /* GTMDebugThreadValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE839A80E8AF72500C611B0 /* GTMDebugThreadValidationTest.m */; }; 8BE869730DBE89C100749827 /* GTMNSBezierPath+RoundRectTest.x86_64.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8BE869720DBE89C100749827 /* GTMNSBezierPath+RoundRectTest.x86_64.tiff */; }; 8BEEA90D0DA7446300894774 /* GTMUnitTestingImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8BEEA90A0DA7446300894774 /* GTMUnitTestingImage.tiff */; }; 8BEEA90E0DA7446300894774 /* GTMUnitTestingWindow.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8BEEA90B0DA7446300894774 /* GTMUnitTestingWindow.tiff */; }; @@ -303,6 +309,11 @@ 7F3EB38C0E5E09C700A7A75E /* GTMNSImage+Scaling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSImage+Scaling.h"; sourceTree = "<group>"; }; 7F3EB38D0E5E09C700A7A75E /* GTMNSImage+Scaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSImage+Scaling.m"; sourceTree = "<group>"; }; 7F3EB3930E5E0A2100A7A75E /* GTMNSImage+ScalingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSImage+ScalingTest.m"; sourceTree = "<group>"; }; + 848269C80E9FF4BD006E6D9C /* DebugSnowLeopardOrLater.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugSnowLeopardOrLater.xcconfig; sourceTree = "<group>"; }; + 848269C90E9FF4BD006E6D9C /* ReleaseSnowLeopardOrLater.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseSnowLeopardOrLater.xcconfig; sourceTree = "<group>"; }; + 84B91B890EA3CC2E0087500F /* GTMUnitTestingImage.10.6.0.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMUnitTestingImage.10.6.0.tiff; sourceTree = "<group>"; }; + 84B91B8A0EA3CC2E0087500F /* GTMUnitTestingWindow.10.6.0.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMUnitTestingWindow.10.6.0.tiff; sourceTree = "<group>"; }; + 84D99F360EA661C900C007D5 /* BuildAllSDKs.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = BuildAllSDKs.sh; sourceTree = "<group>"; }; 8B1801A00E2533D500280961 /* GTMLargeTypeWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMLargeTypeWindow.m; sourceTree = "<group>"; }; 8B1801A10E2533D500280961 /* GTMLargeTypeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMLargeTypeWindow.h; sourceTree = "<group>"; }; 8B1801A40E2533DB00280961 /* GTMLargeTypeWindowTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMLargeTypeWindowTest.m; sourceTree = "<group>"; }; @@ -355,9 +366,11 @@ 8B6F32040DA34A1B0052CA40 /* GTMObjC2Runtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMObjC2Runtime.m; sourceTree = "<group>"; }; 8B6F32050DA34A1B0052CA40 /* GTMObjC2RuntimeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMObjC2RuntimeTest.m; sourceTree = "<group>"; }; 8B6F32060DA34A1B0052CA40 /* GTMObjC2Runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMObjC2Runtime.h; sourceTree = "<group>"; }; + 8B6F4B610E8856CA00425D9F /* GTMDebugThreadValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDebugThreadValidation.h; sourceTree = "<group>"; }; + 8B6F4B620E8856CA00425D9F /* GTMDebugThreadValidation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMDebugThreadValidation.m; sourceTree = "<group>"; }; 8B726BD00D91C0860090C251 /* GTMCALayer+UnitTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMCALayer+UnitTesting.m"; sourceTree = "<group>"; }; 8B726BD10D91C0860090C251 /* GTMCALayer+UnitTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMCALayer+UnitTesting.h"; sourceTree = "<group>"; }; - 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.10.5.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMNSBezierPath+ShadingTest.10.5.tiff"; sourceTree = "<group>"; }; + 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMNSBezierPath+ShadingTest.tiff"; sourceTree = "<group>"; }; 8B7AD4980DABBB5800B84F4A /* GTMNSBezierPath+CGPathTest.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMNSBezierPath+CGPathTest.tiff"; sourceTree = "<group>"; }; 8B7AD4990DABBB5800B84F4A /* GTMNSBezierPath+RoundRectTest.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMNSBezierPath+RoundRectTest.tiff"; sourceTree = "<group>"; }; 8B7AD4AD0DABBFEE00B84F4A /* GTMUnitTestingBindingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMUnitTestingBindingTest.m; sourceTree = "<group>"; }; @@ -370,6 +383,7 @@ 8BE2836B0DED0F130035B3F8 /* GTMFourCharCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFourCharCode.m; sourceTree = "<group>"; }; 8BE2836C0DED0F130035B3F8 /* GTMFourCharCodeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFourCharCodeTest.m; sourceTree = "<group>"; }; 8BE2836D0DED0F130035B3F8 /* GTMFourCharCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMFourCharCode.h; sourceTree = "<group>"; }; + 8BE839A80E8AF72500C611B0 /* GTMDebugThreadValidationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMDebugThreadValidationTest.m; sourceTree = "<group>"; }; 8BE869720DBE89C100749827 /* GTMNSBezierPath+RoundRectTest.x86_64.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "GTMNSBezierPath+RoundRectTest.x86_64.tiff"; sourceTree = "<group>"; }; 8BEEA90A0DA7446300894774 /* GTMUnitTestingImage.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMUnitTestingImage.tiff; sourceTree = "<group>"; }; 8BEEA90B0DA7446300894774 /* GTMUnitTestingWindow.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = GTMUnitTestingWindow.tiff; sourceTree = "<group>"; }; @@ -577,6 +591,7 @@ F48FE23E0D197F70009257D2 /* XcodeConfig */, F48B91030D94485500D45044 /* TigerGcov */, 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 84D99F350EA661C900C007D5 /* BuildScripts */, 034768DFFF38A50411DB9C8B /* Products */, 32DBCF5E0370ADEE00C91783 /* GTM_Prefix.pch */, F42E086E0D199A5B00D5DDE0 /* GTM-Info.plist */, @@ -600,6 +615,14 @@ name = "External Frameworks and Libraries"; sourceTree = "<group>"; }; + 84D99F350EA661C900C007D5 /* BuildScripts */ = { + isa = PBXGroup; + children = ( + 84D99F360EA661C900C007D5 /* BuildAllSDKs.sh */, + ); + path = BuildScripts; + sourceTree = "<group>"; + }; 8B45A2A20DA49C47001148C5 /* GTMUIUnitTestingHarness */ = { isa = PBXGroup; children = ( @@ -613,6 +636,8 @@ F435E46C0DC8F23A0069CDE8 /* TestData */ = { isa = PBXGroup; children = ( + 84B91B890EA3CC2E0087500F /* GTMUnitTestingImage.10.6.0.tiff */, + 84B91B8A0EA3CC2E0087500F /* GTMUnitTestingWindow.10.6.0.tiff */, 8B45A2DE0DA51A7E001148C5 /* GTMUnitTestingTest.nib */, 8B45A6B90DA67DD5001148C5 /* GTMUnitTestingImage.gtmUTState */, 8B45A5F50DA5EB9F001148C5 /* GTMUnitTestingWindow.gtmUTState */, @@ -637,7 +662,7 @@ 8B7AD4990DABBB5800B84F4A /* GTMNSBezierPath+RoundRectTest.tiff */, F435DE8A0DC0B7620069CDE8 /* GTMNSBezierPath+RoundRectTest.ppc64.tiff */, 8BE869720DBE89C100749827 /* GTMNSBezierPath+RoundRectTest.x86_64.tiff */, - 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.10.5.tiff */, + 8B7AD4970DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.tiff */, ); path = TestData; sourceTree = "<group>"; @@ -673,6 +698,7 @@ children = ( F48FE27C0D198D0E009257D2 /* GTMDelegatingTableColumn.h */, F48FE27D0D198D0E009257D2 /* GTMDelegatingTableColumn.m */, + 8B58E9940E547EB000A0E02E /* GTMGetURLHandler.m */, 8B1801A10E2533D500280961 /* GTMLargeTypeWindow.h */, 8B1801A00E2533D500280961 /* GTMLargeTypeWindow.m */, 8B1801A40E2533DB00280961 /* GTMLargeTypeWindowTest.m */, @@ -725,7 +751,6 @@ F48FE27E0D198D0E009257D2 /* GTMGeometryUtils.h */, F48FE27F0D198D0E009257D2 /* GTMGeometryUtils.m */, F48FE2800D198D0E009257D2 /* GTMGeometryUtilsTest.m */, - 8B58E9940E547EB000A0E02E /* GTMGetURLHandler.m */, F47F1D2D0D4914AD00925B8F /* GTMCalculatedRange.h */, F47F1D2E0D4914AD00925B8F /* GTMCalculatedRange.m */, F47F1D2F0D4914AD00925B8F /* GTMCalculatedRangeTest.m */, @@ -840,8 +865,10 @@ F4CA852B0DAFA92A00B4AB10 /* Project */ = { isa = PBXGroup; children = ( + 848269C80E9FF4BD006E6D9C /* DebugSnowLeopardOrLater.xcconfig */, F4CA864A0DB3ACB200B4AB10 /* DebugLeopardOrLater.xcconfig */, F48FE2410D197F9A009257D2 /* DebugTigerOrLater.xcconfig */, + 848269C90E9FF4BD006E6D9C /* ReleaseSnowLeopardOrLater.xcconfig */, F4CA864B0DB3ACB200B4AB10 /* ReleaseLeopardOrLater.xcconfig */, F48FE2440D197F9A009257D2 /* ReleaseTigerOrLater.xcconfig */, ); @@ -870,6 +897,9 @@ 8B6F31EF0DA347720052CA40 /* GTMMethodCheck.m */, 8B6F31F40DA3489B0052CA40 /* GTMMethodCheck.h */, 8B6F31F10DA347720052CA40 /* GTMMethodCheckTest.m */, + 8B6F4B610E8856CA00425D9F /* GTMDebugThreadValidation.h */, + 8B6F4B620E8856CA00425D9F /* GTMDebugThreadValidation.m */, + 8BE839A80E8AF72500C611B0 /* GTMDebugThreadValidationTest.m */, ); path = DebugUtils; sourceTree = "<group>"; @@ -927,6 +957,7 @@ 8B1B49180E5F8E2100A08972 /* GTMExceptionalInlines.h in Headers */, 7F3EB38E0E5E09C700A7A75E /* GTMNSImage+Scaling.h in Headers */, 8B3590160E8190FA0041E21C /* GTMTestTimer.h in Headers */, + 8B6F4B630E8856CA00425D9F /* GTMDebugThreadValidation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1099,6 +1130,8 @@ 8BEEA90D0DA7446300894774 /* GTMUnitTestingImage.tiff in Resources */, 8BEEA90E0DA7446300894774 /* GTMUnitTestingWindow.tiff in Resources */, 8BEEA90F0DA7446300894774 /* GTMUnitTestingView.tiff in Resources */, + 84B91B8B0EA3CC2E0087500F /* GTMUnitTestingImage.10.6.0.tiff in Resources */, + 84B91B8C0EA3CC2E0087500F /* GTMUnitTestingWindow.10.6.0.tiff in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1129,7 +1162,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8B7AD49A0DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.10.5.tiff in Resources */, + 8B7AD49A0DABBB5800B84F4A /* GTMNSBezierPath+ShadingTest.tiff in Resources */, 8B7AD49B0DABBB5800B84F4A /* GTMNSBezierPath+CGPathTest.tiff in Resources */, 8B7AD49C0DABBB5800B84F4A /* GTMNSBezierPath+RoundRectTest.tiff in Resources */, 8BE869730DBE89C100749827 /* GTMNSBezierPath+RoundRectTest.x86_64.tiff in Resources */, @@ -1216,6 +1249,7 @@ 8B7DCBC40DFF0F800017E983 /* GTMMethodCheck.m in Sources */, 8B7DCEF10E002C210017E983 /* GTMDevLogUnitTestingBridge.m in Sources */, 8B4D7A150E40D79200EFEDD8 /* GTMObjC2Runtime.m in Sources */, + 84978FBC0EA6A67C00C5DC83 /* GTMSystemVersion.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1259,6 +1293,7 @@ F95803FB0E2FB0A80049A088 /* GTMLoggerRingBufferWriterTest.m in Sources */, F427EFC40E4023DD00ADD2AA /* GTMProgressMonitorInputStreamTest.m in Sources */, 8B1B49260E5F97C800A08972 /* GTMExceptionalInlinesTest.m in Sources */, + 8BE839AA0E8AF72E00C611B0 /* GTMDebugThreadValidationTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1308,6 +1343,7 @@ 8B58E9950E547EB000A0E02E /* GTMGetURLHandler.m in Sources */, 8B1B49190E5F8E2100A08972 /* GTMExceptionalInlines.m in Sources */, 7F3EB38F0E5E09C700A7A75E /* GTMNSImage+Scaling.m in Sources */, + 8B6F4B640E8856CA00425D9F /* GTMDebugThreadValidation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1405,6 +1441,297 @@ }; name = "TigerOrLater-Release"; }; + 842575E60E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 848269C80E9FF4BD006E6D9C /* DebugSnowLeopardOrLater.xcconfig */; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = GTM_Prefix.pch; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575E70E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4CA864C0DB3ACD200B4AB10 /* LoadableBundleGCSupported.xcconfig */; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "GTM-Info.plist"; + INSTALL_PATH = "@loader_path/../Frameworks"; + PRODUCT_NAME = GoogleToolboxForMac; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575E80E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575E90E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - AppKit"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575EA0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + GTM_NO_DEBUG_FRAMEWORKS = YES; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - Foundation"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575EB0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - UnitTesting"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GTMUIUnitTestingHarness.app/Contents/MacOS/GTMUIUnitTestingHarness"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575EC0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = UnitTesting/GTMUIUnitTestingHarness/Info.plist; + PRODUCT_NAME = GTMUIUnitTestingHarness; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575ED0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "Build GTM All SDKs"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575EE0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests All SDKs"; + }; + name = "SnowLeopardOrLater-Debug"; + }; + 842575EF0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 848269C80E9FF4BD006E6D9C /* DebugSnowLeopardOrLater.xcconfig */; + buildSettings = { + GCC_GENERATE_TEST_COVERAGE_FILES = YES; + GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = GTM_Prefix.pch; + OTHER_LDFLAGS = "-lgcov"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575F00E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 848269C90E9FF4BD006E6D9C /* ReleaseSnowLeopardOrLater.xcconfig */; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = GTM_Prefix.pch; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575F10E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4CA864C0DB3ACD200B4AB10 /* LoadableBundleGCSupported.xcconfig */; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "GTM-Info.plist"; + INSTALL_PATH = "@loader_path/../Frameworks"; + PRODUCT_NAME = GoogleToolboxForMac; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575F20E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4CA864C0DB3ACD200B4AB10 /* LoadableBundleGCSupported.xcconfig */; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "GTM-Info.plist"; + INSTALL_PATH = "@loader_path/../Frameworks"; + PRODUCT_NAME = GoogleToolboxForMac; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575F30E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575F40E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests"; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575F50E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - AppKit"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575F60E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2450D197F9A009257D2 /* ReleaseUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - AppKit"; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575F70E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + GTM_NO_DEBUG_FRAMEWORKS = YES; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - Foundation"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575F80E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2450D197F9A009257D2 /* ReleaseUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + GTM_NO_DEBUG_FRAMEWORKS = YES; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - Foundation"; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575F90E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - UnitTesting"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GTMUIUnitTestingHarness.app/Contents/MacOS/GTMUIUnitTestingHarness"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575FA0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F48FE2450D197F9A009257D2 /* ReleaseUnittest.xcconfig */; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(value)", + "$(DEVELOPER_FRAMEWORKS_DIR_QUOTED)", + ); + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = "UnitTest-Info.plist"; + PRODUCT_NAME = "UnitTest - UnitTesting"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GTMUIUnitTestingHarness.app/Contents/MacOS/GTMUIUnitTestingHarness"; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575FB0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = UnitTesting/GTMUIUnitTestingHarness/Info.plist; + PRODUCT_NAME = GTMUIUnitTestingHarness; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575FC0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_ENABLE_OBJC_GC = supported; + INFOPLIST_FILE = UnitTesting/GTMUIUnitTestingHarness/Info.plist; + PRODUCT_NAME = GTMUIUnitTestingHarness; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575FD0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "Build GTM All SDKs"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842575FE0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "Build GTM All SDKs"; + }; + name = "SnowLeopardOrLater-Release"; + }; + 842575FF0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests All SDKs"; + }; + name = "SnowLeopardOrLater-Debug-gcov"; + }; + 842576000E9FCFB8003E4511 /* SnowLeopardOrLater-Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "All UnitTests All SDKs"; + }; + name = "SnowLeopardOrLater-Release"; + }; 8B45A02A0DA4696D001148C5 /* TigerOrLater-Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = F48FE2420D197F9A009257D2 /* DebugUnittest.xcconfig */; @@ -1716,6 +2043,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = F4CA864A0DB3ACB200B4AB10 /* DebugLeopardOrLater.xcconfig */; buildSettings = { + "ARCHS[sdk=macosx10.5*]" = ( + i386, + x86_64, + ppc, + ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; }; @@ -1798,6 +2130,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = F4CA864A0DB3ACB200B4AB10 /* DebugLeopardOrLater.xcconfig */; buildSettings = { + "ARCHS[sdk=macosx10.5*]" = ( + i386, + x86_64, + ppc, + ); GCC_GENERATE_TEST_COVERAGE_FILES = YES; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -1883,6 +2220,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = F4CA864B0DB3ACB200B4AB10 /* ReleaseLeopardOrLater.xcconfig */; buildSettings = { + "ARCHS[sdk=macosx10.5*]" = ( + i386, + x86_64, + ppc, + ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; }; @@ -1973,6 +2315,9 @@ F4CA864F0DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865A0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86610DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575E60E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575EF0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575F00E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -1986,6 +2331,9 @@ F4CA86540DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865F0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86660DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575EB0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575F90E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575FA0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -1999,6 +2347,9 @@ F4CA86550DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA86600DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86670DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575EC0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575FB0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575FC0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2012,6 +2363,9 @@ F41A6EE40E02DB4F00788A6C /* LeopardOrLater-Debug */, F41A6EE50E02DB4F00788A6C /* LeopardOrLater-Debug-gcov */, F41A6EE60E02DB4F00788A6C /* LeopardOrLater-Release */, + 842575ED0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575FD0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575FE0E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2025,6 +2379,9 @@ F41A6EFC0E02DCFC00788A6C /* LeopardOrLater-Debug */, F41A6EFD0E02DCFC00788A6C /* LeopardOrLater-Debug-gcov */, F41A6EFE0E02DCFC00788A6C /* LeopardOrLater-Release */, + 842575EE0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575FF0E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842576000E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2038,6 +2395,9 @@ F4CA86530DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865E0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86650DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575EA0E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575F70E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575F80E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2051,6 +2411,9 @@ F4CA86500DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865B0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86620DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575E70E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575F10E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575F20E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2064,6 +2427,9 @@ F4CA86510DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865C0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86630DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575E80E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575F30E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575F40E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; @@ -2077,6 +2443,9 @@ F4CA86520DB3ACE500B4AB10 /* LeopardOrLater-Debug */, F4CA865D0DB3AD0300B4AB10 /* LeopardOrLater-Debug-gcov */, F4CA86640DB3AD0D00B4AB10 /* LeopardOrLater-Release */, + 842575E90E9FCFA5003E4511 /* SnowLeopardOrLater-Debug */, + 842575F50E9FCFB8003E4511 /* SnowLeopardOrLater-Debug-gcov */, + 842575F60E9FCFB8003E4511 /* SnowLeopardOrLater-Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "TigerOrLater-Release"; diff --git a/GTMDefines.h b/GTMDefines.h index 0cf7e95..1d1c908 100644 --- a/GTMDefines.h +++ b/GTMDefines.h @@ -18,6 +18,13 @@ // ============================================================================ +#include <AvailabilityMacros.h> + +#ifndef MAC_OS_X_VERSION_10_6 +// MAC_OS_X_VERSION_10_6 not defined in some earlier SDKs +#define MAC_OS_X_VERSION_10_6 1060 +#endif + // ---------------------------------------------------------------------------- // CPP symbols that can be overridden in a prefix to control how the toolbox // is compiled. @@ -132,6 +139,11 @@ extern void _GTMUnitTestDevLog(NSString *format, ...); #if TARGET_OS_IPHONE // iPhone SDK // For iPhone specific stuff #define GTM_IPHONE_SDK 1 + #if TARGET_IPHONE_SIMULATOR + #define GTM_IPHONE_SIMULATOR 1 + #else + #define GTM_IPHONE_DEVICE 1 + #endif // TARGET_IPHONE_SIMULATOR #else // For MacOS specific stuff #define GTM_MACOS_SDK 1 @@ -171,3 +183,15 @@ extern void _GTMUnitTestDevLog(NSString *format, ...); #define CGFLOAT_DEFINED 1 #endif // CGFLOAT_DEFINED #endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 + + +// Give ourselves a consistent way to do inlines. Apple's macros even use +// a few different actual definitions, so we're based off of the foundation +// one. +#if !defined(GTM_INLINE) + #if defined (__GNUC__) && (__GNUC__ == 4) + #define GTM_INLINE static __inline__ __attribute__((always_inline)) + #else + #define GTM_INLINE static __inline__ + #endif +#endif diff --git a/GTMiPhone.xcodeproj/project.pbxproj b/GTMiPhone.xcodeproj/project.pbxproj index f470ec8..aa2bb78 100644 --- a/GTMiPhone.xcodeproj/project.pbxproj +++ b/GTMiPhone.xcodeproj/project.pbxproj @@ -71,6 +71,8 @@ 8BDA25120E759A6300C9769D /* GTMHTTPFetcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA91E0E033624007E31B5 /* GTMHTTPFetcherTest.m */; }; 8BDA25130E759A6400C9769D /* GTMHTTPServerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3AA9210E033624007E31B5 /* GTMHTTPServerTest.m */; }; 8BDA25140E759A6500C9769D /* GTMNSData+zlibTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC047800DAE928A00C2D1CA /* GTMNSData+zlibTest.m */; }; + 8BE839890E89C74B00C611B0 /* GTMDebugThreadValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE839870E89C74A00C611B0 /* GTMDebugThreadValidation.m */; }; + 8BE83A660E8B059A00C611B0 /* GTMDebugThreadValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE83A650E8B059A00C611B0 /* GTMDebugThreadValidationTest.m */; }; F418AF990E7558EC004FB565 /* GTMExceptionalInlines.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AF940E7558DC004FB565 /* GTMExceptionalInlines.m */; }; F418AF9A0E7558EC004FB565 /* GTMExceptionalInlinesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AF950E7558DC004FB565 /* GTMExceptionalInlinesTest.m */; }; F418AFA50E7559C7004FB565 /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F418AFA30E7559C7004FB565 /* GTMLogger.m */; }; @@ -182,6 +184,9 @@ 8BC04A740DAF145200C2D1CA /* GTMSystemVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMSystemVersion.m; sourceTree = "<group>"; }; 8BC04D470DB0088500C2D1CA /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 8BC04DE70DB023D400C2D1CA /* ReleaseNotes.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReleaseNotes.txt; sourceTree = "<group>"; }; + 8BE839870E89C74A00C611B0 /* GTMDebugThreadValidation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMDebugThreadValidation.m; sourceTree = "<group>"; }; + 8BE839880E89C74A00C611B0 /* GTMDebugThreadValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDebugThreadValidation.h; sourceTree = "<group>"; }; + 8BE83A650E8B059A00C611B0 /* GTMDebugThreadValidationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMDebugThreadValidationTest.m; sourceTree = "<group>"; }; F418AF6D0E755732004FB565 /* GTMiPhone-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GTMiPhone-Info.plist"; sourceTree = "<group>"; }; F418AF910E755893004FB565 /* xcconfigs-readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "xcconfigs-readme.txt"; sourceTree = "<group>"; }; F418AF930E7558DC004FB565 /* GTMExceptionalInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMExceptionalInlines.h; sourceTree = "<group>"; }; @@ -370,6 +375,9 @@ isa = PBXGroup; children = ( 8BC0479B0DAE928A00C2D1CA /* GTMDebugSelectorValidation.h */, + 8BE83A650E8B059A00C611B0 /* GTMDebugThreadValidationTest.m */, + 8BE839870E89C74A00C611B0 /* GTMDebugThreadValidation.m */, + 8BE839880E89C74A00C611B0 /* GTMDebugThreadValidation.h */, 8BC0479C0DAE928A00C2D1CA /* GTMMethodCheck.h */, 8BC0479D0DAE928A00C2D1CA /* GTMMethodCheck.m */, 8BC0479E0DAE928A00C2D1CA /* GTMMethodCheckTest.m */, @@ -523,7 +531,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/UnitTesting/RunIPhoneUnitTest.sh\""; + shellScript = "# Run the unit tests in this test bundle.\n\"${SRCROOT}/UnitTesting/RunIPhoneUnitTest.sh\"\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -586,6 +594,8 @@ 8BDA25120E759A6300C9769D /* GTMHTTPFetcherTest.m in Sources */, 8BDA25130E759A6400C9769D /* GTMHTTPServerTest.m in Sources */, 8BDA25140E759A6500C9769D /* GTMNSData+zlibTest.m in Sources */, + 8BE839890E89C74B00C611B0 /* GTMDebugThreadValidation.m in Sources */, + 8BE83A660E8B059A00C611B0 /* GTMDebugThreadValidationTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -605,6 +615,7 @@ buildSettings = { INFOPLIST_FILE = "GTMiPhone-Info.plist"; PRODUCT_NAME = GTMiPhoneTest; + SDKROOT = iphonesimulator2.0; }; name = Debug; }; @@ -613,6 +624,7 @@ buildSettings = { INFOPLIST_FILE = "GTMiPhone-Info.plist"; PRODUCT_NAME = GTMiPhoneTest; + SDKROOT = iphonesimulator2.0; }; name = Release; }; @@ -620,8 +632,8 @@ isa = XCBuildConfiguration; baseConfigurationReference = 8BC049850DAEC59100C2D1CA /* DebugiPhone20.xcconfig */; buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; - SDKROOT = iphonesimulator2.0; }; name = "Debug-gcov"; }; @@ -631,6 +643,7 @@ buildSettings = { INFOPLIST_FILE = "GTMiPhone-Info.plist"; PRODUCT_NAME = GTMiPhoneTest; + SDKROOT = iphonesimulator2.0; }; name = "Debug-gcov"; }; @@ -638,8 +651,8 @@ isa = XCBuildConfiguration; baseConfigurationReference = 8BC049850DAEC59100C2D1CA /* DebugiPhone20.xcconfig */; buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; - SDKROOT = iphonesimulator2.0; }; name = Debug; }; @@ -647,8 +660,8 @@ isa = XCBuildConfiguration; baseConfigurationReference = 8BC049890DAEC59100C2D1CA /* ReleaseiPhone20.xcconfig */; buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; - SDKROOT = iphonesimulator2.0; }; name = Release; }; diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 220e105..1ffac73 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -101,9 +101,6 @@ Changes since 1.5.1 - Added GTMTestTimer.h for doing high fidelity timings. -- Added leaks checking to iPhone unit test script. It can be controlled by - the GTM_DISABLE_LEAKS environment variable - - Added ability to control using zombies to iPhone unit test script. It can be controlled by the GTM_DISABLE_ZOMBIES environment variable @@ -114,6 +111,49 @@ Changes since 1.5.1 - Updated the iPhone xcconfigs to support the different OS versions. +- 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. Release 1.5.1 Changes since 1.5.0 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 diff --git a/XcodeConfig/Project/DebugLeopardOrLater.xcconfig b/XcodeConfig/Project/DebugLeopardOrLater.xcconfig index 5bbd4a2..b00a6cc 100644 --- a/XcodeConfig/Project/DebugLeopardOrLater.xcconfig +++ b/XcodeConfig/Project/DebugLeopardOrLater.xcconfig @@ -33,3 +33,5 @@ // Debug settings #include "../subconfig/Debug.xcconfig" +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/DebugSnowLeopardOrLater.xcconfig b/XcodeConfig/Project/DebugSnowLeopardOrLater.xcconfig new file mode 100644 index 0000000..a090412 --- /dev/null +++ b/XcodeConfig/Project/DebugSnowLeopardOrLater.xcconfig @@ -0,0 +1,37 @@ +// +// DebugSnowLeopardOrLater.xcconfig +// +// Xcode configuration file for building a Debug configuration of a project +// on SnowLeopard or later. +// +// This is a _Configuration_ Xcode config file for use in the "Based on" popup +// of the project configuration editor. Do _not_ use this as the config base +// and individual Xcode target, there are other configuration files for that +// purpose. +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Pull in the general settings +#include "../subconfig/General.xcconfig" + +// SnowLeopard or later +#include "../subconfig/SnowLeopardOrLater.xcconfig" + +// Debug settings +#include "../subconfig/Debug.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/DebugTigerOrLater.xcconfig b/XcodeConfig/Project/DebugTigerOrLater.xcconfig index b8893ce..34b7b1c 100644 --- a/XcodeConfig/Project/DebugTigerOrLater.xcconfig +++ b/XcodeConfig/Project/DebugTigerOrLater.xcconfig @@ -33,3 +33,5 @@ // Debug settings #include "../subconfig/Debug.xcconfig" +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/DebugiPhone20.xcconfig b/XcodeConfig/Project/DebugiPhone20.xcconfig index 1f08ee4..7424704 100644 --- a/XcodeConfig/Project/DebugiPhone20.xcconfig +++ b/XcodeConfig/Project/DebugiPhone20.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Debug.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/DebugiPhone21.xcconfig b/XcodeConfig/Project/DebugiPhone21.xcconfig index b718cfa..18c923a 100644 --- a/XcodeConfig/Project/DebugiPhone21.xcconfig +++ b/XcodeConfig/Project/DebugiPhone21.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Debug.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/ReleaseLeopardOrLater.xcconfig b/XcodeConfig/Project/ReleaseLeopardOrLater.xcconfig index f62b287..31ac835 100644 --- a/XcodeConfig/Project/ReleaseLeopardOrLater.xcconfig +++ b/XcodeConfig/Project/ReleaseLeopardOrLater.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Release.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/ReleaseSnowLeopardOrLater.xcconfig b/XcodeConfig/Project/ReleaseSnowLeopardOrLater.xcconfig new file mode 100644 index 0000000..0d24069 --- /dev/null +++ b/XcodeConfig/Project/ReleaseSnowLeopardOrLater.xcconfig @@ -0,0 +1,37 @@ +// +// ReleaseSnowLeopardOrLater.xcconfig +// +// Xcode configuration file for building a Release configuration of a project +// on SnowLeopard or later. +// +// This is a _Configuration_ Xcode config file for use in the "Based on" popup +// of the project configuration editor. Do _not_ use this as the config base +// and individual Xcode target, there are other configuration files for that +// purpose. +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Pull in the general settings +#include "../subconfig/General.xcconfig" + +// SnowLeopard or later +#include "../subconfig/SnowLeopardOrLater.xcconfig" + +// Release settings +#include "../subconfig/Release.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/ReleaseTigerOrLater.xcconfig b/XcodeConfig/Project/ReleaseTigerOrLater.xcconfig index d604d88..9301912 100644 --- a/XcodeConfig/Project/ReleaseTigerOrLater.xcconfig +++ b/XcodeConfig/Project/ReleaseTigerOrLater.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Release.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/ReleaseiPhone20.xcconfig b/XcodeConfig/Project/ReleaseiPhone20.xcconfig index 16895c5..8d31ead 100644 --- a/XcodeConfig/Project/ReleaseiPhone20.xcconfig +++ b/XcodeConfig/Project/ReleaseiPhone20.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Release.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/Project/ReleaseiPhone21.xcconfig b/XcodeConfig/Project/ReleaseiPhone21.xcconfig index 4ea90d6..8a9a0c3 100644 --- a/XcodeConfig/Project/ReleaseiPhone21.xcconfig +++ b/XcodeConfig/Project/ReleaseiPhone21.xcconfig @@ -32,3 +32,6 @@ // Release settings #include "../subconfig/Release.xcconfig" + +// Merge settings +#include "../subconfig/GTMMerge.xcconfig" diff --git a/XcodeConfig/subconfig/Debug.xcconfig b/XcodeConfig/subconfig/Debug.xcconfig index a6290c3..d8fbd1c 100644 --- a/XcodeConfig/subconfig/Debug.xcconfig +++ b/XcodeConfig/subconfig/Debug.xcconfig @@ -30,8 +30,14 @@ DEAD_CODE_STRIPPING = NO // Debug symbols should be on obviously GCC_GENERATE_DEBUGGING_SYMBOLS = YES -// Define the DEBUG macro in all debug builds -OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1 +// Turn off warnings about uninitialized autos +// can only be done when GCC_OPTIMIZATION_LEVEL is actually optimizing +GCC_WARN_UNINITIALIZED_AUTOS = NO // Turns on special C++ STL checks to "encourage" good STL use -GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS +GTM_CONFIGURATION_GCC_PREPROCESSOR_DEFINITIONS = _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS DEBUG=1 + +// Turns on stack protection on debug builds for Leopard and above +GTM_CONFIGURATION_OTHER_CFLAGS = -fstack-protector -fstack-protector-all +// Stack protection doesn't exist on Tiger +GTM_CONFIGURATION_OTHER_CFLAGS[sdk=macosx10.4*] = diff --git a/XcodeConfig/subconfig/GTMMerge.xcconfig b/XcodeConfig/subconfig/GTMMerge.xcconfig new file mode 100644 index 0000000..33d3e70 --- /dev/null +++ b/XcodeConfig/subconfig/GTMMerge.xcconfig @@ -0,0 +1,35 @@ +// +// GTMMerge.xcconfig +// +// Xcode configuration file that merges other xcconfig settings. +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Xcode doesn't allow you to "inherit" settings with includes so you always +// end up overriding settings accidentally. To avoid this, we instead +// allow you to define settings at different levels +// (GENERAL, PLATFORM (iPhone/Mac), CONFIGURATION (Release/Debug) and we merge +// those together here. +// We DO NOT inherit OTHER_CPLUSPLUSFLAGS because OTHER_CPLUSPLUSFLAGS by default +// takes on OTHER_CFLAGS settings, and we don't want those applied to our +// C++ files. OTHER_CFLAGS is the only way to set C specific settings on our +// C files that we don't want to have applied to our C++ files such as +// -Wold-style-definition +WARNING_CFLAGS = $(inherited) $(GTM_GENERAL_WARNING_CFLAGS) $(GTM_PLATFORM_WARNING_CFLAGS) $(GTM_CONFIGURATION_WARNING_CFLAGS) +OTHER_CFLAGS = $(inherited) $(GTM_GENERAL_OTHER_CFLAGS) $(GTM_PLATFORM_OTHER_CFLAGS) $(GTM_CONFIGURATION_OTHER_CFLAGS) +OTHER_CPLUSPLUSFLAGS = $(GTM_GENERAL_OTHER_CPLUSPLUSFLAGS) $(GTM_PLATFORM_OTHER_CPLUSPLUSFLAGS) $(GTM_CONFIGURATION_OTHER_CPLUSPLUSFLAGS) +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(GTM_GENERAL_GCC_PREPROCESSOR_DEFINITIONS) $(GTM_PLATFORM_GCC_PREPROCESSOR_DEFINITIONS) $(GTM_CONFIGURATION_GCC_PREPROCESSOR_DEFINITIONS) +OTHER_LDFLAGS = $(inherited) $(GTM_GENERAL_OTHER_LDFLAGS) $(GTM_PLATFORM_OTHER_LDFLAGS) $(GTM_CONFIGURATION_OTHER_LDFLAGS) diff --git a/XcodeConfig/subconfig/General.xcconfig b/XcodeConfig/subconfig/General.xcconfig index 114b718..89304b9 100644 --- a/XcodeConfig/subconfig/General.xcconfig +++ b/XcodeConfig/subconfig/General.xcconfig @@ -27,10 +27,18 @@ // for Mac OS developement, the values are: // SDK_NAME macosx10.4 // SDK_NAME macosx10.5 +// SDK_NAME macosx10.6 -// Build for PPC and Intel (Leopard gets 64bit also) +// Build for PPC and Intel (Leopard/SnowLeopard gets 64 bit also) +// Note that you can't build 10.5 with using SenTestingKit on ppc64 with +// SnowLeopard XCode because it doesn't ship with a ppc64 version of +// SenTestingKit. For this reason we are NOT building/testing GTM +// with ppc64 at this time. We override the 10.5 setting in the project +// file to turn it off. ARCHS[sdk=macosx10.4*] = i386 ppc ARCHS[sdk=macosx10.5*] = i386 x86_64 ppc ppc64 +ARCHS[sdk=macosx10.6*] = i386 x86_64 ppc + // Build for arm for iPhone or Intel for the iPhone Simulator ARCHS[sdk=iphoneos*] = armv6 ARCHS[sdk=iphonesimulator*] = i386 @@ -44,9 +52,6 @@ ZERO_LINK = NO // Prebinding considered unhelpful in 10.3 and later PREBINDING = NO -// Strictest warning policy -WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof - // Work around Xcode bugs by using external strip. See: // http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html SEPARATE_STRIP = YES @@ -63,8 +68,94 @@ ALWAYS_SEARCH_USER_PATHS = NO // Turn on position dependent code for most cases (overridden where appropriate) GCC_DYNAMIC_NO_PIC = YES +// For ObjC++ we want C++ cdtors called +GCC_OBJC_CALL_CXX_CDTORS = YES + +// Use Obj-C fast dispatch +GCC_FAST_OBJC_DISPATCH = YES + // Warn on implicit data conversions in 64bit builds GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64*] = YES -// Use Obj-C fast dispatch (configs don't support 10.2 where you don't want it) -GCC_FAST_OBJC_DISPATCH = YES +// Strictest warning policy that we can do +// Options intentionally turned off +// http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html +// -Wsystem-headers - since we can't fix them we are going to assume they're ok +// -Wtraditional - we are compiling with c99, so we don't care about trad +// -Wdeclaration-after-statement - we are compiling with c99 which allows this +// -Wpadded - lots of structures will get padded, so although this warning may +// be useful to show us badly padded structures, it causes to many +// warnings to be on generally. +// -Wunreachable-code - several macros use the do {} while (0) which always +// flags this. e.g. all the ST... macros for unittesting +// -Wredundant-decls - we sometimes use redundant decls to add an attribute +// to a function/method (i.e. +// -Waggregate-return - NSPoint, NSRect etc are often returned as aggregates +// -Wshorten-64-to-32 - this is defined in the 64 bit build settings +// -Wcast-qual - Would love to turn this on, but causes issues when converting +// CFTypes to NSTypes and also has issues with some external +// libraries (notably zlib) +// -Wundef - we conditionalize on TARGET_OS_IPHONE which is only defined +// in the iPhoneSDK making us unable to turn this warning on. +// -Wstrict-prototypes - breaks the GTM_METHOD_CHECK macro +// -Wcast-align - causes a whole pile of problems buildng with iPhoneSDK + +// Objective C warnings +// http://gcc.gnu.org/onlinedocs/gcc/Objective_002dC-and-Objective_002dC_002b_002b-Dialect-Options.html +// -Wassign-intercept - this really is more informational than a warning. +// -Wselector - the system headers define lots of methods with the same selector +// rendering this mostly useless to us +// -Wstrict-selector-match - the system headers define lots of methods with the +// same selector rendering this mostly useless to us +// Not being used currently because of Radar 5978978 +// GTM_GENERAL_WARNING_OBJC_ONLY_FLAGS=-Wundeclared-selector + +// C Only Warnings +GTM_GENERAL_OTHER_CFLAGS = -Wdiv-by-zero -Wbad-function-cast -Wnested-externs -Wold-style-definition + +// C++ Only Warnings +GTM_GENERAL_OTHER_CPLUSPLUSFLAGS = -Wabi -Wctor-dtor-privacy -Wstrict-null-sentinel -Wsign-promo +GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = YES +GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES +GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES +GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES + +// General C/C++/ObjC/ObjC++ warnings +// These are generally ordered in easiest to hardest to support. +// If you are transitioning, you can turn on the levels one level at a time +// in your project file by editing GTM_GENERAL_WARNING_CFLAGS and only +// including the warning levels that you currently are compiling against. +// GTM should always compile with full warnings. +GTM_GENERAL_WARNING_CFLAGS1 = -Wall -Wendif-labels -Winvalid-pch -Wformat=2 -Wmissing-format-attribute -Wwrite-strings -Wstack-protector -Wstrict-aliasing=2 +GTM_GENERAL_WARNING_CFLAGS2 = -Wpacked -Wmissing-field-initializers +GTM_GENERAL_WARNING_CFLAGS3 = -Wextra -Wno-unused-parameter -Wpointer-arith -Wdisabled-optimization -Wfloat-equal +GTM_GENERAL_WARNING_CFLAGS = $(GTM_GENERAL_WARNING_CFLAGS1) $(GTM_GENERAL_WARNING_CFLAGS2) $(GTM_GENERAL_WARNING_CFLAGS3) + +// GCC_WARN_UNINITIALIZED_AUTOS is defined in the release/debug xcconfigs. +GCC_WARN_CHECK_SWITCH_STATEMENTS = YES +GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES +GCC_WARN_ABOUT_MISSING_NEWLINE = YES +GCC_TREAT_WARNINGS_AS_ERRORS = YES +GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES +GCC_WARN_ABOUT_RETURN_TYPE = YES +GCC_WARN_MISSING_PARENTHESES = YES +GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES +GCC_WARN_SIGN_COMPARE = YES +GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES +GCC_WARN_UNKNOWN_PRAGMAS = YES +GCC_WARN_UNUSED_LABEL = YES +GCC_WARN_UNUSED_FUNCTION = YES +GCC_WARN_UNUSED_VALUE = YES +GCC_WARN_UNUSED_VARIABLE = YES +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES +GCC_WARN_SHADOW = YES + +GCC_WARN_PEDANTIC = NO +GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO +GCC_WARN_PROTOTYPE_CONVERSION = NO +GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO +GCC_TREAT_NONCONFORMANT_CODE_ERRORS_AS_WARNINGS = NO +GCC_WARN_UNUSED_PARAMETER = NO +// Use of Gestalt requires 4 char constants (amongst other things) +GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO + diff --git a/XcodeConfig/subconfig/LeopardOrLater.xcconfig b/XcodeConfig/subconfig/LeopardOrLater.xcconfig index fa4dfce..c0f75bc 100644 --- a/XcodeConfig/subconfig/LeopardOrLater.xcconfig +++ b/XcodeConfig/subconfig/LeopardOrLater.xcconfig @@ -1,8 +1,8 @@ // // LeopardOrLater.xcconfig // -// Xcode configuration file for projects targeting 10.4 Tiger or later. These -// settings produce a Universal binary compatible with 10.4 for PPC and Intel. +// Xcode configuration file for projects targeting 10.5 Leopard or later. These +// settings produce a Universal binary compatible with 10.5 for PPC and Intel. // // Copyright 2006-2008 Google Inc. // diff --git a/XcodeConfig/subconfig/Release.xcconfig b/XcodeConfig/subconfig/Release.xcconfig index 74df258..4c5ad8a 100644 --- a/XcodeConfig/subconfig/Release.xcconfig +++ b/XcodeConfig/subconfig/Release.xcconfig @@ -30,9 +30,16 @@ GCC_GENERATE_DEBUGGING_SYMBOLS = NO // Dead code strip does not affect ObjC code but can help for C DEAD_CODE_STRIPPING = YES -// NDEBUG is used by things like assert.h, so define it for general compat. // ASSERT going away in release tends to create unused vars. -OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable +// init-self can only be turned on when optimizations are on +GTM_CONFIGURATION_WARNING_CFLAGS = -Wno-unused-variable -Winit-self -Wno-extra + +// NDEBUG is used by things like assert.h, so define it for general compat. +GTM_CONFIGURATION_GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1 + +// Give us warnings about uninitialized autos +// can only be done when GCC_OPTIMIZATION_LEVEL is actually optimizing +GCC_WARN_UNINITIALIZED_AUTOS = YES // When we strip we want to strip all symbols in release, but save externals. STRIP_STYLE = all diff --git a/XcodeConfig/subconfig/SnowLeopardOrLater.xcconfig b/XcodeConfig/subconfig/SnowLeopardOrLater.xcconfig new file mode 100644 index 0000000..0a7475e --- /dev/null +++ b/XcodeConfig/subconfig/SnowLeopardOrLater.xcconfig @@ -0,0 +1,26 @@ +// +// SnowLeopardOrLater.xcconfig +// +// Xcode configuration file for projects targeting 10.6 SnowLeopard or later. +// These settings produce a Universal binary compatible with 10.6 for +// PPC and Intel. +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Default SDK and minimum OS version is 10.6 +SDKROOT = ${DEVELOPER_SDK_DIR}/MacOSX10.6.sdk +MACOSX_DEPLOYMENT_TARGET = 10.6 +GCC_VERSION = 4.0 diff --git a/XcodeConfig/subconfig/iPhone20.xcconfig b/XcodeConfig/subconfig/iPhone20.xcconfig index fea781b..2509ba8 100644 --- a/XcodeConfig/subconfig/iPhone20.xcconfig +++ b/XcodeConfig/subconfig/iPhone20.xcconfig @@ -17,9 +17,6 @@ // License for the specific language governing permissions and limitations under // the License. -// Code signing. Should be overridden if releasing -CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer - // Default SDK and minimum OS version is the iphone SDK. SDKROOT = iphoneos2.0 MACOSX_DEPLOYMENT_TARGET = 10.5 diff --git a/XcodeConfig/subconfig/iPhone21.xcconfig b/XcodeConfig/subconfig/iPhone21.xcconfig index 6265000..e543ce5 100644 --- a/XcodeConfig/subconfig/iPhone21.xcconfig +++ b/XcodeConfig/subconfig/iPhone21.xcconfig @@ -17,9 +17,6 @@ // License for the specific language governing permissions and limitations under // the License. -// Code signing. Should be overridden if releasing -CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer - // Default SDK and minimum OS version is the iphone SDK. SDKROOT = iphoneos2.1 MACOSX_DEPLOYMENT_TARGET = 10.5 diff --git a/XcodeConfig/xcconfigs-readme.txt b/XcodeConfig/xcconfigs-readme.txt index 5a44bb0..87a6dd7 100644 --- a/XcodeConfig/xcconfigs-readme.txt +++ b/XcodeConfig/xcconfigs-readme.txt @@ -1,4 +1,4 @@ -Xcode Config is sorta a black art, any time you have a set of rules, you +Xcode Configs are sort of a black art, any time you have a set of rules, you quickly hit a few exceptions. The main goal of using these is as follow: @@ -6,7 +6,7 @@ The main goal of using these is as follow: Edit your Project level build settings by removing as much as possible, and then set the per Configuration settings to one of the project xcode config files w/in the Project subfolder here. This will batch setup the project to -build Debug/Release w/ a specific SDK. +build Debug/Release with a specific SDK. If you are building a Shared Library, Loadable Bundle (Framework) or UnitTest you will need to apply a further Xcode Config file at the target level. You do @@ -30,3 +30,24 @@ support to make mixing SDKs easier. Remember: When using the configs at any given layer, make sure you set them for each build configuration you need (not just the active one). + +Many of the build settings are more than just yes/no flags and take +a list of values that you may want to change at different levels. +Xcode doesn't allow you to "inherit" settings with includes so you always +end up overriding settings accidentally. To avoid this, we instead +allow you to define settings at different levels +(GENERAL, PLATFORM (iPhone/Mac), CONFIGURATION (Release/Debug). +We do this by setting a GTM version of the setting (so for OTHER_CFLAGS it's +GTM_XXX_OTHER_CFLAGS where xxx is GENERAL, PLATFORM or CONFIGURATION depending +at what level the flag is set. These are all merged together in the +GTMMerge.xcconfig. Do not modify the base setting (OTHER_CFLAGS) instead modify +the GTM one at the level you want it modified. + +The major place this may affect you is that we have really tightened down on +the warnings. To make it easier for you to move your code onto the new +xcconfig files, we have split the warnings up into three categories, which in +general you can think of as easy, moderate and extreme. If you run into a lot +of warnings when you compile, look at changing the GTM_GENERAL_WARNING_CFLAGS +setting to only include lower levels (eg GTM_GENERAL_WARNING_CFLAGS1) and see +if that makes it easier on you. Look inside General.xcconfig and search for +GTM_GENERAL_WARNING_CFLAGS1 for more info. diff --git a/iPhone/GTMABAddressBook.h b/iPhone/GTMABAddressBook.h index 48e7f88..1a73545 100644 --- a/iPhone/GTMABAddressBook.h +++ b/iPhone/GTMABAddressBook.h @@ -26,6 +26,8 @@ // (GTMABAddressBook.strings). // // If things seem strange, it may be due to one of the following radars: +// 6240394 AddressBook framework constants not initialized until +// ABCreateAddressBook called // 6208390 Integer and real values don't work in ABMultiValueRefs // (and this isn't part of the title, but dictionaries don't work // either) diff --git a/iPhone/GTMABAddressBookTest.m b/iPhone/GTMABAddressBookTest.m index 56106a9..29f46a6 100644 --- a/iPhone/GTMABAddressBookTest.m +++ b/iPhone/GTMABAddressBookTest.m @@ -491,7 +491,7 @@ STAssertNotNULL(ref, nil); NSString *label = [[NSString alloc] initWithString:@"label"]; STAssertNotNil(label, nil); - id val; + id val = nil; switch (type) { case kABDictionaryPropertyType: val = [[NSDictionary alloc] initWithObjectsAndKeys:@"1", @"1", nil]; @@ -562,4 +562,24 @@ CFRelease(ref); } } + +// Globals used by testRadar6240394. +static ABPropertyID gGTMTestID; +static const ABPropertyID *gGTMTestIDPtr; + +void __attribute__((constructor))SetUpIDForTestRadar6240394(void) { + // These must be set up BEFORE ABAddressBookCreate is called. + gGTMTestID = kABPersonLastNameProperty; + gGTMTestIDPtr = &kABPersonLastNameProperty; +} + +- (void)testRadar6240394 { + // As of iPhone SDK 2.1, the property IDs aren't initialized until + // ABAddressBookCreate is actually called. They will return zero until + // then. Logged as radar 6240394. + STAssertEquals(gGTMTestID, 0, @"If this isn't zero, Apple has fixed 6240394"); + (void)ABAddressBookCreate(); + STAssertEquals(*gGTMTestIDPtr, kABPersonLastNameProperty, + @"If this doesn't work, something else has broken"); +} @end |