diff options
author | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2010-04-15 17:31:09 +0000 |
---|---|---|
committer | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2010-04-15 17:31:09 +0000 |
commit | 2ddb245fac99802e63742c21f7da0d499e9cecf6 (patch) | |
tree | 3eebbf1aeed8269c8b14de81e8b680e784b8709b | |
parent | 30ac0ff87b594d7bca3a5cc2789ca415840ea0b1 (diff) |
[Author: dmaclach]
refactor GTMUnitTestingUtilities into GTMAppKitUnitTestingUtilties and GTMFoundationUnitTestingUtilities.
convert GTMSignalHandler over to using new runloop routines
fix bug in GTMSignalHandler API with GC where releasing it wasn't sufficient to stop it listening.
R=thomasvl
DELTA=1227 (638 added, 566 deleted, 23 changed)
-rw-r--r-- | AppKit/GTMCarbonEventTest.m | 10 | ||||
-rw-r--r-- | AppKit/GTMGetURLHandlerTest.m | 1 | ||||
-rw-r--r-- | AppKit/GTMNSAnimatablePropertyContainerTest.m | 2 | ||||
-rw-r--r-- | Foundation/GTMSignalHandler.h | 3 | ||||
-rw-r--r-- | Foundation/GTMSignalHandler.m | 18 | ||||
-rw-r--r-- | Foundation/GTMSignalHandlerTest.m | 52 | ||||
-rw-r--r-- | GTM.xcodeproj/project.pbxproj | 28 | ||||
-rw-r--r-- | UnitTesting/GTMAppKitUnitTestingUtilities.h (renamed from UnitTesting/GTMUnitTestingUtilities.h) | 77 | ||||
-rw-r--r-- | UnitTesting/GTMAppKitUnitTestingUtilities.m (renamed from UnitTesting/GTMUnitTestingUtilities.m) | 73 | ||||
-rw-r--r-- | UnitTesting/GTMFoundationUnitTestingUtilities.h | 88 | ||||
-rw-r--r-- | UnitTesting/GTMFoundationUnitTestingUtilities.m | 88 | ||||
-rw-r--r-- | UnitTesting/GTMUIUnitTestingHarness/main.m | 4 |
12 files changed, 258 insertions, 186 deletions
diff --git a/AppKit/GTMCarbonEventTest.m b/AppKit/GTMCarbonEventTest.m index 81acbd0..4cc039c 100644 --- a/AppKit/GTMCarbonEventTest.m +++ b/AppKit/GTMCarbonEventTest.m @@ -18,7 +18,7 @@ #import "GTMSenTestCase.h" #import "GTMCarbonEvent.h" -#import "GTMUnitTestingUtilities.h" +#import "GTMAppKitUnitTestingUtilities.h" #import "GTMUnitTestDevLog.h" @interface GTMCarbonEventTest : GTMTestCase { @@ -286,7 +286,7 @@ extern EventTargetRef GetApplicationEventTarget(void); // This test can't be run if the screen saver is active because the security // agent blocks us from sending events via remote operations - if (![GTMUnitTestingUtilities isScreenSaverActive]) { + if (![GTMAppKitUnitTestingUtilities isScreenSaverActive]) { GTMCarbonEventDispatcherHandler *dispatcher = [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; STAssertNotNil(dispatcher, @"Unable to acquire singleton"); @@ -312,7 +312,7 @@ extern EventTargetRef GetApplicationEventTarget(void); // correctly hitHotKey: should get called, and hotKeyHit_ will be set for // us. We run the event loop for a set amount of time waiting for this to // happen. - [GTMUnitTestingUtilities postTypeCharacterEvent:'g' modifiers:keyMods]; + [GTMAppKitUnitTestingUtilities postTypeCharacterEvent:'g' modifiers:keyMods]; STAssertTrue([NSApp gtm_runUpToSixtySecondsWithContext:hotKeyHit_], nil); [dispatcher unregisterHotKey:hotKey]; } @@ -322,7 +322,7 @@ extern EventTargetRef GetApplicationEventTarget(void); // This test can't be run if the screen saver is active because the security // agent blocks us from sending events via remote operations - if (![GTMUnitTestingUtilities isScreenSaverActive]) { + if (![GTMAppKitUnitTestingUtilities isScreenSaverActive]) { GTMCarbonEventDispatcherHandler *dispatcher = [GTMCarbonEventDispatcherHandler sharedEventDispatcherHandler]; STAssertNotNil(dispatcher, @"Unable to acquire singleton"); @@ -339,7 +339,7 @@ extern EventTargetRef GetApplicationEventTarget(void); // correctly hitHotKey: should get called, and hotKeyHit_ will be set for // us. We run the event loop for a set amount of time waiting for this to // happen. - [GTMUnitTestingUtilities postTypeCharacterEvent:'g' modifiers:keyMods]; + [GTMAppKitUnitTestingUtilities postTypeCharacterEvent:'g' modifiers:keyMods]; [GTMUnitTestDevLog expectString:@"Exception fired in hotkey: foo (bar)"]; STAssertTrue([NSApp gtm_runUpToSixtySecondsWithContext:hotKeyHit_], nil); [dispatcher unregisterHotKey:hotKey]; diff --git a/AppKit/GTMGetURLHandlerTest.m b/AppKit/GTMGetURLHandlerTest.m index ba0be7d..940d90f 100644 --- a/AppKit/GTMGetURLHandlerTest.m +++ b/AppKit/GTMGetURLHandlerTest.m @@ -16,7 +16,6 @@ // #import "GTMSenTestCase.h" -#import "GTMUnitTestingUtilities.h" #import "GTMUnitTestDevLog.h" static BOOL sURLHandlerWasHit; diff --git a/AppKit/GTMNSAnimatablePropertyContainerTest.m b/AppKit/GTMNSAnimatablePropertyContainerTest.m index 9a1d497..9676086 100644 --- a/AppKit/GTMNSAnimatablePropertyContainerTest.m +++ b/AppKit/GTMNSAnimatablePropertyContainerTest.m @@ -19,7 +19,7 @@ #import "GTMNSAnimatablePropertyContainerTest.h" #import "GTMNSAnimatablePropertyContainer.h" #import "GTMTypeCasting.h" -#import "GTMUnitTestingUtilities.h" +#import "GTMFoundationUnitTestingUtilities.h" #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 diff --git a/Foundation/GTMSignalHandler.h b/Foundation/GTMSignalHandler.h index b1c7c2f..6297197 100644 --- a/Foundation/GTMSignalHandler.h +++ b/Foundation/GTMSignalHandler.h @@ -70,4 +70,7 @@ target:(id)target action:(SEL)action; +// Invalidates the handler so that it isn't listening anymore. +- (void)invalidate; + @end diff --git a/Foundation/GTMSignalHandler.m b/Foundation/GTMSignalHandler.m index dd67269..677c10a 100644 --- a/Foundation/GTMSignalHandler.m +++ b/Foundation/GTMSignalHandler.m @@ -44,7 +44,6 @@ static CFSocketRef gRunLoopSocket = NULL; - (void)notify; - (void)addFileDescriptorMonitor:(int)fd; - (void)registerWithKQueue; -- (void)unregisterWithKQueue; @end @@ -88,19 +87,17 @@ static CFSocketRef gRunLoopSocket = NULL; } #if GTM_SUPPORT_GC + - (void)finalize { - [self unregisterWithKQueue]; - + [self invalidate]; [super finalize]; - } + #endif - (void)dealloc { - [self unregisterWithKQueue]; - + [self invalidate]; [super dealloc]; - } // Cribbed from Advanced Mac OS X Programming. @@ -181,7 +178,7 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, } -- (void)unregisterWithKQueue { +- (void)invalidate { // Short-circuit cases where we didn't actually register a kqueue event. if (signo_ == 0) return; if (action_ == nil) return; @@ -193,7 +190,10 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, if (kevent(gSignalKQueueFileDescriptor, &filter, 1, NULL, 0, &noWait) != 0) { _GTMDevLog(@"could not remove event for signal %d. Errno %d", signo_, errno); // COV_NF_LINE } - + + // Set action_ to nil so that if invalidate is called on us twice, + // nothing happens. + action_ = nil; } - (void)notify { diff --git a/Foundation/GTMSignalHandlerTest.m b/Foundation/GTMSignalHandlerTest.m index a0019f3..191d67f 100644 --- a/Foundation/GTMSignalHandlerTest.m +++ b/Foundation/GTMSignalHandlerTest.m @@ -19,19 +19,22 @@ #import "GTMSenTestCase.h" #import "GTMSignalHandler.h" #import "GTMUnitTestDevLog.h" +#import "GTMFoundationUnitTestingUtilities.h" @interface GTMSignalHandlerTest : GTMTestCase @end -@interface SignalCounter : NSObject { +@interface SignalCounter : NSObject<GTMUnitTestingRunLoopContext> { @public int signalCount_; int lastSeenSignal_; + BOOL shouldStop_; } - (int)count; - (int)lastSeen; - (void)countSignal:(int)signo; + (id)signalCounter; +- (void)resetShouldStop; @end // SignalCounter @implementation SignalCounter @@ -48,17 +51,21 @@ - (void)countSignal:(int)signo { signalCount_++; lastSeenSignal_ = signo; + shouldStop_ = YES; } -@end -@implementation GTMSignalHandlerTest +- (BOOL)shouldStop { + return shouldStop_; +} -// Spin the run loop so that the kqueue event notifications will get delivered. -- (void)giveSomeLove { - NSDate *endTime = [NSDate dateWithTimeIntervalSinceNow:0.5]; - [[NSRunLoop currentRunLoop] runUntilDate:endTime]; +- (void)resetShouldStop { + shouldStop_ = NO; } +@end + +@implementation GTMSignalHandlerTest + - (void)testNillage { GTMSignalHandler *handler; @@ -81,23 +88,28 @@ SignalCounter *counter = [SignalCounter signalCounter]; STAssertNotNil(counter, nil); - GTMSignalHandler *handler = [[GTMSignalHandler alloc] - initWithSignal:SIGWINCH - target:counter - action:@selector(countSignal:)]; + GTMSignalHandler *handler = [[[GTMSignalHandler alloc] + initWithSignal:SIGWINCH + target:counter + action:@selector(countSignal:)] + autorelease]; STAssertNotNil(handler, nil); raise(SIGWINCH); - [self giveSomeLove]; + + NSRunLoop *rl = [NSRunLoop currentRunLoop]; + [rl gtm_runUpToSixtySecondsWithContext:counter]; STAssertEquals([counter count], 1, nil); STAssertEquals([counter lastSeen], SIGWINCH, nil); - + [counter resetShouldStop]; + raise(SIGWINCH); - [self giveSomeLove]; + [rl gtm_runUpToSixtySecondsWithContext:counter]; STAssertEquals([counter count], 2, nil); STAssertEquals([counter lastSeen], SIGWINCH, nil); - + [counter resetShouldStop]; + // create a second one to make sure we're seding data where we want SignalCounter *counter2 = [SignalCounter signalCounter]; STAssertNotNil(counter2, nil); @@ -106,19 +118,20 @@ action:@selector(countSignal:)] autorelease]; raise(SIGUSR1); - [self giveSomeLove]; + [rl gtm_runUpToSixtySecondsWithContext:counter2]; STAssertEquals([counter count], 2, nil); STAssertEquals([counter lastSeen], SIGWINCH, nil); STAssertEquals([counter2 count], 1, nil); STAssertEquals([counter2 lastSeen], SIGUSR1, nil); - [handler release]; + [handler invalidate]; // The signal is still ignored (so we shouldn't die), but the // the handler method should not get called. raise(SIGWINCH); - + [rl runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.2]]; + STAssertEquals([counter count], 2, nil); STAssertEquals([counter lastSeen], SIGWINCH, nil); STAssertEquals([counter2 count], 1, nil); @@ -135,7 +148,8 @@ action:NULL] autorelease]; raise(SIGUSR1); - [self giveSomeLove]; + NSRunLoop *rl = [NSRunLoop currentRunLoop]; + [rl runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.2]]; STAssertEquals([counter count], 0, nil); } diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj index 9afd678..e241a21 100644 --- a/GTM.xcodeproj/project.pbxproj +++ b/GTM.xcodeproj/project.pbxproj @@ -87,6 +87,11 @@ 8B0E65510FD80D5E00461C4A /* GTMHotKeyTextField.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8B0E653F0FD80D5E00461C4A /* GTMHotKeyTextField.strings */; }; 8B158A9B10A8C31100C93125 /* GTMNSAnimation+Duration.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B158A6010A8BE4500C93125 /* GTMNSAnimation+Duration.m */; }; 8B158ADE10A8C42000C93125 /* GTMNSAnimation+Duration.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B158A5F10A8BE4500C93125 /* GTMNSAnimation+Duration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8B17FD15117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B17FD13117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m */; }; + 8B17FD16117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B17FD13117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m */; }; + 8B17FD1A117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B17FD18117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m */; }; + 8B17FE091176672300E7A908 /* GTMAppKitUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B17FD18117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m */; }; + 8B17FE0B1176673400E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B17FD13117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m */; }; 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 */; }; @@ -113,7 +118,6 @@ 8B3E292E0EEB53F8000681D8 /* GTMCarbonEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3E292A0EEB53F3000681D8 /* GTMCarbonEvent.m */; }; 8B3E292F0EEB53F8000681D8 /* GTMCarbonEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B3E292B0EEB53F3000681D8 /* GTMCarbonEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8B3E2A3F0EEB564D000681D8 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F42E09AD0D19A62F00D5DDE0 /* Carbon.framework */; }; - 8B3E2A410EEB565B000681D8 /* GTMUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B45A2680DA498A0001148C5 /* GTMUnitTestingUtilities.m */; }; 8B40994B0F93C5CC00DF540E /* GTMUILocalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B4099490F93C5CC00DF540E /* GTMUILocalizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8B40994C0F93C5CC00DF540E /* GTMUILocalizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B40994A0F93C5CC00DF540E /* GTMUILocalizer.m */; }; 8B409BC60F94405A00DF540E /* GTMUILocalizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B409BC50F94405A00DF540E /* GTMUILocalizerTest.m */; }; @@ -136,7 +140,6 @@ 8B45A21E0DA46E34001148C5 /* GTMObjC2Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6F32040DA34A1B0052CA40 /* GTMObjC2Runtime.m */; }; 8B45A2AC0DA49C47001148C5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B45A2A80DA49C47001148C5 /* main.m */; }; 8B45A2B30DA49CA9001148C5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; - 8B45A2D00DA51A01001148C5 /* GTMUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B45A2680DA498A0001148C5 /* GTMUnitTestingUtilities.m */; }; 8B45A2DF0DA51A7E001148C5 /* GTMUnitTestingTest.nib in Resources */ = {isa = PBXBuildFile; fileRef = 8B45A2DE0DA51A7E001148C5 /* GTMUnitTestingTest.nib */; }; 8B45A2E20DA51ABC001148C5 /* GTMUnitTestingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B45A2E10DA51ABC001148C5 /* GTMUnitTestingTest.m */; }; 8B45A5F80DA5EB9F001148C5 /* GTMUnitTestingWindow.gtmUTState in Resources */ = {isa = PBXBuildFile; fileRef = 8B45A5F50DA5EB9F001148C5 /* GTMUnitTestingWindow.gtmUTState */; }; @@ -179,7 +182,6 @@ 8B7DCEF10E002C210017E983 /* GTMDevLogUnitTestingBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B7DCBE10DFF18720017E983 /* GTMDevLogUnitTestingBridge.m */; }; 8B8B10290EEB8B1600E543D0 /* GTMHotKeyTextFieldTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F4A420EE0EDDF8E000397A11 /* GTMHotKeyTextFieldTest.m */; }; 8B8B10F90EEB8B9E00E543D0 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F42E09AD0D19A62F00D5DDE0 /* Carbon.framework */; }; - 8B8B10FD0EEB8BC300E543D0 /* GTMUnitTestingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B45A2680DA498A0001148C5 /* GTMUnitTestingUtilities.m */; }; 8B8EC87D0EF17C270044D13F /* GTMNSFileManager+Carbon.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B8EC87B0EF17C270044D13F /* GTMNSFileManager+Carbon.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8B8EC87E0EF17C270044D13F /* GTMNSFileManager+Carbon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8EC87C0EF17C270044D13F /* GTMNSFileManager+Carbon.m */; }; 8B8EC8800EF17C2F0044D13F /* GTMNSFileManager+CarbonTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8EC87F0EF17C2F0044D13F /* GTMNSFileManager+CarbonTest.m */; }; @@ -539,6 +541,10 @@ 8B0E65500FD80D5E00461C4A /* zh_TW */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = zh_TW; path = zh_TW.lproj/GTMHotKeyTextField.strings; sourceTree = "<group>"; }; 8B158A5F10A8BE4500C93125 /* GTMNSAnimation+Duration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSAnimation+Duration.h"; sourceTree = "<group>"; }; 8B158A6010A8BE4500C93125 /* GTMNSAnimation+Duration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSAnimation+Duration.m"; sourceTree = "<group>"; }; + 8B17FD13117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFoundationUnitTestingUtilities.m; sourceTree = "<group>"; }; + 8B17FD14117638D500E7A908 /* GTMFoundationUnitTestingUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMFoundationUnitTestingUtilities.h; sourceTree = "<group>"; }; + 8B17FD18117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMAppKitUnitTestingUtilities.m; sourceTree = "<group>"; }; + 8B17FD19117638F400E7A908 /* GTMAppKitUnitTestingUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMAppKitUnitTestingUtilities.h; 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>"; }; @@ -591,8 +597,6 @@ 8B409F120F95352500DF540E /* GTMUILocalizerView1State.gtmUTState */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = GTMUILocalizerView1State.gtmUTState; sourceTree = "<group>"; }; 8B45A0280DA4696C001148C5 /* UnitTest - UnitTesting.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UnitTest - UnitTesting.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; 8B45A1990DA46AAA001148C5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; }; - 8B45A2670DA498A0001148C5 /* GTMUnitTestingUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMUnitTestingUtilities.h; sourceTree = "<group>"; }; - 8B45A2680DA498A0001148C5 /* GTMUnitTestingUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMUnitTestingUtilities.m; sourceTree = "<group>"; }; 8B45A28A0DA49B99001148C5 /* GTMUIUnitTestingHarness.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GTMUIUnitTestingHarness.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8B45A2A70DA49C47001148C5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 8B45A2A80DA49C47001148C5 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; @@ -1364,9 +1368,13 @@ children = ( 8B55479A0DB3B7A50014CC1C /* GTMAppKit+UnitTesting.h */, 8B55479B0DB3B7A50014CC1C /* GTMAppKit+UnitTesting.m */, + 8B17FD18117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m */, + 8B17FD19117638F400E7A908 /* GTMAppKitUnitTestingUtilities.h */, 8B726BD10D91C0860090C251 /* GTMCALayer+UnitTesting.h */, 8B726BD00D91C0860090C251 /* GTMCALayer+UnitTesting.m */, 8B7DCBE10DFF18720017E983 /* GTMDevLogUnitTestingBridge.m */, + 8B17FD13117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m */, + 8B17FD14117638D500E7A908 /* GTMFoundationUnitTestingUtilities.h */, 8B1A14EA0D900BC800CA1E8E /* GTMNSObject+BindingUnitTesting.h */, 8B1A14E90D900BC800CA1E8E /* GTMNSObject+BindingUnitTesting.m */, F48FE29B0D198D36009257D2 /* GTMNSObject+UnitTesting.h */, @@ -1382,8 +1390,6 @@ 8B7AD4AD0DABBFEE00B84F4A /* GTMUnitTestingBindingTest.m */, 8B45A2E00DA51ABC001148C5 /* GTMUnitTestingTest.h */, 8B45A2E10DA51ABC001148C5 /* GTMUnitTestingTest.m */, - 8B45A2670DA498A0001148C5 /* GTMUnitTestingUtilities.h */, - 8B45A2680DA498A0001148C5 /* GTMUnitTestingUtilities.m */, 8BC04D140DB0061300C2D1CA /* RunMacOSUnitTests.sh */, 8B45A2A20DA49C47001148C5 /* GTMUIUnitTestingHarness */, F435E46C0DC8F23A0069CDE8 /* TestData */, @@ -1936,7 +1942,6 @@ 8B7DCBEF0DFF1A4F0017E983 /* GTMUnitTestDevLog.m in Sources */, 8B7DCE1B0DFF39850017E983 /* GTMSenTestCase.m in Sources */, 8B35901B0E8191750041E21C /* GTMTestTimerTest.m in Sources */, - 8B3E2A410EEB565B000681D8 /* GTMUnitTestingUtilities.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1945,10 +1950,11 @@ buildActionMask = 2147483647; files = ( 8B45A2AC0DA49C47001148C5 /* main.m in Sources */, - 8B45A2D00DA51A01001148C5 /* GTMUnitTestingUtilities.m in Sources */, 8B7DCBC40DFF0F800017E983 /* GTMMethodCheck.m in Sources */, 8B7DCEF10E002C210017E983 /* GTMDevLogUnitTestingBridge.m in Sources */, 8B4D7A150E40D79200EFEDD8 /* GTMObjC2Runtime.m in Sources */, + 8B17FE091176672300E7A908 /* GTMAppKitUnitTestingUtilities.m in Sources */, + 8B17FE0B1176673400E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2015,6 +2021,7 @@ 0BFAD4CC104D06FE002BEB27 /* GTMNSDictionary+CaseInsensitiveTest.m in Sources */, 8B3080151056B917006C4C7A /* GTMNSNumber+64BitTest.m in Sources */, 0B1B9B8A10FECDA00084EE4B /* GTMStringEncodingTest.m in Sources */, + 8B17FD15117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2104,7 +2111,6 @@ 8B7DCBED0DFF1A4F0017E983 /* GTMUnitTestDevLog.m in Sources */, 8B7DCE190DFF39850017E983 /* GTMSenTestCase.m in Sources */, 8B8B10290EEB8B1600E543D0 /* GTMHotKeyTextFieldTest.m in Sources */, - 8B8B10FD0EEB8BC300E543D0 /* GTMUnitTestingUtilities.m in Sources */, 8BAA9EF20F7C2AB500DF4F12 /* GTMCarbonEventTest.m in Sources */, 8BAA9EF30F7C2AB500DF4F12 /* GTMGetURLHandlerTest.m in Sources */, 8BAA9EF40F7C2AB500DF4F12 /* GTMLargeTypeWindowTest.m in Sources */, @@ -2123,6 +2129,8 @@ 7FF768E31051B17900D34F4B /* GTMNSImage+SearchCacheTest.m in Sources */, F4C62489109753960069CADD /* GTMIBArrayTest.m in Sources */, 8BDB8C3A115329EC00C411B1 /* GTMNSAnimatablePropertyContainerTest.m in Sources */, + 8B17FD16117638D500E7A908 /* GTMFoundationUnitTestingUtilities.m in Sources */, + 8B17FD1A117638F400E7A908 /* GTMAppKitUnitTestingUtilities.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/UnitTesting/GTMUnitTestingUtilities.h b/UnitTesting/GTMAppKitUnitTestingUtilities.h index d47c1ec..d6a653c 100644 --- a/UnitTesting/GTMUnitTestingUtilities.h +++ b/UnitTesting/GTMAppKitUnitTestingUtilities.h @@ -1,7 +1,7 @@ // -// GTMUnitTestingUtilities.h +// GTMAppKitUnitTestingUtilities.h // -// Copyright 2006-2008 Google Inc. +// Copyright 2006-2010 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,41 +16,10 @@ // the License. // -#import <Foundation/Foundation.h> -#import <objc/objc.h> - -// Many tests need to spin the runloop and wait for an event to happen. This is -// often done by calling: -// NSDate* next = [NSDate dateWithTimeIntervalSinceNow:resolution]; -// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode -// beforeDate:next]; -// where |resolution| is a guess at how long it will take for the event to -// happen. There are two major problems with this approach: -// a) By guessing we force the test to take at least |resolution| time. -// b) It makes for flaky tests in that sometimes this guess isn't good, and the -// test takes slightly longer than |resolution| time causing the test to post -// a possibly false-negative failure. -// To make timing callback tests easier use this class and the -// GTMUnitTestingAdditions additions to NSRunLoop and NSApplication. -// Your call would look something like this: -// id<GTMUnitTestingRunLoopContext> context = [self getMeAContext]; -// [[NSRunLoop currentRunLoop] gtm_runUpToSixtySecondsWithContext:context]; -// Then in some callback method within your test you would call -// [context setShouldStop:YES]; -// Internally gtm_runUpToSixtySecondsWithContext will poll the runloop really -// quickly to keep test times down to a minimum, but will stop after a good time -// interval (in this case 60 seconds) for failures. -@protocol GTMUnitTestingRunLoopContext -// Return YES if the NSRunLoop (or equivalent) that this context applies to -// should stop as soon as possible. -- (BOOL)shouldStop; -@end +#import "GTMFoundationUnitTestingUtilities.h" // Collection of utilities for unit testing -@interface GTMUnitTestingUtilities : NSObject - -// Returns YES if we are currently being unittested. -+ (BOOL)areWeBeingUnitTested; +@interface GTMAppKitUnitTestingUtilities : NSObject // Sets up the user interface so that we can run consistent UI unittests on // it. This includes setting scroll bar types, setting selection colors @@ -58,8 +27,9 @@ // This should be called in main, before NSApplicationMain is called. + (void)setUpForUIUnitTests; -// Syntactic sugar combining the above, and wrapping them in an -// NSAutoreleasePool so that your main can look like this: +// Syntactic sugar combining that checks to see if we are running unittests +// and then calls setUpForUIUnitTests wrapped up in a NSAutoreleasePool so that +// your main can look like this: // int main(int argc, const char *argv[]) { // [UnitTestingUtilities setUpForUIUnitTestsIfBeingTested]; // return NSApplicationMain(argc, argv); @@ -105,39 +75,6 @@ @end -// An implementation of the GTMUnitTestingRunLoopContext that is a simple -// BOOL flag. See GTMUnitTestingRunLoopContext documentation. -@interface GTMUnitTestingBooleanRunLoopContext : NSObject <GTMUnitTestingRunLoopContext> { - @private - BOOL shouldStop_; -} -+ (id)context; -- (BOOL)shouldStop; -- (void)setShouldStop:(BOOL)stop; -@end - -// Some category methods to simplify spinning the runloops in such a way as -// to make tests less flaky, but have them complete as fast as possible. -@interface NSRunLoop (GTMUnitTestingAdditions) -// Will spin the runloop in mode until date in mode until the runloop returns -// because all sources have been removed or the current date is greater than -// |date| or [context shouldStop] returns YES. -// Return YES if the runloop was stopped because [context shouldStop] returned -// YES. -- (BOOL)gtm_runUntilDate:(NSDate *)date - mode:(NSString *)mode - context:(id<GTMUnitTestingRunLoopContext>)context; - -// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode. -- (BOOL)gtm_runUntilDate:(NSDate *)date - context:(id<GTMUnitTestingRunLoopContext>)context; - -// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode, -// and the timeout date set to 60 seconds. -- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context; - -@end - // Some category methods to simplify spinning the runloops in such a way as // to make tests less flaky, but have them complete as fast as possible. @interface NSApplication (GTMUnitTestingAdditions) diff --git a/UnitTesting/GTMUnitTestingUtilities.m b/UnitTesting/GTMAppKitUnitTestingUtilities.m index 2bd7b88..551738e 100644 --- a/UnitTesting/GTMUnitTestingUtilities.m +++ b/UnitTesting/GTMAppKitUnitTestingUtilities.m @@ -1,5 +1,5 @@ // -// GTMUnitTestingUtilities.m +// GTMAppKitUnitTestingUtilities.m // // Copyright 2006-2008 Google Inc. // @@ -16,7 +16,7 @@ // the License. // -#import "GTMUnitTestingUtilities.h" +#import "GTMAppKitUnitTestingUtilities.h" #import <AppKit/AppKit.h> #include <signal.h> #include <unistd.h> @@ -37,26 +37,7 @@ static void GTMHandleCrashSignal(int signalNumber); static CGKeyCode GTMKeyCodeForCharCode(CGCharCode charCode); -@implementation GTMUnitTestingUtilities - -// Returns YES if we are currently being unittested. -+ (BOOL)areWeBeingUnitTested { - BOOL answer = NO; - - // Check to see if the SenTestProbe class is linked in before we call it. - Class SenTestProbeClass = NSClassFromString(@"SenTestProbe"); - if (SenTestProbeClass != Nil) { - // Doing this little dance so we don't actually have to link - // SenTestingKit in - SEL selector = NSSelectorFromString(@"isTesting"); - NSMethodSignature *sig = [SenTestProbeClass methodSignatureForSelector:selector]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; - [invocation setSelector:selector]; - [invocation invokeWithTarget:SenTestProbeClass]; - [invocation getReturnValue:&answer]; - } - return answer; -} +@implementation GTMAppKitUnitTestingUtilities // Sets up the user interface so that we can run consistent UI unittests on it. + (void)setUpForUIUnitTests { @@ -93,7 +74,7 @@ static CGKeyCode GTMKeyCodeForCharCode(CGCharCode charCode); + (void)setUpForUIUnitTestsIfBeingTested { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if ([self areWeBeingUnitTested]) { + if ([GTMFoundationUnitTestingUtilities areWeBeingUnitTested]) { [self setUpForUIUnitTests]; } [pool drain]; @@ -314,52 +295,6 @@ static CGKeyCode GTMKeyCodeForCharCode(CGCharCode charCode) { return outCode; } -@implementation GTMUnitTestingBooleanRunLoopContext - -+ (id)context { - return [[[GTMUnitTestingBooleanRunLoopContext alloc] init] autorelease]; -} - -- (BOOL)shouldStop { - return shouldStop_; -} - -- (void)setShouldStop:(BOOL)stop { - shouldStop_ = stop; -} - -@end - -@implementation NSRunLoop (GTMUnitTestingAdditions) - -- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context { - return [self gtm_runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60] - context:context]; -} - -- (BOOL)gtm_runUntilDate:(NSDate *)date - context:(id<GTMUnitTestingRunLoopContext>)context { - return [self gtm_runUntilDate:date mode:NSDefaultRunLoopMode context:context]; -} - -- (BOOL)gtm_runUntilDate:(NSDate *)date - mode:(NSString *)mode - context:(id<GTMUnitTestingRunLoopContext>)context { - BOOL contextShouldStop = NO; - NSRunLoop *rl = [NSRunLoop currentRunLoop]; - while (1) { - contextShouldStop = [context shouldStop]; - if (contextShouldStop) break; - NSDate* next = [[NSDate alloc] initWithTimeIntervalSinceNow:0.01]; - if (!([rl runMode:mode beforeDate:next])) break; - if ([next compare:date] == NSOrderedDescending) break; - [next release]; - } - return contextShouldStop; -} - -@end - @implementation NSApplication (GTMUnitTestingAdditions) - (BOOL)gtm_runUntilDate:(NSDate *)date diff --git a/UnitTesting/GTMFoundationUnitTestingUtilities.h b/UnitTesting/GTMFoundationUnitTestingUtilities.h new file mode 100644 index 0000000..7d0792e --- /dev/null +++ b/UnitTesting/GTMFoundationUnitTestingUtilities.h @@ -0,0 +1,88 @@ +// +// GTMFoundationUnitTestingUtilities.h +// +// Copyright 2006-2010 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 <Foundation/Foundation.h> +#import <objc/objc.h> + +// Many tests need to spin the runloop and wait for an event to happen. This is +// often done by calling: +// NSDate* next = [NSDate dateWithTimeIntervalSinceNow:resolution]; +// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode +// beforeDate:next]; +// where |resolution| is a guess at how long it will take for the event to +// happen. There are two major problems with this approach: +// a) By guessing we force the test to take at least |resolution| time. +// b) It makes for flaky tests in that sometimes this guess isn't good, and the +// test takes slightly longer than |resolution| time causing the test to post +// a possibly false-negative failure. +// To make timing callback tests easier use this class and the +// GTMUnitTestingAdditions additions to NSRunLoop and NSApplication. +// Your call would look something like this: +// id<GTMUnitTestingRunLoopContext> context = [self getMeAContext]; +// [[NSRunLoop currentRunLoop] gtm_runUpToSixtySecondsWithContext:context]; +// Then in some callback method within your test you would call +// [context setShouldStop:YES]; +// Internally gtm_runUpToSixtySecondsWithContext will poll the runloop really +// quickly to keep test times down to a minimum, but will stop after a good time +// interval (in this case 60 seconds) for failures. +@protocol GTMUnitTestingRunLoopContext +// Return YES if the NSRunLoop (or equivalent) that this context applies to +// should stop as soon as possible. +- (BOOL)shouldStop; +@end + +// Collection of utilities for unit testing +@interface GTMFoundationUnitTestingUtilities : NSObject + +// Returns YES if we are currently being unittested. ++ (BOOL)areWeBeingUnitTested; + +@end + +// An implementation of the GTMUnitTestingRunLoopContext that is a simple +// BOOL flag. See GTMUnitTestingRunLoopContext documentation. +@interface GTMUnitTestingBooleanRunLoopContext : NSObject <GTMUnitTestingRunLoopContext> { + @private + BOOL shouldStop_; +} ++ (id)context; +- (BOOL)shouldStop; +- (void)setShouldStop:(BOOL)stop; +@end + +// Some category methods to simplify spinning the runloops in such a way as +// to make tests less flaky, but have them complete as fast as possible. +@interface NSRunLoop (GTMUnitTestingAdditions) +// Will spin the runloop in mode until date in mode until the runloop returns +// because all sources have been removed or the current date is greater than +// |date| or [context shouldStop] returns YES. +// Return YES if the runloop was stopped because [context shouldStop] returned +// YES. +- (BOOL)gtm_runUntilDate:(NSDate *)date + mode:(NSString *)mode + context:(id<GTMUnitTestingRunLoopContext>)context; + +// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode. +- (BOOL)gtm_runUntilDate:(NSDate *)date + context:(id<GTMUnitTestingRunLoopContext>)context; + +// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode, +// and the timeout date set to 60 seconds. +- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context; + +@end diff --git a/UnitTesting/GTMFoundationUnitTestingUtilities.m b/UnitTesting/GTMFoundationUnitTestingUtilities.m new file mode 100644 index 0000000..ab1f29b --- /dev/null +++ b/UnitTesting/GTMFoundationUnitTestingUtilities.m @@ -0,0 +1,88 @@ +// +// GTMFoundationUnitTestingUtilities.m +// +// Copyright 2006-2010 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 "GTMFoundationUnitTestingUtilities.h" + +@implementation GTMFoundationUnitTestingUtilities + +// Returns YES if we are currently being unittested. ++ (BOOL)areWeBeingUnitTested { + BOOL answer = NO; + + // Check to see if the SenTestProbe class is linked in before we call it. + Class SenTestProbeClass = NSClassFromString(@"SenTestProbe"); + if (SenTestProbeClass != Nil) { + // Doing this little dance so we don't actually have to link + // SenTestingKit in + SEL selector = NSSelectorFromString(@"isTesting"); + NSMethodSignature *sig = [SenTestProbeClass methodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:selector]; + [invocation invokeWithTarget:SenTestProbeClass]; + [invocation getReturnValue:&answer]; + } + return answer; +} + +@end + +@implementation GTMUnitTestingBooleanRunLoopContext + ++ (id)context { + return [[[GTMUnitTestingBooleanRunLoopContext alloc] init] autorelease]; +} + +- (BOOL)shouldStop { + return shouldStop_; +} + +- (void)setShouldStop:(BOOL)stop { + shouldStop_ = stop; +} + +@end + +@implementation NSRunLoop (GTMUnitTestingAdditions) + +- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context { + return [self gtm_runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60] + context:context]; +} + +- (BOOL)gtm_runUntilDate:(NSDate *)date + context:(id<GTMUnitTestingRunLoopContext>)context { + return [self gtm_runUntilDate:date mode:NSDefaultRunLoopMode context:context]; +} + +- (BOOL)gtm_runUntilDate:(NSDate *)date + mode:(NSString *)mode + context:(id<GTMUnitTestingRunLoopContext>)context { + BOOL contextShouldStop = NO; + NSRunLoop *rl = [NSRunLoop currentRunLoop]; + while (1) { + contextShouldStop = [context shouldStop]; + if (contextShouldStop) break; + NSDate* next = [[NSDate alloc] initWithTimeIntervalSinceNow:0.01]; + if (!([rl runMode:mode beforeDate:next])) break; + if ([next compare:date] == NSOrderedDescending) break; + [next release]; + } + return contextShouldStop; +} + +@end diff --git a/UnitTesting/GTMUIUnitTestingHarness/main.m b/UnitTesting/GTMUIUnitTestingHarness/main.m index 8fb364d..57ef9c2 100644 --- a/UnitTesting/GTMUIUnitTestingHarness/main.m +++ b/UnitTesting/GTMUIUnitTestingHarness/main.m @@ -19,9 +19,9 @@ #import <Cocoa/Cocoa.h> -#import "GTMUnitTestingUtilities.h" +#import "GTMAppKitUnitTestingUtilities.h" int main(int argc, char *argv[]) { - [GTMUnitTestingUtilities setUpForUIUnitTestsIfBeingTested]; + [GTMAppKitUnitTestingUtilities setUpForUIUnitTestsIfBeingTested]; return NSApplicationMain(argc, (const char **) argv); } |