Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
161 lines (150 sloc) 6.14 KB
//
// GTMIPhoneUnitTestDelegate.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 "GTMIPhoneUnitTestDelegate.h"
#import "GTMDefines.h"
#if !GTM_IPHONE_SDK
#error GTMIPhoneUnitTestDelegate 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
@implementation GTMIPhoneUnitTestDelegate
// Return YES if class is subclass (1 or more generations) of SenTestCase
- (BOOL)isTestFixture:(Class)aClass {
BOOL iscase = NO;
Class testCaseClass = [SenTestCase class];
Class superclass;
for (superclass = aClass;
!iscase && superclass;
superclass = class_getSuperclass(superclass)) {
iscase = superclass == testCaseClass ? YES : NO;
}
return iscase;
}
// 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 {
[self runTests];
// Using private call to end our tests
[[UIApplication sharedApplication] terminate];
}
// Run through all the registered classes and run test methods on any
// that are subclasses of SenTestCase. Print results and run time to
// the default output.
- (void)runTests {
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];
fputs([suiteStartString UTF8String], stderr);
fflush(stderr);
for (int 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;
fputs([fixtureStartString UTF8String], stderr);
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 (size_t 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;
BOOL failed = NO;
NSDate *caseStartDate = [NSDate date];
@try {
[testcase performTest:sel];
} @catch (NSException *exception) {
failed = YES;
}
if (failed) {
fixtureFailures += 1;
} else {
fixtureSuccesses += 1;
}
NSTimeInterval caseEndTime = [[NSDate date] timeIntervalSinceDate:caseStartDate];
NSString *caseEndString = [NSString stringWithFormat:@"Test Case '-[%@ %s]' %s (%0.3f seconds).\n",
fixtureName, name,
failed ? "failed" : "passed", caseEndTime];
fputs([caseEndString UTF8String], stderr);
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 (%0.3f) seconds\n",
fixtureName, fixtureEndDate, fixtureTotal,
fixtureFailures, fixtureFailures,
fixtureEndTime, fixtureEndTime];
fputs([fixtureEndString UTF8String], stderr);
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 (%0.3f) seconds\n",
suiteName, suiteEndDate, suiteTotal,
suiteFailures, suiteFailures,
suiteEndTime, suiteEndTime];
fputs([suiteEndString UTF8String], stderr);
fflush(stderr);
}
@end