Line data Source code
1 : /* fd_unit_test.c helps with writing unit tests. 2 : 3 : Usage: 4 : 5 : FD_UNIT_TEST( foo ) { ... } 6 : FD_UNIT_TEST( bar ) { ... } 7 : 8 : #include "fd_unit_test.c" 9 : 10 : void main() { fd_unit_tests( argc, argv ); } 11 : 12 : Then run: ./my_test bar 13 : (Only runs tests matching the string 'bar') */ 14 : 15 : #include "../log/fd_log.h" 16 : #include <string.h> 17 : 18 : struct fd_unit_test { 19 : char const * name; 20 : void (* fn)( void ); 21 : struct fd_unit_test * next; 22 : }; 23 : 24 : typedef struct fd_unit_test fd_unit_test_t; 25 : 26 : /* Linked list of known unit tests */ 27 : static fd_unit_test_t * fd_unit_test_head = NULL; 28 : static fd_unit_test_t * fd_unit_test_tail = NULL; 29 : 30 : static inline void 31 0 : register_unit_test( fd_unit_test_t * test ) { 32 0 : if( fd_unit_test_tail ) fd_unit_test_tail->next = test; 33 0 : else fd_unit_test_head = test; 34 0 : fd_unit_test_tail = test; 35 0 : } 36 : 37 : static inline int 38 : match_test_name( char const * test_name, 39 : int argc, 40 0 : char ** argv ) { 41 0 : if( argc<=1 ) return 1; 42 0 : for( int i=1; i<argc; i++ ) { 43 0 : if( argv[ i ][ strspn( argv[ i ], " \t\n\r" ) ]=='\0' ) continue; 44 0 : if( strstr( test_name, argv[ i ] ) ) return 1; 45 0 : } 46 0 : return 0; 47 0 : } 48 : 49 : #define FD_UNIT_TEST( name ) \ 50 : static void name( void ); \ 51 : static fd_unit_test_t name##_test = { #name, name, NULL }; \ 52 0 : __attribute__((constructor)) static void register_##name( void ) { register_unit_test( &name##_test ); } \ 53 : static void name( void ) 54 : 55 : static inline void 56 : fd_unit_tests( int argc, 57 0 : char ** argv ) { 58 : /* The unit test runner passes workspace options to every test. Strip 59 : unused options so their values do not become test name filters. */ 60 0 : int filter_argc = argc>0; 61 0 : for( int i=1; i<argc; i++ ) { 62 0 : char * arg = argv[ i ]; 63 0 : if( !strcmp( arg, "--numa-idx" ) || !strcmp( arg, "--page-cnt" ) || !strcmp( arg, "--page-sz" ) ) { 64 0 : if( FD_UNLIKELY( i+1>=argc || !strncmp( argv[ i+1 ], "--", 2UL ) ) ) { 65 0 : FD_LOG_ERR(( "missing value for %s", arg )); 66 0 : } 67 0 : i++; 68 0 : } else { 69 0 : if( FD_UNLIKELY( !strncmp( arg, "--", 2UL ) ) ) FD_LOG_ERR(( "unrecognized argument %s", arg )); 70 0 : argv[ filter_argc++ ] = arg; 71 0 : } 72 0 : } 73 0 : argv[ filter_argc ] = NULL; 74 : 75 0 : for( fd_unit_test_t * tc = fd_unit_test_head; tc; tc = tc->next ) { 76 0 : if( match_test_name( tc->name, filter_argc, argv ) ) { 77 0 : FD_LOG_NOTICE(( "Running %s", tc->name )); 78 0 : tc->fn(); 79 0 : } 80 0 : } 81 0 : }