Test.m
author Jens Alfke <jens@mooseyard.com>
Sun Jul 13 10:45:42 2008 -0700 (2008-07-13)
changeset 16 ce9c83f7ec14
parent 12 66b870428f85
child 22 a9da6c5d3f7c
permissions -rw-r--r--
* Minor fixes to glitches detected by the clang static analyzer.
* Added MYAnimatingSplitView class.
     1 //
     2 //  Test.m
     3 //  MYUtilities
     4 //
     5 //  Created by Jens Alfke on 1/5/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "Test.h"
    10 #import "ExceptionUtils.h"
    11 
    12 
    13 #if DEBUG
    14 
    15 BOOL gRunningTestCase;
    16 
    17 struct TestCaseLink *gAllTestCases;
    18 static int sPassed, sFailed;
    19 static int sCurTestCaseExceptions;
    20 
    21 
    22 static void TestCaseExceptionReporter( NSException *x ) {
    23     sCurTestCaseExceptions++;
    24     Log(@"XXX FAILED test case -- backtrace:\n%@\n\n", x.my_callStack);
    25 }
    26 
    27 static BOOL RunTestCase( struct TestCaseLink *test )
    28 {
    29     BOOL oldLogging = EnableLog(YES);
    30     gRunningTestCase = YES;
    31     if( test->testptr ) {
    32         NSAutoreleasePool *pool = [NSAutoreleasePool new];
    33         Log(@"=== Testing %s ...",test->name);
    34         @try{
    35             sCurTestCaseExceptions = 0;
    36             MYSetExceptionReporter(&TestCaseExceptionReporter);
    37 
    38             test->testptr();    //SHAZAM!
    39             
    40             if( sCurTestCaseExceptions == 0 ) {
    41                 Log(@"√√√ %s passed\n\n",test->name);
    42                 test->passed = YES;
    43                 sPassed++;
    44             } else {
    45                 Log(@"XXX FAILED test case '%s' due to %i exception(s) already reported above",
    46                     test->name,sCurTestCaseExceptions);
    47                 sFailed++;
    48             }
    49         }@catch( NSException *x ) {
    50             if( [x.name isEqualToString: @"TestCaseSkipped"] )
    51                 Log(@"... skipping test %s since %@\n\n", test->name, x.reason);
    52             else {
    53                 Log(@"XXX FAILED test case '%s' due to:\nException: %@\n%@\n\n", 
    54                       test->name,x,x.my_callStack);
    55                 sFailed++;
    56             }
    57         }@finally{
    58             [pool drain];
    59             test->testptr = NULL;       // prevents test from being run again
    60         }
    61     }
    62     gRunningTestCase = NO;
    63     EnableLog(oldLogging);
    64     return test->passed;
    65 }
    66 
    67 
    68 static BOOL RunTestCaseNamed( const char *name )
    69 {
    70     for( struct TestCaseLink *test = gAllTestCases; test; test=test->next )
    71         if( strcmp(name,test->name)==0 ) {
    72             return RunTestCase(test);
    73         }
    74     Log(@"... WARNING: Could not find test case named '%s'\n\n",name);
    75     return NO;
    76 }
    77 
    78 
    79 void _RequireTestCase( const char *name )
    80 {
    81     if( ! RunTestCaseNamed(name) ) {
    82         [NSException raise: @"TestCaseSkipped" 
    83                     format: @"prerequisite %s failed", name];
    84     }
    85 }
    86 
    87 
    88 void RunTestCases( int argc, const char **argv )
    89 {
    90     sPassed = sFailed = 0;
    91     BOOL stopAfterTests = NO;
    92     for( int i=1; i<argc; i++ ) {
    93         const char *arg = argv[i];
    94         if( strncmp(arg,"Test_",5)==0 ) {
    95             arg += 5;
    96             if( strcmp(arg,"Only")==0 )
    97                 stopAfterTests = YES;
    98             else if( strcmp(arg,"All") == 0 ) {
    99                 for( struct TestCaseLink *link = gAllTestCases; link; link=link->next )
   100                     RunTestCase(link);
   101             } else {
   102                 RunTestCaseNamed(arg);
   103             }
   104         }
   105     }
   106     if( sPassed>0 || sFailed>0 || stopAfterTests ) {
   107         if( sFailed==0 )
   108             Log(@"√√√√√√ ALL %i TESTS PASSED √√√√√√", sPassed);
   109         else {
   110             Log(@"****** %i TESTS FAILED, %i PASSED ******", sFailed,sPassed);
   111             exit(1);
   112         }
   113         if( stopAfterTests ) {
   114             Log(@"Stopping after tests ('Test_Only' arg detected)");
   115             exit(0);
   116         }
   117     }
   118 }
   119 
   120 
   121 #endif DEBUG
   122 
   123 
   124 #pragma mark -
   125 #pragma mark ASSERTION FAILURE HANDLER:
   126 
   127 
   128 void _AssertFailed( id rcvr, const void *selOrFn, const char *sourceFile, int sourceLine,
   129                     const char *condString, NSString *message, ... )
   130 {
   131     if( message ) {
   132         va_list args;
   133         va_start(args,message);
   134         message = [[[NSString alloc] initWithFormat: message arguments: args] autorelease];
   135         message = [@"Assertion failed: " stringByAppendingString: message];
   136         va_end(args);
   137     } else
   138         message = [NSString stringWithUTF8String: condString];
   139     
   140     if( rcvr )
   141         [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn
   142                                                             object: rcvr 
   143                                                               file: [NSString stringWithUTF8String: sourceFile]
   144                                                         lineNumber: sourceLine 
   145                                                        description: @"%@", message];
   146     else
   147         [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn]
   148                                                                 file: [NSString stringWithUTF8String: sourceFile]
   149                                                           lineNumber: sourceLine 
   150                                                          description: @"%@", message];
   151     abort(); // unreachable, but appeases compiler
   152 }
   153 
   154 
   155 /*
   156  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   157  
   158  Redistribution and use in source and binary forms, with or without modification, are permitted
   159  provided that the following conditions are met:
   160  
   161  * Redistributions of source code must retain the above copyright notice, this list of conditions
   162  and the following disclaimer.
   163  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   164  and the following disclaimer in the documentation and/or other materials provided with the
   165  distribution.
   166  
   167  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   168  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   169  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   170  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   171  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   172   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   173  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   174  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   175  */