Test.m
author Jens Alfke <jens@mooseyard.com>
Sat May 24 13:24:33 2008 -0700 (2008-05-24)
changeset 11 e5976864dfe9
parent 10 82a37ccf6b8c
child 12 66b870428f85
permissions -rw-r--r--
* Added BSD license to more .m files.
* Updated some copyright notices.
* Added some #imports to make the MYNetwork classes build without using the MYUtilities.pch prefix header.
     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 char *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         va_end(args);
   136     } else
   137         message = [NSString stringWithUTF8String: condString];
   138     
   139     if( rcvr )
   140         [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn
   141                                                             object: rcvr 
   142                                                               file: [NSString stringWithUTF8String: sourceFile]
   143                                                         lineNumber: sourceLine 
   144                                                        description: @"%@", message];
   145     else
   146         [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn]
   147                                                                 file: [NSString stringWithUTF8String: sourceFile]
   148                                                           lineNumber: sourceLine 
   149                                                          description: @"%@", message];
   150     abort(); // unreachable, but appeases compiler
   151 }
   152 
   153 
   154 /*
   155  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   156  
   157  Redistribution and use in source and binary forms, with or without modification, are permitted
   158  provided that the following conditions are met:
   159  
   160  * Redistributions of source code must retain the above copyright notice, this list of conditions
   161  and the following disclaimer.
   162  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   163  and the following disclaimer in the documentation and/or other materials provided with the
   164  distribution.
   165  
   166  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   167  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   168  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   169  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   170  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   171   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   172  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   173  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   174  */