Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: d3f87a062e
Fetching contributors…

Cannot retrieve contributors at this time

359 lines (310 sloc) 11.44 kB
//
// GTMSenTestCase.m
//
// Copyright 2007-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 "GTMSenTestCase.h"
#import <unistd.h>
//#if !GTM_IPHONE_SDK
//#import "GTMGarbageCollection.h"
//#endif // !GTM_IPHONE_SDK
#if GTM_IPHONE_SDK
#import <stdarg.h>
@interface NSException (GTMSenTestPrivateAdditions)
+ (NSException *)failureInFile:(NSString *)filename
atLine:(int)lineNumber
reason:(NSString *)reason;
@end
@implementation NSException (GTMSenTestPrivateAdditions)
+ (NSException *)failureInFile:(NSString *)filename
atLine:(int)lineNumber
reason:(NSString *)reason {
NSDictionary *userInfo =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey,
filename, SenTestFilenameKey,
nil];
return [self exceptionWithName:SenTestFailureException
reason:reason
userInfo:userInfo];
}
@end
@implementation NSException (GTMSenTestAdditions)
+ (NSException *)failureInFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason = testDescription;
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
+ (NSException *)failureInCondition:(NSString *)condition
isTrue:(BOOL)isTrue
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
condition, isTrue ? "TRUE" : "FALSE", testDescription];
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
+ (NSException *)failureInEqualityBetweenObject:(id)left
andObject:(id)right
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason =
[NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
[left description], [right description], testDescription];
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left
andValue:(NSValue *)right
withAccuracy:(NSValue *)accuracy
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason;
if (accuracy) {
reason =
[NSString stringWithFormat:@"'%@' should be equal to '%@'. %@",
left, right, testDescription];
} else {
reason =
[NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@",
left, right, accuracy, testDescription];
}
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
+ (NSException *)failureInRaise:(NSString *)expression
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@",
expression, testDescription];
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
+ (NSException *)failureInRaise:(NSString *)expression
exception:(NSException *)exception
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ... {
NSString *testDescription = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
testDescription =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
NSString *reason;
if ([[exception name] isEqualToString:SenTestFailureException]) {
// it's our exception, assume it has the right description on it.
reason = [exception reason];
} else {
// not one of our exception, use the exceptions reason and our description
reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@",
expression, [exception reason], testDescription];
}
return [self failureInFile:filename atLine:lineNumber reason:reason];
}
@end
NSString *STComposeString(NSString *formatString, ...) {
NSString *reason = @"";
if (formatString) {
va_list vl;
va_start(vl, formatString);
reason =
[[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease];
va_end(vl);
}
return reason;
}
NSString *const SenTestFailureException = @"SenTestFailureException";
NSString *const SenTestFilenameKey = @"SenTestFilenameKey";
NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
@interface SenTestCase (SenTestCasePrivate)
// our method of logging errors
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name;
@end
@implementation SenTestCase
- (void)failWithException:(NSException*)exception {
[exception raise];
}
- (void)setUp {
}
- (void)performTest:(SEL)sel {
currentSelector_ = sel;
@try {
[self invokeTest];
} @catch (NSException *exception) {
[[self class] printException:exception
fromTestName:NSStringFromSelector(sel)];
[exception raise];
}
}
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name {
NSDictionary *userInfo = [exception userInfo];
NSString *filename = [userInfo objectForKey:SenTestFilenameKey];
NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey];
NSString *className = NSStringFromClass([self class]);
if ([filename length] == 0) {
filename = @"Unknown.m";
}
fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n",
[filename UTF8String],
(long)[lineNumber integerValue],
[className UTF8String],
[name UTF8String],
[[exception reason] UTF8String]);
fflush(stderr);
}
- (void)invokeTest {
NSException *e = nil;
@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];
// We don't log exceptions here, instead we let the person that called
// this log the exception. This ensures they are only logged once but the
// outer layers get the exceptions to report counts, etc.
@try {
// For internal setup
if ([self respondsToSelector:@selector(_setUp)]) [self _setUp];
[self setUp];
@try {
[self performSelector:currentSelector_];
} @catch (NSException *exception) {
e = [exception retain];
}
[self tearDown];
} @catch (NSException *exception) {
e = [exception retain];
}
[pool release];
} @catch (NSException *exception) {
e = [exception retain];
}
if (e) {
[e autorelease];
[e raise];
}
}
- (void)tearDown {
}
@end
#endif // GTM_IPHONE_SDK
@implementation GTMTestCase : SenTestCase
- (void)invokeTest {
Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");
if (devLogClass) {
[devLogClass performSelector:@selector(enableTracking)];
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
}
[super invokeTest];
if (devLogClass) {
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
[devLogClass performSelector:@selector(disableTracking)];
}
}
@end
// Leak detection
#if !GTM_IPHONE_DEVICE
// Don't want to get leaks on the iPhone Device as the device doesn't
// have 'leaks'. The simulator does though.
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];
}
}
NSString *string
= [NSString stringWithFormat:@"/usr/bin/leaks %@%d"
@"| /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",
__FILE__, __LINE__, ret);
fflush(stderr);
}
}
static __attribute__((constructor)) void _GTMInstallLeaks(void) {
BOOL checkLeaks = YES;
//#if !GTM_IPHONE_SDK
// checkLeaks = GTMIsGarbageCollectionEnabled() ? NO : YES;
//#endif // !GTM_IPHONE_SDK
if (checkLeaks) {
checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO;
if (checkLeaks) {
if (checkLeaks) {
fprintf(stderr, "Leak Checking Enabled\n");
fflush(stderr);
int ret = atexit(&_GTMRunLeaks);
_GTMDevAssert(ret == 0,
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
errno);
}
}
}
}
#endif // !GTM_IPHONE_DEVICE
Jump to Line
Something went wrong with that request. Please try again.