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