Test.h
author Jens Alfke <jens@mooseyard.com>
Sat May 31 11:26:17 2008 -0700 (2008-05-31)
changeset 12 66b870428f85
parent 11 e5976864dfe9
child 13 c59dec088990
permissions -rw-r--r--
* Worked around compiler warnings in Test.h when building for iPhone.
* Made Mercurial ignore the documentation files.
jens@0
     1
//
jens@0
     2
//  Test.h
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 <Foundation/Foundation.h>
jens@0
    10
#import "CollectionUtils.h"
jens@9
    11
#import "Logging.h"
jens@0
    12
jens@0
    13
jens@0
    14
/** Call this first thing in main() to run tests.
jens@0
    15
    This function is a no-op if the DEBUG macro is not defined (i.e. in a release build).
jens@0
    16
    At runtime, to cause a particular test "X" to run, add a command-line argument "Test_X".
jens@0
    17
    To run all tests, add the argument "Test_All".
jens@0
    18
    To run only tests without starting the main program, add the argument "Test_Only". */
jens@0
    19
#if DEBUG
jens@0
    20
void RunTestCases( int argc, const char **argv );
jens@1
    21
extern BOOL gRunningTestCase;
jens@0
    22
#else
jens@0
    23
#define RunTestCases(ARGC,ARGV)
jens@1
    24
#define gRunningTestCase NO
jens@0
    25
#endif
jens@0
    26
jens@0
    27
/** The TestCase() macro declares a test case.
jens@0
    28
    Its argument is a name for the test case (without quotes), and it's followed with a block
jens@0
    29
    of code implementing the test.
jens@0
    30
    The code should raise an exception if anything fails.
jens@0
    31
    The CAssert, CAssertEqual and CAssertEq macros, below, are the most useful way to do this.
jens@0
    32
    A test case can register a dependency on another test case by calling RequireTestCase().
jens@0
    33
    Example:
jens@0
    34
        TestCase(MyLib) {
jens@0
    35
            RequireTestCase("LibIDependOn");
jens@0
    36
            CAssertEq( myFunction(), 12345 );
jens@0
    37
        }
jens@0
    38
    Test cases are disabled if the DEBUG macro is not defined (i.e. in a release build). */
jens@0
    39
#if DEBUG
jens@9
    40
#define TestCase(NAME)      __attribute__ ((section ("__TEXT, Tests"))) void Test_##NAME(void); \
jens@0
    41
                            struct TestCaseLink linkToTest##NAME = {&Test_##NAME,#NAME}; \
jens@0
    42
                            __attribute__((constructor)) static void registerTestCase##NAME() \
jens@0
    43
                                {linkToTest##NAME.next = gAllTestCases; gAllTestCases=&linkToTest##NAME; } \
jens@0
    44
                            void Test_##NAME(void)
jens@0
    45
#else
jens@0
    46
#define TestCase(NAME)      __attribute__((unused)) static void Test_##NAME(void)
jens@0
    47
#endif
jens@0
    48
jens@0
    49
/** Can call this in a test case to indicate a prerequisite.
jens@0
    50
    The prerequisite test will be run first, and if it fails, the current test case will be skipped. */
jens@11
    51
#if DEBUG
jens@0
    52
#define RequireTestCase(NAME)   _RequireTestCase(#NAME)
jens@0
    53
void _RequireTestCase( const char *name );
jens@11
    54
#else
jens@11
    55
#define RequireTestCase(NAME)
jens@11
    56
#endif
jens@0
    57
jens@0
    58
jens@0
    59
/** General-purpose assertions, replacing NSAssert etc.. You can use these outside test cases. */
jens@0
    60
jens@9
    61
#define Assert(COND,MSG...)    do{ if( __builtin_expect(!(COND),NO) ) { \
jens@12
    62
                                    IN_SEGMENT_NORETURN(Logging) {_AssertFailed(self,_cmd, __FILE__, __LINE__,\
jens@9
    63
                                                        #COND,##MSG,NULL);} } }while(0)
jens@9
    64
#define CAssert(COND,MSG...)    do{ if( __builtin_expect(!(COND),NO) ) { \
jens@9
    65
                                    static const char *_name = __PRETTY_FUNCTION__;\
jens@9
    66
                                    IN_SEGMENT_NORETURN(Logging) {_AssertFailed(nil, _name, __FILE__, __LINE__,\
jens@9
    67
                                                        #COND,##MSG,NULL);} } }while(0)
jens@0
    68
jens@0
    69
#define AssertEqual(VAL,EXPECTED)   do{ id _val = VAL, _expected = EXPECTED;\
jens@0
    70
                                        Assert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \
jens@0
    71
                                    }while(0)
jens@0
    72
#define CAssertEqual(VAL,EXPECTED)  do{ id _val = (VAL), _expected = (EXPECTED);\
jens@0
    73
                                        CAssert(_val==_expected || [_val isEqual: _expected], @"Unexpected value for %s: %@ (expected %@)", #VAL,_val,_expected); \
jens@0
    74
                                    }while(0)
jens@0
    75
jens@0
    76
// AssertEq is for scalars (int, float...)
jens@11
    77
// Note: "typeof()" builtin function requires settingn C language dialect to GNU99.
jens@0
    78
#define AssertEq(VAL,EXPECTED)  do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\
jens@0
    79
                                    Assert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \
jens@0
    80
                                }while(0)
jens@0
    81
#define CAssertEq(VAL,EXPECTED) do{ typeof(VAL) _val = VAL; typeof(EXPECTED) _expected = EXPECTED;\
jens@0
    82
                                    CAssert(_val==_expected, @"Unexpected value for %s: %@ (expected %@)", #VAL,$object(_val),$object(_expected)); \
jens@0
    83
                                }while(0)
jens@0
    84
jens@0
    85
jens@0
    86
// Nasty internals ...
jens@0
    87
#if DEBUG
jens@0
    88
void _RunTestCase( void (*testptr)(), const char *name );
jens@0
    89
jens@0
    90
struct TestCaseLink {void (*testptr)(); const char *name; BOOL passed; struct TestCaseLink *next;};
jens@0
    91
extern struct TestCaseLink *gAllTestCases;
jens@0
    92
#endif DEBUG
jens@12
    93
void _AssertFailed( id rcvr, const void *selOrFn, const char *sourceFile, int sourceLine,
jens@0
    94
                   const char *condString, NSString *message, ... ) __attribute__((noreturn));