jens@0: // jens@0: // Test.m jens@0: // MYUtilities jens@0: // jens@0: // Created by Jens Alfke on 1/5/08. jens@0: // Copyright 2008 Jens Alfke. All rights reserved. jens@0: // jens@0: jens@0: #import "Test.h" jens@11: #import "ExceptionUtils.h" jens@10: jens@0: jens@0: #if DEBUG jens@0: jens@1: BOOL gRunningTestCase; jens@1: jens@0: struct TestCaseLink *gAllTestCases; jens@0: static int sPassed, sFailed; jens@10: static int sCurTestCaseExceptions; jens@10: jens@10: jens@10: static void TestCaseExceptionReporter( NSException *x ) { jens@10: sCurTestCaseExceptions++; snej@22: fflush(stderr); jens@10: Log(@"XXX FAILED test case -- backtrace:\n%@\n\n", x.my_callStack); jens@10: } jens@0: jens@0: static BOOL RunTestCase( struct TestCaseLink *test ) jens@0: { jens@1: BOOL oldLogging = EnableLog(YES); jens@1: gRunningTestCase = YES; jens@0: if( test->testptr ) { jens@0: NSAutoreleasePool *pool = [NSAutoreleasePool new]; jens@0: Log(@"=== Testing %s ...",test->name); jens@0: @try{ jens@10: sCurTestCaseExceptions = 0; jens@10: MYSetExceptionReporter(&TestCaseExceptionReporter); jens@10: jens@10: test->testptr(); //SHAZAM! jens@10: jens@10: if( sCurTestCaseExceptions == 0 ) { jens@10: Log(@"√√√ %s passed\n\n",test->name); jens@10: test->passed = YES; jens@10: sPassed++; jens@10: } else { jens@10: Log(@"XXX FAILED test case '%s' due to %i exception(s) already reported above", jens@10: test->name,sCurTestCaseExceptions); jens@10: sFailed++; jens@10: } jens@0: }@catch( NSException *x ) { jens@0: if( [x.name isEqualToString: @"TestCaseSkipped"] ) jens@0: Log(@"... skipping test %s since %@\n\n", test->name, x.reason); jens@0: else { snej@22: fflush(stderr); jens@0: Log(@"XXX FAILED test case '%s' due to:\nException: %@\n%@\n\n", jens@0: test->name,x,x.my_callStack); jens@0: sFailed++; jens@0: } jens@0: }@finally{ jens@0: [pool drain]; jens@0: test->testptr = NULL; // prevents test from being run again jens@0: } jens@0: } jens@1: gRunningTestCase = NO; jens@1: EnableLog(oldLogging); jens@0: return test->passed; jens@0: } jens@0: jens@0: jens@0: static BOOL RunTestCaseNamed( const char *name ) jens@0: { jens@0: for( struct TestCaseLink *test = gAllTestCases; test; test=test->next ) jens@0: if( strcmp(name,test->name)==0 ) { jens@0: return RunTestCase(test); jens@0: } jens@0: Log(@"... WARNING: Could not find test case named '%s'\n\n",name); jens@0: return NO; jens@0: } jens@0: jens@0: jens@0: void _RequireTestCase( const char *name ) jens@0: { jens@0: if( ! RunTestCaseNamed(name) ) { jens@0: [NSException raise: @"TestCaseSkipped" jens@0: format: @"prerequisite %s failed", name]; jens@0: } jens@0: } jens@0: jens@0: jens@0: void RunTestCases( int argc, const char **argv ) jens@0: { jens@0: sPassed = sFailed = 0; jens@0: BOOL stopAfterTests = NO; jens@0: for( int i=1; inext ) jens@0: RunTestCase(link); jens@0: } else { jens@0: RunTestCaseNamed(arg); jens@0: } jens@0: } jens@0: } jens@0: if( sPassed>0 || sFailed>0 || stopAfterTests ) { jens@0: if( sFailed==0 ) snej@23: AlwaysLog(@"√√√√√√ ALL %i TESTS PASSED √√√√√√", sPassed); jens@0: else { snej@23: Warn(@"****** %i TESTS FAILED, %i PASSED ******", sFailed,sPassed); jens@0: exit(1); jens@0: } jens@0: if( stopAfterTests ) { jens@0: Log(@"Stopping after tests ('Test_Only' arg detected)"); jens@0: exit(0); jens@0: } jens@0: } jens@0: } jens@0: jens@0: jens@0: #endif DEBUG jens@0: jens@0: jens@0: #pragma mark - jens@0: #pragma mark ASSERTION FAILURE HANDLER: jens@0: jens@0: jens@12: void _AssertFailed( id rcvr, const void *selOrFn, const char *sourceFile, int sourceLine, jens@0: const char *condString, NSString *message, ... ) jens@0: { jens@0: if( message ) { jens@0: va_list args; jens@0: va_start(args,message); jens@0: message = [[[NSString alloc] initWithFormat: message arguments: args] autorelease]; jens@16: message = [@"Assertion failed: " stringByAppendingString: message]; jens@0: va_end(args); jens@0: } else jens@0: message = [NSString stringWithUTF8String: condString]; jens@0: jens@0: if( rcvr ) jens@0: [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn jens@0: object: rcvr jens@0: file: [NSString stringWithUTF8String: sourceFile] jens@0: lineNumber: sourceLine jens@0: description: @"%@", message]; jens@0: else jens@0: [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn] jens@0: file: [NSString stringWithUTF8String: sourceFile] jens@0: lineNumber: sourceLine jens@0: description: @"%@", message]; jens@0: abort(); // unreachable, but appeases compiler jens@0: } jens@11: jens@11: snej@22: void _AssertAbstractMethodFailed( id rcvr, SEL cmd) snej@22: { snej@22: [NSException raise: NSInternalInconsistencyException snej@22: format: @"Class %@ forgot to implement abstract method %@", snej@22: [rcvr class], NSStringFromSelector(cmd)]; snej@22: abort(); // unreachable, but appeases compiler snej@22: } snej@22: snej@22: jens@11: /* jens@11: Copyright (c) 2008, Jens Alfke . All rights reserved. jens@11: jens@11: Redistribution and use in source and binary forms, with or without modification, are permitted jens@11: provided that the following conditions are met: jens@11: jens@11: * Redistributions of source code must retain the above copyright notice, this list of conditions jens@11: and the following disclaimer. jens@11: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions jens@11: and the following disclaimer in the documentation and/or other materials provided with the jens@11: distribution. jens@11: jens@11: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR jens@11: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND jens@11: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- jens@11: BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES jens@11: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jens@11: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN jens@11: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF jens@11: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jens@11: */