From 8ddb49cefd01b220ad5e1d2f0060b2a0ad54efdb Mon Sep 17 00:00:00 2001 From: "thomasvl@gmail.com" Date: Tue, 4 Nov 2008 20:10:52 +0000 Subject: - Added has ability to check if a script has an open handler to GTMNSAppleScript+Handler. - GTMStackTrace support for building a trace from the call stack in an NSException (for 10.5+ and iPhone). - Added GTMUIFont+LineHeight. - Cleaned up some OS version checks to use constants instead of numbers directly. --- Foundation/GTMGarbageCollection.h | 2 +- Foundation/GTMLogger.h | 2 +- Foundation/GTMLoggerTest.m | 4 +- Foundation/GTMNSAppleEvent+HandlerTest.applescript | 6 +- Foundation/GTMNSAppleScript+Handler.h | 4 + Foundation/GTMNSAppleScript+Handler.m | 15 ++ Foundation/GTMNSAppleScript+HandlerTest.m | 10 +- Foundation/GTMNSFileManager+Path.h | 4 +- Foundation/GTMNSFileManager+Path.m | 4 +- Foundation/GTMNSFileManager+PathTest.m | 6 +- Foundation/GTMNSString+Replace.h | 4 +- Foundation/GTMNSString+Replace.m | 4 +- Foundation/GTMNSString+ReplaceTest.m | 4 +- Foundation/GTMObjC2Runtime.h | 2 +- Foundation/GTMObjC2Runtime.m | 2 +- Foundation/GTMObjC2RuntimeTest.m | 2 +- Foundation/GTMPathTest.m | 2 +- Foundation/GTMStackTrace.h | 15 ++ Foundation/GTMStackTrace.m | 178 ++++++++++++++------- Foundation/GTMStackTraceTest.m | 41 +++++ GTM.xcodeproj/project.pbxproj | 18 +++ GTMDefines.h | 7 +- GTMiPhone.xcodeproj/project.pbxproj | 32 +++- ReleaseNotes.txt | 7 + XcodeConfig/subconfig/General.xcconfig | 11 +- iPhone/GTMUIFont+LineHeight.h | 24 +++ iPhone/GTMUIFont+LineHeight.m | 25 +++ iPhone/GTMUIFont+LineHeightTest.m | 40 +++++ 28 files changed, 384 insertions(+), 91 deletions(-) create mode 100644 iPhone/GTMUIFont+LineHeight.h create mode 100644 iPhone/GTMUIFont+LineHeight.m create mode 100644 iPhone/GTMUIFont+LineHeightTest.m diff --git a/Foundation/GTMGarbageCollection.h b/Foundation/GTMGarbageCollection.h index b29a13b..58c8140 100644 --- a/Foundation/GTMGarbageCollection.h +++ b/Foundation/GTMGarbageCollection.h @@ -28,7 +28,7 @@ // http://developer.apple.com/documentation/Cocoa/Conceptual/GarbageCollection/Articles/gcCoreFoundation.html#//apple_ref/doc/uid/TP40006687-SW1 // for details. -#if (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) && !GTM_IPHONE_SDK +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) && !GTM_IPHONE_SDK // General use would be to call this through GTMCFAutorelease // 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 diff --git a/Foundation/GTMLogger.h b/Foundation/GTMLogger.h index 8fdb0fa..1626b1b 100644 --- a/Foundation/GTMLogger.h +++ b/Foundation/GTMLogger.h @@ -54,7 +54,7 @@ // Predeclaration of used protocols that are declared later in this file. @protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 #define CHECK_FORMAT_NSSTRING(a, b) __attribute__((format(__NSString__, a, b))) #else #define CHECK_FORMAT_NSSTRING(a, b) diff --git a/Foundation/GTMLoggerTest.m b/Foundation/GTMLoggerTest.m index 043c73d..86ced5e 100644 --- a/Foundation/GTMLoggerTest.m +++ b/Foundation/GTMLoggerTest.m @@ -94,7 +94,7 @@ @"GTMLoggerUnitTest.log"] retain]; STAssertNotNil(path_, nil); // Make sure we're cleaned up from the last run -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 [[NSFileManager defaultManager] removeFileAtPath:path_ handler:nil]; #else [[NSFileManager defaultManager] removeItemAtPath:path_ error:NULL]; @@ -103,7 +103,7 @@ - (void)tearDown { STAssertNotNil(path_, nil); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 [[NSFileManager defaultManager] removeFileAtPath:path_ handler:nil]; #else [[NSFileManager defaultManager] removeItemAtPath:path_ error:NULL]; diff --git a/Foundation/GTMNSAppleEvent+HandlerTest.applescript b/Foundation/GTMNSAppleEvent+HandlerTest.applescript index a0822f9..377d733 100644 --- a/Foundation/GTMNSAppleEvent+HandlerTest.applescript +++ b/Foundation/GTMNSAppleEvent+HandlerTest.applescript @@ -27,6 +27,8 @@ script testScript on testScriptFunc() return "child" end testScriptFunc + on open foo + end open end script property foo : 1 @@ -54,5 +56,5 @@ on testGetScript() return testScript end testGetScript -on open -end open +on print +end print diff --git a/Foundation/GTMNSAppleScript+Handler.h b/Foundation/GTMNSAppleScript+Handler.h index e63eaee..6e3af50 100644 --- a/Foundation/GTMNSAppleScript+Handler.h +++ b/Foundation/GTMNSAppleScript+Handler.h @@ -119,4 +119,8 @@ enum { - (BOOL)gtm_setValue:(id)value forPropertyEnum:(DescType)property addingDefinition:(BOOL)adding; + +// Return YES if the script has an open documents (odoc) handler +// Does not require script compilation, so it's a fast check. +- (BOOL)gtm_hasOpenDocumentsHandler; @end diff --git a/Foundation/GTMNSAppleScript+Handler.m b/Foundation/GTMNSAppleScript+Handler.m index 592aca6..be4a2dc 100644 --- a/Foundation/GTMNSAppleScript+Handler.m +++ b/Foundation/GTMNSAppleScript+Handler.m @@ -232,6 +232,21 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); return desc; } +- (BOOL)gtm_hasOpenDocumentsHandler { + ComponentInstance component; + OSAID osaID = [self gtm_realIDAndComponent:&component]; + long value = 0; + OSAError error = OSAGetScriptInfo(component, + osaID, + kASHasOpenHandler, + &value); + if (error) { + _GTMDevLog(@"Unable to get script info about open handler %d", error); + value = 0; + } + return value != 0; +} + - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *signature = [super methodSignatureForSelector:aSelector]; if (!signature) { diff --git a/Foundation/GTMNSAppleScript+HandlerTest.m b/Foundation/GTMNSAppleScript+HandlerTest.m index 102332e..02f62e0 100644 --- a/Foundation/GTMNSAppleScript+HandlerTest.m +++ b/Foundation/GTMNSAppleScript+HandlerTest.m @@ -278,7 +278,7 @@ - (void)testHandlers { NSSet *handlers = [script_ gtm_handlers]; NSSet *expected = [NSSet setWithObjects: - @"aevtodoc", + @"aevtpdoc", @"test", @"testreturnone", @"testreturnparam", @@ -475,6 +475,14 @@ STAssertNotNil(handlers, @"Couldn't get handlers"); } +- (void)testOpenHandler { + STAssertFalse([script_ gtm_hasOpenDocumentsHandler], nil); + id script = [script_ gtm_valueForProperty:@"testscript"]; + STAssertNotNil(script, nil); + STAssertTrue([script gtm_hasOpenDocumentsHandler], nil); +} + + @protocol ScriptInterface - (id)test; - (id)testReturnParam:(id)param; diff --git a/Foundation/GTMNSFileManager+Path.h b/Foundation/GTMNSFileManager+Path.h index 2ed6888..f377215 100644 --- a/Foundation/GTMNSFileManager+Path.h +++ b/Foundation/GTMNSFileManager+Path.h @@ -22,7 +22,7 @@ /// A few useful methods for dealing with paths. @interface NSFileManager (GMFileManagerPathAdditions) -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 /// For the Unix-y at heart, this is "mkdir -p". It tries to create /// the directory specified by |path|, and any intervening directories that @@ -47,7 +47,7 @@ - (BOOL)gtm_createFullPathToDirectory:(NSString *)path attributes:(NSDictionary *)attributes; -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 /// Return an the paths for all resources in |directoryPath| that have the /// |extension| file extension. diff --git a/Foundation/GTMNSFileManager+Path.m b/Foundation/GTMNSFileManager+Path.m index 6dec24b..2d71729 100644 --- a/Foundation/GTMNSFileManager+Path.m +++ b/Foundation/GTMNSFileManager+Path.m @@ -20,7 +20,7 @@ @implementation NSFileManager (GMFileManagerPathAdditions) -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - (BOOL)gtm_createFullPathToDirectory:(NSString *)path attributes:(NSDictionary *)attributes { @@ -52,7 +52,7 @@ return YES; } -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - (NSArray *)gtm_filePathsWithExtension:(NSString *)extension inDirectory:(NSString *)directoryPath { diff --git a/Foundation/GTMNSFileManager+PathTest.m b/Foundation/GTMNSFileManager+PathTest.m index ac36cac..db40c68 100644 --- a/Foundation/GTMNSFileManager+PathTest.m +++ b/Foundation/GTMNSFileManager+PathTest.m @@ -48,7 +48,7 @@ if (baseDir_) { // clean up our directory NSFileManager *fm = [NSFileManager defaultManager]; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 NSError *error = nil; [fm removeItemAtPath:baseDir_ error:&error]; STAssertNil(error, @@ -62,7 +62,7 @@ } } -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - (void)testCreateFullPathToDirectoryAttributes { STAssertNotNil(baseDir_, @"setUp failed"); @@ -91,7 +91,7 @@ @"Should have failed when passed (nil)"); } -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - (void)testfilePathsWithExtensionsInDirectory { STAssertNotNil(baseDir_, @"setUp failed"); diff --git a/Foundation/GTMNSString+Replace.h b/Foundation/GTMNSString+Replace.h index edc8478..71a98c5 100644 --- a/Foundation/GTMNSString+Replace.h +++ b/Foundation/GTMNSString+Replace.h @@ -21,7 +21,7 @@ /// Give easy search-n-replace functionality to NSString. @interface NSString (GTMStringReplaceAdditions) -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 // 10.5 has stringByReplacingOccurrencesOfString:withString:, use that directly. /// Returns a new autoreleased string by replacing all occurrences of @@ -40,6 +40,6 @@ - (NSString *)gtm_stringByReplacingString:(NSString *)target withString:(NSString *)replacement; -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 @end diff --git a/Foundation/GTMNSString+Replace.m b/Foundation/GTMNSString+Replace.m index f617945..ddaad5e 100644 --- a/Foundation/GTMNSString+Replace.m +++ b/Foundation/GTMNSString+Replace.m @@ -21,7 +21,7 @@ @implementation NSString (GTMStringReplaceAdditions) -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 // 10.5 has stringByReplacingOccurrencesOfString:withString:, use that directly. - (NSString *)gtm_stringByReplacingString:(NSString *)target @@ -48,6 +48,6 @@ return result; } -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 @end diff --git a/Foundation/GTMNSString+ReplaceTest.m b/Foundation/GTMNSString+ReplaceTest.m index 805136c..4561af6 100644 --- a/Foundation/GTMNSString+ReplaceTest.m +++ b/Foundation/GTMNSString+ReplaceTest.m @@ -24,7 +24,7 @@ @implementation GTMNSString_ReplaceTest -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - (void)testStringByReplacingStringWithString { NSString *testString = @"a bc debc gh"; @@ -54,6 +54,6 @@ @"replacing '' with anything should yield the original string"); } -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 @end diff --git a/Foundation/GTMObjC2Runtime.h b/Foundation/GTMObjC2Runtime.h index f94e680..f901d1e 100644 --- a/Foundation/GTMObjC2Runtime.h +++ b/Foundation/GTMObjC2Runtime.h @@ -47,7 +47,7 @@ #import #endif -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 #import "objc/Protocol.h" #ifdef __cplusplus diff --git a/Foundation/GTMObjC2Runtime.m b/Foundation/GTMObjC2Runtime.m index ba0cb74..9835654 100644 --- a/Foundation/GTMObjC2Runtime.m +++ b/Foundation/GTMObjC2Runtime.m @@ -18,7 +18,7 @@ #import "GTMObjC2Runtime.h" -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 #import #import diff --git a/Foundation/GTMObjC2RuntimeTest.m b/Foundation/GTMObjC2RuntimeTest.m index 1bc0ee3..d0ce4f7 100644 --- a/Foundation/GTMObjC2RuntimeTest.m +++ b/Foundation/GTMObjC2RuntimeTest.m @@ -299,7 +299,7 @@ AT_REQUIRED // 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 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 // Built for less then leopard gives us the behaviors we defined... // (doesn't take nil) IMP nullImp = method_setImplementation(list[0], nil); diff --git a/Foundation/GTMPathTest.m b/Foundation/GTMPathTest.m index 3a60ea7..211206c 100644 --- a/Foundation/GTMPathTest.m +++ b/Foundation/GTMPathTest.m @@ -46,7 +46,7 @@ // Make sure it's safe to remove this directory before nuking it. STAssertNotNil(testDirectory_, nil); STAssertNotEqualObjects(testDirectory_, @"/", nil); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 [[NSFileManager defaultManager] removeFileAtPath:testDirectory_ handler:nil]; #else [[NSFileManager defaultManager] removeItemAtPath:testDirectory_ error:NULL]; diff --git a/Foundation/GTMStackTrace.h b/Foundation/GTMStackTrace.h index 3b6965d..9726da5 100644 --- a/Foundation/GTMStackTrace.h +++ b/Foundation/GTMStackTrace.h @@ -51,7 +51,17 @@ struct GTMAddressDescriptor { // #6 0x000025b9 tart () [/Users/me/./StackLog] // +#ifdef GTM_MACOS_SDK // currently not supported on iPhone NSString *GTMStackTrace(void); +#endif + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 +// Returns a string containing a nicely formatted stack trace from the +// exception. Only available on 10.5 or later, uses +// -[NSException callStackReturnAddresses]. +// +NSString *GTMStackTraceFromException(NSException *e); +#endif // Returns an array of program counters from the current thread's stack. // *** You should probably use GTMStackTrace() instead of this function *** @@ -67,7 +77,9 @@ NSString *GTMStackTrace(void); // Returns: // The number of program counters actually added to outPcs. // +#ifdef GTM_MACOS_SDK // currently not supported on iPhone NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count); +#endif // Returns an array of GTMAddressDescriptors from the current thread's stack. // *** You should probably use GTMStackTrace() instead of this function *** @@ -85,8 +97,11 @@ NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count); // Returns: // The number of program counters actually added to outPcs. // +#ifdef GTM_MACOS_SDK // currently not supported on iPhone NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], NSUInteger count); +#endif + #ifdef __cplusplus } #endif diff --git a/Foundation/GTMStackTrace.m b/Foundation/GTMStackTrace.m index 8a14bcf..c22c153 100644 --- a/Foundation/GTMStackTrace.m +++ b/Foundation/GTMStackTrace.m @@ -87,49 +87,11 @@ static void GTMFreeClassDescriptions(struct GTMClassDescription *class_descs, free(class_descs); } -#pragma mark Public functions - -// __builtin_frame_address(0) is a gcc builtin that returns a pointer to the -// current frame pointer. We then use the frame pointer to walk the stack -// picking off program counters and other saved frame pointers. This works -// great on i386, but PPC requires a little more work because the PC (or link -// register) isn't always stored on the stack. -// -NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count) { - if (!outPcs || (count < 1)) return 0; - - struct GTMStackFrame *fp; -#if defined (__ppc__) || defined(__ppc64__) - outPcs[0] = __builtin_return_address(0); - fp = (struct GTMStackFrame *)__builtin_frame_address(1); -#elif defined (__i386__) || defined(__x86_64__) - fp = (struct GTMStackFrame *)__builtin_frame_address(0); -#else -#error architecture not supported -#endif - - NSUInteger level = 0; - while (level < count) { - if (fp == NULL) { - level--; - break; - } - outPcs[level] = fp->saved_pc; - level++; - fp = (struct GTMStackFrame *)fp->saved_fp; - } - - return level; -} - -NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], - NSUInteger count) { - if (count < 1 || !outDescs) return 0; +static NSUInteger GTMGetStackAddressDescriptorsForAddresses(void *pcs[], + struct GTMAddressDescriptor outDescs[], + NSUInteger count) { + if (count < 1 || !pcs || !outDescs) return 0; - void **pcs = calloc(count, sizeof(void*)); - if (!pcs) return 0; - - NSUInteger newSize = GTMGetStackProgramCounters(pcs, count); NSUInteger class_desc_count; // Get our obj-c class descriptions. This is expensive, so we do it once @@ -139,7 +101,7 @@ NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], = GTMClassDescriptions(&class_desc_count); // Iterate through the stack. - for (NSUInteger i = 0; i < newSize; ++i) { + for (NSUInteger i = 0; i < count; ++i) { const char *class_name = NULL; Boolean is_class_method = FALSE; size_t smallest_diff = SIZE_MAX; @@ -194,8 +156,84 @@ NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], currDesc->filename = info.dli_fname; } GTMFreeClassDescriptions(class_descs, class_desc_count); + return count; +} + +static NSString *GTMStackTraceFromAddressDescriptors(struct GTMAddressDescriptor descs[], + NSUInteger count) { + NSMutableString *trace = [NSMutableString string]; + + for (NSUInteger i = 0; i < count; i++) { + // Newline between all the lines + if (i) { + [trace appendString:@"\n"]; + } + if (descs[i].class_name) { + [trace appendFormat:@"#%-2u %#08lx %s[%s %s] (%s)", + i, descs[i].address, + (descs[i].is_class_method ? "+" : "-"), + descs[i].class_name, + (descs[i].symbol ? descs[i].symbol : "??"), + (descs[i].filename ? descs[i].filename : "??")]; + } else { + [trace appendFormat:@"#%-2u %#08lx %s() (%s)", + i, descs[i].address, + (descs[i].symbol ? descs[i].symbol : "??"), + (descs[i].filename ? descs[i].filename : "??")]; + } + } + return trace; +} + +#pragma mark Public functions + +// __builtin_frame_address(0) is a gcc builtin that returns a pointer to the +// current frame pointer. We then use the frame pointer to walk the stack +// picking off program counters and other saved frame pointers. This works +// great on i386, but PPC requires a little more work because the PC (or link +// register) isn't always stored on the stack. +// +#ifdef GTM_MACOS_SDK // currently not supported on iPhone +NSUInteger GTMGetStackProgramCounters(void *outPcs[], NSUInteger count) { + if (!outPcs || (count < 1)) return 0; + + struct GTMStackFrame *fp; +#if defined (__ppc__) || defined(__ppc64__) + outPcs[0] = __builtin_return_address(0); + fp = (struct GTMStackFrame *)__builtin_frame_address(1); +#elif defined (__i386__) || defined(__x86_64__) + fp = (struct GTMStackFrame *)__builtin_frame_address(0); +#else +#error architecture not supported +#endif + + NSUInteger level = 0; + while (level < count) { + if (fp == NULL) { + level--; + break; + } + outPcs[level] = fp->saved_pc; + level++; + fp = (struct GTMStackFrame *)fp->saved_fp; + } + + return level; +} + +NSUInteger GTMGetStackAddressDescriptors(struct GTMAddressDescriptor outDescs[], + NSUInteger count) { + if (count < 1 || !outDescs) return 0; + + void **pcs = calloc(count, sizeof(void*)); + if (!pcs) return 0; + + NSUInteger newSize = GTMGetStackProgramCounters(pcs, count); + + NSUInteger result + = GTMGetStackAddressDescriptorsForAddresses(pcs, outDescs, newSize); free(pcs); - return newSize; + return result; } NSString *GTMStackTrace(void) { @@ -206,25 +244,47 @@ NSString *GTMStackTrace(void) { 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 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, - (descs[i].is_class_method ? "+" : "-"), - descs[i].class_name, - (descs[i].symbol ? descs[i].symbol : "??"), - (descs[i].filename ? descs[i].filename : "??")]; - } else { - [trace appendFormat:@"#%-2d 0x%08lx %s() (%s)\n", - i - kTracesToStrip, descs[i].address, - (descs[i].symbol ? descs[i].symbol : "??"), - (descs[i].filename ? descs[i].filename : "??")]; + if (depth > kTracesToStrip) { + return GTMStackTraceFromAddressDescriptors(&descs[kTracesToStrip], + (depth - kTracesToStrip)); + } + // If we didn't have enough frames, return an empty string + return @""; +} +#endif // GTM_MACOS_SDK + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + +NSString *GTMStackTraceFromException(NSException *e) { + NSString *trace = @""; + + // collect the addresses + NSArray *addresses = [e callStackReturnAddresses]; + NSUInteger count = [addresses count]; + if (count) { + void **pcs = calloc(count, sizeof(void*)); + struct GTMAddressDescriptor *descs + = calloc(count, sizeof(struct GTMAddressDescriptor)); + if (pcs && descs) { + void **pcsScanner = pcs; + for (NSNumber *address in addresses) { + NSUInteger addr = [address unsignedIntegerValue]; + *pcsScanner = (void *)addr; + ++pcsScanner; + } + // Fill in the desc structures + count = GTMGetStackAddressDescriptorsForAddresses(pcs, descs, count); + // Build the trace + trace = GTMStackTraceFromAddressDescriptors(descs, count); } + if (pcs) free(pcs); + if (descs) free(descs); } + return trace; } + +#endif // MAC_OS_X_VERSION_MIN_REQUIRED diff --git a/Foundation/GTMStackTraceTest.m b/Foundation/GTMStackTraceTest.m index dc5ea57..01b02a3 100644 --- a/Foundation/GTMStackTraceTest.m +++ b/Foundation/GTMStackTraceTest.m @@ -25,6 +25,7 @@ @implementation GTMStackTraceTest +#ifdef GTM_MACOS_SDK // currently not supported on iPhone - (void)testStackTraceBasic { NSString *stacktrace = GTMStackTrace(); NSArray *stacklines = [stacktrace componentsSeparatedByString:@"\n"]; @@ -44,7 +45,46 @@ @"First frame should contain #0, stack trace: %@", stacktrace); } +#endif // GTM_MACOS_SDK +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + +- (void)helperThatThrows { + [NSException raise:@"TestException" format:@"TestExceptionDescription"]; +} + +- (void)testStackExceptionTrace { + NSException *exception = nil; + @try { + [self helperThatThrows]; + } + @catch (NSException * e) { + exception = e; + } + STAssertNotNil(exception, nil); + NSString *stacktrace = GTMStackTraceFromException(exception); + NSArray *stacklines = [stacktrace componentsSeparatedByString:@"\n"]; + + STAssertGreaterThan([stacklines count], (NSUInteger)4, + @"stack trace must have > 4 lines"); + STAssertLessThan([stacklines count], (NSUInteger)25, + @"stack trace must have < 25 lines"); + STAssertEquals([stacklines count], + [[exception callStackReturnAddresses] count], + @"stack trace should have the same number of lines as the " + @" array of return addresses. stack trace: %@", stacktrace); + + // we can't look for it on a specific frame because NSException doesn't + // really document how deep the stack will be + NSRange range = [stacktrace rangeOfString:@"testStackExceptionTrace"]; + STAssertNotEquals(range.location, (NSUInteger)NSNotFound, + @"Stack trace should contain testStackExceptionTrace," + " stack trace: %@", stacktrace); +} + +#endif + +#ifdef GTM_MACOS_SDK // currently not supported on iPhone - (void)testProgramCountersBasic { void *pcs[10]; NSUInteger depth = 10; @@ -80,5 +120,6 @@ void *current_pc = __builtin_return_address(0); STAssertEquals(pcs2[1], current_pc, @"pcs[1] should equal the current PC"); } +#endif // GTM_MACOS_SDK @end diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj index 017d952..6d7c854 100644 --- a/GTM.xcodeproj/project.pbxproj +++ b/GTM.xcodeproj/project.pbxproj @@ -1429,6 +1429,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "TigerOrLater-Debug"; }; @@ -1438,6 +1440,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "TigerOrLater-Release"; }; @@ -1447,6 +1451,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "SnowLeopardOrLater-Debug"; }; @@ -1545,6 +1551,8 @@ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; OTHER_LDFLAGS = "-lgcov"; }; name = "SnowLeopardOrLater-Debug-gcov"; @@ -1555,6 +1563,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "SnowLeopardOrLater-Release"; }; @@ -1958,6 +1968,8 @@ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/TigerGcov\"", @@ -2050,6 +2062,8 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "LeopardOrLater-Debug"; }; @@ -2139,6 +2153,8 @@ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; OTHER_LDFLAGS = "-lgcov"; }; name = "LeopardOrLater-Debug-gcov"; @@ -2227,6 +2243,8 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "LeopardOrLater-Release"; }; diff --git a/GTMDefines.h b/GTMDefines.h index 1d1c908..bd37b3e 100644 --- a/GTMDefines.h +++ b/GTMDefines.h @@ -20,9 +20,12 @@ #include +// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs +#ifndef MAC_OS_X_VERSION_10_5 +# define MAC_OS_X_VERSION_10_5 1050 +#endif #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 +# define MAC_OS_X_VERSION_10_6 1060 #endif // ---------------------------------------------------------------------------- diff --git a/GTMiPhone.xcodeproj/project.pbxproj b/GTMiPhone.xcodeproj/project.pbxproj index aa2bb78..1d573cd 100644 --- a/GTMiPhone.xcodeproj/project.pbxproj +++ b/GTMiPhone.xcodeproj/project.pbxproj @@ -89,6 +89,10 @@ F439ADEC0DBD3C0000BE9B91 /* GTMBase64Test.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEA0DBD3C0000BE9B91 /* GTMBase64Test.m */; }; F439ADF00DBD3C4000BE9B91 /* GTMGeometryUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEE0DBD3C4000BE9B91 /* GTMGeometryUtils.m */; }; F439ADF10DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F439ADEF0DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m */; }; + F4E3B3D80EB5EF2400CB713D /* GTMUIFont+LineHeight.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E3B3D70EB5EF2400CB713D /* GTMUIFont+LineHeight.m */; }; + F4E3B3E20EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E3B3E10EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m */; }; + F4EF8AD70EBFF814008DD6DA /* GTMStackTrace.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EF8AD50EBFF814008DD6DA /* GTMStackTrace.m */; }; + F4EF8AD80EBFF814008DD6DA /* GTMStackTraceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F4EF8AD60EBFF814008DD6DA /* GTMStackTraceTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -213,6 +217,12 @@ F439ADED0DBD3C4000BE9B91 /* GTMGeometryUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMGeometryUtils.h; sourceTree = ""; }; F439ADEE0DBD3C4000BE9B91 /* GTMGeometryUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMGeometryUtils.m; sourceTree = ""; }; F439ADEF0DBD3C4000BE9B91 /* GTMGeometryUtilsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMGeometryUtilsTest.m; sourceTree = ""; }; + F4E3B3D60EB5EF2400CB713D /* GTMUIFont+LineHeight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMUIFont+LineHeight.h"; sourceTree = ""; }; + F4E3B3D70EB5EF2400CB713D /* GTMUIFont+LineHeight.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMUIFont+LineHeight.m"; sourceTree = ""; }; + F4E3B3E10EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMUIFont+LineHeightTest.m"; sourceTree = ""; }; + F4EF8AD40EBFF814008DD6DA /* GTMStackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMStackTrace.h; sourceTree = ""; }; + F4EF8AD50EBFF814008DD6DA /* GTMStackTrace.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMStackTrace.m; sourceTree = ""; }; + F4EF8AD60EBFF814008DD6DA /* GTMStackTraceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMStackTraceTest.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -287,6 +297,9 @@ 8BA5F4070E75669000798036 /* GTMABAddressBook.h */, 8BA5F4080E75669000798036 /* GTMABAddressBook.m */, 8BA5F52B0E7567AB00798036 /* GTMABAddressBookTest.m */, + F4E3B3D60EB5EF2400CB713D /* GTMUIFont+LineHeight.h */, + F4E3B3D70EB5EF2400CB713D /* GTMUIFont+LineHeight.m */, + F4E3B3E10EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m */, 8BA5F4090E75669000798036 /* TestData */, ); path = iPhone; @@ -303,9 +316,6 @@ 8BC047760DAE928A00C2D1CA /* Foundation */ = { isa = PBXGroup; children = ( - F418AFD40E755D44004FB565 /* GTMPath.h */, - F418AFD50E755D44004FB565 /* GTMPath.m */, - F418AFD60E755D44004FB565 /* GTMPathTest.m */, F439ADE80DBD3C0000BE9B91 /* GTMBase64.h */, F439ADE90DBD3C0000BE9B91 /* GTMBase64.m */, F439ADEA0DBD3C0000BE9B91 /* GTMBase64Test.m */, @@ -354,12 +364,18 @@ 8BC0478C0DAE928A00C2D1CA /* GTMNSString+XMLTest.m */, 8BC0478D0DAE928A00C2D1CA /* GTMObjC2Runtime.h */, 8BC047900DAE928A00C2D1CA /* GTMObjectSingleton.h */, + F418AFD40E755D44004FB565 /* GTMPath.h */, + F418AFD50E755D44004FB565 /* GTMPath.m */, + F418AFD60E755D44004FB565 /* GTMPathTest.m */, F418AFE80E755F21004FB565 /* GTMProgressMonitorInputStream.h */, F418AFE90E755F21004FB565 /* GTMProgressMonitorInputStream.m */, F418AFEA0E755F21004FB565 /* GTMProgressMonitorInputStreamTest.m */, 8BC047910DAE928A00C2D1CA /* GTMRegex.h */, 8BC047920DAE928A00C2D1CA /* GTMRegex.m */, 8BC047930DAE928A00C2D1CA /* GTMRegexTest.m */, + F4EF8AD40EBFF814008DD6DA /* GTMStackTrace.h */, + F4EF8AD50EBFF814008DD6DA /* GTMStackTrace.m */, + F4EF8AD60EBFF814008DD6DA /* GTMStackTraceTest.m */, 8BC04A740DAF145200C2D1CA /* GTMSystemVersion.m */, 8BC04A6F0DAF144200C2D1CA /* GTMSystemVersion.h */, 8BC04A710DAF144700C2D1CA /* GTMSystemVersionTest.m */, @@ -596,6 +612,10 @@ 8BDA25140E759A6500C9769D /* GTMNSData+zlibTest.m in Sources */, 8BE839890E89C74B00C611B0 /* GTMDebugThreadValidation.m in Sources */, 8BE83A660E8B059A00C611B0 /* GTMDebugThreadValidationTest.m in Sources */, + F4E3B3D80EB5EF2400CB713D /* GTMUIFont+LineHeight.m in Sources */, + F4E3B3E20EB5EF9A00CB713D /* GTMUIFont+LineHeightTest.m in Sources */, + F4EF8AD70EBFF814008DD6DA /* GTMStackTrace.m in Sources */, + F4EF8AD80EBFF814008DD6DA /* GTMStackTraceTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -634,6 +654,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = "Debug-gcov"; }; @@ -653,6 +675,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = Debug; }; @@ -662,6 +686,8 @@ buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = GTM_Prefix.pch; + GCC_WARN_SHADOW = YES; + GTM_EXTRA_WARNING_OVERRIDE_CFLAGS = "-Wno-unused-parameter"; }; name = Release; }; diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 1ffac73..1fdd464 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -155,6 +155,13 @@ Changes since 1.5.1 make sure to turn off zombies by defining the GTM_DISABLE_ZOMBIES variable, otherwise every memory allocation you do will look like a leak. +- Added has ability to check if a script has an open handler to + GTMNSAppleScript+Handler. + +- GTMStackTrace support for building a trace from the call stack in an + NSException (for 10.5+ and iPhone). + + Release 1.5.1 Changes since 1.5.0 16-June-2008 diff --git a/XcodeConfig/subconfig/General.xcconfig b/XcodeConfig/subconfig/General.xcconfig index 89304b9..2aea15f 100644 --- a/XcodeConfig/subconfig/General.xcconfig +++ b/XcodeConfig/subconfig/General.xcconfig @@ -128,7 +128,8 @@ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES // 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_EXTRA_WARNING_OVERRIDE_CFLAGS = -Wno-unused-parameter -Wno-sign-compare +GTM_GENERAL_WARNING_CFLAGS3 = -Wextra $(GTM_EXTRA_WARNING_OVERRIDE_CFLAGS) -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. @@ -140,7 +141,6 @@ 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 @@ -148,7 +148,12 @@ 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 +// We don't turn on shadow and sign comparisons because too many 3rd party +// libaries don't compile with them turned on (sign compare rarely catches +// errors, but shadow is very useful). +// NOTE: sign compare is also controlled by -Wextra, we we override it above. +// GCC_WARN_SHADOW = YES +// GCC_WARN_SIGN_COMPARE = YES GCC_WARN_PEDANTIC = NO GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO diff --git a/iPhone/GTMUIFont+LineHeight.h b/iPhone/GTMUIFont+LineHeight.h new file mode 100644 index 0000000..cb2d206 --- /dev/null +++ b/iPhone/GTMUIFont+LineHeight.h @@ -0,0 +1,24 @@ +// +// GTMUIFont+LineHeight.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. +// + +#import +#import + +@interface UIFont (GTMLineHeight) +- (CGFloat)gtm_lineHeight; +@end diff --git a/iPhone/GTMUIFont+LineHeight.m b/iPhone/GTMUIFont+LineHeight.m new file mode 100644 index 0000000..74f8a8f --- /dev/null +++ b/iPhone/GTMUIFont+LineHeight.m @@ -0,0 +1,25 @@ +// +// GTMUIFont+LineHeight.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 "GTMUIFont+LineHeight.h" + +@implementation UIFont (GTMLineHeight) +- (CGFloat)gtm_lineHeight { + return [@"Fake line with gjy" sizeWithFont:self].height; +} +@end diff --git a/iPhone/GTMUIFont+LineHeightTest.m b/iPhone/GTMUIFont+LineHeightTest.m new file mode 100644 index 0000000..8da28eb --- /dev/null +++ b/iPhone/GTMUIFont+LineHeightTest.m @@ -0,0 +1,40 @@ +// +// GTMUIFont+LineHeightTest.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 "GTMUIFont+LineHeight.h" + +@interface GTMUIFontLineHeightTest : GTMTestCase +@end + + +@implementation GTMUIFontLineHeightTest + +- (void)testLineHeight { + UIFont *font = [UIFont systemFontOfSize:[UIFont systemFontSize]]; + STAssertNotNil(font, nil); + STAssertGreaterThanOrEqual([font gtm_lineHeight], (CGFloat)5.0, nil); + + UIFont *fontSmall = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]]; + STAssertNotNil(fontSmall, nil); + STAssertGreaterThanOrEqual([fontSmall gtm_lineHeight], (CGFloat)5.0, nil); + + STAssertGreaterThan([font gtm_lineHeight], [fontSmall gtm_lineHeight], nil); +} + +@end -- cgit v1.2.3