Paul Bakker | 367dae4 | 2009-06-28 21:50:27 +0000 | [diff] [blame] | 1 | /*
|
| 2 | ====================================================================
|
| 3 | Copyright (c) 2008 Ian Blumel. All rights reserved.
|
| 4 |
|
| 5 | FCT (Fast C Test) Unit Testing Framework
|
| 6 |
|
| 7 | Copyright (c) 2008, Ian Blumel (ian.blumel@gmail.com)
|
| 8 | All rights reserved.
|
| 9 |
|
| 10 | This license is based on the BSD License.
|
| 11 |
|
| 12 | Redistribution and use in source and binary forms, with or without
|
| 13 | modification, are permitted provided that the following conditions are
|
| 14 | met:
|
| 15 |
|
| 16 | * Redistributions of source code must retain the above copyright
|
| 17 | notice, this list of conditions and the following disclaimer.
|
| 18 |
|
| 19 | * Redistributions in binary form must reproduce the above copyright
|
| 20 | notice, this list of conditions and the following disclaimer in
|
| 21 | the documentation and/or other materials provided with the
|
| 22 | distribution.
|
| 23 |
|
| 24 | * Neither the name of, Ian Blumel, nor the names of its
|
| 25 | contributors may be used to endorse or promote products derived
|
| 26 | from this software without specific prior written permission.
|
| 27 |
|
| 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
| 29 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
| 30 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
| 31 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
| 32 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
| 33 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| 34 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| 35 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 36 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 37 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| 38 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 39 | ====================================================================
|
| 40 |
|
| 41 | File: fct.h
|
| 42 | */
|
| 43 |
|
| 44 | #if !defined(FCT_INCLUDED__IMB)
|
| 45 | #define FCT_INCLUDED__IMB
|
| 46 |
|
| 47 | #define FCT_VERSION_STR "1.0.2"
|
| 48 | #define FCT_VERSION_MAJOR 1
|
| 49 | #define FCT_VERSION_MINOR 0
|
| 50 | #define FCT_VERSION_MICRO 2
|
| 51 |
|
| 52 | /* Define this to remove unneeded WIN32 warnings. We will undefine this at
|
| 53 | the end of the file so as not to interfere with your build. */
|
| 54 | #if defined(WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)
|
| 55 | # define _CRT_SECURE_NO_WARNINGS
|
| 56 | #endif
|
| 57 |
|
| 58 | #include <string.h>
|
| 59 | #include <assert.h>
|
| 60 | #include <stdarg.h>
|
| 61 | #include <stdlib.h>
|
| 62 | #include <stdio.h>
|
| 63 | #include <time.h>
|
| 64 | #include <float.h>
|
| 65 | #include <math.h>
|
| 66 |
|
| 67 | #define FCT_MAX_NAME 256
|
| 68 | #define FCT_MAX_LOG_LINE 256
|
| 69 |
|
| 70 | #define nbool_t int
|
| 71 | #define FCT_TRUE 1
|
| 72 | #define FCT_FALSE 0
|
| 73 |
|
| 74 | /* Forward declarations. The following forward declarations are required
|
| 75 | because there is a inter-relationship between certain objects that
|
| 76 | just can not be untwined. */
|
| 77 | typedef struct _fct_logger_i fct_logger_i;
|
| 78 | typedef struct _fct_standard_logger_t fct_standard_logger_t;
|
| 79 | typedef struct _fct_minimal_logger_t fct_minimal_logger_t;
|
| 80 | typedef struct _fctchk_t fctchk_t;
|
| 81 | typedef struct _fct_test_t fct_test_t;
|
| 82 | typedef struct _fct_ts_t fct_ts_t;
|
| 83 | typedef struct _fctkern_t fctkern_t;
|
| 84 |
|
| 85 | /* Forward declare some functions used throughout. */
|
| 86 | static fct_standard_logger_t *
|
| 87 | fct_standard_logger__new(void);
|
| 88 |
|
| 89 | static void
|
| 90 | fct_logger__del(fct_logger_i *logger);
|
| 91 |
|
| 92 | static void
|
| 93 | fct_logger__on_cndtn(fct_logger_i *self, fctchk_t const *chk);
|
| 94 |
|
| 95 | static void
|
| 96 | fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test);
|
| 97 |
|
| 98 | static void
|
| 99 | fct_logger__on_test_end(fct_logger_i *logger, fct_test_t const *test);
|
| 100 |
|
| 101 | static void
|
| 102 | fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts);
|
| 103 |
|
| 104 | static void
|
| 105 | fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts);
|
| 106 |
|
| 107 | static void
|
| 108 | fct_logger__on_fct_start(fct_logger_i *logger, fctkern_t const *kern);
|
| 109 |
|
| 110 | static void
|
| 111 | fct_logger__on_fct_end(fct_logger_i *logger, fctkern_t const *kern);
|
| 112 |
|
| 113 |
|
| 114 |
|
| 115 | /* Explicitly indicate a no-op */
|
| 116 | #define fct_pass()
|
| 117 |
|
| 118 | #define fct_unused(x) ((void) (x));
|
| 119 |
|
| 120 | /* This is just a little trick to let me put comments inside of macros. I
|
| 121 | really only want to bother with this when we are "unwinding" the macros
|
| 122 | for debugging purposes. */
|
| 123 | #if defined(FCT_CONF_UNWIND)
|
| 124 | # define _fct_cmt(string) {char*_=string;}
|
| 125 | #else
|
| 126 | # define _fct_cmt(string)
|
| 127 | #endif
|
| 128 |
|
| 129 | /*
|
| 130 | --------------------------------------------------------
|
| 131 | UTILITIES
|
| 132 | --------------------------------------------------------
|
| 133 | */
|
| 134 |
|
| 135 | /* Utility for truncated, safe string copies. */
|
| 136 | static void
|
| 137 | fct_safe_str_cpy(char *dst, char const *src, size_t num)
|
| 138 | {
|
| 139 | assert( dst != NULL );
|
| 140 | assert( src != NULL );
|
| 141 | assert( num > 0 );
|
| 142 | strncpy(dst, src, num);
|
| 143 | dst[num-1] = '\0';
|
| 144 | }
|
| 145 |
|
| 146 | /* Isolate the snprintf implemenation. */
|
| 147 | int
|
| 148 | fct_snprintf(char *buffer, size_t buffer_len, char *format, ...)
|
| 149 | {
|
| 150 | int count =0;
|
| 151 | va_list args;
|
| 152 | va_start(args, format);
|
| 153 | count =vsnprintf(buffer, buffer_len, format, args);
|
| 154 | va_end(args);
|
| 155 | return count;
|
| 156 | }
|
| 157 |
|
| 158 | /* A very, very simple "filter". This just compares the supplied prefix
|
| 159 | against the test_str, to see if they both have the same starting
|
| 160 | characters. If they do we return true, otherwise we return false. If the
|
| 161 | prefix is a blank string or NULL, then it will return FCT_TRUE.*/
|
| 162 | static nbool_t
|
| 163 | fct_filter_pass(char const *prefix, char const *test_str)
|
| 164 | {
|
| 165 | nbool_t is_match = FCT_FALSE;
|
| 166 | char const *prefix_p;
|
| 167 | char const *test_str_p;
|
| 168 |
|
| 169 | /* If you got nothing to test against, why test? */
|
| 170 | assert( test_str != NULL );
|
| 171 |
|
| 172 | /* When the prefix is NULL or blank, we always return FCT_TRUE. */
|
| 173 | if ( prefix == NULL || prefix[0] == '\0' )
|
| 174 | {
|
| 175 | return FCT_TRUE;
|
| 176 | }
|
| 177 |
|
| 178 | /* Iterate through both character arrays at the same time. We are
|
| 179 | going to play a game and see if we can beat the house. */
|
| 180 | for ( prefix_p = prefix, test_str_p = test_str;
|
| 181 | *prefix_p != '\0' && *test_str_p != '\0';
|
| 182 | ++prefix_p, ++test_str_p )
|
| 183 | {
|
| 184 | is_match = *prefix_p == *test_str_p;
|
| 185 | if ( !is_match )
|
| 186 | {
|
| 187 | break; /* Quit the first time we don't match. */
|
| 188 | }
|
| 189 | }
|
| 190 |
|
| 191 | /* If the iterator for the test_str is pointing at the null char, and
|
| 192 | the iterator for the prefix string is not, then the prefix string is
|
| 193 | larger than the actual test string, and therefore we failed to pass the
|
| 194 | filter. */
|
| 195 | if ( *test_str_p == '\0' && *prefix_p != '\0' )
|
| 196 | {
|
| 197 | return FCT_FALSE;
|
| 198 | }
|
| 199 |
|
| 200 | /* is_match will be set to the either FCT_TRUE if we kicked of the loop
|
| 201 | early because our filter ran out of characters or FCT_FALSE if we
|
| 202 | encountered a mismatch before our filter ran out of characters. */
|
| 203 | return is_match;
|
| 204 | }
|
| 205 |
|
| 206 | /* Returns true if two reals are equal. */
|
| 207 | nbool_t
|
| 208 | fct_real_eq(double v1, double v2)
|
| 209 | {
|
| 210 | return (nbool_t)(fabs(v1 - v2) < DBL_EPSILON);
|
| 211 | }
|
| 212 |
|
| 213 | /*
|
| 214 | --------------------------------------------------------
|
| 215 | TIMER
|
| 216 | --------------------------------------------------------
|
| 217 | */
|
| 218 |
|
| 219 | typedef struct _fct_timer_t fct_timer_t;
|
| 220 | struct _fct_timer_t {
|
| 221 | clock_t start;
|
| 222 | clock_t stop;
|
| 223 | double duration;
|
| 224 | };
|
| 225 |
|
| 226 |
|
| 227 | static void
|
| 228 | fct_timer__init(fct_timer_t *timer) {
|
| 229 | assert(timer != NULL);
|
| 230 | memset(timer, 0, sizeof(fct_timer_t));
|
| 231 | }
|
| 232 |
|
| 233 |
|
| 234 | static void
|
| 235 | fct_timer__start(fct_timer_t *timer) {
|
| 236 | assert(timer != NULL);
|
| 237 | timer->start = clock();
|
| 238 | }
|
| 239 |
|
| 240 |
|
| 241 | static void
|
| 242 | fct_timer__stop(fct_timer_t *timer) {
|
| 243 | assert(timer != NULL);
|
| 244 | timer->stop = clock();
|
| 245 | timer->duration = (double) (timer->stop - timer->start) / CLOCKS_PER_SEC;
|
| 246 | }
|
| 247 |
|
| 248 |
|
| 249 | /* Returns the time in seconds. */
|
| 250 | static double
|
| 251 | fct_timer__duration(fct_timer_t *timer) {
|
| 252 | assert( timer != NULL );
|
| 253 | return timer->duration;
|
| 254 | }
|
| 255 |
|
| 256 |
|
| 257 | /*
|
| 258 | --------------------------------------------------------
|
| 259 | GENERIC LIST
|
| 260 | --------------------------------------------------------
|
| 261 | */
|
| 262 |
|
| 263 | /* For now we will just keep it at a linear growth rate. */
|
| 264 | #define FCT_LIST_GROWTH_FACTOR 2
|
| 265 |
|
| 266 | /* Starting size for the list, to keep it simple we will start
|
| 267 | at a reasonable size. */
|
| 268 | #define FCT_LIST_START_SIZE 2
|
| 269 |
|
| 270 | /* Helper macros for quickly iterating through a list. You should be able
|
| 271 | to do something like,
|
| 272 |
|
| 273 | NLIST_FOREACH_BGN(fct_logger_i*, logger, my_list)
|
| 274 | {
|
| 275 | fct_logger__on_blah(logger);
|
| 276 | }
|
| 277 | NLIST_FOREACH_END();
|
| 278 |
|
| 279 | */
|
| 280 | #define NLIST_FOREACH_BGN(Type, Var, List)\
|
| 281 | {\
|
| 282 | if ( List != NULL ) {\
|
| 283 | size_t item_i##Var;\
|
| 284 | size_t num_items##Var = nlist__size(List);\
|
| 285 | for( item_i##Var =0; item_i##Var != num_items##Var; ++item_i##Var )\
|
| 286 | {\
|
| 287 | Type Var = (Type) nlist__at((List), item_i##Var);
|
| 288 |
|
| 289 | #define NLIST_FOREACH_END() }}}
|
| 290 |
|
| 291 | /* Used to manage a list of loggers. This works mostly like
|
| 292 | the STL vector, where the array grows as more items are
|
| 293 | appended. */
|
| 294 | typedef struct _nlist_t nlist_t;
|
| 295 | struct _nlist_t
|
| 296 | {
|
| 297 | /* Item's are stored as pointers to void. */
|
| 298 | void **itm_list;
|
| 299 |
|
| 300 | /* Indicates the number of element's in the array. */
|
| 301 | size_t avail_itm_num;
|
| 302 |
|
| 303 | /* Indicates the number of actually elements in the array. */
|
| 304 | size_t used_itm_num;
|
| 305 | };
|
| 306 |
|
| 307 | static nlist_t *
|
| 308 | nlist_new(void)
|
| 309 | {
|
| 310 | nlist_t *list = (nlist_t*)calloc(1, sizeof(nlist_t));
|
| 311 | assert( list != NULL && "memory check");
|
| 312 |
|
| 313 | list->itm_list = (void**)malloc(sizeof(void*)*FCT_LIST_START_SIZE);
|
| 314 | assert( list->itm_list != NULL && "memory check");
|
| 315 |
|
| 316 | list->avail_itm_num =FCT_LIST_START_SIZE;
|
| 317 | list->used_itm_num =0;
|
| 318 | return list;
|
| 319 | }
|
| 320 |
|
| 321 | typedef void (*on_del_t)(void*);
|
| 322 |
|
| 323 | /* Cleans up list, and applies `on_del` to each item in the list.
|
| 324 | If on_del is NULL, it will not be applied. If `list` is NULL this
|
| 325 | function does nothing. */
|
| 326 | static void
|
| 327 | nlist__del(nlist_t *list, on_del_t on_del)
|
| 328 | {
|
| 329 | size_t itm_i =0;
|
| 330 |
|
| 331 | if ( list == NULL ) { return; }
|
| 332 |
|
| 333 | /* Walk through the list applying the destroy function, if it was
|
| 334 | defined. */
|
| 335 | if ( on_del != NULL )
|
| 336 | {
|
| 337 | for ( itm_i =0; itm_i != list->used_itm_num; ++itm_i )
|
| 338 | {
|
| 339 | on_del(list->itm_list[itm_i]);
|
| 340 | }
|
| 341 | }
|
| 342 |
|
| 343 | free(list->itm_list);
|
| 344 | free(list);
|
| 345 | }
|
| 346 |
|
| 347 |
|
| 348 | /* Returns the number of elements within the list. */
|
| 349 | static size_t
|
| 350 | nlist__size(nlist_t const *list)
|
| 351 | {
|
| 352 | assert( list != NULL );
|
| 353 | return list->used_itm_num;
|
| 354 | }
|
| 355 |
|
| 356 |
|
| 357 | /* Returns the item at idx, asserts otherwise. */
|
| 358 | static void*
|
| 359 | nlist__at(nlist_t const *list, size_t idx)
|
| 360 | {
|
| 361 | assert( list != NULL );
|
| 362 | assert( idx < list->used_itm_num );
|
| 363 | return list->itm_list[idx];
|
| 364 | }
|
| 365 |
|
| 366 |
|
| 367 | static void
|
| 368 | nlist__append(nlist_t *list, void *itm)
|
| 369 | {
|
| 370 | assert( list != NULL );
|
| 371 | assert( list->itm_list != NULL );
|
| 372 | assert( list->avail_itm_num != 0 );
|
| 373 |
|
| 374 | /* If we ran out of room, then the last increment should be equal to the
|
| 375 | available space, in this case we need to grow a little more. */
|
| 376 | if ( list->used_itm_num == list->avail_itm_num )
|
| 377 | {
|
| 378 | list->avail_itm_num = list->avail_itm_num*FCT_LIST_GROWTH_FACTOR;
|
| 379 | list->itm_list = (void**)realloc(
|
| 380 | list->itm_list, sizeof(void*)*list->avail_itm_num
|
| 381 | );
|
| 382 | assert( list->itm_list != NULL && "memory check");
|
| 383 | }
|
| 384 |
|
| 385 | list->itm_list[list->used_itm_num] = itm;
|
| 386 | ++(list->used_itm_num);
|
| 387 | }
|
| 388 |
|
| 389 |
|
| 390 |
|
| 391 | /*
|
| 392 | -----------------------------------------------------------
|
| 393 | A SINGLE CHECK
|
| 394 | -----------------------------------------------------------
|
| 395 | This defines a single check. It indicates what the check was,
|
| 396 | and where it occurred. A "Test" object will have-a bunch
|
| 397 | of "checks".
|
| 398 | */
|
| 399 |
|
| 400 | struct _fctchk_t {
|
| 401 | /* This string that represents the condition. */
|
| 402 | char cndtn[FCT_MAX_LOG_LINE];
|
| 403 |
|
| 404 | /* These indicate where the condition occurred. */
|
| 405 | char file[FCT_MAX_LOG_LINE];
|
| 406 |
|
| 407 | int lineno;
|
| 408 |
|
| 409 | nbool_t is_pass;
|
| 410 | };
|
| 411 |
|
| 412 | #define fctchk__is_pass(_CHK_) ((_CHK_)->is_pass)
|
| 413 | #define fctchk__file(_CHK_) ((_CHK_)->file)
|
| 414 | #define fctchk__lineno(_CHK_) ((_CHK_)->lineno)
|
| 415 | #define fctchk__cndtn(_CHK_) ((_CHK_)->cndtn)
|
| 416 |
|
| 417 |
|
| 418 | static fctchk_t*
|
| 419 | fctchk_new(char const *cndtn, char const *file, int lineno, nbool_t is_pass)
|
| 420 | {
|
| 421 | fctchk_t *chk = NULL;
|
| 422 |
|
| 423 | assert( cndtn != NULL );
|
| 424 | assert( file != NULL );
|
| 425 | assert( lineno > 0 );
|
| 426 |
|
| 427 | chk = (fctchk_t*)calloc(1, sizeof(fctchk_t));
|
| 428 | assert( chk != NULL && "out of memory");
|
| 429 | if ( chk == NULL ) { return NULL; }
|
| 430 |
|
| 431 | fct_safe_str_cpy(chk->cndtn, cndtn, FCT_MAX_LOG_LINE);
|
| 432 | fct_safe_str_cpy(chk->file, file, FCT_MAX_LOG_LINE);
|
| 433 | chk->lineno = lineno;
|
| 434 |
|
| 435 | chk->is_pass =is_pass;
|
| 436 |
|
| 437 | return chk;
|
| 438 | }
|
| 439 |
|
| 440 |
|
| 441 | /* Cleans up a "check" object. If the `chk` is NULL, this function does
|
| 442 | nothing. */
|
| 443 | static void
|
| 444 | fctchk__del(fctchk_t *chk)
|
| 445 | {
|
| 446 | if ( chk == NULL ) { return; }
|
| 447 | free( chk );
|
| 448 | }
|
| 449 |
|
| 450 |
|
| 451 | /*
|
| 452 | -----------------------------------------------------------
|
| 453 | A TEST
|
| 454 | -----------------------------------------------------------
|
| 455 | A suite will have-a list of tests. Where each test will have-a
|
| 456 | list of failed and passed checks.
|
| 457 | */
|
| 458 |
|
| 459 | struct _fct_test_t {
|
| 460 | /* List of failed and passed "checks" (fctchk_t). Two seperate
|
| 461 | lists make it faster to determine how many checks passed and how
|
| 462 | many checks failed. */
|
| 463 | nlist_t *failed_chks;
|
| 464 | nlist_t *passed_chks;
|
| 465 |
|
| 466 | /* The name of the test case. */
|
| 467 | char name[FCT_MAX_NAME];
|
| 468 | };
|
| 469 |
|
| 470 | #define fct_test__name(_TEST_) ((_TEST_)->name)
|
| 471 |
|
| 472 | static fct_test_t*
|
| 473 | fct_test_new(char const *name) {
|
| 474 | fct_test_t *test =NULL;
|
| 475 |
|
| 476 | test = (fct_test_t*)malloc(sizeof(fct_test_t));
|
| 477 | assert( test != NULL && "out of memory");
|
| 478 |
|
| 479 | fct_safe_str_cpy(test->name, name, FCT_MAX_NAME);
|
| 480 |
|
| 481 | test->failed_chks = nlist_new();
|
| 482 | test->passed_chks = nlist_new();
|
| 483 | assert( test->failed_chks != NULL && "out of memory");
|
| 484 | assert( test->passed_chks != NULL && "out of memory");
|
| 485 |
|
| 486 | return test;
|
| 487 | }
|
| 488 |
|
| 489 |
|
| 490 | static nbool_t
|
| 491 | fct_test__is_pass(fct_test_t const *test)
|
| 492 | {
|
| 493 | assert( test != NULL );
|
| 494 | return nlist__size(test->failed_chks) == 0;
|
| 495 | }
|
| 496 |
|
| 497 |
|
| 498 | static void
|
| 499 | fct_test__add(fct_test_t *test, fctchk_t *chk)
|
| 500 | {
|
| 501 |
|
| 502 | assert( test != NULL );
|
| 503 | assert( chk != NULL );
|
| 504 |
|
| 505 | if ( fctchk__is_pass(chk) )
|
| 506 | {
|
| 507 | nlist__append(test->passed_chks, (void*)chk);
|
| 508 | }
|
| 509 | else
|
| 510 | {
|
| 511 | nlist__append(test->failed_chks, (void*)chk);
|
| 512 | }
|
| 513 | }
|
| 514 |
|
| 515 | /* Returns the number of checks made throughout the test. */
|
| 516 | static int
|
| 517 | fct_test__chk_cnt(fct_test_t const *test)
|
| 518 | {
|
| 519 | assert( test != NULL );
|
| 520 | return nlist__size(test->failed_chks) + nlist__size(test->passed_chks);
|
| 521 | }
|
| 522 |
|
| 523 |
|
| 524 | static void
|
| 525 | fct_test__del(fct_test_t *test)
|
| 526 | {
|
| 527 | if (test == NULL ) { return; }
|
| 528 | nlist__del(test->passed_chks, (on_del_t)fctchk__del);
|
| 529 | nlist__del(test->failed_chks, (on_del_t)fctchk__del);
|
| 530 | free(test);
|
| 531 | }
|
| 532 |
|
| 533 |
|
| 534 | /*
|
| 535 | -----------------------------------------------------------
|
| 536 | TEST SUITE (TS)
|
| 537 | -----------------------------------------------------------
|
| 538 | */
|
| 539 |
|
| 540 |
|
| 541 | /* The different types of 'modes' that a test suite can be in.
|
| 542 |
|
| 543 | While the test suite is iterating through all the tests, its "State"
|
| 544 | can change from "setup mode", to "test mode" to "tear down" mode.
|
| 545 | These help to indicate what mode are currently in. Think of it as a
|
| 546 | basic FSM.
|
| 547 |
|
| 548 | if the count was 0 end
|
| 549 | +--------->---------------------> ending_mode-----+
|
| 550 | | ^
|
| 551 | ^ |
|
| 552 | start | [if no more tests]
|
| 553 | | | |
|
| 554 | +-count_mode -> setup_mode -> test_mode -> teardown_mode
|
| 555 | ^ |
|
| 556 | +-----------<---------------+
|
| 557 | */
|
| 558 | enum ts_mode {
|
| 559 | ts_mode_cnt, /* To setup when done counting. */
|
| 560 | ts_mode_setup, /* To test when done setup. */
|
| 561 | ts_mode_teardown, /* To ending mode, when no more tests. */
|
| 562 | ts_mode_test, /* To tear down mode. */
|
| 563 | ts_mode_ending, /* To ... */
|
| 564 | ts_mode_end /* .. The End. */
|
| 565 | };
|
| 566 |
|
| 567 | /* Types of modes the test could be in. */
|
| 568 | typedef enum {
|
| 569 | fct_test_status_SUCCESS,
|
| 570 | fct_test_status_FAILURE
|
| 571 | } fct_test_status;
|
| 572 |
|
| 573 |
|
| 574 | struct _fct_ts_t {
|
| 575 | /* For counting our 'current' test number, and the total number of
|
| 576 | tests. */
|
| 577 | int curr_test_num;
|
| 578 | int total_test_num;
|
| 579 |
|
| 580 | /* Keeps track of the current state of the object while it is walking
|
| 581 | through its "FSM" */
|
| 582 | enum ts_mode mode;
|
| 583 |
|
| 584 | /* The name of the test suite. */
|
| 585 | char name[FCT_MAX_NAME];
|
| 586 |
|
| 587 | /* List of tests that where executed within the test suite. */
|
| 588 | nlist_t *test_list;
|
| 589 | };
|
| 590 |
|
| 591 |
|
| 592 | #define fct_ts__is_setup_mode(ts) ((ts)->mode == ts_mode_setup)
|
| 593 | #define fct_ts__is_teardown_mode(ts) ((ts)->mode == ts_mode_teardown)
|
| 594 | #define fct_ts__is_test_mode(ts) ((ts)->mode == ts_mode_test)
|
| 595 | #define fct_ts__is_ending_mode(ts) ((ts)->mode == ts_mode_ending)
|
| 596 | #define fct_ts__is_end(ts) ((ts)->mode == ts_mode_end)
|
| 597 | #define fct_ts__is_cnt_mode(ts) ((ts)->mode == ts_mode_cnt)
|
| 598 | #define fct_ts__name(ts) ((ts)->name)
|
| 599 |
|
| 600 |
|
| 601 | static fct_ts_t *
|
| 602 | fct_ts_new(char const *name) {
|
| 603 | fct_ts_t *ts =NULL;
|
| 604 | ts = (fct_ts_t*)calloc(1, sizeof(fct_ts_t));
|
| 605 | assert( ts != NULL );
|
| 606 |
|
| 607 | fct_safe_str_cpy(ts->name, name, FCT_MAX_NAME);
|
| 608 | ts->mode = ts_mode_cnt;
|
| 609 |
|
| 610 | ts->test_list = nlist_new();
|
| 611 | assert( ts->test_list != NULL && "no memory");
|
| 612 |
|
| 613 | return ts;
|
| 614 | }
|
| 615 |
|
| 616 | static void
|
| 617 | fct_ts__del(fct_ts_t *ts) {
|
| 618 | if ( ts == NULL ) { return; }
|
| 619 | free(ts);
|
| 620 | }
|
| 621 |
|
| 622 | /* Flag a test suite as complete. It will no longer accept any more tests. */
|
| 623 | #define fct_ts__end(_TS_) ((_TS_)->mode == ts_mode_end)
|
| 624 |
|
| 625 |
|
| 626 | static nbool_t
|
| 627 | fct_ts__is_more_tests(fct_ts_t const *ts) {
|
| 628 | assert( ts != NULL );
|
| 629 | assert( !fct_ts__is_end(ts) );
|
| 630 | return ts->curr_test_num < ts->total_test_num;
|
| 631 | }
|
| 632 |
|
| 633 |
|
| 634 | /* Indicates that we have started a test case. */
|
| 635 | static void
|
| 636 | fct_ts__test_begin(fct_ts_t *ts) {
|
| 637 | assert( !fct_ts__is_end(ts) );
|
| 638 | ++(ts->curr_test_num);
|
| 639 | }
|
| 640 |
|
| 641 |
|
| 642 | /* Takes OWNERSHIP of a test object, and warehouses it for later stat
|
| 643 | generation. */
|
| 644 | static void
|
| 645 | fct_ts__add_test(fct_ts_t *ts, fct_test_t *test) {
|
| 646 | assert( ts != NULL && "invalid arg");
|
| 647 | assert( test != NULL && "invalid arg");
|
| 648 | assert( !fct_ts__is_end(ts) );
|
| 649 | nlist__append(ts->test_list, test);
|
| 650 | }
|
| 651 |
|
| 652 |
|
| 653 | static void
|
| 654 | fct_ts__test_end(fct_ts_t *ts) {
|
| 655 | assert( ts != NULL );
|
| 656 | assert( fct_ts__is_test_mode(ts) && "not in test mode, can't end!" );
|
| 657 |
|
| 658 | /* After a test has completed, move to teardown mode. */
|
| 659 | ts->mode = ts_mode_teardown;
|
| 660 | }
|
| 661 |
|
| 662 |
|
| 663 | /* Increments the internal count by 1. */
|
| 664 | static void
|
| 665 | fct_ts__inc_total_test_num(fct_ts_t *ts)
|
| 666 | {
|
| 667 | assert( ts != NULL );
|
| 668 | assert( fct_ts__is_cnt_mode(ts) );
|
| 669 | assert( !fct_ts__is_end(ts) );
|
| 670 | ++(ts->total_test_num);
|
| 671 | }
|
| 672 |
|
| 673 |
|
| 674 | /* Flags the end of the setup, which implies we are going to move into
|
| 675 | setup mode. You must be already in setup mode for this to work! */
|
| 676 | static void
|
| 677 | fct_ts__setup_end(fct_ts_t *ts)
|
| 678 | {
|
| 679 | assert( fct_ts__is_setup_mode(ts) );
|
| 680 | assert( !fct_ts__is_end(ts) );
|
| 681 | ts->mode = ts_mode_test;
|
| 682 | }
|
| 683 |
|
| 684 |
|
| 685 | /* This cndtn is set when we have iterated through all the tests, and
|
| 686 | there was nothing more to do. */
|
| 687 | static void
|
| 688 | fct_ts__ending(fct_ts_t *ts)
|
| 689 | {
|
| 690 | // We can only go from 'test-mode' to 'end-down' mode.
|
| 691 | assert( fct_ts__is_test_mode(ts) );
|
| 692 | assert( !fct_ts__is_end(ts) );
|
| 693 | ts->mode = ts_mode_ending;
|
| 694 | }
|
| 695 |
|
| 696 |
|
| 697 | /* Flags the end of the teardown, which implies we are going to move
|
| 698 | into setup mode (for the next 'iteration'). */
|
| 699 | static void
|
| 700 | fct_ts__teardown_end(fct_ts_t *ts)
|
| 701 | {
|
| 702 | assert( fct_ts__is_teardown_mode(ts) );
|
| 703 | assert( !fct_ts__is_end(ts) );
|
| 704 | /* We have to decide if we should keep on testing by moving into tear down
|
| 705 | mode or if we have reached the real end and should be moving into the
|
| 706 | ending mode. */
|
| 707 | if ( fct_ts__is_more_tests(ts) ) {
|
| 708 | ts->mode = ts_mode_setup;
|
| 709 | }
|
| 710 | else {
|
| 711 | ts->mode = ts_mode_ending;
|
| 712 | }
|
| 713 | }
|
| 714 |
|
| 715 |
|
| 716 | /* Flags the end of the counting, and proceeding to the first setup.
|
| 717 | Consider the special case when a test suite has NO tests in it, in
|
| 718 | that case we will have a current count that is zero, in which case
|
| 719 | we can skip right to 'ending'. */
|
| 720 | static void
|
| 721 | fct_ts__cnt_end(fct_ts_t *ts)
|
| 722 | {
|
| 723 | assert( ts != NULL );
|
| 724 | assert( fct_ts__is_cnt_mode(ts) );
|
| 725 | assert( !fct_ts__is_end(ts) );
|
| 726 | if (ts->total_test_num == 0 ) {
|
| 727 | ts->mode = ts_mode_ending;
|
| 728 | }
|
| 729 | else {
|
| 730 | ts->mode = ts_mode_setup;
|
| 731 | }
|
| 732 | }
|
| 733 |
|
| 734 |
|
| 735 | static nbool_t
|
| 736 | fct_ts__is_test_cnt(fct_ts_t const *ts, int test_num)
|
| 737 | {
|
| 738 | assert( ts != NULL );
|
| 739 | assert( 0 <= test_num );
|
| 740 | assert( test_num < ts->total_test_num );
|
| 741 | assert( !fct_ts__is_end(ts) );
|
| 742 |
|
| 743 | /* As we roll through the tests we increment the count. With this
|
| 744 | count we can decide if we need to execute a test or not. */
|
| 745 | return test_num == ts->curr_test_num;
|
| 746 | }
|
| 747 |
|
| 748 |
|
| 749 | /* Returns the # of tests on the FCT TS object. This is the actual
|
| 750 | # of tests executed. */
|
| 751 | static int
|
| 752 | fct_ts__tst_cnt(fct_ts_t const *ts)
|
| 753 | {
|
| 754 | assert( ts != NULL );
|
| 755 | assert( !fct_ts__is_end(ts) );
|
| 756 | return nlist__size(ts->test_list);
|
| 757 | }
|
| 758 |
|
| 759 |
|
| 760 | /* Returns the # of tests in the TS object that passed. */
|
| 761 | static int
|
| 762 | fct_ts__tst_cnt_passed(fct_ts_t const *ts)
|
| 763 | {
|
| 764 | int tally =0;
|
| 765 |
|
| 766 | assert( ts != NULL );
|
| 767 | assert( !fct_ts__is_end(ts) );
|
| 768 |
|
| 769 | NLIST_FOREACH_BGN(fct_test_t*, test, ts->test_list)
|
| 770 | {
|
| 771 | if ( fct_test__is_pass(test) )
|
| 772 | {
|
| 773 | tally += 1;
|
| 774 | }
|
| 775 | }
|
| 776 | NLIST_FOREACH_END();
|
| 777 | return tally;
|
| 778 | }
|
| 779 |
|
| 780 |
|
| 781 | /* Returns the # of checks made throughout a test suite. */
|
| 782 | static int
|
| 783 | fct_ts__chk_cnt(fct_ts_t const *ts)
|
| 784 | {
|
| 785 | int tally =0;
|
| 786 |
|
| 787 | assert( ts != NULL );
|
| 788 |
|
| 789 | NLIST_FOREACH_BGN(fct_test_t *, test, ts->test_list)
|
| 790 | {
|
| 791 | tally += fct_test__chk_cnt(test);
|
| 792 | }
|
| 793 | NLIST_FOREACH_END();
|
| 794 | return tally;
|
| 795 | }
|
| 796 |
|
| 797 |
|
| 798 | /*
|
| 799 | --------------------------------------------------------
|
| 800 | FCT KERNAL
|
| 801 | --------------------------------------------------------
|
| 802 |
|
| 803 | The "fctkern" is a singleton that is defined throughout the
|
| 804 | system.
|
| 805 | */
|
| 806 |
|
| 807 | struct _fctkern_t {
|
| 808 | /* This is an list of loggers that can be used in the fct system.
|
| 809 | You/ can attach _MAX_LOGGERS to any framework. */
|
| 810 | nlist_t *logger_list;
|
| 811 |
|
| 812 | /* This is a list of prefix's that can be used to determine if a
|
| 813 | test is should be run or not. */
|
| 814 | nlist_t *prefix_list;
|
| 815 |
|
| 816 | /* This is a list of test suites that where generated throughout the
|
| 817 | testing process. */
|
| 818 | nlist_t *ts_list;
|
| 819 | };
|
| 820 |
|
| 821 |
|
| 822 | /* Returns the number of filters defined for the fct kernal. */
|
| 823 | #define fctkern__filter_cnt(_NK_) (nlist__size((_NK_)->prefix_list))
|
| 824 |
|
| 825 |
|
| 826 | static void
|
| 827 | fctkern__add_logger(fctkern_t *fct, fct_logger_i *logger_owns)
|
| 828 | {
|
| 829 | assert(fct != NULL && "invalid arg");
|
| 830 | assert(logger_owns != NULL && "invalid arg");
|
| 831 | nlist__append(fct->logger_list, logger_owns);
|
| 832 | assert( fct->logger_list != NULL && "memory check");
|
| 833 | }
|
| 834 |
|
| 835 | /* Appends a prefix filter that is used to determine if a test can
|
| 836 | be executed or not. If the test starts with the same characters as
|
| 837 | the prefix, then it should be "runnable". The prefix filter must be
|
| 838 | a non-NULL, non-Blank string. */
|
| 839 | static void
|
| 840 | fctkern__add_prefix_filter(fctkern_t const *fct, char const *prefix_filter)
|
| 841 | {
|
| 842 | char *filter =NULL;
|
| 843 | int filter_len =0;
|
| 844 |
|
| 845 | assert( fct != NULL && "invalid arg" );
|
| 846 | assert( prefix_filter != NULL && "invalid arg" );
|
| 847 | assert( strlen(prefix_filter) > 0 && "invalid arg" );
|
| 848 |
|
| 849 | /* First we make a copy of the prefix, then we store it away
|
| 850 | in our little list. */
|
| 851 | filter_len = strlen(prefix_filter);
|
| 852 | filter = (char*)malloc(sizeof(char)*(filter_len+1));
|
| 853 | strncpy(filter, prefix_filter, filter_len);
|
| 854 | filter[filter_len] = '\0';
|
| 855 |
|
| 856 | nlist__append(fct->prefix_list, (void*)filter);
|
| 857 | }
|
| 858 |
|
| 859 |
|
| 860 | /* Parses the command line and sets up the framework. The argc and argv
|
| 861 | should be directly from the program's main. */
|
| 862 | static void
|
| 863 | fctkern_init(fctkern_t *nk, int argc, char *argv[])
|
| 864 | {
|
| 865 | fct_logger_i *standard_logger = NULL;
|
| 866 | int arg_i =0;
|
| 867 |
|
| 868 | assert( nk != NULL );
|
| 869 |
|
| 870 | memset(nk, 0, sizeof(fctkern_t));
|
| 871 |
|
| 872 | nk->logger_list = nlist_new();
|
| 873 | nk->prefix_list = nlist_new();
|
| 874 | nk->ts_list = nlist_new();
|
| 875 |
|
| 876 | /* Low-budget memory check for now. */
|
| 877 | assert( nk->logger_list != NULL );
|
| 878 | assert( nk->prefix_list != NULL );
|
| 879 | assert( nk->ts_list != NULL );
|
| 880 |
|
| 881 | standard_logger = (fct_logger_i*) fct_standard_logger__new();
|
| 882 | assert( standard_logger != NULL && "no memory!");
|
| 883 |
|
| 884 | fctkern__add_logger(nk, standard_logger);
|
| 885 | standard_logger = NULL; /* Owned by the nk list. */
|
| 886 |
|
| 887 | /* Our basic parser. For now we just take each 'argv' and assume
|
| 888 | that it is a prefix filter. Notice we start at argument 1, since
|
| 889 | we don't care about the *name* of the program. */
|
| 890 | for ( arg_i =1; arg_i < argc; ++arg_i )
|
| 891 | {
|
| 892 | fctkern__add_prefix_filter(nk, argv[arg_i]);
|
| 893 | }
|
| 894 | }
|
| 895 |
|
| 896 |
|
| 897 | /* Takes OWNERSHIP of the test suite after we have finished executing
|
| 898 | its contents. This way we can build up all kinds of summaries at the end
|
| 899 | of a run. */
|
| 900 | static void
|
| 901 | fctkern__add_ts(fctkern_t *nk, fct_ts_t *ts) {
|
| 902 | assert( nk != NULL );
|
| 903 | assert( ts != NULL );
|
| 904 | nlist__append(nk->ts_list, ts);
|
| 905 | }
|
| 906 |
|
| 907 |
|
| 908 |
|
| 909 | /* Returns FCT_TRUE if the supplied test_name passes the filters set on
|
| 910 | this test suite. If there are no filters, we return FCT_TRUE always. */
|
| 911 | static nbool_t
|
| 912 | fctkern__pass_filter(fctkern_t *nk, char const *test_name) {
|
| 913 | int prefix_i =0;
|
| 914 | int prefix_list_size =0;
|
| 915 |
|
| 916 | assert( nk != NULL && "invalid arg");
|
| 917 | assert( test_name != NULL );
|
| 918 | assert( strlen(test_name) > 0 );
|
| 919 |
|
| 920 | prefix_list_size = fctkern__filter_cnt(nk);
|
| 921 |
|
| 922 | /* If there is no filter list, then we return FCT_TRUE always. */
|
| 923 | if ( prefix_list_size == 0 ) {
|
| 924 | return FCT_TRUE;
|
| 925 | }
|
| 926 |
|
| 927 | /* Iterate through the prefix filter list, and see if we have
|
| 928 | anything that does not pass. All we require is ONE item that
|
| 929 | passes the test in order for us to succeed here. */
|
| 930 | for ( prefix_i = 0; prefix_i != prefix_list_size; ++prefix_i ) {
|
| 931 | char const *prefix = (char const*)nlist__at(nk->prefix_list, prefix_i);
|
| 932 | nbool_t pass = fct_filter_pass(prefix, test_name);
|
| 933 | if ( pass ) {
|
| 934 | return FCT_TRUE;
|
| 935 | }
|
| 936 | }
|
| 937 |
|
| 938 | /* Otherwise, we never managed to find a prefix that satisfied the
|
| 939 | supplied test name. Therefore we have failed to pass to the filter
|
| 940 | list test. */
|
| 941 | return FCT_FALSE;
|
| 942 | }
|
| 943 |
|
| 944 |
|
| 945 | /* Returns the number of tests that were performed. */
|
| 946 | static int
|
| 947 | fctkern__tst_cnt(fctkern_t const *nk)
|
| 948 | {
|
| 949 | int tally =0;
|
| 950 | assert( nk != NULL );
|
| 951 |
|
| 952 | NLIST_FOREACH_BGN(fct_ts_t *, ts, nk->ts_list)
|
| 953 | {
|
| 954 | tally += fct_ts__tst_cnt(ts);
|
| 955 | }
|
| 956 | NLIST_FOREACH_END();
|
| 957 | return tally;
|
| 958 | }
|
| 959 |
|
| 960 | /* Returns the number of tests that passed. */
|
| 961 | static int
|
| 962 | fctkern__tst_cnt_passed(fctkern_t const *nk)
|
| 963 | {
|
| 964 | int tally =0;
|
| 965 | assert( nk != NULL );
|
| 966 |
|
| 967 | NLIST_FOREACH_BGN(fct_ts_t*, ts, nk->ts_list)
|
| 968 | {
|
| 969 | tally += fct_ts__tst_cnt_passed(ts);
|
| 970 | }
|
| 971 | NLIST_FOREACH_END();
|
| 972 |
|
| 973 | return tally;
|
| 974 | }
|
| 975 |
|
| 976 |
|
| 977 | /* Returns the number of tests that failed. */
|
| 978 | static int
|
| 979 | fctkern__tst_cnt_failed(fctkern_t const *nk)
|
| 980 | {
|
| 981 | /* Keep it simple for now and just do a little math. */
|
| 982 | int total =0;
|
| 983 | int passed =0;
|
| 984 | int failed =0;
|
| 985 |
|
| 986 | assert( nk != NULL );
|
| 987 |
|
| 988 | total = fctkern__tst_cnt(nk);
|
| 989 | passed = fctkern__tst_cnt_passed(nk);
|
| 990 |
|
| 991 | failed = total - passed;
|
| 992 |
|
| 993 | return failed;
|
| 994 | }
|
| 995 |
|
| 996 |
|
| 997 | /* Returns the number of checks made throughout the entire test. */
|
| 998 | static int
|
| 999 | fctkern__chk_cnt(fctkern_t const *nk)
|
| 1000 | {
|
| 1001 | int tally =0;
|
| 1002 | assert( nk != NULL );
|
| 1003 |
|
| 1004 | NLIST_FOREACH_BGN(fct_ts_t *, ts, nk->ts_list)
|
| 1005 | {
|
| 1006 | tally += fct_ts__chk_cnt(ts);
|
| 1007 | }
|
| 1008 | NLIST_FOREACH_END();
|
| 1009 | return tally;
|
| 1010 | }
|
| 1011 |
|
| 1012 |
|
| 1013 | /* Indicates the very end of all the tests. */
|
| 1014 | static void
|
| 1015 | fctkern__end(fctkern_t *fct)
|
| 1016 | {
|
| 1017 | fct_unused(fct);
|
| 1018 | }
|
| 1019 |
|
| 1020 |
|
| 1021 | /* Cleans up the contents of a fctkern. NULL does nothing. */
|
| 1022 | static void
|
| 1023 | fctkern__final(fctkern_t *fct)
|
| 1024 | {
|
| 1025 | if ( fct == NULL ) { return; }
|
| 1026 |
|
| 1027 | nlist__del(fct->logger_list, (on_del_t)fct_logger__del);
|
| 1028 |
|
| 1029 | /* The prefix list is a list of malloc'd strings. */
|
| 1030 | nlist__del(fct->prefix_list, (on_del_t)free);
|
| 1031 |
|
| 1032 | nlist__del(fct->ts_list, (on_del_t)fct_ts__del);
|
| 1033 | }
|
| 1034 |
|
| 1035 |
|
| 1036 | static void
|
| 1037 | fctkern__log_suite_start(fctkern_t *kern, fct_ts_t const *ts)
|
| 1038 | {
|
| 1039 | assert( kern != NULL );
|
| 1040 | assert( ts != NULL );
|
| 1041 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1042 | {
|
| 1043 | fct_logger__on_test_suite_start(logger, ts);
|
| 1044 | }
|
| 1045 | NLIST_FOREACH_END();
|
| 1046 | }
|
| 1047 |
|
| 1048 |
|
| 1049 | static void
|
| 1050 | fctkern__log_suite_end(fctkern_t *kern, fct_ts_t const *ts)
|
| 1051 | {
|
| 1052 | assert( kern != NULL );
|
| 1053 | assert( ts != NULL );
|
| 1054 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1055 | {
|
| 1056 | fct_logger__on_test_suite_end(logger, ts);
|
| 1057 | }
|
| 1058 | NLIST_FOREACH_END();
|
| 1059 | }
|
| 1060 |
|
| 1061 |
|
| 1062 | static void
|
| 1063 | fctkern__log_chk(fctkern_t *kern, fctchk_t const *chk)
|
| 1064 | {
|
| 1065 | assert( kern != NULL );
|
| 1066 | assert( chk != NULL );
|
| 1067 |
|
| 1068 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1069 | {
|
| 1070 | fct_logger__on_cndtn(logger, chk);
|
| 1071 | }
|
| 1072 | NLIST_FOREACH_END();
|
| 1073 | }
|
| 1074 |
|
| 1075 |
|
| 1076 | /* Called whenever a test is started. */
|
| 1077 | static void
|
| 1078 | fctkern__log_test_start(fctkern_t *kern, fct_test_t const *test)
|
| 1079 | {
|
| 1080 | assert( kern != NULL );
|
| 1081 | assert( test != NULL );
|
| 1082 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1083 | {
|
| 1084 | fct_logger__on_test_start(logger, test);
|
| 1085 | }
|
| 1086 | NLIST_FOREACH_END();
|
| 1087 | }
|
| 1088 |
|
| 1089 |
|
| 1090 | static void
|
| 1091 | fctkern__log_test_end(fctkern_t *kern, fct_test_t const *test)
|
| 1092 | {
|
| 1093 | assert( kern != NULL );
|
| 1094 | assert( test != NULL );
|
| 1095 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1096 | {
|
| 1097 | fct_logger__on_test_end(logger, test);
|
| 1098 | }
|
| 1099 | NLIST_FOREACH_END();
|
| 1100 | }
|
| 1101 |
|
| 1102 |
|
| 1103 | static void
|
| 1104 | fctkern__log_start(fctkern_t *kern)
|
| 1105 | {
|
| 1106 | assert( kern != NULL );
|
| 1107 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1108 | {
|
| 1109 | fct_logger__on_fct_start(logger, kern);
|
| 1110 | }
|
| 1111 | NLIST_FOREACH_END();
|
| 1112 | }
|
| 1113 |
|
| 1114 |
|
| 1115 | static void
|
| 1116 | fctkern__log_end(fctkern_t *kern)
|
| 1117 | {
|
| 1118 | assert( kern != NULL );
|
| 1119 | NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)
|
| 1120 | {
|
| 1121 | fct_logger__on_fct_end(logger, kern);
|
| 1122 | }
|
| 1123 | NLIST_FOREACH_END();
|
| 1124 | }
|
| 1125 |
|
| 1126 |
|
| 1127 | /*
|
| 1128 | -----------------------------------------------------------
|
| 1129 | LOGGER INTERFACE
|
| 1130 |
|
| 1131 | Defines an interface to a logging system. A logger
|
| 1132 | must define the following functions in order to hook
|
| 1133 | into the logging system.
|
| 1134 |
|
| 1135 | See the "Standard Logger" and "Minimal Logger" as examples
|
| 1136 | of the implementation.
|
| 1137 | -----------------------------------------------------------
|
| 1138 | */
|
| 1139 |
|
| 1140 | typedef void (*fct_logger_on_cndtn_fn)(fct_logger_i *self,
|
| 1141 | fctchk_t const *chk);
|
| 1142 | #define _fct_logger_head \
|
| 1143 | fct_logger_on_cndtn_fn on_cndtn;\
|
| 1144 | void (*on_test_start)(fct_logger_i *logger, fct_test_t const *test);\
|
| 1145 | void (*on_test_end)(fct_logger_i *logger, fct_test_t const *test);\
|
| 1146 | void (*on_test_suite_start)(fct_logger_i *logger, fct_ts_t const *ts);\
|
| 1147 | void (*on_test_suite_end)(fct_logger_i *logger, fct_ts_t const *ts);\
|
| 1148 | void (*on_fct_start)(fct_logger_i *logger, fctkern_t const *kern);\
|
| 1149 | void (*on_fct_end)(fct_logger_i *logger, fctkern_t const *kern);\
|
| 1150 | void (*on_delete)(fct_logger_i *logger)\
|
| 1151 |
|
| 1152 | struct _fct_logger_i {
|
| 1153 | _fct_logger_head;
|
| 1154 | };
|
| 1155 |
|
| 1156 |
|
| 1157 | /* Initializes the elements of a logger interface so they are at their
|
| 1158 | standard values. */
|
| 1159 | static void
|
| 1160 | fct_logger__init(fct_logger_i *logger)
|
| 1161 | {
|
| 1162 | assert( logger != NULL );
|
| 1163 | logger->on_cndtn =NULL;
|
| 1164 | logger->on_test_start =NULL;
|
| 1165 | logger->on_test_end =NULL;
|
| 1166 | logger->on_test_suite_start =NULL;
|
| 1167 | logger->on_test_suite_end =NULL;
|
| 1168 | logger->on_fct_start =NULL;
|
| 1169 | logger->on_fct_end =NULL;
|
| 1170 | logger->on_delete =NULL;
|
| 1171 | }
|
| 1172 |
|
| 1173 |
|
| 1174 | static void
|
| 1175 | fct_logger__del(fct_logger_i *logger)
|
| 1176 | {
|
| 1177 | if ( logger == NULL ) { return; }
|
| 1178 | if ( logger->on_delete) { logger->on_delete(logger); }
|
| 1179 | }
|
| 1180 |
|
| 1181 |
|
| 1182 | static void
|
| 1183 | fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test)
|
| 1184 | {
|
| 1185 | assert( logger != NULL && "invalid arg");
|
| 1186 | assert( test != NULL && "invalid arg");
|
| 1187 |
|
| 1188 | if ( logger->on_test_start != NULL )
|
| 1189 | {
|
| 1190 | logger->on_test_start(logger, test);
|
| 1191 | }
|
| 1192 | }
|
| 1193 |
|
| 1194 |
|
| 1195 | static void
|
| 1196 | fct_logger__on_test_end(fct_logger_i *logger, fct_test_t const *test)
|
| 1197 | {
|
| 1198 | assert( logger != NULL && "invalid arg");
|
| 1199 | assert( test != NULL && "invalid arg");
|
| 1200 |
|
| 1201 | if ( logger->on_test_end != NULL )
|
| 1202 | {
|
| 1203 | logger->on_test_end(logger, test);
|
| 1204 | }
|
| 1205 | }
|
| 1206 |
|
| 1207 |
|
| 1208 | static void
|
| 1209 | fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts)
|
| 1210 | {
|
| 1211 | assert( logger != NULL && "invalid arg");
|
| 1212 | assert( ts != NULL && "invalid arg");
|
| 1213 |
|
| 1214 | if ( logger->on_test_suite_start != NULL )
|
| 1215 | {
|
| 1216 | logger->on_test_suite_start(logger, ts);
|
| 1217 | }
|
| 1218 | }
|
| 1219 |
|
| 1220 |
|
| 1221 | static void
|
| 1222 | fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts)
|
| 1223 | {
|
| 1224 | assert( logger != NULL && "invalid arg");
|
| 1225 | assert( ts != NULL && "invalid arg");
|
| 1226 |
|
| 1227 | if ( logger->on_test_suite_end != NULL )
|
| 1228 | {
|
| 1229 | logger->on_test_suite_end(logger, ts);
|
| 1230 | }
|
| 1231 | }
|
| 1232 |
|
| 1233 |
|
| 1234 | static void
|
| 1235 | fct_logger__on_cndtn(fct_logger_i *logger, fctchk_t const *chk)
|
| 1236 | {
|
| 1237 | assert( logger != NULL && "invalid arg");
|
| 1238 | assert( chk != NULL && "invalid arg");
|
| 1239 |
|
| 1240 | if ( logger->on_cndtn )
|
| 1241 | {
|
| 1242 | logger->on_cndtn(logger, chk);
|
| 1243 | }
|
| 1244 | }
|
| 1245 |
|
| 1246 |
|
| 1247 | /* When we start all our tests. */
|
| 1248 | static void
|
| 1249 | fct_logger__on_fct_start(fct_logger_i *logger, fctkern_t const *kern)
|
| 1250 | {
|
| 1251 | assert( logger != NULL );
|
| 1252 | assert( kern != NULL );
|
| 1253 |
|
| 1254 | if ( logger->on_fct_start != NULL )
|
| 1255 | {
|
| 1256 | logger->on_fct_start(logger, kern);
|
| 1257 | }
|
| 1258 | }
|
| 1259 |
|
| 1260 |
|
| 1261 | /* When we have reached the end of ALL of our testing. */
|
| 1262 | static void
|
| 1263 | fct_logger__on_fct_end(fct_logger_i *logger, fctkern_t const *kern)
|
| 1264 | {
|
| 1265 | assert( logger != NULL );
|
| 1266 | assert( kern != NULL );
|
| 1267 |
|
| 1268 | if ( logger->on_fct_end )
|
| 1269 | {
|
| 1270 | logger->on_fct_end(logger, kern);
|
| 1271 | }
|
| 1272 | }
|
| 1273 |
|
| 1274 |
|
| 1275 |
|
| 1276 | /*
|
| 1277 | -----------------------------------------------------------
|
| 1278 | MINIMAL LOGGER
|
| 1279 | -----------------------------------------------------------
|
| 1280 | */
|
| 1281 |
|
| 1282 | /* Minimal logger, reports the minimum amount of information needed
|
| 1283 | to determine "something is happening". */
|
| 1284 | struct _fct_minimal_logger_t {
|
| 1285 | _fct_logger_head;
|
| 1286 | };
|
| 1287 |
|
| 1288 |
|
| 1289 | static void
|
| 1290 | fct_minimal_logger__on_cndtn(fct_logger_i *self, fctchk_t const *chk)
|
| 1291 | {
|
| 1292 | fct_unused(self);
|
| 1293 | printf(fctchk__is_pass(chk) ? "." : "!");
|
| 1294 | }
|
| 1295 |
|
| 1296 |
|
| 1297 | static void
|
| 1298 | fct_minimal_logger__del(fct_logger_i *self)
|
| 1299 | {
|
| 1300 | free(self);
|
| 1301 | }
|
| 1302 |
|
| 1303 |
|
| 1304 | static fct_minimal_logger_t *
|
| 1305 | fct_minimal_logger__new(void)
|
| 1306 | {
|
| 1307 | fct_minimal_logger_t *self = (fct_minimal_logger_t*)\
|
| 1308 | calloc(1,sizeof(fct_minimal_logger_t));
|
| 1309 | if ( self == NULL ) { return NULL; }
|
| 1310 |
|
| 1311 | fct_logger__init((fct_logger_i*)self);
|
| 1312 |
|
| 1313 | self->on_cndtn = fct_minimal_logger__on_cndtn;
|
| 1314 | self->on_delete = fct_minimal_logger__del;
|
| 1315 | return self;
|
| 1316 | }
|
| 1317 |
|
| 1318 |
|
| 1319 | /*
|
| 1320 | -----------------------------------------------------------
|
| 1321 | STANDARD LOGGER
|
| 1322 | -----------------------------------------------------------
|
| 1323 | */
|
| 1324 |
|
| 1325 | struct _fct_standard_logger_t {
|
| 1326 | _fct_logger_head;
|
| 1327 |
|
| 1328 | /* Start time. For now we use the low-accuracy time_t version. */
|
| 1329 | fct_timer_t timer;
|
| 1330 |
|
| 1331 | /* A list of char*'s that needs to be cleaned up. */
|
| 1332 | nlist_t *failed_cndtns_list;
|
| 1333 | };
|
| 1334 |
|
| 1335 |
|
| 1336 | /* When a failure occurrs, we will record the details so we can display
|
| 1337 | them when the log "finishes" up. */
|
| 1338 | static void
|
| 1339 | fct_standard_logger__on_cndtn(fct_logger_i *logger_, fctchk_t const *chk)
|
| 1340 | {
|
| 1341 | fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
|
| 1342 |
|
| 1343 | assert( logger != NULL );
|
| 1344 | assert( chk != NULL );
|
| 1345 |
|
| 1346 | /* Only record failures. */
|
| 1347 | if ( !fctchk__is_pass(chk) )
|
| 1348 | {
|
| 1349 | /* For now we will truncate the string to some set amount, later
|
| 1350 | we can work out a dynamic string object. */
|
| 1351 | char *str = (char*)malloc(sizeof(char)*FCT_MAX_LOG_LINE);
|
| 1352 | assert( str != NULL );
|
| 1353 |
|
| 1354 | fct_snprintf(
|
| 1355 | str,
|
| 1356 | FCT_MAX_LOG_LINE,
|
| 1357 | "%s(%d): %s",
|
| 1358 | fctchk__file(chk),
|
| 1359 | fctchk__lineno(chk),
|
| 1360 | fctchk__cndtn(chk)
|
| 1361 | );
|
| 1362 |
|
| 1363 | /* Append it to the listing ... */
|
| 1364 | nlist__append(logger->failed_cndtns_list, (void*)str);
|
| 1365 | }
|
| 1366 | }
|
| 1367 |
|
| 1368 |
|
| 1369 | static void
|
| 1370 | fct_standard_logger__on_test_start(fct_logger_i *logger_,
|
| 1371 | fct_test_t const *test)
|
| 1372 | {
|
| 1373 | fct_unused(logger_);
|
| 1374 | printf("%s ... ", fct_test__name(test));
|
| 1375 | }
|
| 1376 |
|
| 1377 |
|
| 1378 | static void
|
| 1379 | fct_standard_logger__on_test_end(fct_logger_i *logger_,
|
| 1380 | fct_test_t const *test)
|
| 1381 | {
|
| 1382 | nbool_t is_pass;
|
| 1383 | fct_unused(logger_);
|
| 1384 |
|
| 1385 | is_pass = fct_test__is_pass(test);
|
| 1386 | printf("%s\n", (is_pass) ? "PASS" : "FAIL" );
|
| 1387 | }
|
| 1388 |
|
| 1389 |
|
| 1390 | static void
|
| 1391 | fct_standard_logger__on_test_suite_start(fct_logger_i *logger_,
|
| 1392 | fct_ts_t const *ts)
|
| 1393 | {
|
| 1394 | fct_unused(logger_);
|
| 1395 | fct_unused(ts);
|
| 1396 | }
|
| 1397 |
|
| 1398 |
|
| 1399 | static void
|
| 1400 | fct_standard_logger__on_test_suite_end(fct_logger_i *logger_,
|
| 1401 | fct_ts_t const *ts)
|
| 1402 | {
|
| 1403 | fct_unused(logger_);
|
| 1404 | fct_unused(ts);
|
| 1405 | }
|
| 1406 |
|
| 1407 |
|
| 1408 | static void
|
| 1409 | fct_standard_logger__on_fct_start(fct_logger_i *logger_,
|
| 1410 | fctkern_t const *nk)
|
| 1411 | {
|
| 1412 | fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
|
| 1413 | fct_unused(nk);
|
| 1414 | fct_timer__start(&(logger->timer));
|
| 1415 | }
|
| 1416 |
|
| 1417 |
|
| 1418 | static void
|
| 1419 | fct_standard_logger__on_fct_end(fct_logger_i *logger_, fctkern_t const *nk)
|
| 1420 | {
|
| 1421 | fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
|
| 1422 | nbool_t is_success =1;
|
| 1423 | double elasped_time =0;
|
| 1424 | int num_tests =0;
|
| 1425 | int num_passed =0;
|
| 1426 |
|
| 1427 | fct_timer__stop(&(logger->timer));
|
| 1428 |
|
| 1429 | is_success = nlist__size(logger->failed_cndtns_list) ==0;
|
| 1430 |
|
| 1431 | if ( !is_success )
|
| 1432 | {
|
| 1433 | printf("\n--------------------------------------------------------\n");
|
| 1434 | printf("FAILED TESTS\n\n");
|
| 1435 |
|
| 1436 | NLIST_FOREACH_BGN(char *, cndtn_str, logger->failed_cndtns_list)
|
| 1437 | {
|
| 1438 | printf("%s\n", cndtn_str);
|
| 1439 | }
|
| 1440 | NLIST_FOREACH_END();
|
| 1441 |
|
| 1442 | printf("\n");
|
| 1443 | }
|
| 1444 |
|
| 1445 | printf("\n--------------------------------------------------------\n");
|
| 1446 |
|
| 1447 | num_tests = fctkern__tst_cnt(nk);
|
| 1448 | num_passed = fctkern__tst_cnt_passed(nk);
|
| 1449 |
|
| 1450 | printf(
|
| 1451 | "%s (%d/%d tests",
|
| 1452 | (is_success) ? "PASSED" : "FAILED",
|
| 1453 | num_passed,
|
| 1454 | num_tests
|
| 1455 | );
|
| 1456 |
|
| 1457 | elasped_time = fct_timer__duration(&(logger->timer));
|
| 1458 | if ( elasped_time > 0.0000001 )
|
| 1459 | {
|
| 1460 | printf(" in %.6fs)\n", elasped_time);
|
| 1461 | }
|
| 1462 | else
|
| 1463 | {
|
| 1464 | /* Don't bother displaying the time to execute. */
|
| 1465 | printf(")\n");
|
| 1466 | }
|
| 1467 | }
|
| 1468 |
|
| 1469 |
|
| 1470 | static void
|
| 1471 | fct_standard_logger__del(fct_logger_i *logger_)
|
| 1472 | {
|
| 1473 | fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
|
| 1474 |
|
| 1475 | NLIST_FOREACH_BGN(char *, cndtn_str, logger->failed_cndtns_list)
|
| 1476 | {
|
| 1477 | free(cndtn_str);
|
| 1478 | }
|
| 1479 | NLIST_FOREACH_END();
|
| 1480 |
|
| 1481 | free(logger);
|
| 1482 | logger_ =NULL;
|
| 1483 | }
|
| 1484 |
|
| 1485 |
|
| 1486 | fct_standard_logger_t *
|
| 1487 | fct_standard_logger__new(void)
|
| 1488 | {
|
| 1489 | fct_standard_logger_t *logger = (fct_standard_logger_t *)calloc(
|
| 1490 | 1, sizeof(fct_standard_logger_t)
|
| 1491 | );
|
| 1492 | if ( logger == NULL )
|
| 1493 | {
|
| 1494 | return NULL;
|
| 1495 | }
|
| 1496 | fct_logger__init((fct_logger_i*)logger);
|
| 1497 | logger->on_cndtn = fct_standard_logger__on_cndtn;
|
| 1498 | logger->on_test_start = fct_standard_logger__on_test_start;
|
| 1499 | logger->on_test_end = fct_standard_logger__on_test_end;
|
| 1500 | logger->on_test_suite_start = fct_standard_logger__on_test_suite_start;
|
| 1501 | logger->on_test_suite_end = fct_standard_logger__on_test_suite_end;
|
| 1502 | logger->on_fct_start = fct_standard_logger__on_fct_start;
|
| 1503 | logger->on_fct_end = fct_standard_logger__on_fct_end;
|
| 1504 | logger->on_delete = fct_standard_logger__del;
|
| 1505 |
|
| 1506 | logger->failed_cndtns_list = nlist_new();
|
| 1507 | assert( logger->failed_cndtns_list != NULL );
|
| 1508 |
|
| 1509 | fct_timer__init(&(logger->timer));
|
| 1510 |
|
| 1511 | return logger;
|
| 1512 | }
|
| 1513 |
|
| 1514 |
|
| 1515 |
|
| 1516 | /*
|
| 1517 | ------------------------------------------------------------
|
| 1518 | MAGIC MACROS
|
| 1519 | ------------------------------------------------------------
|
| 1520 | */
|
| 1521 |
|
| 1522 | #define FCT_BGN() \
|
| 1523 | int \
|
| 1524 | main(int argc, char *argv[])\
|
| 1525 | {\
|
| 1526 | fctkern_t fctkern__;\
|
| 1527 | fctkern_init(&fctkern__, argc, argv);\
|
| 1528 | fctkern__log_start(&fctkern__);
|
| 1529 |
|
| 1530 |
|
| 1531 | #define FCT_END()\
|
| 1532 | {\
|
| 1533 | int num_failed__ =0;\
|
| 1534 | num_failed__ = fctkern__tst_cnt_failed((&fctkern__));\
|
| 1535 | fctkern__log_end(&fctkern__);\
|
| 1536 | fctkern__end(&fctkern__);\
|
| 1537 | fctkern__final(&fctkern__);\
|
| 1538 | return num_failed__;\
|
| 1539 | }\
|
| 1540 | }
|
| 1541 |
|
| 1542 | #define FCT_FIXTURE_SUITE_BGN(_NAME_) \
|
| 1543 | {\
|
| 1544 | fct_ts_t *ts__ = fct_ts_new( #_NAME_ );\
|
| 1545 | fctkern__log_suite_start((&fctkern__), ts__);\
|
| 1546 | for (;;)\
|
| 1547 | {\
|
| 1548 | int fct_test_num__ = -1;\
|
| 1549 | _fct_cmt("Strict compiler warnings will complain in 'blank' suites.")\
|
| 1550 | _fct_cmt("so we are going to do a 'noop' to trick them.")\
|
| 1551 | fct_test_num__ = fct_test_num__;\
|
| 1552 | if ( fct_ts__is_ending_mode(ts__) )\
|
| 1553 | {\
|
| 1554 | _fct_cmt("flag the test suite as complete.");\
|
| 1555 | fct_ts__end(ts__);\
|
| 1556 | break;\
|
| 1557 | }
|
| 1558 |
|
| 1559 |
|
| 1560 | /* Closes off a "Fixture" test suite. */
|
| 1561 | #define FCT_FIXTURE_SUITE_END() \
|
| 1562 | if ( fct_ts__is_cnt_mode(ts__) )\
|
| 1563 | {\
|
| 1564 | fct_ts__cnt_end(ts__);\
|
| 1565 | }\
|
| 1566 | }\
|
| 1567 | fctkern__add_ts((&fctkern__), ts__);\
|
| 1568 | fctkern__log_suite_end((&fctkern__), ts__);\
|
| 1569 | ts__ = NULL;\
|
| 1570 | }
|
| 1571 |
|
| 1572 |
|
| 1573 |
|
| 1574 | #define FCT_SETUP_BGN()\
|
| 1575 | if ( fct_ts__is_setup_mode(ts__) ) {
|
| 1576 |
|
| 1577 | #define FCT_SETUP_END() \
|
| 1578 | fct_ts__setup_end(ts__); }
|
| 1579 |
|
| 1580 | #define FCT_TEARDOWN_BGN() \
|
| 1581 | if ( fct_ts__is_teardown_mode(ts__) ) {\
|
| 1582 |
|
| 1583 | #define FCT_TEARDOWN_END() \
|
| 1584 | fct_ts__teardown_end(ts__); \
|
| 1585 | continue; \
|
| 1586 | }
|
| 1587 |
|
| 1588 | /* Lets you create a test suite, where maybe you don't want a fixture. We
|
| 1589 | do it by 'stubbing' out the setup/teardown logic. */
|
| 1590 | #define FCT_SUITE_BGN(Name) \
|
| 1591 | FCT_FIXTURE_SUITE_BGN(Name) {\
|
| 1592 | FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\
|
| 1593 | FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\
|
| 1594 |
|
| 1595 | #define FCT_SUITE_END() } FCT_FIXTURE_SUITE_END()
|
| 1596 |
|
| 1597 | /* Depending on whether or not we are counting the tests, we will have to
|
| 1598 | first determine if the test is the "current" count. Then we have to determine
|
| 1599 | if we can pass the filter. Finally we will execute everything so that when a
|
| 1600 | check fails, we can "break" out to the end of the test. */
|
| 1601 | #define FCT_TEST_BGN(_NAME_) \
|
| 1602 | {\
|
| 1603 | char const *test_name__ = #_NAME_;\
|
| 1604 | ++fct_test_num__;\
|
| 1605 | if ( fct_ts__is_cnt_mode(ts__) )\
|
| 1606 | {\
|
| 1607 | fct_ts__inc_total_test_num(ts__);\
|
| 1608 | }\
|
| 1609 | else if ( fct_ts__is_test_mode(ts__) \
|
| 1610 | && fct_ts__is_test_cnt(ts__, fct_test_num__) )\
|
| 1611 | {\
|
| 1612 | int is_pass__;\
|
| 1613 | is_pass__ = FCT_FALSE;\
|
| 1614 | fct_ts__test_begin(ts__);\
|
| 1615 | if ( fctkern__pass_filter(&fctkern__, test_name__ ) )\
|
| 1616 | {\
|
| 1617 | fct_test_t *test__ = fct_test_new( test_name__ );\
|
| 1618 | fctkern__log_test_start(&fctkern__, test__);\
|
| 1619 | for (;;) \
|
| 1620 | {
|
| 1621 |
|
| 1622 | #define FCT_TEST_END() \
|
| 1623 | break;\
|
| 1624 | }\
|
| 1625 | fct_ts__add_test(ts__, test__);\
|
| 1626 | fctkern__log_test_end(&fctkern__, test__);\
|
| 1627 | }\
|
| 1628 | fct_ts__test_end(ts__);\
|
| 1629 | continue;\
|
| 1630 | }\
|
| 1631 | }
|
| 1632 |
|
| 1633 |
|
| 1634 |
|
| 1635 | /*
|
| 1636 | ---------------------------------------------------------
|
| 1637 | CHECKING MACROS
|
| 1638 | ----------------------------------------------------------
|
| 1639 |
|
| 1640 | For now we only have the one "positive" check macro. In the future I plan
|
| 1641 | to add more macros that check for different types of common conditions.
|
| 1642 | */
|
| 1643 |
|
| 1644 | #define fct_chk(_CNDTN_) \
|
| 1645 | {\
|
| 1646 | fctchk_t *chk =NULL;\
|
| 1647 | is_pass__ = (_CNDTN_);\
|
| 1648 | chk = fctchk_new(#_CNDTN_, __FILE__, __LINE__, is_pass__);\
|
| 1649 | fct_test__add(test__, chk);\
|
| 1650 | fctkern__log_chk(&fctkern__, chk);\
|
| 1651 | if ( !is_pass__ ) { break; }\
|
| 1652 | }
|
| 1653 |
|
| 1654 |
|
| 1655 | /*
|
| 1656 | ---------------------------------------------------------
|
| 1657 | GUT CHECK MACROS
|
| 1658 | ----------------------------------------------------------
|
| 1659 |
|
| 1660 | The following macros are used to help check the "guts" of
|
| 1661 | the FCT, and to confirm that it all works according to spec.
|
| 1662 | */
|
| 1663 |
|
| 1664 | /* Generates a message to STDERR and exits the application with a
|
| 1665 | non-zero number. */
|
| 1666 | #define _FCT_GUTCHK(_CNDTN_) \
|
| 1667 | if ( !(_CNDTN_) ) {\
|
| 1668 | fprintf(stderr, "gutchk fail: '" #_CNDTN_ "' was not true.\n");\
|
| 1669 | exit(1);\
|
| 1670 | }\
|
| 1671 | else {\
|
| 1672 | fprintf(stdout, "gutchk pass: '" #_CNDTN_ "'\n");\
|
| 1673 | }
|
| 1674 |
|
| 1675 |
|
| 1676 | /*
|
| 1677 | ---------------------------------------------------------
|
| 1678 | CLOSING STATEMENTS
|
| 1679 | ----------------------------------------------------------
|
| 1680 | */
|
| 1681 |
|
| 1682 | /* This is defined at the start of the file. We are undefining it
|
| 1683 | here so it doesn't conflict with existing. */
|
| 1684 | #if defined(WIN32)
|
| 1685 | # undef _CRT_SECURE_NO_WARNINGS
|
| 1686 | #endif
|
| 1687 |
|
| 1688 | #endif /* !FCT_INCLUDED__IMB */
|