From 91fdd6d09d6390b67ff3258b6418437dca11d6e1 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 29 Apr 2016 13:47:13 -0400 Subject: Add GTMSynchronizationAsserts.h/m and a unit test file. These macros allow code to assert being in or not in a @sync-protected section, which is important when calling across methods or calling out to other classes or callbacks. --- DebugUtils/GTMSynchronizationAsserts.h | 124 +++++++++++++ DebugUtils/GTMSynchronizationAsserts.m | 93 ++++++++++ DebugUtils/GTMSynchronizationAssertsTest.m | 288 +++++++++++++++++++++++++++++ 3 files changed, 505 insertions(+) create mode 100644 DebugUtils/GTMSynchronizationAsserts.h create mode 100644 DebugUtils/GTMSynchronizationAsserts.m create mode 100644 DebugUtils/GTMSynchronizationAssertsTest.m diff --git a/DebugUtils/GTMSynchronizationAsserts.h b/DebugUtils/GTMSynchronizationAsserts.h new file mode 100644 index 0000000..b026565 --- /dev/null +++ b/DebugUtils/GTMSynchronizationAsserts.h @@ -0,0 +1,124 @@ +// +// GTMSynchronizationAsserts.h +// +// Copyright 2016 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 !__has_feature(objc_arc) +#error "This file needs to be compiled with ARC enabled." +#endif + +#import + +#import "GTMDefines.h" // For _GTMDevAssert. + +// Macros to monitor synchronization blocks in debug builds. +// +// These report problems using _GTMDevAssert, which may be defined by the +// project or by GTMDefines.h +// +// GTMMonitorSynchronized Start monitoring a top-level-only @sync scope. +// Asserts if already inside a monitored @sync scope. +// GTMMonitorRecursiveSynchronized Start monitoring a top-level or recursive @sync +// scope. +// GTMCheckSynchronized Assert that the current execution is inside a monitored @sync +// scope. +// GTMCheckNotSynchronized Assert that the current execution is not inside a monitored +// @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMCheckNotSynchronized(self); +// +// GTMCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state, important when posting notifications and +// invoking callbacks. +// +// Don't use GTMCheckNotSynchronized immediately before a @sync scope; the +// normal recursiveness check of GTMMonitorSynchronized can catch those. + +#if DEBUG + + #define __GTMMonitorSynchronizedVariableInner(varname, counter) \ + varname ## counter + #define __GTMMonitorSynchronizedVariable(varname, counter) \ + __GTMMonitorSynchronizedVariableInner(varname, counter) + + #define GTMMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + + #define GTMMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id \ + __GTMMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + + #define GTMCheckSynchronized(obj) { \ + _GTMDevAssert( \ + [GTMSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + + #define GTMCheckNotSynchronized(obj) { \ + _GTMDevAssert( \ + ![GTMSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \ + [GTMSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes, relying on ARC to release +// it at the end of a scope. +// +// This class should not be used directly, but only via the +// GTMMonitorSynchronized macro. +@interface GTMSyncMonitorInternal : NSObject { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else + + // !DEBUG + #define GTMMonitorSynchronized(obj) do { } while (0) + #define GTMMonitorRecursiveSynchronized(obj) do { } while (0) + #define GTMCheckSynchronized(obj) do { } while (0) + #define GTMCheckNotSynchronized(obj) do { } while (0) + +#endif // DEBUG diff --git a/DebugUtils/GTMSynchronizationAsserts.m b/DebugUtils/GTMSynchronizationAsserts.m new file mode 100644 index 0000000..6c76550 --- /dev/null +++ b/DebugUtils/GTMSynchronizationAsserts.m @@ -0,0 +1,93 @@ +// +// GTMSyncAsserts.m +// +// Copyright 2016 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 "GTMSynchronizationAsserts.h" + +#if DEBUG + +@implementation GTMSyncMonitorInternal + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + // In the thread's dictionary, we keep a counted set of the names + // of functions that are synchronizing on the object. + Class threadKey = [GTMSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + _GTMDevAssert(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:@(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + _GTMDevAssert(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} + +@end + +#endif // DEBUG diff --git a/DebugUtils/GTMSynchronizationAssertsTest.m b/DebugUtils/GTMSynchronizationAssertsTest.m new file mode 100644 index 0000000..f08fc3e --- /dev/null +++ b/DebugUtils/GTMSynchronizationAssertsTest.m @@ -0,0 +1,288 @@ +/* Copyright (c) 2016 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 + +// For testing, force use of the default debug versions of the _GTMDevAssert macro. +#undef _GTMDevAssert +#undef NS_BLOCK_ASSERTIONS +#undef DEBUG +#define DEBUG 1 + +#import "GTMSynchronizationAsserts.h" + +@interface GTMSynchonizationAssertsTest : XCTestCase +@end + +@implementation GTMSynchonizationAssertsTest + +- (void)verifySynchronized { + // Test both GTMCheckSynchronized and GTMCheckNotSynchronized assuming we're in a sync block. + @try { + GTMCheckSynchronized(self); + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + @try { + GTMCheckNotSynchronized(self); + XCTFail(@"should have thrown"); + } @catch (NSException *exception) { + } +} + +- (void)verifyNotSynchronized { + // Test both GTMCheckSynchronized and GTMCheckNotSynchronized assuming we're not in a sync block. + @try { + GTMCheckNotSynchronized(self); + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + @try { + GTMCheckSynchronized(self); + XCTFail(@"shoul have thrown"); + } @catch (NSException *exception) { + } +} + +- (void)testChecks_SingleMethod { + [self verifyNotSynchronized]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self verifySynchronized]; + } + } + } + [self verifyNotSynchronized]; +} + +- (void)testChecks_AcrossMethods { + [self doIndirectCheckNotSynchronized]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + [self verifySynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self doIndirectCheckSynchronized]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [self doIndirectCheckSynchronized]; + } + } + } + [self doIndirectCheckNotSynchronized]; +} + +- (void)doIndirectCheckSynchronized { + // Verify from a separate method. + [self verifySynchronized]; +} + +- (void)doIndirectCheckNotSynchronized { + // Verify from a separate method. + [self verifyNotSynchronized]; +} + +#pragma mark Sync Monitor Tests + +- (void)testNonrecursiveSync { + // Non-recursive monitors. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveSync_SingleMethod { + // The inner monitors are recursive. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner1 = [self expectationWithDescription:@"inner1"]; + XCTestExpectation *inner2 = [self expectationWithDescription:@"inner2"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner2 fulfill]; + } + } + } + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveSync_AcrossMethods { + // The inner monitors are recursive. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *inner1 = [self expectationWithDescription:@"inner1"]; + XCTestExpectation *inner2 = [self expectationWithDescription:@"inner2"]; + + @try { + @synchronized(self) { + GTMMonitorSynchronized(self); + [outer fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [inner1 fulfill]; + + [self doInnerRecursiveSync]; + [inner2 fulfill]; + } + } + } @catch (NSException *exception) { + XCTFail(@"shouldn't have thrown"); + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)doInnerRecursiveSync { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + } +} + +- (void)testRecursiveThenNonrecursiveSync_SingleMethod { + // The outer monitors are recursive, but the inner one is not and should throw. + XCTestExpectation *outer1 = [self expectationWithDescription:@"outer1"]; + XCTestExpectation *outer2 = [self expectationWithDescription:@"outer2"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer2 fulfill]; + + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testRecursiveThenNonrecursiveSync_AcrossMethods { + // The outer monitors are recursive, but the inner one is not and should throw. + XCTestExpectation *outer1 = [self expectationWithDescription:@"outer1"]; + XCTestExpectation *outer2 = [self expectationWithDescription:@"outer2"]; + XCTestExpectation *inner = [self expectationWithDescription:@"inner"]; + + @try { + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer1 fulfill]; + + @synchronized(self) { + GTMMonitorRecursiveSynchronized(self); + [outer2 fulfill]; + + [self doInnerNonrecursiveSync]; + } + } + } @catch (NSException *exception) { + [inner fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)doInnerNonrecursiveSync { + @synchronized(self) { + GTMMonitorSynchronized(self); + XCTFail(@"should have thrown"); + } +} + +- (void)testSyncOnSeparateObjects { + // Verify that monitoring works for distinct sync objects. + XCTestExpectation *outer = [self expectationWithDescription:@"outer"]; + XCTestExpectation *innerA = [self expectationWithDescription:@"innerA"]; + XCTestExpectation *innerB = [self expectationWithDescription:@"innerB"]; + + id obj1 = [[NSObject alloc] init]; + id obj2 = [[NSObject alloc] init]; + + @try { + @synchronized(obj1) { + GTMMonitorSynchronized(obj1); + [outer fulfill]; + + @synchronized(obj2) { + GTMMonitorSynchronized(obj2); + [innerA fulfill]; + + @synchronized(obj1) { + GTMMonitorSynchronized(obj1); + XCTFail(@"should have thrown"); + } + } + } + } @catch (NSException *exception) { + [innerB fulfill]; + } + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +@end -- cgit v1.2.3 From 7331352a30da15c92f942d07ed1a1a7db8e61250 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 29 Apr 2016 13:51:31 -0400 Subject: Update GTMDebugThreadValidation with general queue support. --- AppKit/GTMGoogleSearch.m | 4 ++- DebugUtils/GTMDebugThreadValidation.h | 59 ++++++++++++++--------------------- DebugUtils/GTMDebugThreadValidation.m | 22 ++----------- Foundation/GTMNSAppleScript+Handler.m | 15 +++++---- 4 files changed, 36 insertions(+), 64 deletions(-) diff --git a/AppKit/GTMGoogleSearch.m b/AppKit/GTMGoogleSearch.m index 320c71d..9384ade 100644 --- a/AppKit/GTMGoogleSearch.m +++ b/AppKit/GTMGoogleSearch.m @@ -100,8 +100,10 @@ static LanguageDefaultInfo kLanguageListDefaultMappingTable[] = { }; // the notification we use for syncing up instances in different processes -static NSString *const kNotificationName +#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS +static NSString *const kNotificationName = @"com.google.GoogleSearchAllApps.prefsWritten"; +#endif // this is the bundle id we use for the pref file used for all apps static CFStringRef const kAllAppsBuildIdentifier diff --git a/DebugUtils/GTMDebugThreadValidation.h b/DebugUtils/GTMDebugThreadValidation.h index 0636159..3f50f17 100644 --- a/DebugUtils/GTMDebugThreadValidation.h +++ b/DebugUtils/GTMDebugThreadValidation.h @@ -1,7 +1,7 @@ // // GTMDebugThreadValidation.h // -// Copyright 2008 Google Inc. +// Copyright 2016 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 @@ -16,40 +16,29 @@ // the License. // -#if DEBUG #import "GTMDefines.h" #import -// 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 -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 +// GTMCheckCurrentQueue, GTMIsCurrentQueue +// +// GTMCheckCurrentQueue takes a target queue and uses _GTMDevAssert to +// report if that is not the currently executing queue. +// +// GTMIsCurrentQueue takes a target queue and returns true if the target queue +// is the currently executing dispatch queue. This can be passed to another +// assertion call in debug builds; it should never be used in release code. +// +// The dispatch queue must have a label. +#define GTMCheckCurrentQueue(targetQueue) \ + _GTMDevAssert(GTMIsCurrentQueue(targetQueue), \ + @"Current queue is %s (expected %s)", \ + _GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) + +#define GTMIsCurrentQueue(targetQueue) \ + (strcmp(_GTMQueueName(DISPATCH_CURRENT_QUEUE_LABEL), \ + _GTMQueueName(targetQueue)) == 0) + +#define _GTMQueueName(queue) \ + (strlen(dispatch_queue_get_label(queue)) > 0 ? \ + dispatch_queue_get_label(queue) : "unnamed") diff --git a/DebugUtils/GTMDebugThreadValidation.m b/DebugUtils/GTMDebugThreadValidation.m index 30ee757..f2af8a0 100644 --- a/DebugUtils/GTMDebugThreadValidation.m +++ b/DebugUtils/GTMDebugThreadValidation.m @@ -1,7 +1,7 @@ // // GTMDebugThreadValidation.m // -// Copyright 2008 Google Inc. +// Copyright 2016 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 @@ -16,22 +16,4 @@ // the License. // -#import "GTMDebugThreadValidation.h" - -#if DEBUG && MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 - -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 +// No implementation source currently needed. diff --git a/Foundation/GTMNSAppleScript+Handler.m b/Foundation/GTMNSAppleScript+Handler.m index e17ba91..850de58 100644 --- a/Foundation/GTMNSAppleScript+Handler.m +++ b/Foundation/GTMNSAppleScript+Handler.m @@ -22,7 +22,6 @@ #import "GTMNSAppleEventDescriptor+Handler.h" #import "GTMFourCharCode.h" #import "GTMMethodCheck.h" -#import "GTMDebugThreadValidation.h" // Keys for passing AppleScript calls from other threads to the main thread // and back through gtm_internalExecuteAppleEvent: @@ -326,7 +325,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSAppleEventDescriptor*)gtm_valueDescriptorForProperty:(id)property { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); OSAError error = paramErr; NSAppleEventDescriptor *desc = nil; NSAppleEventDescriptor *propertyName @@ -377,7 +376,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSSet*)gtm_scriptHandlers { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); AEDescList names = { typeNull, NULL }; NSArray *array = nil; ComponentInstance component = NULL; @@ -396,7 +395,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (NSSet*)gtm_scriptProperties { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); AEDescList names = { typeNull, NULL }; NSArray *array = nil; ComponentInstance component = NULL; @@ -415,7 +414,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (OSAID)gtm_genericID:(OSAID)osaID forComponent:(ComponentInstance)component { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); ComponentInstance genericComponent = [NSAppleScript _defaultScriptingComponent]; OSAID exactID = osaID; OSAError error = OSARealToGenericID(genericComponent, &exactID, component); @@ -428,7 +427,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); - (NSAppleEventDescriptor*)descForScriptID:(OSAID)osaID component:(ComponentInstance)component { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); NSAppleEventDescriptor *desc = nil; // If we have a script, return a typeGTMOSAID, otherwise convert it to // it's default AEDesc using OSACoerceToDesc with typeWildCard. @@ -468,7 +467,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (OSAID)gtm_realIDAndComponent:(ComponentInstance*)component { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); if (![self isCompiled]) { NSDictionary *error; if (![self compileAndReturnError:&error]) { @@ -487,7 +486,7 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:); } - (void)gtm_internalExecuteAppleEvent:(NSMutableDictionary *)data { - GTMAssertRunningOnMainThread(); + _GTMDevAssert([NSThread isMainThread], @"Requires main thread."); NSDictionary *error = nil; if (![self isCompiled]) { [self compileAndReturnError:&error]; -- cgit v1.2.3 From 296d521919da2cebe0e5074cc8b6b2b5fdb85fd6 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 29 Apr 2016 13:52:35 -0400 Subject: Start updating the unittesting support - Remove GTM_ENABLE_LEAKS (pretty stale at this point). - Remove imageFromResource from GTMSenTestCase (asset catalogs, etc. have changed patterns). - Remove XCTest macros that are now supplied by XCTest directly. Checked back to Xcode 6.4 and they are built into XCTest. - Start removing SenTest support. --- ReleaseNotes.md | 1 + UnitTesting/GTMSenTestCase.h | 193 --------------------------- UnitTesting/GTMSenTestCase.m | 76 ----------- UnitTesting/RunIPhoneUnitTest.sh | 15 --- UnitTesting/RunMacOSUnitTests.sh | 151 +-------------------- UnitTesting/RuniOSUnitTestsUnderSimulator.sh | 15 --- 6 files changed, 3 insertions(+), 448 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 75524a9..339aaa3 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -37,6 +37,7 @@ Changes since 1.6.0
- Removed GTMNSNumber+64Bit methods as obsolete. +- Removed GTM_ENABLE_LEAKS. **Release 1.6.0**
Changes since 1.5.1
diff --git a/UnitTesting/GTMSenTestCase.h b/UnitTesting/GTMSenTestCase.h index b637b43..a96cb20 100644 --- a/UnitTesting/GTMSenTestCase.h +++ b/UnitTesting/GTMSenTestCase.h @@ -216,90 +216,6 @@ }) #endif // XCTAssertNULL -// Generates a failure when a1 is not 'op' to a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// format: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#ifndef XCTAssertOperation -#define XCTAssertOperation(a1, a2, op, format...) \ -({ \ - NSString *_failure = nil; \ - @try { \ - __typeof__(a1) _a1value = (a1); \ - __typeof__(a2) _a2value = (a2); \ - if (!(_a1value op _a2value)) { \ - _failure = [NSString stringWithFormat:@"(%@) is not %s (%@)", @(_a1value), #op, @(_a2value)]; \ - } \ - } \ - @catch (NSException *_exception) { \ - _failure = [NSString stringWithFormat:_XCExceptionFormatString, [_exception reason]]; \ - } \ - @catch (...) { \ - _failure = _XCUnknownExceptionString; \ - } \ - if (_failure) { \ - NSString *_expression = [NSString stringWithFormat:@"((%@) %s (%@)) failed: %@", @#a1, #op, @#a2, _failure]; \ - _GTMXCRegisterFailure(_expression, format); \ - } \ -}) -#endif // XCTAssertOperation - -// Generates a failure when a1 is not > a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#ifndef XCTAssertGreaterThanOrEqual -#define XCTAssertGreaterThan(a1, a2, format...) \ - XCTAssertOperation(a1, a2, >, ##format) -#endif // XCTAssertGreaterThan - -// Generates a failure when a1 is not >= a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#ifndef XCTAssertGreaterThanOrEqual -#define XCTAssertGreaterThanOrEqual(a1, a2, format...) \ - XCTAssertOperation(a1, a2, >=, ##format) -#endif // XCTAssertGreaterThanOrEqual - -// Generates a failure when a1 is not < a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#ifndef XCTAssertLessThan -#define XCTAssertLessThan(a1, a2, format...) \ - XCTAssertOperation(a1, a2, <, ##format) -#endif // XCTAssertLessThan - -// Generates a failure when a1 is not <= a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#ifndef XCTAssertLessThanOrEqual -#define XCTAssertLessThanOrEqual(a1, a2, format...) \ - XCTAssertOperation(a1, a2, <=, ##format) -#endif // XCTAssertLessThanOrEqual - // Generates a failure when string a1 is not equal to string a2. This call // differs from XCTAssertEqualObjects in that strings that are different in // composition (precomposed vs decomposed) will compare equal if their final @@ -812,100 +728,6 @@ do { \ } \ } while (0) -// Generates a failure when c-string a1 is equal to c-string a2. -// Args: -// a1: string 1 -// a2: string 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotEqualCStrings(a1, a2, description, ...) \ -do { \ - @try { \ - const char* _a1value = (a1); \ - const char* _a2value = (a2); \ - if (strcmp(_a1value, _a2value) != 0) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:[NSString stringWithUTF8String:_a1value] \ - andObject:[NSString stringWithUTF8String:_a2value] \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - -/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. - This test is for GLKit types (GLKVector, GLKMatrix) where small differences - could make these items not exactly equal. Do not use this version directly. - Use the explicit STAssertEqualGLKVectors and STAssertEqualGLKMatrices defined - below. - _{a1 The GLKType on the left.} - _{a2 The GLKType on the right.} - _{accuracy The maximum difference between a1 and a2 for these values to be - considered equal.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ - -#define STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1GLKValue = (a1); \ - __typeof__(a2) a2GLKValue = (a2); \ - __typeof__(accuracy) accuracyvalue = (accuracy); \ - float *a1FloatValue = ((float*)&a1GLKValue); \ - float *a2FloatValue = ((float*)&a2GLKValue); \ - for (size_t i = 0; i < sizeof(__typeof__(a1)) / sizeof(float); ++i) { \ - float _a1value = a1FloatValue[i]; \ - float _a2value = a2FloatValue[i]; \ - if (STAbsoluteDifference(_a1value, _a2value) > accuracyvalue) { \ - NSMutableArray *strings = [NSMutableArray arrayWithCapacity:sizeof(a1) / sizeof(float)]; \ - NSString *string; \ - for (size_t j = 0; j < sizeof(__typeof__(a1)) / sizeof(float); ++j) { \ - string = [NSString stringWithFormat:@"(%0.3f == %0.3f)", a1FloatValue[j], a2FloatValue[j]]; \ - [strings addObject:string]; \ - } \ - string = [strings componentsJoinedByString:@", "]; \ - NSString *desc = STComposeString(description, ##__VA_ARGS__); \ - desc = [NSString stringWithFormat:@"%@ With Accuracy %0.3f: %@", string, (float)accuracyvalue, desc]; \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", desc]]; \ - break; \ - } \ - } \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - -#define STAssertEqualGLKVectors(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - -#define STAssertEqualGLKMatrices(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - -#define STAssertEqualGLKQuaternions(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - #endif // GTM_USING_XCTEST #if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST && !GTM_USING_XCTEST // When not using the Xcode provided version, define everything ourselves. @@ -1469,12 +1291,6 @@ GTM_EXTERN NSString *const SenTestLineNumberKey; #endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST && !GTM_USING_XCTEST -#if GTM_IPHONE_SDK - -@class UIImage; - -#endif // GTM_IPHONE_SDK - // All unittest cases in GTM should inherit from GTMTestCase. It makes sure // to set up our logging system correctly to verify logging calls. // See GTMUnitTestDevLog.h for details @@ -1506,13 +1322,4 @@ GTM_EXTERN NSString *const SenTestLineNumberKey; // "AbstractTest" (case sensitive). + (BOOL)isAbstractTestCase; -#if GTM_IPHONE_SDK -// Returns the UIImage for the the named |resource|. Asserts that the image is -// loaded (is non-nil). -// -// This is required as while under test, [UIImage imageNamed:...] does not -// correctly load images from the resources associated with a test class. -- (UIImage *)imageFromResource:(NSString *)resource; -#endif // GTM_IPHONE_SDK - @end diff --git a/UnitTesting/GTMSenTestCase.m b/UnitTesting/GTMSenTestCase.m index ecab057..1de4ca7 100644 --- a/UnitTesting/GTMSenTestCase.m +++ b/UnitTesting/GTMSenTestCase.m @@ -422,20 +422,6 @@ static NSInteger MethodSort(id a, id b, void *context) { return [name rangeOfString:@"AbstractTest"].location != NSNotFound; } -#if GTM_IPHONE_SDK -- (UIImage *)imageFromResource:(NSString *)resource { - NSBundle *bundle = [NSBundle bundleForClass:[self class]]; - NSString *path = [bundle pathForResource:resource ofType:nil]; - UIImage *image = [UIImage imageWithContentsOfFile:path]; -#if GTM_USING_XCTEST - XCTAssertNotNil(image, @"Could not load image from resource: %@", path); -#else - STAssertNotNil(image, @"Could not load image from resource: %@", path); -#endif // GTM_USING_XCTEST - return image; -} -#endif - + (NSArray *)testInvocations { NSArray *invocations = nil; if (![self isAbstractTestCase]) { @@ -445,65 +431,3 @@ static NSInteger MethodSort(id a, id b, void *context) { } @end - -// Leak detection -#if !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK -// Don't want to get leaks on the iPhone Device as the device doesn't -// have 'leaks'. The simulator does though. - -// COV_NF_START -// We don't have leak checking on by default, so this won't be hit. -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:@","]; - NSString *exclusion; - NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet]; - GTM_FOREACH_OBJECT(exclusion, exclusionsArray) { - exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet]; - [exclusions appendFormat:@"-exclude \"%@\" ", exclusion]; - } - } - // Clearing out DYLD_ROOT_PATH because iPhone Simulator framework libraries - // are different from regular OS X libraries and leaks will fail to run - // because of missing symbols. Also capturing the output of leaks and then - // pipe rather than a direct pipe, because otherwise if leaks failed, - // the system() call will still be successful. Bug: - // http://code.google.com/p/google-toolbox-for-mac/issues/detail?id=56 - NSString *string - = [NSString stringWithFormat: - @"LeakOut=`DYLD_ROOT_PATH='' /usr/bin/leaks %@%d` &&" - @"echo \"$LeakOut\"|/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\n", - __FILE__, __LINE__, ret); - fflush(stderr); - } -} -// COV_NF_END - -static __attribute__((constructor)) void _GTMInstallLeaks(void) { - BOOL checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO; - if (checkLeaks) { - // COV_NF_START - // We don't have leak checking on by default, so this won't be hit. - fprintf(stderr, "Leak Checking Enabled\n"); - fflush(stderr); - int ret = atexit(&_GTMRunLeaks); - // To avoid unused variable warning when _GTMDevAssert is stripped. - (void)ret; - _GTMDevAssert(ret == 0, - @"Unable to install _GTMRunLeaks as an atexit handler (%d)", - errno); - // COV_NF_END - } -} - -#endif // !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK diff --git a/UnitTesting/RunIPhoneUnitTest.sh b/UnitTesting/RunIPhoneUnitTest.sh index 743d1ec..f27f854 100755 --- a/UnitTesting/RunIPhoneUnitTest.sh +++ b/UnitTesting/RunIPhoneUnitTest.sh @@ -28,22 +28,11 @@ set -o nounset # want to turn this off if you enable leaks. GTM_DISABLE_ZOMBIES=${GTM_DISABLE_ZOMBIES:=1} -# 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. - # GTM_REMOVE_GCOV_DATA # Before starting the test, remove any *.gcda files for the current run so # you won't get errors when the source file has changed and the data can't @@ -194,10 +183,6 @@ elif [ "$PLATFORM_NAME" == "iphonesimulator" ]; then export OBJC_DEBUG_NIL_SYNC=YES export OBJC_PRINT_REPLACED_METHODS=YES - # 6251475 iPhone simulator leaks @ CFHTTPCookieStore shutdown if - # CFFIXED_USER_HOME empty - GTM_LEAKS_SYMBOLS_TO_IGNORE="CFHTTPCookieStore" - # Start our app. "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents diff --git a/UnitTesting/RunMacOSUnitTests.sh b/UnitTesting/RunMacOSUnitTests.sh index 2f72a12..ed412c0 100755 --- a/UnitTesting/RunMacOSUnitTests.sh +++ b/UnitTesting/RunMacOSUnitTests.sh @@ -35,19 +35,6 @@ export TEST_AFTER_BUILD=YES # want to turn this off if you enable leaks. GTM_DISABLE_ZOMBIES=${GTM_DISABLE_ZOMBIES:=0} -# 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_ENABLE_LEAKS=${GTM_ENABLE_LEAKS:=0} - -# 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. -GTM_LEAKS_SYMBOLS_TO_IGNORE=${GTM_LEAKS_SYMBOLS_TO_IGNORE:=""} - # GTM_DO_NOT_REMOVE_GCOV_DATA # By default before starting the test, we remove any *.gcda files for the # current project build configuration so you won't get errors when a source @@ -96,71 +83,6 @@ sys.exit(subprocess.call(sys.argv[1:]))" "${@}" fi } -# 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 -} - SetMemoryVariables() { # Jack up some memory stress so we can catch more bugs. @@ -189,68 +111,6 @@ SetMemoryVariables() { export OBJC_DEBUG_NIL_SYNC=YES } -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]" - # radar 7598715 Leak when creating new NSColor using lab color space. - AppendToSymbolsLeaksShouldIgnore "CMSSetLabCLUT" - - # Running leaks on architectures that support leaks. - export MallocStackLogging=YES - export GTM_LEAKS_SYMBOLS_TO_IGNORE="${GTM_LEAKS_SYMBOLS_TO_IGNORE}" - ARCHS="${LEAK_TEST_ARCHS}" - VALID_ARCHS="${LEAK_TEST_ARCHS}" - GTMXcodeNote ${LINENO} "Leak checking enabled for $ARCHS. Ignoring leaks from $GTM_LEAKS_SYMBOLS_TO_IGNORE." - SetMemoryVariables - MaybeFlock "${SYSTEM_DEVELOPER_DIR}/Tools/RunTargetUnitTests" - - # 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}" - GTMXcodeNote ${LINENO} "Leak checking disabled for $ARCHS due to no support for leaks on platform". - MaybeFlock "${SYSTEM_DEVELOPER_DIR}/Tools/RunTargetUnitTests" -} - if [ ! $GTM_DO_NOT_REMOVE_GCOV_DATA ]; then GTM_GCOV_CLEANUP_DIR="${CONFIGURATION_TEMP_DIR}" if [ $GTM_REMOVE_TARGET_GCOV_ONLY ]; then @@ -265,12 +125,5 @@ if [ ! $GTM_DO_NOT_REMOVE_GCOV_DATA ]; then fi fi -# 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 -ne 0 ]; then - RunTests -else - GTMXcodeNote ${LINENO} "Leak checking disabled." - SetMemoryVariables - MaybeFlock "${SYSTEM_DEVELOPER_DIR}/Tools/RunTargetUnitTests" -fi +SetMemoryVariables +MaybeFlock "${SYSTEM_DEVELOPER_DIR}/Tools/RunTargetUnitTests" diff --git a/UnitTesting/RuniOSUnitTestsUnderSimulator.sh b/UnitTesting/RuniOSUnitTestsUnderSimulator.sh index 975ce78..ac81def 100755 --- a/UnitTesting/RuniOSUnitTestsUnderSimulator.sh +++ b/UnitTesting/RuniOSUnitTestsUnderSimulator.sh @@ -51,22 +51,11 @@ GTM_SIMULATOR_USER_HOME=${GTM_SIMULATOR_USER_HOME:=default} # Space separated set env variables in format of "KEY1=value1 KEY2=value2" GTM_SIMULATOR_EXTRA_ENV=${GTM_SIMULATOR_EXTRA_ENV:=default} -# 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. - # GTM_REMOVE_GCOV_DATA # Before starting the test, remove any *.gcda files for the current run so # you won't get errors when the source file has changed and the data can't @@ -202,10 +191,6 @@ if [[ $GTM_REMOVE_GCOV_DATA -ne 0 ]]; then fi fi -# 6251475 iPhone Simulator leaks @ CFHTTPCookieStore shutdown if -# CFFIXED_USER_HOME empty -GTM_LEAKS_SYMBOLS_TO_IGNORE="CFHTTPCookieStore" - # # Build up the command line to run. # -- cgit v1.2.3