Test.m
author Jens Alfke <jens@mooseyard.com>
Tue May 20 17:40:28 2008 -0700 (2008-05-20)
changeset 10 82a37ccf6b8c
parent 1 e55a17cdabd2
child 11 e5976864dfe9
permissions -rw-r--r--
Split ExceptionUtils out of Test.
jens@0
     1
//
jens@0
     2
//  Test.m
jens@0
     3
//  MYUtilities
jens@0
     4
//
jens@0
     5
//  Created by Jens Alfke on 1/5/08.
jens@0
     6
//  Copyright 2008 Jens Alfke. All rights reserved.
jens@0
     7
//
jens@0
     8
jens@0
     9
#import "Test.h"
jens@10
    10
jens@0
    11
jens@0
    12
#if DEBUG
jens@0
    13
jens@1
    14
BOOL gRunningTestCase;
jens@1
    15
jens@0
    16
struct TestCaseLink *gAllTestCases;
jens@0
    17
static int sPassed, sFailed;
jens@10
    18
static int sCurTestCaseExceptions;
jens@10
    19
jens@10
    20
jens@10
    21
static void TestCaseExceptionReporter( NSException *x ) {
jens@10
    22
    sCurTestCaseExceptions++;
jens@10
    23
    Log(@"XXX FAILED test case -- backtrace:\n%@\n\n", x.my_callStack);
jens@10
    24
}
jens@0
    25
jens@0
    26
static BOOL RunTestCase( struct TestCaseLink *test )
jens@0
    27
{
jens@1
    28
    BOOL oldLogging = EnableLog(YES);
jens@1
    29
    gRunningTestCase = YES;
jens@0
    30
    if( test->testptr ) {
jens@0
    31
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
jens@0
    32
        Log(@"=== Testing %s ...",test->name);
jens@0
    33
        @try{
jens@10
    34
            sCurTestCaseExceptions = 0;
jens@10
    35
            MYSetExceptionReporter(&TestCaseExceptionReporter);
jens@10
    36
jens@10
    37
            test->testptr();    //SHAZAM!
jens@10
    38
            
jens@10
    39
            if( sCurTestCaseExceptions == 0 ) {
jens@10
    40
                Log(@"√√√ %s passed\n\n",test->name);
jens@10
    41
                test->passed = YES;
jens@10
    42
                sPassed++;
jens@10
    43
            } else {
jens@10
    44
                Log(@"XXX FAILED test case '%s' due to %i exception(s) already reported above",
jens@10
    45
                    test->name,sCurTestCaseExceptions);
jens@10
    46
                sFailed++;
jens@10
    47
            }
jens@0
    48
        }@catch( NSException *x ) {
jens@0
    49
            if( [x.name isEqualToString: @"TestCaseSkipped"] )
jens@0
    50
                Log(@"... skipping test %s since %@\n\n", test->name, x.reason);
jens@0
    51
            else {
jens@0
    52
                Log(@"XXX FAILED test case '%s' due to:\nException: %@\n%@\n\n", 
jens@0
    53
                      test->name,x,x.my_callStack);
jens@0
    54
                sFailed++;
jens@0
    55
            }
jens@0
    56
        }@finally{
jens@0
    57
            [pool drain];
jens@0
    58
            test->testptr = NULL;       // prevents test from being run again
jens@0
    59
        }
jens@0
    60
    }
jens@1
    61
    gRunningTestCase = NO;
jens@1
    62
    EnableLog(oldLogging);
jens@0
    63
    return test->passed;
jens@0
    64
}
jens@0
    65
jens@0
    66
jens@0
    67
static BOOL RunTestCaseNamed( const char *name )
jens@0
    68
{
jens@0
    69
    for( struct TestCaseLink *test = gAllTestCases; test; test=test->next )
jens@0
    70
        if( strcmp(name,test->name)==0 ) {
jens@0
    71
            return RunTestCase(test);
jens@0
    72
        }
jens@0
    73
    Log(@"... WARNING: Could not find test case named '%s'\n\n",name);
jens@0
    74
    return NO;
jens@0
    75
}
jens@0
    76
jens@0
    77
jens@0
    78
void _RequireTestCase( const char *name )
jens@0
    79
{
jens@0
    80
    if( ! RunTestCaseNamed(name) ) {
jens@0
    81
        [NSException raise: @"TestCaseSkipped" 
jens@0
    82
                    format: @"prerequisite %s failed", name];
jens@0
    83
    }
jens@0
    84
}
jens@0
    85
jens@0
    86
jens@0
    87
void RunTestCases( int argc, const char **argv )
jens@0
    88
{
jens@0
    89
    sPassed = sFailed = 0;
jens@0
    90
    BOOL stopAfterTests = NO;
jens@0
    91
    for( int i=1; i<argc; i++ ) {
jens@0
    92
        const char *arg = argv[i];
jens@0
    93
        if( strncmp(arg,"Test_",5)==0 ) {
jens@0
    94
            arg += 5;
jens@0
    95
            if( strcmp(arg,"Only")==0 )
jens@0
    96
                stopAfterTests = YES;
jens@0
    97
            else if( strcmp(arg,"All") == 0 ) {
jens@0
    98
                for( struct TestCaseLink *link = gAllTestCases; link; link=link->next )
jens@0
    99
                    RunTestCase(link);
jens@0
   100
            } else {
jens@0
   101
                RunTestCaseNamed(arg);
jens@0
   102
            }
jens@0
   103
        }
jens@0
   104
    }
jens@0
   105
    if( sPassed>0 || sFailed>0 || stopAfterTests ) {
jens@0
   106
        if( sFailed==0 )
jens@0
   107
            Log(@"√√√√√√ ALL %i TESTS PASSED √√√√√√", sPassed);
jens@0
   108
        else {
jens@0
   109
            Log(@"****** %i TESTS FAILED, %i PASSED ******", sFailed,sPassed);
jens@0
   110
            exit(1);
jens@0
   111
        }
jens@0
   112
        if( stopAfterTests ) {
jens@0
   113
            Log(@"Stopping after tests ('Test_Only' arg detected)");
jens@0
   114
            exit(0);
jens@0
   115
        }
jens@0
   116
    }
jens@0
   117
}
jens@0
   118
jens@0
   119
jens@0
   120
#endif DEBUG
jens@0
   121
jens@0
   122
jens@0
   123
#pragma mark -
jens@0
   124
#pragma mark ASSERTION FAILURE HANDLER:
jens@0
   125
jens@0
   126
jens@0
   127
void _AssertFailed( id rcvr, const char *selOrFn, const char *sourceFile, int sourceLine,
jens@0
   128
                    const char *condString, NSString *message, ... )
jens@0
   129
{
jens@0
   130
    if( message ) {
jens@0
   131
        va_list args;
jens@0
   132
        va_start(args,message);
jens@0
   133
        message = [[[NSString alloc] initWithFormat: message arguments: args] autorelease];
jens@0
   134
        va_end(args);
jens@0
   135
    } else
jens@0
   136
        message = [NSString stringWithUTF8String: condString];
jens@0
   137
    
jens@0
   138
    if( rcvr )
jens@0
   139
        [[NSAssertionHandler currentHandler] handleFailureInMethod: (SEL)selOrFn
jens@0
   140
                                                            object: rcvr 
jens@0
   141
                                                              file: [NSString stringWithUTF8String: sourceFile]
jens@0
   142
                                                        lineNumber: sourceLine 
jens@0
   143
                                                       description: @"%@", message];
jens@0
   144
    else
jens@0
   145
        [[NSAssertionHandler currentHandler] handleFailureInFunction: [NSString stringWithUTF8String:selOrFn]
jens@0
   146
                                                                file: [NSString stringWithUTF8String: sourceFile]
jens@0
   147
                                                          lineNumber: sourceLine 
jens@0
   148
                                                         description: @"%@", message];
jens@0
   149
    abort(); // unreachable, but appeases compiler
jens@0
   150
}