aboutsummaryrefslogtreecommitdiff
path: root/UnitTesting/GTMIPhoneUnitTestMain.m
diff options
context:
space:
mode:
Diffstat (limited to 'UnitTesting/GTMIPhoneUnitTestMain.m')
-rwxr-xr-xUnitTesting/GTMIPhoneUnitTestMain.m181
1 files changed, 181 insertions, 0 deletions
diff --git a/UnitTesting/GTMIPhoneUnitTestMain.m b/UnitTesting/GTMIPhoneUnitTestMain.m
new file mode 100755
index 0000000..2af060b
--- /dev/null
+++ b/UnitTesting/GTMIPhoneUnitTestMain.m
@@ -0,0 +1,181 @@
+//
+// GTMIPhoneUnitTestMain.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 "GTMDefines.h"
+#if !GTM_IPHONE_SDK
+ #error GTMIPhoneUnitTestMain for iPhone only
+#endif
+#import <objc/runtime.h>
+#import <stdio.h>
+#import <UIKit/UIKit.h>
+#import "GTMSenTestCase.h"
+
+// Used for sorting methods below
+static int MethodSort(const void *a, const void *b) {
+ const char *nameA = sel_getName(method_getName(*(Method*)a));
+ const char *nameB = sel_getName(method_getName(*(Method*)b));
+ return strcmp(nameA, nameB);
+}
+
+@interface UIApplication (iPhoneUnitTestAdditions)
+// "Private" method that we need
+- (void)terminate;
+@end
+
+@interface GTMIPhoneUnitTestDelegate : NSObject
+@end
+
+@implementation GTMIPhoneUnitTestDelegate
+
+// Return YES if class is subclass (1 or more generations) of SenTestCase
+- (BOOL)isTestFixture:(Class)class {
+ BOOL iscase = NO;
+ Class testCaseClass = [SenTestCase class];
+ Class superclass;
+ for (superclass = class;
+ !iscase && superclass;
+ superclass = class_getSuperclass(superclass)) {
+ iscase = superclass == testCaseClass ? YES : NO;
+ }
+ return iscase;
+}
+
+// Log an error out to console in a way that Xcode will recognize it.
+- (void)printError:(NSString *)error {
+ if ([error rangeOfString:@"error:"].location == NSNotFound) {
+ fprintf(stderr, "error: %s\n", [error UTF8String]);
+ } else {
+ fprintf(stderr, "%s\n", [error UTF8String]);
+ }
+ fflush(stderr);
+}
+
+// Run through all the registered classes and run test methods on any
+// that are subclasses of SenTestCase.
+- (void)applicationDidFinishLaunching:(UIApplication *)application {
+ int count = objc_getClassList(NULL, 0);
+ Class *classes = (Class*)malloc(sizeof(Class) * count);
+ _GTMDevAssert(classes, @"Couldn't allocate class list");
+ objc_getClassList(classes, count);
+ int suiteSuccesses = 0;
+ int suiteFailures = 0;
+ int suiteTotal = 0;
+ NSString *suiteName = [[NSBundle mainBundle] bundlePath];
+ NSDate *suiteStartDate = [NSDate date];
+ NSString *suiteStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n",
+ suiteName, suiteStartDate];
+ fprintf(stderr, [suiteStartString UTF8String]);
+ fflush(stderr);
+ int i, j;
+ for (i = 0; i < count; ++i) {
+ Class currClass = classes[i];
+ if ([self isTestFixture:currClass]) {
+ NSDate *fixtureStartDate = [NSDate date];
+ NSString *fixtureName = NSStringFromClass(currClass);
+ NSString *fixtureStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n",
+ fixtureName, fixtureStartDate];
+ int fixtureSuccesses = 0;
+ int fixtureFailures = 0;
+ int fixtureTotal = 0;
+ fprintf(stderr, [fixtureStartString UTF8String]);
+ fflush(stderr);
+ id testcase = [[currClass alloc] init];
+ _GTMDevAssert(testcase, @"Unable to instantiate Test Suite: '%@'\n",
+ fixtureName);
+ unsigned int methodCount;
+ Method *methods = class_copyMethodList(currClass, &methodCount);
+ // Sort our methods so they are called in Alphabetical order just
+ // because we can.
+ qsort(methods, methodCount, sizeof(Method), MethodSort);
+ for (j = 0; j < methodCount; ++j) {
+ Method currMethod = methods[j];
+ SEL sel = method_getName(currMethod);
+ const char *name = sel_getName(sel);
+ // If it starts with test, run it.
+ if (strstr(name, "test") == name) {
+ fixtureTotal += 1;
+ NSDate *caseStartDate = [NSDate date];
+ BOOL failed = NO;
+ @try {
+ // Wrap things in autorelease pools because they may
+ // have an STMacro in their dealloc which may get called
+ // when the pool is cleaned up
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ @try {
+ [testcase setUp];
+ [testcase performSelector:sel];
+ [testcase tearDown];
+ fixtureSuccesses += 1;
+ } @catch (NSException *exception) {
+ fixtureFailures += 1;
+ failed = YES;
+ [self printError:[exception reason]];
+ }
+ [pool release];
+ } @catch (NSException *exception) {
+ fixtureFailures += 1;
+ failed = YES;
+ [self printError:[exception reason]];
+ }
+ NSTimeInterval caseEndTime = [[NSDate date] timeIntervalSinceDate:caseStartDate];
+ NSString *caseEndString = [NSString stringWithFormat:@"Test Case '-[%@ %s]' %s (%0.3f seconds).\n",
+ fixtureName, name,
+ failed ? "failed" : "passed", caseEndTime];
+ fprintf(stderr, [caseEndString UTF8String]);
+ fflush(stderr);
+ }
+ }
+ if (methods) {
+ free(methods);
+ }
+ [testcase release];
+ NSDate *fixtureEndDate = [NSDate date];
+ NSTimeInterval fixtureEndTime = [fixtureEndDate timeIntervalSinceDate:fixtureStartDate];
+ NSString *fixtureEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n"
+ "Executed %d tests, with %d failures (%d unexpected) in %0.3f seconds\n",
+ fixtureName, fixtureEndDate, fixtureTotal,
+ fixtureFailures, fixtureFailures, fixtureEndTime];
+
+ fprintf(stderr, [fixtureEndString UTF8String]);
+ fflush(stderr);
+ suiteTotal += fixtureTotal;
+ suiteSuccesses += fixtureSuccesses;
+ suiteFailures += fixtureFailures;
+ }
+ }
+ NSDate *suiteEndDate = [NSDate date];
+ NSTimeInterval suiteEndTime = [suiteEndDate timeIntervalSinceDate:suiteStartDate];
+ NSString *suiteEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n"
+ "Executed %d tests, with %d failures (%d unexpected) in %0.3f seconds\n",
+ suiteName, suiteEndDate, suiteTotal,
+ suiteFailures, suiteFailures, suiteEndTime];
+ fprintf(stderr, [suiteEndString UTF8String]);
+ fflush(stderr);
+
+ // Using private call to end our tests
+ [[UIApplication sharedApplication] terminate];
+}
+
+@end
+
+int main(int argc, char *argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int retVal = UIApplicationMain(argc, argv, nil, @"GTMIPhoneUnitTestDelegate");
+ [pool release];
+ return retVal;
+}