From 676f5758e421061f4407337a821a89842c0c98e6 Mon Sep 17 00:00:00 2001 From: "gtm.daemon" Date: Thu, 1 Jul 2010 17:31:05 +0000 Subject: [Author: dmaclach] Fix up GTMiPhone Unit test issue with tests never starting. DELTA=64 (63 added, 0 deleted, 1 changed) R=thomasvl --- GTMDefines.h | 16 ++++++++++++ UnitTesting/GTMIPhoneUnitTestDelegate.h | 7 +++-- UnitTesting/GTMIPhoneUnitTestDelegate.m | 46 ++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/GTMDefines.h b/GTMDefines.h index 687f2a7..76b7947 100644 --- a/GTMDefines.h +++ b/GTMDefines.h @@ -298,6 +298,14 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...); #endif #endif +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + #ifndef CF_RETURNS_RETAINED #if __has_feature(attribute_cf_returns_retained) #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) @@ -306,6 +314,14 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...); #endif #endif +#ifndef CF_RETURNS_NOT_RETAINED + #if __has_feature(attribute_cf_returns_not_retained) + #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) + #else + #define CF_RETURNS_NOT_RETAINED + #endif +#endif + // Defined on 10.6 and above. #ifndef NS_FORMAT_ARGUMENT #define NS_FORMAT_ARGUMENT(A) diff --git a/UnitTesting/GTMIPhoneUnitTestDelegate.h b/UnitTesting/GTMIPhoneUnitTestDelegate.h index 4583b5d..5a361b3 100644 --- a/UnitTesting/GTMIPhoneUnitTestDelegate.h +++ b/UnitTesting/GTMIPhoneUnitTestDelegate.h @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -27,7 +27,10 @@ @private NSUInteger totalFailures_; NSUInteger totalSuccesses_; + BOOL applicationDidFinishLaunchingCalled_; + GTMIPhoneUnitTestDelegate *retainer_; } + // Runs through all the registered classes and runs test methods on any // that are subclasses of SenTestCase. Prints results and run time to // the default output. diff --git a/UnitTesting/GTMIPhoneUnitTestDelegate.m b/UnitTesting/GTMIPhoneUnitTestDelegate.m index dc4b182..6d56602 100644 --- a/UnitTesting/GTMIPhoneUnitTestDelegate.m +++ b/UnitTesting/GTMIPhoneUnitTestDelegate.m @@ -29,17 +29,57 @@ @interface UIApplication (GTMIPhoneUnitTestDelegate) -// SPI that we need to exti cleanly with a value. +// SPI that we need to exit cleanly with a value. - (void)_terminateWithStatus:(int)status; @end +@interface GTMIPhoneUnitTestDelegate () +// We have cases where we are created in UIApplicationMain, but then the +// user accidentally/intentionally replaces us as a delegate in their xib file +// which means that we never get the applicationDidFinishLaunching: message. +// We can register for the notification, but when the applications delegate +// is reset, it releases us, and we get dealloced. Therefore we have retainer +// which is responsible for retaining us until we get the notification. +// We do it through this slightly roundabout route (instead of just an extra +// retain in the init) so that clang doesn't complain about a leak. +// We also check to make sure we aren't called twice with the +// applicationDidFinishLaunchingCalled flag. +@property (readwrite, retain, nonatomic) GTMIPhoneUnitTestDelegate *retainer; +@end + @implementation GTMIPhoneUnitTestDelegate +@synthesize retainer = retainer_; + +- (id)init { + if ((self = [super init])) { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(applicationDidFinishLaunching:) + name:UIApplicationDidFinishLaunchingNotification + object:[UIApplication sharedApplication]]; + [self setRetainer:self]; + } + return self; +} + // Run through all the registered classes and run test methods on any // that are subclasses of SenTestCase. Terminate the application upon // test completion. - (void)applicationDidFinishLaunching:(UIApplication *)application { + + // We could get called twice once from our notification registration, and + // once if we actually still are the delegate of the application after + // it has finished launching. So we'll just return if we've been called once. + if (applicationDidFinishLaunchingCalled_) return; + applicationDidFinishLaunchingCalled_ = YES; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self + name:UIApplicationDidFinishLaunchingNotification + object:[UIApplication sharedApplication]]; + [self runTests]; if (!getenv("GTM_DISABLE_TERMINATION")) { @@ -55,6 +95,10 @@ exit(exitStatus); } } + + // Release ourself now that we're done. If we really are the application + // delegate, it will have retained us, so we'll stick around if necessary. + [self setRetainer:nil]; } // Run through all the registered classes and run test methods on any -- cgit v1.2.3