Simple XUnit test library / objects in plain C Snapshot
vtest.c
Go to the documentation of this file.
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */
00002 
00003 
00004 
00005 #include "vtest.h"
00006 #include "vtestrunner.h"
00007 #include <string.h>
00008 #include <malloc.h>
00009 
00010 #ifdef WIN32
00011 #include <windows.h>
00012 #endif
00013 
00014 
00015 /**
00016 
00017  @mainpage
00018 
00019  All this is a very small XUnit type testing framework.
00020 
00021  Usage is explained in example file
00022 
00023  @example example.c
00024 */
00025 
00026 VTEST_RUNNER_IMPL * vtest_impl;
00027 static char *g_suite_name;
00028 
00029 #ifdef WIN32
00030 
00031 typedef BOOL (WINAPI *PIsDebuggerPresent)(void);
00032 
00033 BOOL DynIsDebuggerPresent(void)
00034 {
00035         PIsDebuggerPresent isDeb;
00036         CHAR K32Path[ MAX_PATH ];
00037         HINSTANCE hK32;
00038         BOOL Rc;
00039 
00040         Rc = FALSE;
00041         GetSystemDirectory( K32Path, MAX_PATH );
00042         strcat(K32Path,"\\");
00043         strcat( K32Path, "KERNEL32.DLL" );
00044 
00045         hK32 = LoadLibrary( K32Path );
00046         if( hK32 != NULL ) {
00047                 isDeb = (PIsDebuggerPresent) GetProcAddress(hK32,"IsDebuggerPresent");
00048                 if(isDeb != NULL) {
00049                         Rc = isDeb();
00050                 }
00051                 FreeLibrary( hK32 );
00052         }
00053 
00054         return Rc;
00055 }
00056 #endif
00057 
00058 void VFAIL(const char *cond, const char *file,int line)
00059 {
00060         vtest_impl->results( vtest_impl->scope_fail, 
00061                                                  vtest_impl->suite->name, 
00062                                                  vtest_impl->test ? vtest_impl->test->name : 0,
00063                                                  0, 
00064                                                  cond, file, line);
00065 
00066         vtest_impl->current_test_state = 0;
00067 
00068 #ifdef WIN32
00069         if (DynIsDebuggerPresent()) {
00070                 DebugBreak();   
00071         }
00072 #endif
00073 
00074 }
00075 
00076 
00077 static int parse_suite_name(const char *line, char **suite_name,int *len)
00078 {
00079         const char *tmp = line;
00080         char *next;
00081         
00082         *suite_name = (char *) line;
00083         next = strchr(tmp,'/');
00084 
00085         if (next) {
00086                 *len = next - tmp;
00087         } else {
00088                 *len = strlen(line);
00089         }
00090 
00091         return 1;
00092 
00093 }
00094 
00095 static int parse_next_test_name(const char *line, char **test_name, int *len, char **last_pos)
00096 {
00097         const char *next;
00098 
00099         if (*last_pos == 0) {
00100                 *last_pos = strchr(line,'/');
00101                 if (*last_pos == 0) {
00102                         return 0;
00103                 }
00104                 *last_pos += 1;
00105         } else {
00106                 if (**last_pos != ',') {
00107                         return 0;
00108                 }
00109                 *last_pos = *last_pos + 1;
00110         }
00111 
00112         if (**last_pos == '\0') {
00113                 return 0;
00114         }
00115 
00116         next = strchr( *last_pos, ',');
00117 
00118         *test_name = *last_pos;
00119         if (next) {
00120                 *len = next - *last_pos;
00121         } else {
00122                 *len = strlen(*last_pos);
00123                 next = *last_pos + *len;
00124         }
00125         *last_pos = (char *) next;
00126         return 1;
00127 }
00128 
00129 
00130 /* do we run the given suite, given the current command line */
00131 static int VTEST_is_run_suite(const char *suite_name, char *argv[], int argc)
00132 {
00133         int i;
00134         char *tmp_suite_name;
00135         int suite_name_len;
00136         
00137         if (!argv || !argc) {
00138                 return 1;
00139         }
00140 
00141         for(i = 0; i < argc; i++) {
00142                 
00143                 if (parse_suite_name(argv[i],&tmp_suite_name, &suite_name_len)) {
00144                         if (strlen(suite_name) == (size_t) suite_name_len) {
00145                                 if (memcmp(suite_name, tmp_suite_name, suite_name_len) == 0) {
00146                                         return 1;
00147                                 }                       
00148                         }
00149                 }
00150 
00151         }
00152 
00153         return 0;
00154 }
00155 
00156 /* do we run the given test, given the current command line */
00157 static int VTEST_is_run_test(const char *suite_name, const char *test_name,  char *argv[],int argc)
00158 {
00159         char *last_pos, *tstname, *tmp_suite_name;
00160         int tstlen, i, is_suite, suite_name_len, test_count;
00161 
00162         if (!argv || !argc) {
00163                 return 1;
00164         }
00165 
00166         for(i = 0; i < argc; i++) {
00167 
00168                 is_suite = 0;
00169                 if (parse_suite_name(argv[i],&tmp_suite_name, &suite_name_len)) {
00170                         if (strlen(suite_name) == (size_t) suite_name_len) {
00171                                 if (memcmp(suite_name, tmp_suite_name, suite_name_len) == 0) {
00172                                         is_suite = 1;
00173                                 }                       
00174                         }
00175                 }
00176 
00177                 if (!is_suite) {
00178                         continue;
00179                 }
00180 
00181                 for( test_count = 0, last_pos = 0; parse_next_test_name(argv[i],&tstname,&tstlen,&last_pos); test_count += 1 ) {
00182                         if (strlen(test_name) == (size_t) tstlen) {
00183                                 if (memcmp(test_name, tstname, tstlen) == 0) {
00184                                         return 1;
00185                                 }
00186                         }
00187                 }
00188 
00189                 if (!test_count) {
00190                         return 1;
00191                 }
00192         
00193         }
00194         return 0;
00195 }
00196 
00197 
00198 
00199 void VTEST_goto_next_suite(const char *suite_name)
00200 {
00201         if (suite_name) {
00202                 g_suite_name = strdup(suite_name);
00203         }
00204 }
00205 
00206 static VTEST_TEST_SUITE *find_suite_by_name(VTEST_TEST_SUITE *first_suite, const char *suite_name)
00207 {
00208 
00209         for( ;first_suite; first_suite = first_suite->next_suite ) {
00210 
00211                 if (strcmp( first_suite->name, suite_name) == 0) {
00212                         return first_suite;
00213                 }
00214         }
00215         return 0;
00216 }
00217 
00218 #define timerclear_timeval(tvp)         ((tvp)->tv_sec = (tvp)->tv_usec = 0)
00219 
00220 #define timersub_timeval(a, b, result)                                                \
00221   do {                                                                        \
00222     (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
00223     (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
00224     if ((result)->tv_usec < 0) {                                              \
00225       --(result)->tv_sec;                                                     \
00226       (result)->tv_usec += 1000000;                                           \
00227     }                                                                         \
00228   } while (0)
00229 
00230 #define timeradd_timeval(a, b, result)                                                \
00231   do {                                                                        \
00232     (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                             \
00233     (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                          \
00234     if ((result)->tv_usec >= 1000000)                                         \
00235       {                                                                       \
00236         ++(result)->tv_sec;                                                   \
00237         (result)->tv_usec -= 1000000;                                         \
00238       }                                                                       \
00239   } while (0)
00240 
00241 
00242 int VTEST_test_runner_cmdline(VTEST_TEST_SUITE *suite, VTEST_RUNNER_IMPL *impl, int argc,  char *argv[])
00243 {
00244         int testsfailed = 0;
00245         int testspassed = 0;
00246         int testnotrun  = 0;
00247         int suitesinitfailed = 0;
00248         int suitesteardownfailed = 0;
00249         VTEST_TEST_SUITE *first_suite = suite;
00250 #ifdef TIME_TEST_GETTIMEOFDAY
00251         struct timeval start, end, duration;
00252 #endif
00253 
00254 
00255 
00256         int i,suite_ok;
00257 
00258         vtest_impl = impl;
00259 
00260         for(;suite; suite = suite->next_suite) {
00261                 VTEST_TEST *test;
00262 
00263                 if (g_suite_name) {
00264                         VTEST_TEST_SUITE *next;
00265 
00266                         next = find_suite_by_name(first_suite, g_suite_name);
00267                         free(g_suite_name);
00268                         g_suite_name = 0;
00269                         
00270                         if (next) {
00271                                 suite = next;
00272                         }                       
00273                 }
00274 
00275                 vtest_impl->suite = suite;
00276                 vtest_impl->test = 0;
00277 
00278 
00279                 if (!VTEST_is_run_suite(suite->name, argv, argc)) {
00280                         continue;
00281                 }
00282 
00283                 if (impl->suite_start) {
00284                   impl->suite_start(suite->name);
00285                 }
00286 
00287                 suite_ok = 1;
00288 
00289 #if 0
00290                 if (suite->setUp) {
00291                         
00292                         vtest_impl->current_test_state = 1; 
00293                         vtest_impl->scope_fail = VTEST_SUITE_SETUP_FAILED;
00294 
00295                         suite->setUp();
00296 
00297                         if (!vtest_impl->current_test_state) {
00298                                 suite_ok = 0;   
00299                         }
00300                 }
00301 #endif
00302                 if (suite_ok)  {
00303 
00304                         vtest_impl->results( VTEST_SUITE_SETUP_OK, suite->name, 0, 0, 0, 0, 0);
00305                 
00306                         for(test = suite->test_cases; test->name != 0; test++) {
00307 
00308                            if (!VTEST_is_run_test(suite->name, test->name, argv, argc)) {
00309                                 continue;
00310                            }
00311 
00312 
00313                            vtest_impl->test = test;
00314 
00315 
00316                                 
00317                            for(i = 0; i < test->repeat /*&& !g_suite_name*/ ; i++) {
00318 
00319                                    impl->test_start( suite->name, test->name, i+1, test->repeat);
00320 
00321                                    vtest_impl->current_test_state = 1; 
00322 
00323 
00324 #ifdef TIME_TEST_GETTIMEOFDAY
00325                                    gettimeofday( &start, 0 );
00326 #endif
00327                                    
00328                                    if (suite->setUp) {
00329                                         vtest_impl->scope_fail = VTEST_SUITE_SETUP_FAILED;
00330                                         suite->setUp();
00331                                    
00332                                    }
00333 
00334                                    if (vtest_impl->current_test_state) {
00335                                      vtest_impl->scope_fail = VTEST_TEST_FAILED;
00336                                      test->function();
00337                                    }
00338 
00339 
00340                                    if (vtest_impl->current_test_state && suite->tearDown) {
00341                                         vtest_impl->scope_fail = VTEST_SUITE_TEARDOWN_FAILED;
00342                                         suite->tearDown();
00343                                    }
00344 
00345 
00346                                    if (vtest_impl->current_test_state) {
00347 #ifdef TIME_TEST_GETTIMEOFDAY
00348                                           gettimeofday( &end, 0 );
00349                                           timersub_timeval( &end, &start, &duration );
00350 
00351                                           vtest_impl->results( VTEST_TEST_OK, 
00352                                                                         vtest_impl->suite->name, 
00353                                                                         vtest_impl->test->name, 
00354                                                                         &duration,
00355                                                                         0, 0, 0);
00356 #else
00357                                           vtest_impl->results( VTEST_TEST_OK,
00358                                                                         vtest_impl->suite->name, 
00359                                                                         vtest_impl->test->name, 
00360                                                                         0,
00361                                                                         0, 0, 0);
00362 #endif                             
00363                                    }
00364                                    if (vtest_impl->current_test_state) {
00365                                            testspassed++;
00366                                    } else {
00367                                            testsfailed++;
00368                                    }
00369                            } // eof test
00370                            
00371                         } // eof suite
00372 
00373 #if 0
00374                         if (suite->tearDown) {
00375 
00376                                 vtest_impl->current_test_state = 1; 
00377                                 vtest_impl->scope_fail = VTEST_SUITE_TEARDOWN_FAILED;
00378                                 vtest_impl->test = 0;
00379 
00380                                 suite->tearDown();
00381 
00382                         
00383                                 if (vtest_impl->current_test_state) {
00384                                         vtest_impl->results( VTEST_SUITE_TEARDOWN_OK, suite->name, 0, 0, 0, 0);
00385                                         
00386                                 } else {
00387                                         suitesteardownfailed++;
00388                                 }
00389                         }
00390 #endif
00391                 } else {
00392                         /*test setup failed*/
00393                         for(test = suite->test_cases;test->name != 0;test++) {
00394                                 testnotrun ++;
00395                         }
00396                         suitesinitfailed ++;
00397                 }
00398                 
00399         }
00400 
00401         vtest_impl->wrapup( suitesinitfailed, suitesteardownfailed,
00402                                             testspassed, testsfailed, testnotrun);
00403 
00404         return suitesinitfailed == 0 && suitesteardownfailed == 0 && testspassed == 0 && testsfailed == 0;
00405 }
00406 
00407 
00408 int VTEST_test_runner(VTEST_TEST_SUITE *suite, VTEST_RUNNER_IMPL *impl)
00409 {
00410         return VTEST_test_runner_cmdline(suite, impl,0,0);
00411 }
00412 
00413 
00414 
00415 
00416