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