Simple XUnit test library / objects in plain C Snapshot
|
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