fct.h

00001 /*
00002 ====================================================================
00003 Copyright (c) 2008 Ian Blumel.  All rights reserved.
00004 
00005 FCTX (Fast C Test) Unit Testing Framework
00006 
00007 Copyright (c) 2008, Ian Blumel (ian.blumel@gmail.com)
00008 All rights reserved.
00009 
00010 This license is based on the BSD License.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are
00014 met:
00015 
00016     * Redistributions of source code must retain the above copyright
00017     notice, this list of conditions and the following disclaimer.
00018 
00019     * Redistributions in binary form must reproduce the above copyright
00020     notice, this list of conditions and the following disclaimer in
00021     the documentation and/or other materials provided with the
00022     distribution.
00023 
00024     * Neither the name of, Ian Blumel, nor the names of its
00025     contributors may be used to endorse or promote products derived
00026     from this software without specific prior written permission.
00027 
00028 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00029 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00030 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00031 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00032 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00033 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00034 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00035 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00036 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00037 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00038 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039 ====================================================================
00040 
00041 File: fct.h
00042 */
00043 
00044 #if !defined(FCT_INCLUDED__IMB)
00045 #define FCT_INCLUDED__IMB
00046 
00047 /* Configuration Values. You can over-ride these values in your own
00048 header, then include this header. For example, in your file, myfct.h,
00049 
00050     #define FCT_DEFAULT_LOGGER "standard"
00051     #include "fct.h"
00052 
00053 then if your unit tests included, myfct.h, you would default to work
00054 with a standard logger. */
00055 
00056 #if !defined(FCT_DEFAULT_LOGGER)
00057 #   define FCT_DEFAULT_LOGGER  "standard"
00058 #endif /* !FCT_DEFAULT_LOGGER */
00059 
00060 #define FCT_VERSION_MAJOR 1
00061 #define FCT_VERSION_MINOR 6
00062 #define FCT_VERSION_MICRO 1
00063 
00064 #define _FCT_QUOTEME(x) #x
00065 #define FCT_QUOTEME(x) _FCT_QUOTEME(x)
00066 
00067 #define FCT_VERSION_STR (FCT_QUOTEME(FCT_VERSION_MAJOR) "."\
00068                          FCT_QUOTEME(FCT_VERSION_MINOR) "."\
00069                          FCT_QUOTEME(FCT_VERSION_MICRO))
00070 
00071 #include <string.h>
00072 #include <assert.h>
00073 #include <stdarg.h>
00074 #include <stdlib.h>
00075 #include <stdio.h>
00076 #include <time.h>
00077 #include <float.h>
00078 #include <math.h>
00079 #include <ctype.h>
00080 
00081 #define FCT_MAX_NAME           256
00082 #define FCT_MAX_LOG_LINE       256
00083 
00084 #define nbool_t int
00085 #define FCT_TRUE   1
00086 #define FCT_FALSE  0
00087 
00088 #define FCTMIN(x, y) ( x < y) ? (x) : (y)
00089 
00090 #ifndef __INTEL_COMPILER
00091 /* Use regular assertions for non-Intel compilers */
00092 #define FCT_ASSERT(expr) assert(expr)
00093 #else
00094 /* Silence Intel warnings on assert(expr && "str") or assert("str") */
00095 #define FCT_ASSERT(expr) do {             \
00096     _Pragma("warning(push,disable:279)"); \
00097     assert(expr);                         \
00098     _Pragma("warning(pop)");              \
00099     } while (0)
00100 #endif
00101 
00102 #if defined(__cplusplus)
00103 #define FCT_EXTERN_C extern "C"
00104 #else
00105 #define FCT_EXTERN_C
00106 #endif
00107 
00108 /* Forward declarations. The following forward declarations are required
00109 because there is a inter-relationship between certain objects that
00110 just can not be untwined. */
00111 typedef struct _fct_logger_evt_t fct_logger_evt_t;
00112 typedef struct _fct_logger_i fct_logger_i;
00113 typedef struct _fct_logger_types_t fct_logger_types_t;
00114 typedef struct _fct_standard_logger_t fct_standard_logger_t;
00115 typedef struct _fct_junit_logger_t fct_junit_logger_t;
00116 typedef struct _fct_minimal_logger_t fct_minimal_logger_t;
00117 typedef struct _fctchk_t fctchk_t;
00118 typedef struct _fct_test_t fct_test_t;
00119 typedef struct _fct_ts_t fct_ts_t;
00120 typedef struct _fctkern_t fctkern_t;
00121 
00122 /* Forward declare some functions used throughout. */
00123 static fct_logger_i*
00124 fct_standard_logger_new(void);
00125 
00126 static fct_logger_i*
00127 fct_minimal_logger_new(void);
00128 
00129 static fct_junit_logger_t *
00130 fct_junit_logger_new(void);
00131 
00132 static void
00133 fct_logger__del(fct_logger_i *logger);
00134 
00135 static void
00136 fct_logger__on_chk(fct_logger_i *self, fctchk_t const *chk);
00137 
00138 static void
00139 fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test);
00140 
00141 static void
00142 fct_logger__on_test_end(fct_logger_i *logger, fct_test_t *test);
00143 
00144 static void
00145 fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts);
00146 
00147 static void
00148 fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts);
00149 
00150 static void
00151 fct_logger__on_test_suite_skip(
00152     fct_logger_i *logger,
00153     char const *condition,
00154     char const *name
00155 );
00156 
00157 static void
00158 fct_logger__on_test_skip(
00159     fct_logger_i *logger,
00160     char const *condition,
00161     char const *name
00162 );
00163 
00164 
00165 static void
00166 fct_logger__on_warn(fct_logger_i *logger, char const *warn);
00167 
00168 
00169 
00170 /* Explicitly indicate a no-op */
00171 #define fct_pass()
00172 
00173 #define fct_unused(x)  (void)(x)
00174 
00175 /* This is just a little trick to let me put comments inside of macros. I
00176 really only want to bother with this when we are "unwinding" the macros
00177 for debugging purposes. */
00178 #if defined(FCT_CONF_UNWIND)
00179 #       define _fct_cmt(string)         {char*_=string;}
00180 #else
00181 #       define _fct_cmt(string)
00182 #endif
00183 
00184 /*
00185 --------------------------------------------------------
00186 UTILITIES
00187 --------------------------------------------------------
00188 */
00189 
00190 
00191 /* STDIO and STDERR redirect support */
00192 #define FCT_PIPE_RESERVE_BYTES_DEFAULT  512
00193 static int fct_stdout_pipe[2];
00194 static int fct_stderr_pipe[2];
00195 static int fct_saved_stdout;
00196 static int fct_saved_stderr;
00197 
00198 /* Platform indepedent pipe functions. TODO: Look to figure this out in a way
00199 that follows the ISO C++ conformant naming convention. */
00200 #if defined(WIN32)
00201 #    include <io.h>
00202 #    include <fcntl.h>
00203 #    define _fct_pipe(_PFDS_) \
00204         _pipe((_PFDS_), FCT_PIPE_RESERVE_BYTES_DEFAULT, _O_TEXT)
00205 #    define _fct_dup  _dup
00206 #    define _fct_dup2 _dup2
00207 #    define _fct_close _close
00208 #    define _fct_read  _read
00209 /* Until I can figure a better way to do this, rely on magic numbers. */
00210 #    define STDOUT_FILENO 1
00211 #    define STDERR_FILENO 2
00212 #else
00213 #    include <unistd.h>
00214 #    define _fct_pipe  pipe
00215 #    define _fct_dup   dup
00216 #    define _fct_dup2  dup2
00217 #    define _fct_close close
00218 #    define _fct_read  read
00219 #endif /* WIN32 */
00220 
00221 
00222 
00223 
00224 static void
00225 fct_switch_std_to_buffer(int std_pipe[2], FILE *out, int fileno_, int *save_handle)
00226 {
00227     fflush(out);
00228     *save_handle = _fct_dup(fileno_);
00229     if ( _fct_pipe(std_pipe) != 0 )
00230     {
00231         exit(1);
00232     }
00233     _fct_dup2(std_pipe[1], fileno_);
00234     _fct_close(std_pipe[1]);
00235 }
00236 
00237 
00238 static void
00239 fct_switch_std_to_std(FILE *out, int fileno_, int save_handle)
00240 {
00241     fflush(out);
00242     _fct_dup2(save_handle, fileno_);
00243 }
00244 
00245 
00246 #define FCT_SWITCH_STDOUT_TO_BUFFER() \
00247     fct_switch_std_to_buffer(fct_stdout_pipe, stdout, STDOUT_FILENO, &fct_saved_stdout)
00248 #define FCT_SWITCH_STDOUT_TO_STDOUT() \
00249     fct_switch_std_to_std(stdout, STDOUT_FILENO, fct_saved_stdout)
00250 #define FCT_SWITCH_STDERR_TO_BUFFER() \
00251     fct_switch_std_to_buffer(fct_stderr_pipe, stderr, STDERR_FILENO, &fct_saved_stderr)
00252 #define FCT_SWITCH_STDERR_TO_STDERR() \
00253     fct_switch_std_to_std(stderr, STDERR_FILENO, fct_saved_stderr)
00254 
00255 
00256 /* Utility for truncated, safe string copies. The NUM
00257 should be the length of DST plus the null-termintor. */
00258 static void
00259 fctstr_safe_cpy(char *dst, char const *src, size_t num)
00260 {
00261     FCT_ASSERT( dst != NULL );
00262     FCT_ASSERT( src != NULL );
00263     FCT_ASSERT( num > 0 );
00264 #if defined(WIN32) && _MSC_VER >= 1400
00265     strncpy_s(dst, num, src, _TRUNCATE);
00266 #else
00267     strncpy(dst, src, num);
00268 #endif
00269     dst[num-1] = '\0';
00270 }
00271 
00272 /* Isolate the vsnprintf implementation */
00273 static int
00274 fct_vsnprintf(char *buffer,
00275               size_t buffer_len,
00276               char const *format,
00277               va_list args)
00278 {
00279     int count =0;
00280     /* Older microsoft compilers where not ANSI compliant with this
00281     function and you had to use _vsnprintf. I will assume that newer
00282     Microsoft Compilers start implementing vsnprintf. */
00283 #if defined(_MSC_VER) && (_MSC_VER < 1400)
00284     count = _vsnprintf(buffer, buffer_len, format, args);
00285 #elif defined(_MSC_VER) && (_MSC_VER >= 1400)
00286     count = vsnprintf_s(buffer, buffer_len, _TRUNCATE, format, args);
00287 #else
00288     count = vsnprintf(buffer, buffer_len, format, args);
00289 #endif
00290     return count;
00291 }
00292 
00293 
00294 /* Isolate the snprintf implemenation. */
00295 static int
00296 fct_snprintf(char *buffer, size_t buffer_len, char const *format, ...)
00297 {
00298     int count =0;
00299     va_list args;
00300     va_start(args, format);
00301     count =fct_vsnprintf(buffer, buffer_len, format, args);
00302     va_end(args);
00303     return count;
00304 }
00305 
00306 
00307 /* Helper to for cloning strings on the heap. Returns NULL for
00308 an out of memory condition. */
00309 static char*
00310 fctstr_clone(char const *s)
00311 {
00312     char *k =NULL;
00313     size_t klen =0;
00314     FCT_ASSERT( s != NULL && "invalid arg");
00315     klen = strlen(s)+1;
00316     k = (char*)malloc(sizeof(char)*klen+1);
00317     fctstr_safe_cpy(k, s, klen);
00318     return k;
00319 }
00320 
00321 
00322 /* Clones and returns a lower case version of the original string. */
00323 static char*
00324 fctstr_clone_lower(char const *s)
00325 {
00326     char *k =NULL;
00327     size_t klen =0;
00328     size_t i;
00329     if ( s == NULL )
00330     {
00331         return NULL;
00332     }
00333     klen = strlen(s)+1;
00334     k = (char*)malloc(sizeof(char)*klen+1);
00335     for ( i=0; i != klen; ++i )
00336     {
00337         k[i] = (char)tolower(s[i]);
00338     }
00339     return k;
00340 }
00341 
00342 
00343 /* A very, very simple "filter". This just compares the supplied prefix
00344 against the test_str, to see if they both have the same starting
00345 characters. If they do we return true, otherwise we return false. If the
00346 prefix is a blank string or NULL, then it will return FCT_TRUE.*/
00347 static nbool_t
00348 fct_filter_pass(char const *prefix, char const *test_str)
00349 {
00350     nbool_t is_match = FCT_FALSE;
00351     char const *prefix_p;
00352     char const *test_str_p;
00353 
00354     /* If you got nothing to test against, why test? */
00355     FCT_ASSERT( test_str != NULL );
00356 
00357     /* When the prefix is NULL or blank, we always return FCT_TRUE. */
00358     if ( prefix == NULL  || prefix[0] == '\0' )
00359     {
00360         return FCT_TRUE;
00361     }
00362 
00363     /* Iterate through both character arrays at the same time. We are
00364     going to play a game and see if we can beat the house. */
00365     for ( prefix_p = prefix, test_str_p = test_str;
00366             *prefix_p != '\0' && *test_str_p != '\0';
00367             ++prefix_p, ++test_str_p )
00368     {
00369         is_match = *prefix_p == *test_str_p;
00370         if ( !is_match )
00371         {
00372             break;   /* Quit the first time we don't match. */
00373         }
00374     }
00375 
00376     /* If the iterator for the test_str is pointing at the null char, and
00377     the iterator for the prefix string is not, then the prefix string is
00378     larger than the actual test string, and therefore we failed to pass the
00379     filter. */
00380     if ( *test_str_p == '\0' && *prefix_p != '\0' )
00381     {
00382         return FCT_FALSE;
00383     }
00384 
00385     /* is_match will be set to the either FCT_TRUE if we kicked of the loop
00386     early because our filter ran out of characters or FCT_FALSE if we
00387     encountered a mismatch before our filter ran out of characters. */
00388     return is_match;
00389 }
00390 
00391 
00392 /* Routine checks if two strings are equal. Taken from
00393 http://publications.gbdirect.co.uk/c_book/chapter5/character_handling.html
00394 */
00395 static int
00396 fctstr_eq(char const *s1, char const *s2)
00397 {
00398     if ( s1 == s2 )
00399     {
00400         return 1;
00401     }
00402     if ( (s1 == NULL && s2 != NULL)
00403             || (s1 != NULL && s2 == NULL) )
00404     {
00405         return 0;
00406     }
00407     while (*s1 == *s2)
00408     {
00409         if (*s1 == '\0')
00410             return 1;
00411         s1++;
00412         s2++;
00413     }
00414     /* Difference detected! */
00415     return 0;
00416 }
00417 
00418 
00419 static int
00420 fctstr_ieq(char const *s1, char const *s2)
00421 {
00422     if ( s1 == s2 )
00423     {
00424         return 1;
00425     }
00426     if ( (s1 == NULL && s2 != NULL)
00427             || (s1 != NULL && s2 == NULL) )
00428     {
00429         return 0;
00430     }
00431     while (tolower(*s1) == tolower(*s2))
00432     {
00433         if (*s1 == '\0')
00434             return 1;
00435         s1++;
00436         s2++;
00437     }
00438     /* Difference detected! */
00439     return 0;
00440 }
00441 
00442 
00443 /* Returns 1 if the STR contains the CHECK_INCL substring. NULL's
00444 are handled, and NULL always INCLUDES NULL. This check is case
00445 sensitive. If two strings point to the same place they are
00446 included. */
00447 static int
00448 fctstr_incl(char const *str, char const *check_incl)
00449 {
00450     static char const *blank_s = "";
00451     char const *found = NULL;
00452     if ( str == NULL )
00453     {
00454         str = blank_s;
00455     }
00456     if ( check_incl == NULL )
00457     {
00458         check_incl = blank_s;
00459     }
00460     if ( str == check_incl )
00461     {
00462         return 1;
00463     }
00464     found = strstr(str, check_incl);
00465     return found != NULL;
00466 }
00467 
00468 
00469 /* Does a case insensitive include check. */
00470 static int
00471 fctstr_iincl(char const *str, char const *check_incl)
00472 {
00473     /* Going to do this with a memory allocation to save coding
00474     time. In the future this can be rewritten. Both clone_lower
00475     and _incl are NULL tolerant. */
00476     char *lstr = fctstr_clone_lower(str);
00477     char *lcheck_incl = fctstr_clone_lower(check_incl);
00478     int found = fctstr_incl(lstr, lcheck_incl);
00479     free(lstr);
00480     free(lcheck_incl);
00481     return found;
00482 }
00483 
00484 
00485 /* Returns true if STR starts with CHECK. NULL and NULL is consider
00486 true. */
00487 static int
00488 fctstr_startswith(char const *str, char const *check)
00489 {
00490     char const *sp;
00491     if ( str == NULL && check == NULL )
00492     {
00493         return 1;
00494     }
00495     else if ( ((str == NULL) && (check != NULL))
00496               || ((str != NULL) && (check == NULL)) )
00497     {
00498         return 0;
00499     }
00500     sp = strstr(str, check);
00501     return sp == str;
00502 }
00503 
00504 
00505 /* Case insenstive variant of fctstr_startswith. */
00506 static int
00507 fctstr_istartswith(char const *str, char const *check)
00508 {
00509     /* Taking the lazy approach for now. */
00510     char *istr = fctstr_clone_lower(str);
00511     char *icheck = fctstr_clone_lower(check);
00512     /* TODO: check for memory. */
00513     int startswith = fctstr_startswith(istr, icheck);
00514     free(istr);
00515     free(icheck);
00516     return startswith;
00517 }
00518 
00519 
00520 /* Returns true if the given string ends with the given
00521 check. Treats NULL as a blank string, and as such, will
00522 pass the ends with (a blank string endswith a blank string). */
00523 static int
00524 fctstr_endswith(char const *str, char const *check)
00525 {
00526     size_t check_i;
00527     size_t str_i;
00528     if ( str == NULL && check == NULL )
00529     {
00530         return 1;
00531     }
00532     else if ( ((str == NULL) && (check != NULL))
00533               || ((str != NULL) && (check == NULL)) )
00534     {
00535         return 0;
00536     }
00537     check_i = strlen(check);
00538     str_i = strlen(str);
00539     if ( str_i < check_i )
00540     {
00541         return 0;   /* Can't do it string is too small. */
00542     }
00543     for ( ; check_i != 0; --check_i, --str_i)
00544     {
00545         if ( str[str_i] != check[check_i] )
00546         {
00547             return 0; /* Found a case where they are not equal. */
00548         }
00549     }
00550     /* Exahausted check against string, can only be true. */
00551     return 1;
00552 }
00553 
00554 
00555 static int
00556 fctstr_iendswith(char const *str, char const *check)
00557 {
00558     size_t check_i;
00559     size_t str_i;
00560     if ( str == NULL && check == NULL )
00561     {
00562         return 1;
00563     }
00564     else if ( ((str == NULL) && (check != NULL))
00565               || ((str != NULL) && (check == NULL)) )
00566     {
00567         return 0;
00568     }
00569     check_i = strlen(check);
00570     str_i = strlen(str);
00571     if ( str_i < check_i )
00572     {
00573         return 0;   /* Can't do it string is too small. */
00574     }
00575     for ( ; check_i != 0; --check_i, --str_i)
00576     {
00577         if ( tolower(str[str_i]) != tolower(check[check_i]) )
00578         {
00579             return 0; /* Found a case where they are not equal. */
00580         }
00581     }
00582     /* Exahausted check against string, can only be true. */
00583     return 1;
00584 }
00585 
00586 
00587 /* Use this with the _end variant to get the
00588 
00589 STARTSWITH ........................................ END
00590 
00591 effect. Assumes that the line will be maxwidth in characters. The
00592 maxwidth can't be greater than FCT_DOTTED_MAX_LEN. */
00593 #define FCT_DOTTED_MAX_LEN  256
00594 static void
00595 fct_dotted_line_start(size_t maxwidth, char const *startwith)
00596 {
00597     char line[FCT_DOTTED_MAX_LEN];
00598     size_t len =0;
00599     size_t line_len =0;
00600 
00601     memset(line, '.', sizeof(char)*maxwidth);
00602     len = strlen(startwith);
00603     line_len = FCTMIN(maxwidth-1, len);
00604     memcpy(line, startwith, sizeof(char)*line_len);
00605     if ( len < maxwidth-1)
00606     {
00607         line[len] = ' ';
00608     }
00609     line[maxwidth-1] = '\0';
00610     fputs(line, stdout);
00611 }
00612 
00613 
00614 static void
00615 fct_dotted_line_end(char const *endswith)
00616 {
00617     printf(" %s\n", endswith);
00618 }
00619 
00620 
00621 /*
00622 --------------------------------------------------------
00623 TIMER
00624 --------------------------------------------------------
00625 This is a low-res implementation at the moment.
00626 
00627 We will improve this in the future, and isolate the
00628 implementation from the rest of the code.
00629 */
00630 
00631 typedef struct _fct_timer_t fct_timer_t;
00632 struct _fct_timer_t
00633 {
00634     clock_t start;
00635     clock_t stop;
00636     double duration;
00637 };
00638 
00639 
00640 static void
00641 fct_timer__init(fct_timer_t *timer)
00642 {
00643     FCT_ASSERT(timer != NULL);
00644     memset(timer, 0, sizeof(fct_timer_t));
00645 }
00646 
00647 
00648 static void
00649 fct_timer__start(fct_timer_t *timer)
00650 {
00651     FCT_ASSERT(timer != NULL);
00652     timer->start = clock();
00653 }
00654 
00655 
00656 static void
00657 fct_timer__stop(fct_timer_t *timer)
00658 {
00659     FCT_ASSERT(timer != NULL);
00660     timer->stop = clock();
00661     timer->duration = (double) (timer->stop - timer->start) / CLOCKS_PER_SEC;
00662 }
00663 
00664 
00665 /* Returns the time in seconds. */
00666 static double
00667 fct_timer__duration(fct_timer_t const *timer)
00668 {
00669     FCT_ASSERT( timer != NULL );
00670     return timer->duration;
00671 }
00672 
00673 
00674 /*
00675 --------------------------------------------------------
00676 GENERIC LIST
00677 --------------------------------------------------------
00678 */
00679 
00680 /* For now we will just keep it at a linear growth rate. */
00681 #define FCT_LIST_GROWTH_FACTOR   2
00682 
00683 /* Starting size for the list, to keep it simple we will start
00684 at a reasonable size. */
00685 #define FCT_LIST_DEFAULT_START_SZ      8
00686 
00687 /* Helper macros for quickly iterating through a list. You should be able
00688 to do something like,
00689 
00690   FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, my_list)
00691   {
00692      fct_logger__on_blah(logger);
00693   }
00694   FCT_NLIST_FOREACH_END();
00695 
00696 */
00697 #define FCT_NLIST_FOREACH_BGN(Type, Var, List)\
00698 {\
00699    if ( List != NULL ) {\
00700       size_t item_i##Var;\
00701       size_t num_items##Var = fct_nlist__size(List);\
00702       for( item_i##Var =0; item_i##Var != num_items##Var; ++item_i##Var )\
00703       {\
00704          Type Var = (Type) fct_nlist__at((List), item_i##Var);
00705 
00706 #define FCT_NLIST_FOREACH_END() }}}
00707 
00708 /* Used to manage a list of loggers. This works mostly like
00709 the STL vector, where the array grows as more items are
00710 appended. */
00711 typedef struct _fct_nlist_t fct_nlist_t;
00712 struct _fct_nlist_t
00713 {
00714     /* Item's are stored as pointers to void. */
00715     void **itm_list;
00716 
00717     /* Indicates the number of element's in the array. */
00718     size_t avail_itm_num;
00719 
00720     /* Indicates the number of actually elements in the array. */
00721     size_t used_itm_num;
00722 };
00723 typedef void (*fct_nlist_on_del_t)(void*);
00724 
00725 
00726 /* Clears the contents of the list, and sets the list count to 0. The
00727 actual count remains unchanged. If on_del is supplied it is executed
00728 against each list element. */
00729 static void
00730 fct_nlist__clear(fct_nlist_t *list, fct_nlist_on_del_t on_del)
00731 {
00732     size_t itm_i__ =0;
00733     FCT_ASSERT( list != NULL );
00734     if ( on_del != NULL )
00735     {
00736         for ( itm_i__=0; itm_i__ != list->used_itm_num; ++itm_i__ )
00737         {
00738             on_del(list->itm_list[itm_i__]);
00739         }
00740     }
00741     list->used_itm_num =0;
00742 }
00743 
00744 
00745 /* If you used init, then close with final. This is useful for
00746 working with structures that live on the stack. */
00747 static void
00748 fct_nlist__final(fct_nlist_t *list, fct_nlist_on_del_t on_del)
00749 {
00750     FCT_ASSERT( list != NULL );
00751     fct_nlist__clear(list, on_del);
00752     free(list->itm_list);
00753 }
00754 
00755 
00756 static int
00757 fct_nlist__init2(fct_nlist_t *list, size_t start_sz)
00758 {
00759     FCT_ASSERT( list != NULL );
00760     if ( start_sz == 0 )
00761     {
00762         list->itm_list = NULL;
00763     }
00764     else
00765     {
00766         list->itm_list = (void**)malloc(sizeof(void*)*start_sz);
00767         if ( list->itm_list == NULL )
00768         {
00769             return 0;
00770         }
00771     }
00772     /* If these are both 0, then they are equal and that means
00773     that the first append operation will allocate memory. The beauty
00774     here is that if the list remains empty, then we save a malloc.
00775     Empty lists are relatively common in FCT (consider an error list). */
00776     list->avail_itm_num = start_sz;
00777     list->used_itm_num =0;
00778     return 1;
00779 }
00780 
00781 
00782 /* Initializes a list. Useful for populating existing structures.
00783 Returns 0 if there was an error allocating memory. Returns 1 otherwise. */
00784 #define fct_nlist__init(_LIST_PTR_) \
00785    (fct_nlist__init2((_LIST_PTR_), FCT_LIST_DEFAULT_START_SZ))
00786 
00787 
00788 /* Returns the number of elements within the list. */
00789 static size_t
00790 fct_nlist__size(fct_nlist_t const *list)
00791 {
00792     FCT_ASSERT( list != NULL );
00793     return list->used_itm_num;
00794 }
00795 
00796 
00797 /* Returns the item at idx, asserts otherwise. */
00798 static void*
00799 fct_nlist__at(fct_nlist_t const *list, size_t idx)
00800 {
00801     FCT_ASSERT( list != NULL );
00802     FCT_ASSERT( idx < list->used_itm_num );
00803     return list->itm_list[idx];
00804 }
00805 
00806 
00807 static void
00808 fct_nlist__append(fct_nlist_t *list, void *itm)
00809 {
00810     FCT_ASSERT( list != NULL );
00811     /* If we ran out of room, then the last increment should be equal to the
00812     available space, in this case we need to grow a little more. If this
00813     list started as size 0, then we should encounter the same effect as
00814     "running out of room." */
00815     if ( list->used_itm_num == list->avail_itm_num )
00816     {
00817         /* Use multiple and add, since the avail_itm_num could be 0. */
00818         list->avail_itm_num = list->avail_itm_num*FCT_LIST_GROWTH_FACTOR+\
00819                               FCT_LIST_GROWTH_FACTOR;
00820         list->itm_list = (void**)realloc(
00821                              list->itm_list, sizeof(void*)*list->avail_itm_num
00822                          );
00823         FCT_ASSERT( list->itm_list != NULL && "memory check");
00824     }
00825 
00826     list->itm_list[list->used_itm_num] = itm;
00827     ++(list->used_itm_num);
00828 }
00829 
00830 
00831 
00832 /*
00833 -----------------------------------------------------------
00834 A SINGLE CHECK
00835 -----------------------------------------------------------
00836 This defines a single check. It indicates what the check was,
00837 and where it occurred. A "Test" object will have-a bunch
00838 of "checks".
00839 */
00840 
00841 struct _fctchk_t
00842 {
00843     /* This string that represents the condition. */
00844     char cndtn[FCT_MAX_LOG_LINE];
00845 
00846     /* These indicate where the condition occurred. */
00847     char file[FCT_MAX_LOG_LINE];
00848 
00849     int lineno;
00850 
00851     nbool_t is_pass;
00852 
00853     /* This is a message that we can "format into", if
00854     no format string is specified this should be
00855     equivalent to the cntdn. */
00856     char msg[FCT_MAX_LOG_LINE];
00857 };
00858 
00859 #define fctchk__is_pass(_CHK_) ((_CHK_)->is_pass)
00860 #define fctchk__file(_CHK_)    ((_CHK_)->file)
00861 #define fctchk__lineno(_CHK_)  ((_CHK_)->lineno)
00862 #define fctchk__cndtn(_CHK_)   ((_CHK_)->cndtn)
00863 #define fctchk__msg(_CHK_)     ((_CHK_)->msg)
00864 
00865 static fctchk_t*
00866 fctchk_new(int is_pass,
00867            char const *cndtn,
00868            char const *file,
00869            int lineno,
00870            char const *format,
00871            va_list args)
00872 {
00873     fctchk_t *chk = NULL;
00874 
00875     FCT_ASSERT( cndtn != NULL );
00876     FCT_ASSERT( file != NULL );
00877     FCT_ASSERT( lineno > 0 );
00878 
00879     chk = (fctchk_t*)calloc(1, sizeof(fctchk_t));
00880     if ( chk == NULL )
00881     {
00882         return NULL;
00883     }
00884 
00885     fctstr_safe_cpy(chk->cndtn, cndtn, FCT_MAX_LOG_LINE);
00886     fctstr_safe_cpy(chk->file, file, FCT_MAX_LOG_LINE);
00887     chk->lineno = lineno;
00888 
00889     chk->is_pass =is_pass;
00890 
00891     if ( format != NULL )
00892     {
00893         fct_vsnprintf(chk->msg, FCT_MAX_LOG_LINE, format, args);
00894     }
00895     else
00896     {
00897         /* Default to make the condition be the message, if there was no format
00898         specified. */
00899         fctstr_safe_cpy(chk->msg, cndtn, FCT_MAX_LOG_LINE);
00900     }
00901 
00902     return chk;
00903 }
00904 
00905 
00906 /* Cleans up a "check" object. If the `chk` is NULL, this function does
00907 nothing. */
00908 static void
00909 fctchk__del(fctchk_t *chk)
00910 {
00911     if ( chk == NULL )
00912     {
00913         return;
00914     }
00915     free( chk );
00916 }
00917 
00918 
00919 /*
00920 -----------------------------------------------------------
00921 A TEST
00922 -----------------------------------------------------------
00923 A suite will have-a list of tests. Where each test will have-a
00924 list of failed and passed checks.
00925 */
00926 
00927 struct _fct_test_t
00928 {
00929     /* List of failed and passed "checks" (fctchk_t). Two seperate
00930     lists make it faster to determine how many checks passed and how
00931     many checks failed. */
00932     fct_nlist_t failed_chks;
00933     fct_nlist_t passed_chks;
00934 
00935     /* To store the test run time */
00936     fct_timer_t timer;
00937 
00938     /* The name of the test case. */
00939     char name[FCT_MAX_NAME];
00940 };
00941 
00942 #define fct_test__name(_TEST_) ((_TEST_)->name)
00943 
00944 /* Clears the failed tests ... partly for internal testing. */
00945 #define fct_test__clear_failed(test) \
00946     fct_nlist__clear(test->failed_chks, (fct_nlist_on_del_t)fctchk__del);\
00947  
00948 
00949 static void
00950 fct_test__del(fct_test_t *test)
00951 {
00952     if (test == NULL )
00953     {
00954         return;
00955     }
00956     fct_nlist__final(&(test->passed_chks), (fct_nlist_on_del_t)fctchk__del);
00957     fct_nlist__final(&(test->failed_chks), (fct_nlist_on_del_t)fctchk__del);
00958     free(test);
00959 }
00960 
00961 
00962 static fct_test_t*
00963 fct_test_new(char const *name)
00964 {
00965     nbool_t ok =FCT_FALSE;
00966     fct_test_t *test =NULL;
00967 
00968     test = (fct_test_t*)malloc(sizeof(fct_test_t));
00969     if ( test == NULL )
00970     {
00971         return NULL;
00972     }
00973 
00974     fctstr_safe_cpy(test->name, name, FCT_MAX_NAME);
00975 
00976     /* Failures are an exception, so lets not allocate up
00977     the list until we need to. */
00978     fct_nlist__init2(&(test->failed_chks), 0);
00979     if (!fct_nlist__init(&(test->passed_chks)))
00980     {
00981         ok =FCT_FALSE;
00982         goto finally;
00983     }
00984 
00985     fct_timer__init(&(test->timer));
00986 
00987     ok =FCT_TRUE;
00988 finally:
00989     if ( !ok )
00990     {
00991         fct_test__del(test);
00992         test =NULL;
00993     }
00994     return test;
00995 }
00996 
00997 
00998 static void
00999 fct_test__start_timer(fct_test_t *test)
01000 {
01001     FCT_ASSERT( test != NULL );
01002     fct_timer__start(&(test->timer));
01003 }
01004 
01005 
01006 static void
01007 fct_test__stop_timer(fct_test_t *test)
01008 {
01009     FCT_ASSERT( test != NULL );
01010     fct_timer__stop(&(test->timer));
01011 }
01012 
01013 
01014 static double
01015 fct_test__duration(fct_test_t const *test)
01016 {
01017     FCT_ASSERT( test != NULL );
01018     return fct_timer__duration(&(test->timer));
01019 }
01020 
01021 
01022 static nbool_t
01023 fct_test__is_pass(fct_test_t const *test)
01024 {
01025     FCT_ASSERT( test != NULL );
01026     return fct_nlist__size(&(test->failed_chks)) == 0;
01027 }
01028 
01029 
01030 static void
01031 fct_test__add(fct_test_t *test, fctchk_t *chk)
01032 {
01033 
01034     FCT_ASSERT( test != NULL );
01035     FCT_ASSERT( chk != NULL );
01036 
01037     if ( fctchk__is_pass(chk) )
01038     {
01039         fct_nlist__append(&(test->passed_chks), (void*)chk);
01040     }
01041     else
01042     {
01043         fct_nlist__append(&(test->failed_chks), (void*)chk);
01044     }
01045 }
01046 
01047 /* Returns the number of checks made throughout the test. */
01048 static size_t
01049 fct_test__chk_cnt(fct_test_t const *test)
01050 {
01051     FCT_ASSERT( test != NULL );
01052     return fct_nlist__size(&(test->failed_chks)) \
01053            + fct_nlist__size(&(test->passed_chks));
01054 }
01055 
01056 
01057 /*
01058 -----------------------------------------------------------
01059 TEST SUITE (TS)
01060 -----------------------------------------------------------
01061 */
01062 
01063 
01064 /* The different types of 'modes' that a test suite can be in.
01065 
01066 While the test suite is iterating through all the tests, its "State"
01067 can change from "setup mode", to "test mode" to "tear down" mode.
01068 These help to indicate what mode are currently in. Think of it as a
01069 basic FSM.
01070 
01071             if the count was 0                                 end
01072            +--------->---------------------> ending_mode-----+-+
01073            |                                       ^         |
01074            ^                                       |         ^
01075 start      |                              [if no more tests] |
01076   |        |                                       |         |
01077   +-count_mode -> setup_mode -> test_mode -> teardown_mode->-+
01078                    |  ^                           |          |
01079                    |  +-----------<---------------+          |
01080                    +----------->---[if fct_req fails]--------+
01081 
01082 */
01083 enum ts_mode
01084 {
01085     ts_mode_cnt,         /* To setup when done counting. */
01086     ts_mode_setup,       /* To test when done setup. */
01087     ts_mode_teardown,    /* To ending mode, when no more tests. */
01088     ts_mode_test,        /* To tear down mode. */
01089     ts_mode_ending,      /* To ... */
01090     ts_mode_end,         /* .. The End. */
01091     ts_mode_abort        /* Abort */
01092 };
01093 
01094 /* Types of states the test could be in. */
01095 typedef enum
01096 {
01097     fct_test_status_SUCCESS,
01098     fct_test_status_FAILURE
01099 } fct_test_status;
01100 
01101 
01102 struct _fct_ts_t
01103 {
01104     /* For counting our 'current' test number, and the total number of
01105     tests. */
01106     int  curr_test_num;
01107     int  total_test_num;
01108 
01109     /* Keeps track of the current state of the object while it is walking
01110     through its "FSM" */
01111     enum ts_mode mode;
01112 
01113     /* The name of the test suite. */
01114     char name[FCT_MAX_NAME];
01115 
01116     /* List of tests that where executed within the test suite. */
01117     fct_nlist_t test_list;
01118 };
01119 
01120 
01121 #define fct_ts__is_setup_mode(ts)     ((ts)->mode == ts_mode_setup)
01122 #define fct_ts__is_teardown_mode(ts)  ((ts)->mode == ts_mode_teardown)
01123 #define fct_ts__is_test_mode(ts)      ((ts)->mode == ts_mode_test)
01124 #define fct_ts__is_ending_mode(ts)    ((ts)->mode == ts_mode_ending)
01125 #define fct_ts__is_end(ts)            ((ts)->mode == ts_mode_end)
01126 #define fct_ts__is_cnt_mode(ts)       ((ts)->mode == ts_mode_cnt)
01127 #define fct_ts__is_abort_mode(ts)     ((ts)->mode == ts_mode_abort)
01128 
01129 /* This cndtn is set when we have iterated through all the tests, and
01130 there was nothing more to do. */
01131 #define fct_ts__ending(ts)          ((ts)->mode = ts_mode_ending)
01132 
01133 /* Flag a test suite as complete. It will no longer accept any more tests. */
01134 #define fct_ts__end(ts)  ((ts)->mode = ts_mode_end)
01135 
01136 #define fct_ts__name(ts)              ((ts)->name)
01137 
01138 
01139 static void
01140 fct_ts__del(fct_ts_t *ts)
01141 {
01142     if ( ts == NULL )
01143     {
01144         return;
01145     }
01146     fct_nlist__final(&(ts->test_list), (fct_nlist_on_del_t)fct_test__del);
01147     free(ts);
01148 }
01149 
01150 static fct_ts_t *
01151 fct_ts_new(char const *name)
01152 {
01153     fct_ts_t *ts =NULL;
01154     ts = (fct_ts_t*)calloc(1, sizeof(fct_ts_t));
01155     FCT_ASSERT( ts != NULL );
01156 
01157     fctstr_safe_cpy(ts->name, name, FCT_MAX_NAME);
01158     ts->mode = ts_mode_cnt;
01159     fct_nlist__init(&(ts->test_list));
01160     return ts;
01161 }
01162 
01163 
01164 
01165 static nbool_t
01166 fct_ts__is_more_tests(fct_ts_t const *ts)
01167 {
01168     FCT_ASSERT( ts != NULL );
01169     FCT_ASSERT( !fct_ts__is_end(ts) );
01170     return ts->curr_test_num < ts->total_test_num;
01171 }
01172 
01173 
01174 /* Indicates that we have started a test case. */
01175 static void
01176 fct_ts__test_begin(fct_ts_t *ts)
01177 {
01178     FCT_ASSERT( !fct_ts__is_end(ts) );
01179     ++(ts->curr_test_num);
01180 }
01181 
01182 
01183 /* Takes OWNERSHIP of a test object, and warehouses it for later stat
01184 generation. */
01185 static void
01186 fct_ts__add_test(fct_ts_t *ts, fct_test_t *test)
01187 {
01188     FCT_ASSERT( ts != NULL && "invalid arg");
01189     FCT_ASSERT( test != NULL && "invalid arg");
01190     FCT_ASSERT( !fct_ts__is_end(ts) );
01191     fct_nlist__append(&(ts->test_list), test);
01192 }
01193 
01194 
01195 static void
01196 fct_ts__test_end(fct_ts_t *ts)
01197 {
01198     FCT_ASSERT( ts != NULL );
01199     /* After a test has completed, move to teardown mode. */
01200     ts->mode = ts_mode_teardown;
01201 }
01202 
01203 
01204 /* Increments the internal count by 1. */
01205 static void
01206 fct_ts__inc_total_test_num(fct_ts_t *ts)
01207 {
01208     FCT_ASSERT( ts != NULL );
01209     FCT_ASSERT( fct_ts__is_cnt_mode(ts) );
01210     FCT_ASSERT( !fct_ts__is_end(ts) );
01211     ++(ts->total_test_num);
01212 }
01213 
01214 
01215 /* Flags the end of the setup, which implies we are going to move into
01216 setup mode. You must be already in setup mode for this to work! */
01217 static void
01218 fct_ts__setup_end(fct_ts_t *ts)
01219 {
01220     if ( ts->mode != ts_mode_abort )
01221     {
01222         ts->mode = ts_mode_test;
01223     }
01224 }
01225 
01226 
01227 static fct_test_t *
01228 fct_ts__make_abort_test(fct_ts_t *ts)
01229 {
01230     char setup_testname[FCT_MAX_LOG_LINE+1] = {'\0'};
01231     char const *suitename = fct_ts__name(ts);
01232     fct_snprintf(setup_testname, FCT_MAX_LOG_LINE, "setup_%s", suitename);
01233     return fct_test_new(setup_testname);
01234 }
01235 
01236 /* Flags a pre-mature abort of a setup (like a failed fct_req). */
01237 static void
01238 fct_ts__setup_abort(fct_ts_t *ts)
01239 {
01240     FCT_ASSERT( ts != NULL );
01241     ts->mode = ts_mode_abort;
01242 }
01243 
01244 /* Flags the end of the teardown, which implies we are going to move
01245 into setup mode (for the next 'iteration'). */
01246 static void
01247 fct_ts__teardown_end(fct_ts_t *ts)
01248 {
01249     if ( ts->mode == ts_mode_abort )
01250     {
01251         return; /* Because we are aborting . */
01252     }
01253     /* We have to decide if we should keep on testing by moving into tear down
01254     mode or if we have reached the real end and should be moving into the
01255     ending mode. */
01256     if ( fct_ts__is_more_tests(ts) )
01257     {
01258         ts->mode = ts_mode_setup;
01259     }
01260     else
01261     {
01262         ts->mode = ts_mode_ending;
01263     }
01264 }
01265 
01266 
01267 /* Flags the end of the counting, and proceeding to the first setup.
01268 Consider the special case when a test suite has NO tests in it, in
01269 that case we will have a current count that is zero, in which case
01270 we can skip right to 'ending'. */
01271 static void
01272 fct_ts__cnt_end(fct_ts_t *ts)
01273 {
01274     FCT_ASSERT( ts != NULL );
01275     FCT_ASSERT( fct_ts__is_cnt_mode(ts) );
01276     FCT_ASSERT( !fct_ts__is_end(ts) );
01277     if (ts->total_test_num == 0  )
01278     {
01279         ts->mode = ts_mode_ending;
01280     }
01281     else
01282     {
01283         ts->mode = ts_mode_setup;
01284     }
01285 }
01286 
01287 
01288 static nbool_t
01289 fct_ts__is_test_cnt(fct_ts_t const *ts, int test_num)
01290 {
01291     FCT_ASSERT( ts != NULL );
01292     FCT_ASSERT( 0 <= test_num );
01293     FCT_ASSERT( test_num < ts->total_test_num );
01294     FCT_ASSERT( !fct_ts__is_end(ts) );
01295 
01296     /* As we roll through the tests we increment the count. With this
01297     count we can decide if we need to execute a test or not. */
01298     return test_num == ts->curr_test_num;
01299 }
01300 
01301 
01302 /* Returns the # of tests on the FCT TS object. This is the actual
01303 # of tests executed. */
01304 static size_t
01305 fct_ts__tst_cnt(fct_ts_t const *ts)
01306 {
01307     FCT_ASSERT( ts != NULL );
01308     FCT_ASSERT(
01309         fct_ts__is_end(ts)
01310         && "can't count number of tests executed until the test suite ends"
01311     );
01312     return fct_nlist__size(&(ts->test_list));
01313 }
01314 
01315 
01316 /* Returns the # of tests in the TS object that passed. */
01317 static size_t
01318 fct_ts__tst_cnt_passed(fct_ts_t const *ts)
01319 {
01320     size_t tally =0;
01321 
01322     FCT_ASSERT( ts != NULL );
01323     FCT_ASSERT( fct_ts__is_end(ts) );
01324 
01325     FCT_NLIST_FOREACH_BGN(fct_test_t*, test, &(ts->test_list))
01326     {
01327         if ( fct_test__is_pass(test) )
01328         {
01329             tally += 1;
01330         }
01331     }
01332     FCT_NLIST_FOREACH_END();
01333     return tally;
01334 }
01335 
01336 
01337 /* Returns the # of checks made throughout a test suite. */
01338 static size_t
01339 fct_ts__chk_cnt(fct_ts_t const *ts)
01340 {
01341     size_t tally =0;
01342 
01343     FCT_ASSERT( ts != NULL );
01344 
01345     FCT_NLIST_FOREACH_BGN(fct_test_t *, test, &(ts->test_list))
01346     {
01347         tally += fct_test__chk_cnt(test);
01348     }
01349     FCT_NLIST_FOREACH_END();
01350     return tally;
01351 }
01352 
01353 /* Currently the duration is simply a sum of all the tests. */
01354 static double
01355 fct_ts__duration(fct_ts_t const *ts)
01356 {
01357     double tally =0.0;
01358     FCT_ASSERT( ts != NULL );
01359     FCT_NLIST_FOREACH_BGN(fct_test_t *, test, &(ts->test_list))
01360     {
01361         tally += fct_test__duration(test);
01362     }
01363     FCT_NLIST_FOREACH_END();
01364     return tally;
01365 }
01366 
01367 
01368 /*
01369 --------------------------------------------------------
01370 FCT COMMAND LINE OPTION INITIALIZATION (fctcl_init)
01371 --------------------------------------------------------
01372 
01373 Structure used for command line initialization. To keep it clear that we do
01374 not delete the char*'s present on this structure.
01375 */
01376 
01377 
01378 typedef enum
01379 {
01380     FCTCL_STORE_UNDEFINED,
01381     FCTCL_STORE_TRUE,
01382     FCTCL_STORE_VALUE
01383 } fctcl_store_t;
01384 
01385 
01386 typedef struct _fctcl_init_t
01387 {
01388     /* What to parse for this option. --long versus -s. */
01389     char const *long_opt;     /* i.e. --help */
01390     char const *short_opt;    /* i.e. -h */
01391 
01392     /* What action to take when the option is activated. */
01393     fctcl_store_t action;
01394 
01395     /* The help string for the action. */
01396     char const *help;
01397 } fctcl_init_t;
01398 
01399 
01400 /* Use when defining the option list. */
01401 #define FCTCL_INIT_NULL  \
01402     {NULL, NULL, FCTCL_STORE_UNDEFINED, NULL}
01403 
01404 
01405 /*
01406 --------------------------------------------------------
01407 FCT COMMAND LINE OPTION (fctcl)
01408 --------------------------------------------------------
01409 
01410 Specifies the command line configuration options. Use this
01411 to help initialize the fct_clp (command line parser).
01412 */
01413 
01414 
01415 /* Handy strings for storing "true" and "false". We can reference
01416 these strings throughout the parse operation and not have to
01417 worry about dealing with memory. */
01418 #define FCTCL_TRUE_STR "1"
01419 
01420 
01421 typedef struct _fctcl_t
01422 {
01423     /* What to parse for this option. --long versus -s. */
01424     char *long_opt;     /* i.e. --help */
01425     char *short_opt;    /* i.e. -h */
01426 
01427     /* What action to take when the option is activated. */
01428     fctcl_store_t action;
01429 
01430     /* The help string for the action. */
01431     char *help;
01432 
01433     /* The result. */
01434     char *value;
01435 } fctcl_t;
01436 
01437 
01438 #define fctcl_new()  ((fctcl_t*)calloc(1, sizeof(fctcl_t)))
01439 
01440 
01441 static void
01442 fctcl__del(fctcl_t *clo)
01443 {
01444     if ( clo == NULL )
01445     {
01446         return;
01447     }
01448     if ( clo->long_opt )
01449     {
01450         free(clo->long_opt);
01451     }
01452     if ( clo->short_opt)
01453     {
01454         free(clo->short_opt);
01455     }
01456     if ( clo->value )
01457     {
01458         free(clo->value);
01459     }
01460     if ( clo->help )
01461     {
01462         free(clo->help);
01463     }
01464     free(clo);
01465 }
01466 
01467 
01468 static fctcl_t*
01469 fctcl_new2(fctcl_init_t const *clo_init)
01470 {
01471     fctcl_t *clone = NULL;
01472     int ok =0;
01473     clone = fctcl_new();
01474     if ( clone == NULL )
01475     {
01476         return NULL;
01477     }
01478     clone->action = clo_init->action;
01479     if ( clo_init->help == NULL )
01480     {
01481         clone->help = NULL;
01482     }
01483     else
01484     {
01485         clone->help = fctstr_clone(clo_init->help);
01486         if ( clone->help == NULL )
01487         {
01488             ok =0;
01489             goto finally;
01490         }
01491     }
01492     if ( clo_init->long_opt == NULL )
01493     {
01494         clone->long_opt = NULL;
01495     }
01496     else
01497     {
01498         clone->long_opt = fctstr_clone(clo_init->long_opt);
01499         if ( clone->long_opt == NULL )
01500         {
01501             ok = 0;
01502             goto finally;
01503         }
01504     }
01505     if ( clo_init->short_opt == NULL )
01506     {
01507         clone->short_opt = NULL;
01508     }
01509     else
01510     {
01511         clone->short_opt = fctstr_clone(clo_init->short_opt);
01512         if ( clone->short_opt == NULL )
01513         {
01514             ok =0;
01515             goto finally;
01516         }
01517     }
01518     ok = 1;
01519 finally:
01520     if ( !ok )
01521     {
01522         fctcl__del(clone);
01523         clone = NULL;
01524     }
01525     return clone;
01526 }
01527 
01528 
01529 static int
01530 fctcl__is_option(fctcl_t const *clo, char const *option)
01531 {
01532     FCT_ASSERT( clo != NULL );
01533     if ( option == NULL )
01534     {
01535         return 0;
01536     }
01537     return ((clo->long_opt != NULL
01538              && fctstr_eq(clo->long_opt, option))
01539             ||
01540             (clo->short_opt != NULL
01541              && fctstr_eq(clo->short_opt, option))
01542            );
01543 }
01544 
01545 
01546 #define fctcl__set_value(_CLO_, _VAL_) \
01547     (_CLO_)->value = fctstr_clone((_VAL_));
01548 
01549 /*
01550 --------------------------------------------------------
01551 FCT COMMAND PARSER (fct_clp)
01552 --------------------------------------------------------
01553 */
01554 
01555 #define FCT_CLP_MAX_ERR_MSG_LEN     256
01556 
01557 typedef struct _fct_clp_t
01558 {
01559     /* List of command line options. */
01560     fct_nlist_t clo_list;
01561 
01562     /* List of parameters (not options). */
01563     fct_nlist_t param_list;
01564 
01565     char error_msg[FCT_CLP_MAX_ERR_MSG_LEN];
01566     int is_error;
01567 } fct_clp_t;
01568 
01569 
01570 static void
01571 fct_clp__final(fct_clp_t *clp)
01572 {
01573     fct_nlist__final(&(clp->clo_list), (fct_nlist_on_del_t)fctcl__del);
01574     fct_nlist__final(&(clp->param_list), (fct_nlist_on_del_t)free);
01575 }
01576 
01577 
01578 /* Add an configuration options. */
01579 static int
01580 fct_clp__add_options(fct_clp_t *clp, fctcl_init_t const *options)
01581 {
01582     fctcl_init_t const *pclo =NULL;
01583     int ok;
01584     for ( pclo = options; pclo->action != FCTCL_STORE_UNDEFINED; ++pclo )
01585     {
01586         fctcl_t *cpy = fctcl_new2(pclo);
01587         if ( cpy == NULL )
01588         {
01589             ok = 0;
01590             goto finally;
01591         }
01592         fct_nlist__append(&(clp->clo_list), (void*)cpy);
01593     }
01594     ok =1;
01595 finally:
01596     return ok;
01597 }
01598 
01599 /* Returns false if we ran out of memory. */
01600 static int
01601 fct_clp__init(fct_clp_t *clp, fctcl_init_t const *options)
01602 {
01603     int ok =0;
01604     FCT_ASSERT( clp != NULL );
01605     /* It is just much saner to manage a clone of the options. Then we know
01606     who is in charge of the memory. */
01607     ok = fct_nlist__init(&(clp->clo_list));
01608     if ( !ok )
01609     {
01610         goto finally;
01611     }
01612     if ( options != NULL )
01613     {
01614         ok = fct_clp__add_options(clp, options);
01615         if ( !ok )
01616         {
01617             goto finally;
01618         }
01619     }
01620     ok = fct_nlist__init(&(clp->param_list));
01621     if ( !ok )
01622     {
01623         goto finally;
01624     }
01625     ok =1;
01626 finally:
01627     if ( !ok )
01628     {
01629         fct_clp__final(clp);
01630     }
01631     return ok;
01632 }
01633 
01634 
01635 /* Parses the command line arguments. Use fct_clp__is_error and
01636 fct_clp__get_error to figure out if something went awry. */
01637 static void
01638 fct_clp__parse(fct_clp_t *clp, int argc, char const *argv[])
01639 {
01640     int argi =1;
01641     int is_option =0;
01642     char *arg =NULL;
01643     char *token =NULL;
01644     char *next_token =NULL;
01645 
01646     clp->error_msg[0] = '\0';
01647     clp->is_error =0;
01648 
01649     while ( argi < argc )
01650     {
01651         is_option =0;
01652         token =NULL;
01653         next_token = NULL;
01654         arg = fctstr_clone(argv[argi]);
01655 
01656 #if defined(_MSC_VER) && _MSC_VER > 1300
01657         token = strtok_s(arg, "=", &next_token);
01658 #else
01659         token = strtok(arg, "=");
01660         next_token = strtok(NULL, "=");
01661 #endif
01662 
01663         FCT_NLIST_FOREACH_BGN(fctcl_t*, pclo, &(clp->clo_list))
01664         {
01665             /* Need to reset for each search. strtok below is destructive. */
01666             if ( fctcl__is_option(pclo, token) )
01667             {
01668                 is_option =1;
01669                 if ( pclo->action == FCTCL_STORE_VALUE )
01670                 {
01671                     /* If this is --xxxx=value then the next strtok should succeed.
01672                     Otherwise, we need to chew up the next argument. */
01673                     if ( next_token != NULL && strlen(next_token) > 0 )
01674                     {
01675                         fctcl__set_value(pclo, next_token);
01676                     }
01677                     else
01678                     {
01679                         ++argi; /* Chew up the next value */
01680                         if ( argi >= argc )
01681                         {
01682                             /* error */
01683                             fct_snprintf(
01684                                 clp->error_msg,
01685                                 FCT_CLP_MAX_ERR_MSG_LEN,
01686                                 "missing argument for %s",
01687                                 token
01688                             );
01689                             clp->is_error =1;
01690                             break;
01691                         }
01692                         fctcl__set_value(pclo, argv[argi]);
01693                     }
01694                 }
01695                 else if (pclo->action == FCTCL_STORE_TRUE)
01696                 {
01697                     fctcl__set_value(pclo, FCTCL_TRUE_STR);
01698                 }
01699                 else
01700                 {
01701                     FCT_ASSERT("undefined action requested");
01702                 }
01703                 break;  /* No need to parse this argument further. */
01704             }
01705         }
01706         FCT_NLIST_FOREACH_END();
01707         /* If we have an error, exit. */
01708         if ( clp->is_error )
01709         {
01710             break;
01711         }
01712         /* If we walked through all the options, and didn't find
01713         anything, then we must have a parameter. Forget the fact that
01714         an unknown option will be treated like a parameter... */
01715         if ( !is_option )
01716         {
01717             fct_nlist__append(&(clp->param_list), arg);
01718             arg =NULL;  /* Owned by the nlist */
01719         }
01720         ++argi;
01721         if ( arg != NULL )
01722         {
01723             free(arg);
01724             arg =NULL;
01725         }
01726     }
01727 }
01728 
01729 
01730 static fctcl_t const*
01731 fct_clp__get_clo(fct_clp_t const *clp, char const *option)
01732 {
01733     fctcl_t const *found =NULL;
01734 
01735     FCT_NLIST_FOREACH_BGN(fctcl_t const*, pclo, &(clp->clo_list))
01736     {
01737         if ( fctcl__is_option(pclo, option) )
01738         {
01739             found = pclo;
01740             break;
01741         }
01742     }
01743     FCT_NLIST_FOREACH_END();
01744     return found;
01745 }
01746 
01747 
01748 #define fct_clp__optval(_CLP_, _OPTION_) \
01749     fct_clp__optval2((_CLP_), (_OPTION_), NULL)
01750 
01751 
01752 /* Returns the value parsed at the command line, and equal to OPTION.
01753 If the value wasn't parsed, the DEFAULT_VAL is returned instead. */
01754 static char const*
01755 fct_clp__optval2(fct_clp_t *clp, char const *option, char const *default_val)
01756 {
01757     fctcl_t const *clo =NULL;
01758     FCT_ASSERT( clp != NULL );
01759     FCT_ASSERT( option != NULL );
01760     clo = fct_clp__get_clo(clp, option);
01761     if ( clo == NULL || clo->value == NULL)
01762     {
01763         return default_val;
01764     }
01765     return clo->value;
01766 }
01767 
01768 
01769 
01770 /* Mainly used for unit tests. */
01771 static int
01772 fct_clp__is_param(fct_clp_t *clp, char const *param)
01773 {
01774     if ( clp == NULL || param == NULL )
01775     {
01776         return 0;
01777     }
01778     FCT_NLIST_FOREACH_BGN(char *, aparam, &(clp->param_list))
01779     {
01780         if ( fctstr_eq(aparam, param) )
01781         {
01782             return 1;
01783         }
01784     }
01785     FCT_NLIST_FOREACH_END();
01786     return 0;
01787 }
01788 
01789 
01790 #define fct_clp__is_error(_CLP_) ((_CLP_)->is_error)
01791 #define fct_clp__get_error(_CLP_) ((_CLP_)->error_msg);
01792 
01793 #define fct_clp__num_clo(_CLP_) \
01794     (fct_nlist__size(&((_CLP_)->clo_list)))
01795 
01796 #define fct_clp__param_cnt(_CLP_) \
01797     (fct_nlist__size(&((_CLP_)->param_list)))
01798 
01799 /* Returns a *reference* to the parameter at _IDX_. Do not modify
01800 its contents. */
01801 #define fct_clp__param_at(_CLP_, _IDX_) \
01802     ((char const*)fct_nlist__at(&((_CLP_)->param_list), (_IDX_)))
01803 
01804 
01805 /* Returns true if the given option was on the command line.
01806 Use either the long or short option name to check against. */
01807 #define fct_clp__is(_CLP_, _OPTION_) \
01808     (fct_clp__optval((_CLP_), (_OPTION_)) != NULL)
01809 
01810 
01811 
01812 /*
01813 --------------------------------------------------------
01814 FCT NAMESPACE
01815 --------------------------------------------------------
01816 
01817 The macros below start to pollute the watch window with
01818 lots of "system" variables. This NAMESPACE is an
01819 attempt to hide all the "system" variables in one place.
01820 */
01821 typedef struct _fct_namespace_t
01822 {
01823     /* The currently active test suite. */
01824     fct_ts_t *ts_curr;
01825     int ts_is_skip_suite;
01826     char const *ts_skip_cndtn;
01827 
01828     /* Current test name. */
01829     char const* curr_test_name;
01830     fct_test_t *curr_test;
01831     const char *test_skip_cndtn;
01832     int test_is_skip;
01833 
01834     /* Counts the number of tests in a test suite. */
01835     int test_num;
01836 
01837     /* Set at the end of the test suites. */
01838     size_t num_total_failed;
01839 } fct_namespace_t;
01840 
01841 
01842 static void
01843 fct_namespace_init(fct_namespace_t *ns)
01844 {
01845     FCT_ASSERT( ns != NULL && "invalid argument!");
01846     memset(ns, 0, sizeof(fct_namespace_t));
01847 }
01848 
01849 
01850 /*
01851 --------------------------------------------------------
01852 FCT KERNAL
01853 --------------------------------------------------------
01854 
01855 The "fctkern" is a singleton that is defined throughout the
01856 system.
01857 */
01858 
01859 struct _fctkern_t
01860 {
01861     /* Holds variables used throughout MACRO MAGIC. In order to reduce
01862     the "noise" in the watch window during a debug trace. */
01863     fct_namespace_t ns;
01864 
01865     /* Command line parsing. */
01866     fct_clp_t cl_parser;
01867 
01868     /* Hold onto the command line arguments. */
01869     int cl_argc;
01870     char const **cl_argv;
01871     /* Track user options. */
01872     fctcl_init_t const *cl_user_opts;
01873 
01874     /* Tracks the delay parsing. */
01875     int cl_is_parsed;
01876 
01877     /* This is an list of loggers that can be used in the fct system. */
01878     fct_nlist_t logger_list;
01879 
01880     /* Array of custom types, you have built-in system ones and you
01881     have optionally supplied user ones.. */
01882     fct_logger_types_t *lt_usr;
01883     fct_logger_types_t *lt_sys;
01884 
01885     /* This is a list of prefix's that can be used to determine if a
01886     test is should be run or not. */
01887     fct_nlist_t prefix_list;
01888 
01889     /* This is a list of test suites that where generated throughout the
01890     testing process. */
01891     fct_nlist_t ts_list;
01892 
01893     /* Records what we expect to fail. */
01894     size_t num_expected_failures;
01895 };
01896 
01897 
01898 #define FCT_OPT_VERSION       "--version"
01899 #define FCT_OPT_VERSION_SHORT "-v"
01900 #define FCT_OPT_HELP          "--help"
01901 #define FCT_OPT_HELP_SHORT    "-h"
01902 #define FCT_OPT_LOGGER        "--logger"
01903 #define FCT_OPT_LOGGER_SHORT  "-l"
01904 static fctcl_init_t FCT_CLP_OPTIONS[] =
01905 {
01906     /* Totally unsafe, since we are assuming we can clean out this data,
01907     what I need to do is have an "initialization" object, full of
01908     const objects. But for now, this should work. */
01909     {
01910         FCT_OPT_VERSION,
01911         FCT_OPT_VERSION_SHORT,
01912         FCTCL_STORE_TRUE,
01913         "Displays the FCTX version number and exits."
01914     },
01915     {
01916         FCT_OPT_HELP,
01917         FCT_OPT_HELP_SHORT,
01918         FCTCL_STORE_TRUE,
01919         "Shows this help."
01920     },
01921     {
01922         FCT_OPT_LOGGER,
01923         FCT_OPT_LOGGER_SHORT,
01924         FCTCL_STORE_VALUE,
01925         NULL
01926     },
01927     FCTCL_INIT_NULL /* Sentinel */
01928 };
01929 
01930 typedef fct_logger_i* (*fct_logger_new_fn)(void);
01931 struct _fct_logger_types_t
01932 {
01933     char const *name;
01934     fct_logger_new_fn logger_new_fn;
01935     char const *desc;
01936 };
01937 
01938 static fct_logger_types_t FCT_LOGGER_TYPES[] =
01939 {
01940     {
01941         "standard",
01942         (fct_logger_new_fn)fct_standard_logger_new,
01943         "the basic fctx logger"
01944     },
01945     {
01946         "minimal",
01947         (fct_logger_new_fn)fct_minimal_logger_new,
01948         "the least amount of logging information."
01949     },
01950     {
01951         "junit",
01952         (fct_logger_new_fn)fct_junit_logger_new,
01953         "junit compatable xml"
01954     },
01955     {NULL, (fct_logger_new_fn)NULL, NULL} /* Sentinel */
01956 };
01957 
01958 
01959 /* Returns the number of filters defined for the fct kernal. */
01960 #define fctkern__filter_cnt(_NK_) (fct_nlist__size(&((_NK_)->prefix_list)))
01961 
01962 
01963 static void
01964 fctkern__add_logger(fctkern_t *nk, fct_logger_i *logger_owns)
01965 {
01966     FCT_ASSERT(nk != NULL && "invalid arg");
01967     FCT_ASSERT(logger_owns != NULL && "invalid arg");
01968     fct_nlist__append(&(nk->logger_list), logger_owns);
01969 }
01970 
01971 
01972 static void
01973 fctkern__write_help(fctkern_t *nk, FILE *out)
01974 {
01975     fct_clp_t *clp = &(nk->cl_parser);
01976     fprintf(out, "test.exe [options] prefix_filter ...\n\n");
01977     FCT_NLIST_FOREACH_BGN(fctcl_t*, clo, &(clp->clo_list))
01978     {
01979         if ( clo->short_opt != NULL )
01980         {
01981             fprintf(out, "%s, %s\n", clo->short_opt, clo->long_opt);
01982         }
01983         else
01984         {
01985             fprintf(out, "%s\n", clo->long_opt);
01986         }
01987         if ( !fctstr_ieq(clo->long_opt, FCT_OPT_LOGGER) )
01988         {
01989             /* For now lets not get to fancy with the text wrapping. */
01990             fprintf(out, "  %s\n", clo->help);
01991         }
01992         else
01993         {
01994             fct_logger_types_t *types[2];
01995             int type_i;
01996             fct_logger_types_t *itr;
01997             types[0] = nk->lt_sys;
01998             types[1] = nk->lt_usr;
01999             fputs("  Sets the logger. The types of loggers currently "
02000                   "available are,\n", out);
02001             for (type_i =0; type_i != 2; ++type_i )
02002             {
02003                 for ( itr=types[type_i]; itr && itr->name != NULL; ++itr )
02004                 {
02005                     fprintf(out, "   =%s : %s\n", itr->name, itr->desc);
02006                 }
02007             }
02008             fprintf(out, "  default is '%s'.\n", FCT_DEFAULT_LOGGER);
02009         }
02010     }
02011     FCT_NLIST_FOREACH_END();
02012     fputs("\n", out);
02013 }
02014 
02015 
02016 /* Appends a prefix filter that is used to determine if a test can
02017 be executed or not. If the test starts with the same characters as
02018 the prefix, then it should be "runnable". The prefix filter must be
02019 a non-NULL, non-Blank string. */
02020 static void
02021 fctkern__add_prefix_filter(fctkern_t *nk, char const *prefix_filter)
02022 {
02023     char *filter =NULL;
02024     size_t filter_len =0;
02025     FCT_ASSERT( nk != NULL && "invalid arg" );
02026     FCT_ASSERT( prefix_filter != NULL && "invalid arg" );
02027     FCT_ASSERT( strlen(prefix_filter) > 0 && "invalid arg" );
02028     /* First we make a copy of the prefix, then we store it away
02029     in our little list. */
02030     filter_len = strlen(prefix_filter);
02031     filter = (char*)malloc(sizeof(char)*(filter_len+1));
02032     fctstr_safe_cpy(filter, prefix_filter, filter_len+1);
02033     fct_nlist__append(&(nk->prefix_list), (void*)filter);
02034 }
02035 
02036 
02037 /* Cleans up the contents of a fctkern. NULL does nothing. */
02038 static void
02039 fctkern__final(fctkern_t *nk)
02040 {
02041     if ( nk == NULL )
02042     {
02043         return;
02044     }
02045     fct_clp__final(&(nk->cl_parser));
02046     fct_nlist__final(&(nk->logger_list), (fct_nlist_on_del_t)fct_logger__del);
02047     /* The prefix list is a list of malloc'd strings. */
02048     fct_nlist__final(&(nk->prefix_list), (fct_nlist_on_del_t)free);
02049     fct_nlist__final(&(nk->ts_list), (fct_nlist_on_del_t)fct_ts__del);
02050 }
02051 
02052 
02053 #define fctkern__cl_is_parsed(_NK_) ((_NK_)->cl_is_parsed)
02054 
02055 
02056 static int
02057 fctkern__cl_is(fctkern_t *nk, char const *opt_str)
02058 {
02059     FCT_ASSERT( opt_str != NULL );
02060     return opt_str[0] != '\0'
02061            && fct_clp__is(&(nk->cl_parser), opt_str);
02062 }
02063 
02064 
02065 /* Returns the command line value given by OPT_STR. If OPT_STR was not defined
02066 at the command line, DEF_STR is returned (you can use NULL for the DEF_STR).
02067 The result returned should not be mofidied, and MAY even be the same pointer
02068 to DEF_STR. */
02069 static char const *
02070 fctkern__cl_val2(fctkern_t *nk, char const *opt_str, char const *def_str)
02071 {
02072     FCT_ASSERT( opt_str != NULL );
02073     if ( nk == NULL )
02074     {
02075         return NULL;
02076     }
02077     return fct_clp__optval2(&(nk->cl_parser), opt_str, def_str);
02078 }
02079 
02080 
02081 /* Selects a logger from the list based on the selection name.
02082 May return NULL if the name doesn't exist in the list. */
02083 static fct_logger_i*
02084 fckern_sel_log(fct_logger_types_t *search, char const *sel_logger)
02085 {
02086     fct_logger_types_t *iter;
02087     FCT_ASSERT(search != NULL);
02088     FCT_ASSERT(sel_logger != NULL);
02089     FCT_ASSERT(strlen(sel_logger) > 0);
02090     for ( iter = search; iter->name != NULL; ++iter)
02091     {
02092         if ( fctstr_ieq(iter->name, sel_logger) )
02093         {
02094             return iter->logger_new_fn();
02095         }
02096     }
02097     return NULL;
02098 }
02099 
02100 static int
02101 fctkern__cl_parse_config_logger(fctkern_t *nk)
02102 {
02103     fct_logger_i *logger =NULL;
02104     char const *sel_logger =NULL;
02105     char const *def_logger =FCT_DEFAULT_LOGGER;
02106     sel_logger = fctkern__cl_val2(nk, FCT_OPT_LOGGER, def_logger);
02107     FCT_ASSERT(sel_logger != NULL && "should never be NULL");
02108     /* First search the user selected types, then search the
02109     built-in types. */
02110     if ( nk->lt_usr != NULL )
02111     {
02112         logger = fckern_sel_log(nk->lt_usr, sel_logger);
02113     }
02114     if ( nk->lt_sys != NULL && logger == NULL )
02115     {
02116         logger = fckern_sel_log(nk->lt_sys, sel_logger);
02117     }
02118     if ( logger == NULL )
02119     {
02120         /* No logger configured, you must have supplied an invalid selection. */
02121         fprintf(stderr, "error: unknown logger selected - '%s'", sel_logger);
02122         return 0;
02123     }
02124     fctkern__add_logger(nk, logger);
02125     logger = NULL;  /* owned by nk. */
02126     return 1;
02127 }
02128 
02129 
02130 
02131 /* Call this if you want to (re)parse the command line options with a new
02132 set of options. Returns -1 if you are to abort with EXIT_SUCCESS, returns
02133 0 if you are to abort with EXIT_FAILURE and returns 1 if you are to continue. */
02134 static int
02135 fctkern__cl_parse(fctkern_t *nk)
02136 {
02137     int status =0;
02138     size_t num_params =0;
02139     size_t param_i =0;
02140     if ( nk == NULL )
02141     {
02142         return 0;
02143     }
02144     if ( nk->cl_user_opts != NULL )
02145     {
02146         if ( !fct_clp__add_options(&(nk->cl_parser), nk->cl_user_opts) )
02147         {
02148             status =0;
02149             goto finally;
02150         }
02151     }
02152     /* You want to add the "house options" after the user defined ones. The
02153     options are stored as a list so it means that any option listed after
02154     the above ones won't get parsed. */
02155     if ( !fct_clp__add_options(&(nk->cl_parser), FCT_CLP_OPTIONS) )
02156     {
02157         status =0;
02158         goto finally;
02159     }
02160     fct_clp__parse(&(nk->cl_parser), nk->cl_argc, nk->cl_argv);
02161     if ( fct_clp__is_error(&(nk->cl_parser)) )
02162     {
02163         char *err = fct_clp__get_error(&(nk->cl_parser));
02164         fprintf(stderr, "error: %s", err);
02165         status =0;
02166         goto finally;
02167     }
02168     num_params = fct_clp__param_cnt(&(nk->cl_parser));
02169     for ( param_i =0; param_i != num_params; ++param_i )
02170     {
02171         char const *param = fct_clp__param_at(&(nk->cl_parser), param_i);
02172         fctkern__add_prefix_filter(nk, param);
02173     }
02174     if ( fctkern__cl_is(nk, FCT_OPT_VERSION) )
02175     {
02176         (void)printf("Built using FCTX version %s.\n", FCT_VERSION_STR);
02177         status = -1;
02178         goto finally;
02179     }
02180     if ( fctkern__cl_is(nk, FCT_OPT_HELP) )
02181     {
02182         fctkern__write_help(nk, stdout);
02183         status = -1;
02184         goto finally;
02185     }
02186     if ( !fctkern__cl_parse_config_logger(nk) )
02187     {
02188         status = -1;
02189         goto finally;
02190     }
02191     status =1;
02192     nk->cl_is_parsed =1;
02193 finally:
02194     return status;
02195 }
02196 
02197 
02198 
02199 /* Parses the command line and sets up the framework. The argc and argv
02200 should be directly from the program's main. */
02201 static int
02202 fctkern__init(fctkern_t *nk, int argc, const char *argv[])
02203 {
02204     if ( argc == 0 && argv == NULL )
02205     {
02206         return 0;
02207     }
02208     memset(nk, 0, sizeof(fctkern_t));
02209     fct_clp__init(&(nk->cl_parser), NULL);
02210     fct_nlist__init(&(nk->logger_list));
02211     nk->lt_usr = NULL;  /* Supplied via 'install' mechanics. */
02212     nk->lt_sys = FCT_LOGGER_TYPES;
02213     fct_nlist__init2(&(nk->prefix_list), 0);
02214     fct_nlist__init2(&(nk->ts_list), 0);
02215     nk->cl_is_parsed =0;
02216     /* Save a copy of the arguments. We do a delay parse of the command
02217     line arguments in order to allow the client code to optionally configure
02218     the command line parser.*/
02219     nk->cl_argc = argc;
02220     nk->cl_argv = argv;
02221     fct_namespace_init(&(nk->ns));
02222     return 1;
02223 }
02224 
02225 
02226 /* Takes OWNERSHIP of the test suite after we have finished executing
02227 its contents. This way we can build up all kinds of summaries at the end
02228 of a run. */
02229 static void
02230 fctkern__add_ts(fctkern_t *nk, fct_ts_t *ts)
02231 {
02232     FCT_ASSERT( nk != NULL );
02233     FCT_ASSERT( ts != NULL );
02234     fct_nlist__append(&(nk->ts_list), ts);
02235 }
02236 
02237 
02238 /* Returns FCT_TRUE if the supplied test_name passes the filters set on
02239 this test suite. If there are no filters, we return FCT_TRUE always. */
02240 static nbool_t
02241 fctkern__pass_filter(fctkern_t *nk, char const *test_name)
02242 {
02243     size_t prefix_i =0;
02244     size_t prefix_list_size =0;
02245     FCT_ASSERT( nk != NULL && "invalid arg");
02246     FCT_ASSERT( test_name != NULL );
02247     FCT_ASSERT( strlen(test_name) > 0 );
02248     prefix_list_size = fctkern__filter_cnt(nk);
02249     /* If there is no filter list, then we return FCT_TRUE always. */
02250     if ( prefix_list_size == 0 )
02251     {
02252         return FCT_TRUE;
02253     }
02254     /* Iterate through the prefix filter list, and see if we have
02255     anything that does not pass. All we require is ONE item that
02256     passes the test in order for us to succeed here. */
02257     for ( prefix_i = 0; prefix_i != prefix_list_size; ++prefix_i )
02258     {
02259         char const *prefix = (char const*)fct_nlist__at(
02260                                  &(nk->prefix_list), prefix_i
02261                              );
02262         nbool_t pass = fct_filter_pass(prefix, test_name);
02263         if ( pass )
02264         {
02265             return FCT_TRUE;
02266         }
02267     }
02268     /* Otherwise, we never managed to find a prefix that satisfied the
02269     supplied test name. Therefore we have failed to pass to the filter
02270     list test. */
02271     return FCT_FALSE;
02272 }
02273 
02274 
02275 /* Returns the number of tests that were performed. */
02276 static size_t
02277 fctkern__tst_cnt(fctkern_t const *nk)
02278 {
02279     size_t tally =0;
02280     FCT_ASSERT( nk != NULL );
02281     FCT_NLIST_FOREACH_BGN(fct_ts_t *, ts, &(nk->ts_list))
02282     {
02283         tally += fct_ts__tst_cnt(ts);
02284     }
02285     FCT_NLIST_FOREACH_END();
02286     return tally;
02287 }
02288 
02289 
02290 /* Returns the number of tests that passed. */
02291 static size_t
02292 fctkern__tst_cnt_passed(fctkern_t const *nk)
02293 {
02294     size_t tally =0;
02295     FCT_ASSERT( nk != NULL );
02296 
02297     FCT_NLIST_FOREACH_BGN(fct_ts_t*, ts, &(nk->ts_list))
02298     {
02299         tally += fct_ts__tst_cnt_passed(ts);
02300     }
02301     FCT_NLIST_FOREACH_END();
02302 
02303     return tally;
02304 }
02305 
02306 
02307 /* Returns the number of tests that failed. */
02308 #define fctkern__tst_cnt_failed(nk) \
02309     (fctkern__tst_cnt(nk) - fctkern__tst_cnt_passed(nk))
02310 
02311 
02312 /* Returns the number of checks made throughout the entire test. */
02313 #if defined(FCT_USE_TEST_COUNT)
02314 static size_t
02315 fctkern__chk_cnt(fctkern_t const *nk)
02316 {
02317     size_t tally =0;
02318     FCT_ASSERT( nk != NULL );
02319 
02320     FCT_NLIST_FOREACH_BGN(fct_ts_t *, ts, &(nk->ts_list))
02321     {
02322         tally += fct_ts__chk_cnt(ts);
02323     }
02324     FCT_NLIST_FOREACH_END();
02325     return tally;
02326 }
02327 #endif /* FCT_USE_TEST_COUNT */
02328 
02329 
02330 /* Indicates the very end of all the tests. */
02331 #define fctkern__end(nk) /* unused */
02332 
02333 
02334 static void
02335 fctkern__log_suite_start(fctkern_t *nk, fct_ts_t const *ts)
02336 {
02337     FCT_ASSERT( nk != NULL );
02338     FCT_ASSERT( ts != NULL );
02339     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02340     {
02341         fct_logger__on_test_suite_start(logger, ts);
02342     }
02343     FCT_NLIST_FOREACH_END();
02344 }
02345 
02346 
02347 static void
02348 fctkern__log_suite_end(fctkern_t *nk, fct_ts_t const *ts)
02349 {
02350     FCT_ASSERT( nk != NULL );
02351     FCT_ASSERT( ts != NULL );
02352     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02353     {
02354         fct_logger__on_test_suite_end(logger, ts);
02355     }
02356     FCT_NLIST_FOREACH_END();
02357 }
02358 
02359 
02360 static void
02361 fctkern__log_suite_skip(fctkern_t *nk, char const *condition, char const *name)
02362 {
02363     if ( nk == NULL )
02364     {
02365         return;
02366     }
02367     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02368     {
02369         fct_logger__on_test_suite_skip(logger, condition, name);
02370     }
02371     FCT_NLIST_FOREACH_END();
02372 }
02373 
02374 
02375 static void
02376 fctkern__log_test_skip(fctkern_t *nk, char const *condition, char const *name)
02377 {
02378     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02379     {
02380         fct_logger__on_test_skip(logger, condition, name);
02381     }
02382     FCT_NLIST_FOREACH_END();
02383 }
02384 
02385 
02386 /* Use this for displaying information about a "Check" (i.e.
02387 a condition). */
02388 static void
02389 fctkern__log_chk(fctkern_t *nk, fctchk_t const *chk)
02390 {
02391     FCT_ASSERT( nk != NULL );
02392     FCT_ASSERT( chk != NULL );
02393     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02394     {
02395         fct_logger__on_chk(logger, chk);
02396     }
02397     FCT_NLIST_FOREACH_END();
02398 }
02399 
02400 
02401 /* Use this for displaying warning messages. */
02402 static void
02403 fctkern__log_warn(fctkern_t *nk, char const *warn)
02404 {
02405     FCT_ASSERT( nk != NULL );
02406     FCT_ASSERT( warn != NULL );
02407     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02408     {
02409         fct_logger__on_warn(logger, warn);
02410     }
02411     FCT_NLIST_FOREACH_END();
02412 }
02413 
02414 
02415 /* Called whenever a test is started. */
02416 static void
02417 fctkern__log_test_start(fctkern_t *nk, fct_test_t const *test)
02418 {
02419     FCT_ASSERT( nk != NULL );
02420     FCT_ASSERT( test != NULL );
02421     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02422     {
02423         fct_logger__on_test_start(logger, test);
02424     }
02425     FCT_NLIST_FOREACH_END();
02426 }
02427 
02428 
02429 static void
02430 fctkern__log_test_end(fctkern_t *nk, fct_test_t *test)
02431 {
02432     FCT_ASSERT( nk != NULL );
02433     FCT_ASSERT( test != NULL );
02434     FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
02435     {
02436         fct_logger__on_test_end(logger, test);
02437     }
02438     FCT_NLIST_FOREACH_END();
02439 }
02440 
02441 
02442 #define fctkern__log_start(_NK_) \
02443    {\
02444        FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &((_NK_)->logger_list))\
02445        {\
02446           fct_logger__on_fctx_start(logger, (_NK_));\
02447        }\
02448        FCT_NLIST_FOREACH_END();\
02449    }
02450 
02451 
02452 #define fctkern__log_end(_NK_) \
02453     {\
02454        FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &((_NK_)->logger_list))\
02455        {\
02456           fct_logger__on_fctx_end(logger, (_NK_));\
02457        }\
02458        FCT_NLIST_FOREACH_END();\
02459     }
02460 
02461 
02462 
02463 
02464 /*
02465 -----------------------------------------------------------
02466 LOGGER INTERFACE
02467 
02468 Defines an interface to a logging system. A logger
02469 must define the following functions in order to hook
02470 into the logging system.
02471 
02472 See the "Standard Logger" and "Minimal Logger" as examples
02473 of the implementation.
02474 -----------------------------------------------------------
02475 */
02476 
02477 /* Common event argument. The values of the each event may or may not be
02478 defined depending on the event in question. */
02479 struct _fct_logger_evt_t
02480 {
02481     fctkern_t const *kern;
02482     fctchk_t const *chk;
02483     fct_test_t const *test;
02484     fct_ts_t const *ts;
02485     char const *msg;
02486     char const *cndtn;
02487     char const *name;
02488 };
02489 
02490 
02491 typedef struct _fct_logger_i_vtable_t
02492 {
02493     /* 1
02494      * Fired when an "fct_chk*" (check) function is completed. The event
02495      * will contain a reference to the "chk" object created.
02496      * */
02497     void (*on_chk)(fct_logger_i *logger, fct_logger_evt_t const *e);
02498 
02499     /* 2
02500      * Fired when a test starts and before any checks are made. The
02501      * event will have its "test" object set. */
02502     void (*on_test_start)(
02503         fct_logger_i *logger,
02504         fct_logger_evt_t const *e
02505     );
02506     /* 3 */
02507     void (*on_test_end)(
02508         fct_logger_i *logger,
02509         fct_logger_evt_t const *e
02510     );
02511     /* 4 */
02512     void (*on_test_suite_start)(
02513         fct_logger_i *logger,
02514         fct_logger_evt_t const *e
02515     );
02516     /* 5 */
02517     void (*on_test_suite_end)(
02518         fct_logger_i *logger,
02519         fct_logger_evt_t const *e
02520     );
02521     /* 6 */
02522     void (*on_fctx_start)(
02523         fct_logger_i *logger,
02524         fct_logger_evt_t const *e
02525     );
02526     /* 7 */
02527     void (*on_fctx_end)(
02528         fct_logger_i *logger,
02529         fct_logger_evt_t const *e
02530     );
02531     /* 8
02532     Called when the logger object must "clean up". */
02533     void (*on_delete)(
02534         fct_logger_i *logger,
02535         fct_logger_evt_t const *e
02536     );
02537     /* 9 */
02538     void (*on_warn)(
02539         fct_logger_i *logger,
02540         fct_logger_evt_t const *e
02541     );
02542     /* -- new in 1.2 -- */
02543     /* 10 */
02544     void (*on_test_suite_skip)(
02545         fct_logger_i *logger,
02546         fct_logger_evt_t const *e
02547     );
02548     /* 11 */
02549     void (*on_test_skip)(
02550         fct_logger_i *logger,
02551         fct_logger_evt_t const *e
02552     );
02553 } fct_logger_i_vtable_t;
02554 
02555 #define _fct_logger_head \
02556     fct_logger_i_vtable_t vtable; \
02557     fct_logger_evt_t evt
02558 
02559 struct _fct_logger_i
02560 {
02561     _fct_logger_head;
02562 };
02563 
02564 
02565 static void
02566 fct_logger__stub(fct_logger_i *l, fct_logger_evt_t const *e)
02567 {
02568     fct_unused(l);
02569     fct_unused(e);
02570 }
02571 
02572 
02573 static fct_logger_i_vtable_t fct_logger_default_vtable =
02574 {
02575     fct_logger__stub,   /* 1.  on_chk */
02576     fct_logger__stub,   /* 2.  on_test_start */
02577     fct_logger__stub,   /* 3.  on_test_end */
02578     fct_logger__stub,   /* 4.  on_test_suite_start */
02579     fct_logger__stub,   /* 5.  on_test_suite_end */
02580     fct_logger__stub,   /* 6.  on_fctx_start */
02581     fct_logger__stub,   /* 7.  on_fctx_end */
02582     fct_logger__stub,   /* 8.  on_delete */
02583     fct_logger__stub,   /* 9.  on_warn */
02584     fct_logger__stub,   /* 10. on_test_suite_skip */
02585     fct_logger__stub,   /* 11. on_test_skip */
02586 };
02587 
02588 
02589 /* Initializes the elements of a logger interface so they are at their
02590 standard values. */
02591 static void
02592 fct_logger__init(fct_logger_i *logger)
02593 {
02594     FCT_ASSERT( logger != NULL );
02595     memcpy(
02596         &(logger->vtable),
02597         &fct_logger_default_vtable,
02598         sizeof(fct_logger_i_vtable_t)
02599     );
02600     memset(&(logger->evt),0, sizeof(fct_logger_evt_t));
02601 }
02602 
02603 static void
02604 fct_logger__del(fct_logger_i *logger)
02605 {
02606     if ( logger )
02607     {
02608         logger->vtable.on_delete(logger, &(logger->evt));
02609     }
02610 }
02611 
02612 
02613 static void
02614 fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test)
02615 {
02616     logger->evt.test = test;
02617     logger->vtable.on_test_start(logger, &(logger->evt));
02618 }
02619 
02620 
02621 static void
02622 fct_logger__on_test_end(fct_logger_i *logger, fct_test_t *test)
02623 {
02624     logger->evt.test = test;
02625     logger->vtable.on_test_end(logger, &(logger->evt));
02626 }
02627 
02628 
02629 static void
02630 fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts)
02631 {
02632     logger->evt.ts = ts;
02633     logger->vtable.on_test_suite_start(logger, &(logger->evt));
02634 }
02635 
02636 
02637 static void
02638 fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts)
02639 {
02640     logger->evt.ts = ts;
02641     logger->vtable.on_test_suite_end(logger, &(logger->evt));
02642 }
02643 
02644 
02645 static void
02646 fct_logger__on_test_suite_skip(
02647     fct_logger_i *logger,
02648     char const *condition,
02649     char const *name
02650 )
02651 {
02652     logger->evt.cndtn = condition;
02653     logger->evt.name = name;
02654     logger->vtable.on_test_suite_skip(logger, &(logger->evt));
02655 }
02656 
02657 
02658 static void
02659 fct_logger__on_test_skip(
02660     fct_logger_i *logger,
02661     char const *condition,
02662     char const *name
02663 )
02664 {
02665     logger->evt.cndtn = condition;
02666     logger->evt.name = name;
02667     logger->vtable.on_test_skip(logger, &(logger->evt));
02668 }
02669 
02670 
02671 static void
02672 fct_logger__on_chk(fct_logger_i *logger, fctchk_t const *chk)
02673 {
02674     logger->evt.chk = chk;
02675     logger->vtable.on_chk(logger, &(logger->evt));
02676 }
02677 
02678 /* When we start all our tests. */
02679 #define fct_logger__on_fctx_start(LOGGER, KERN) \
02680    (LOGGER)->evt.kern = (KERN);\
02681    (LOGGER)->vtable.on_fctx_start((LOGGER), &((LOGGER)->evt));
02682 
02683 
02684 /* When we have reached the end of ALL of our testing. */
02685 #define fct_logger__on_fctx_end(LOGGER, KERN) \
02686     (LOGGER)->evt.kern = (KERN);\
02687     (LOGGER)->vtable.on_fctx_end((LOGGER), &((LOGGER)->evt));
02688 
02689 
02690 static void
02691 fct_logger__on_warn(fct_logger_i *logger, char const *msg)
02692 {
02693     logger->evt.msg = msg;
02694     logger->vtable.on_warn(logger, &(logger->evt));
02695 }
02696 
02697 
02698 /* Commmon routine to record strings representing failures. The
02699 chk should be a failure before we call this, and the list is a list
02700 of char*'s that will eventually be free'd by the logger. */
02701 static void
02702 fct_logger_record_failure(fctchk_t const* chk, fct_nlist_t* fail_list)
02703 {
02704     /* For now we will truncate the string to some set amount, later
02705     we can work out a dynamic string object. */
02706     char *str = (char*)malloc(sizeof(char)*FCT_MAX_LOG_LINE);
02707     FCT_ASSERT( str != NULL );
02708     fct_snprintf(
02709         str,
02710         FCT_MAX_LOG_LINE,
02711         "%s(%d):\n    %s",
02712         fctchk__file(chk),
02713         fctchk__lineno(chk),
02714         fctchk__msg(chk)
02715     );
02716     /* Append it to the listing ... */
02717     fct_nlist__append(fail_list, (void*)str);
02718 }
02719 
02720 
02721 /* Another common routine, to print the failures at the end of a run. */
02722 static void
02723 fct_logger_print_failures(fct_nlist_t const *fail_list)
02724 {
02725     puts(
02726         "\n----------------------------------------------------------------------------\n"
02727     );
02728     puts("FAILED TESTS\n\n");
02729     FCT_NLIST_FOREACH_BGN(char *, cndtn_str, fail_list)
02730     {
02731         printf("%s\n", cndtn_str);
02732     }
02733     FCT_NLIST_FOREACH_END();
02734 
02735     puts("\n");
02736 }
02737 
02738 
02739 
02740 
02741 /*
02742 -----------------------------------------------------------
02743 MINIMAL LOGGER
02744 -----------------------------------------------------------
02745 
02746 At the moment the MINIMAL LOGGER is currently disabled. Hope
02747 to bring it back online soon. The only reason it is
02748 disabled is that we don't currently have the ability to specify
02749 loggers.
02750 */
02751 
02752 
02753 /* Minimal logger, reports the minimum amount of information needed
02754 to determine "something is happening". */
02755 struct _fct_minimal_logger_t
02756 {
02757     _fct_logger_head;
02758     /* A list of char*'s that needs to be cleaned up. */
02759     fct_nlist_t failed_cndtns_list;
02760 };
02761 
02762 
02763 static void
02764 fct_minimal_logger__on_chk(
02765     fct_logger_i *self_,
02766     fct_logger_evt_t const *e
02767 )
02768 {
02769     fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
02770     if ( fctchk__is_pass(e->chk) )
02771     {
02772         fputs(".", stdout);
02773     }
02774     else
02775     {
02776         fputs("x", stdout);
02777         fct_logger_record_failure(e->chk, &(self->failed_cndtns_list));
02778 
02779     }
02780 }
02781 
02782 static void
02783 fct_minimal_logger__on_fctx_end(
02784     fct_logger_i *self_,
02785     fct_logger_evt_t const *e
02786 )
02787 {
02788     fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
02789     fct_unused(e);
02790     if ( fct_nlist__size(&(self->failed_cndtns_list)) >0 )
02791     {
02792         fct_logger_print_failures(&(self->failed_cndtns_list));
02793     }
02794 }
02795 
02796 
02797 static void
02798 fct_minimal_logger__on_delete(
02799     fct_logger_i *self_,
02800     fct_logger_evt_t const *e
02801 )
02802 {
02803     fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
02804     fct_unused(e);
02805     fct_nlist__final(&(self->failed_cndtns_list), free);
02806     free(self);
02807 
02808 }
02809 
02810 
02811 fct_logger_i*
02812 fct_minimal_logger_new(void)
02813 {
02814     fct_minimal_logger_t *self = (fct_minimal_logger_t*)\
02815                                  calloc(1,sizeof(fct_minimal_logger_t));
02816     if ( self == NULL )
02817     {
02818         return NULL;
02819     }
02820     fct_logger__init((fct_logger_i*)self);
02821     self->vtable.on_chk = fct_minimal_logger__on_chk;
02822     self->vtable.on_fctx_end = fct_minimal_logger__on_fctx_end;
02823     self->vtable.on_delete = fct_minimal_logger__on_delete;
02824     fct_nlist__init2(&(self->failed_cndtns_list), 0);
02825     return (fct_logger_i*)self;
02826 }
02827 
02828 
02829 /*
02830 -----------------------------------------------------------
02831 STANDARD LOGGER
02832 -----------------------------------------------------------
02833 */
02834 
02835 struct _fct_standard_logger_t
02836 {
02837     _fct_logger_head;
02838 
02839     /* Start time. For now we use the low-accuracy time_t version. */
02840     fct_timer_t timer;
02841 
02842     /* A list of char*'s that needs to be cleaned up. */
02843     fct_nlist_t failed_cndtns_list;
02844 };
02845 
02846 
02847 #define FCT_STANDARD_LOGGER_MAX_LINE 68
02848 
02849 
02850 /* When a failure occurrs, we will record the details so we can display
02851 them when the log "finishes" up. */
02852 static void
02853 fct_standard_logger__on_chk(
02854     fct_logger_i *logger_,
02855     fct_logger_evt_t const *e
02856 )
02857 {
02858     fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
02859     /* Only record failures. */
02860     if ( !fctchk__is_pass(e->chk) )
02861     {
02862         fct_logger_record_failure(e->chk, &(logger->failed_cndtns_list));
02863     }
02864 }
02865 
02866 
02867 static void
02868 fct_standard_logger__on_test_skip(
02869     fct_logger_i* logger_,
02870     fct_logger_evt_t const *e
02871 )
02872 {
02873     char const *condition = e->cndtn;
02874     char const *name = e->name;
02875     char msg[256] = {'\0'};
02876     fct_unused(logger_);
02877     fct_unused(condition);
02878     fct_snprintf(msg, sizeof(msg), "%s (%s)", name, condition);
02879     msg[sizeof(msg)-1] = '\0';
02880     fct_dotted_line_start(FCT_STANDARD_LOGGER_MAX_LINE, msg);
02881     fct_dotted_line_end("- SKIP -");
02882 }
02883 
02884 
02885 static void
02886 fct_standard_logger__on_test_start(
02887     fct_logger_i *logger_,
02888     fct_logger_evt_t const *e
02889 )
02890 {
02891     fct_unused(logger_);
02892     fct_dotted_line_start(
02893         FCT_STANDARD_LOGGER_MAX_LINE,
02894         fct_test__name(e->test)
02895     );
02896 }
02897 
02898 
02899 static void
02900 fct_standard_logger__on_test_end(
02901     fct_logger_i *logger_,
02902     fct_logger_evt_t const *e
02903 )
02904 {
02905     nbool_t is_pass;
02906     fct_unused(logger_);
02907     is_pass = fct_test__is_pass(e->test);
02908     fct_dotted_line_end((is_pass) ? "PASS" : "FAIL ***" );
02909 }
02910 
02911 
02912 static void
02913 fct_standard_logger__on_fctx_start(
02914     fct_logger_i *logger_,
02915     fct_logger_evt_t const *e
02916 )
02917 {
02918     fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
02919     fct_unused(e);
02920     fct_timer__start(&(logger->timer));
02921 }
02922 
02923 
02924 static void
02925 fct_standard_logger__on_fctx_end(
02926     fct_logger_i *logger_,
02927     fct_logger_evt_t const *e
02928 )
02929 {
02930     fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
02931     nbool_t is_success =1;
02932     double elasped_time =0;
02933     size_t num_tests =0;
02934     size_t num_passed =0;
02935 
02936     fct_timer__stop(&(logger->timer));
02937 
02938     is_success = fct_nlist__size(&(logger->failed_cndtns_list)) ==0;
02939 
02940     if (  !is_success )
02941     {
02942         fct_logger_print_failures(&(logger->failed_cndtns_list));
02943     }
02944     puts(
02945         "\n----------------------------------------------------------------------------\n"
02946     );
02947     num_tests = fctkern__tst_cnt(e->kern);
02948     num_passed = fctkern__tst_cnt_passed(e->kern);
02949     printf(
02950         "%s (%lu/%lu tests",
02951         (is_success) ? "PASSED" : "FAILED",
02952         (unsigned long) num_passed,
02953         (unsigned long) num_tests
02954     );
02955     elasped_time = fct_timer__duration(&(logger->timer));
02956     if ( elasped_time > 0.0000001 )
02957     {
02958         printf(" in %.6fs)\n", elasped_time);
02959     }
02960     else
02961     {
02962         /* Don't bother displaying the time to execute. */
02963         puts(")\n");
02964     }
02965 }
02966 
02967 
02968 static void
02969 fct_standard_logger__on_delete(
02970     fct_logger_i *logger_,
02971     fct_logger_evt_t const *e
02972 )
02973 {
02974     fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
02975     fct_unused(e);
02976     fct_nlist__final(&(logger->failed_cndtns_list), free);
02977     free(logger);
02978     logger_ =NULL;
02979 }
02980 
02981 
02982 static void
02983 fct_standard_logger__on_warn(
02984     fct_logger_i* logger_,
02985     fct_logger_evt_t const *e
02986 )
02987 {
02988     fct_unused(logger_);
02989     (void)printf("WARNING: %s", e->msg);
02990 }
02991 
02992 
02993 fct_logger_i*
02994 fct_standard_logger_new(void)
02995 {
02996     fct_standard_logger_t *logger = (fct_standard_logger_t *)calloc(
02997                                         1, sizeof(fct_standard_logger_t)
02998                                     );
02999     if ( logger == NULL )
03000     {
03001         return NULL;
03002     }
03003     fct_logger__init((fct_logger_i*)logger);
03004     logger->vtable.on_chk = fct_standard_logger__on_chk;
03005     logger->vtable.on_test_start = fct_standard_logger__on_test_start;
03006     logger->vtable.on_test_end = fct_standard_logger__on_test_end;
03007     logger->vtable.on_fctx_start = fct_standard_logger__on_fctx_start;
03008     logger->vtable.on_fctx_end = fct_standard_logger__on_fctx_end;
03009     logger->vtable.on_delete = fct_standard_logger__on_delete;
03010     logger->vtable.on_warn = fct_standard_logger__on_warn;
03011     logger->vtable.on_test_skip = fct_standard_logger__on_test_skip;
03012     fct_nlist__init2(&(logger->failed_cndtns_list), 0);
03013     fct_timer__init(&(logger->timer));
03014     return (fct_logger_i*)logger;
03015 }
03016 
03017 
03018 /*
03019 -----------------------------------------------------------
03020 JUNIT LOGGER
03021 -----------------------------------------------------------
03022 */
03023 
03024 
03025 /* JUnit logger */
03026 struct _fct_junit_logger_t
03027 {
03028     _fct_logger_head;
03029 };
03030 
03031 
03032 static void
03033 fct_junit_logger__on_test_suite_start(
03034     fct_logger_i *l,
03035     fct_logger_evt_t const *e
03036 )
03037 {
03038     fct_unused(l);
03039     fct_unused(e);
03040     FCT_SWITCH_STDOUT_TO_BUFFER();
03041     FCT_SWITCH_STDERR_TO_BUFFER();
03042 }
03043 
03044 
03045 static void
03046 fct_junit_logger__on_test_suite_end(
03047     fct_logger_i *logger_,
03048     fct_logger_evt_t const *e
03049 )
03050 {
03051     fct_ts_t const *ts = e->ts; /* Test Suite */
03052     nbool_t is_pass;
03053     double elasped_time = 0;
03054     char std_buffer[1024];
03055     int read_length;
03056     int first_out_line;
03057 
03058     fct_unused(logger_);
03059 
03060     elasped_time = fct_ts__duration(ts);
03061 
03062     FCT_SWITCH_STDOUT_TO_STDOUT();
03063     FCT_SWITCH_STDERR_TO_STDERR();
03064 
03065     /* opening testsuite tag */
03066     printf("\t<testsuite errors=\"%lu\" failures=\"0\" tests=\"%lu\" "
03067            "name=\"%s\" time=\"%.4f\">\n",
03068            (unsigned long)   fct_ts__tst_cnt(ts)
03069            - fct_ts__tst_cnt_passed(ts),
03070            (unsigned long) fct_ts__tst_cnt(ts),
03071            fct_ts__name(ts),
03072            elasped_time);
03073 
03074     FCT_NLIST_FOREACH_BGN(fct_test_t*, test, &(ts->test_list))
03075     {
03076         is_pass = fct_test__is_pass(test);
03077 
03078         /* opening testcase tag */
03079         if (is_pass)
03080         {
03081             printf("\t\t<testcase name=\"%s\" time=\"%.3f\"",
03082                    fct_test__name(test),
03083                    fct_test__duration(test)
03084                   );
03085         }
03086         else
03087         {
03088             printf("\t\t<testcase name=\"%s\" time=\"%.3f\">\n",
03089                    fct_test__name(test),
03090                    fct_test__duration(test)
03091                   );
03092         }
03093 
03094         FCT_NLIST_FOREACH_BGN(fctchk_t*, chk, &(test->failed_chks))
03095         {
03096             /* error tag */
03097             printf("\t\t\t<error message=\"%s\" "
03098                    "type=\"fctx\">", chk->msg);
03099             printf("file:%s, line:%d", chk->file, chk->lineno);
03100             printf("</error>\n");
03101         }
03102         FCT_NLIST_FOREACH_END();
03103 
03104         /* closing testcase tag */
03105         if (is_pass)
03106         {
03107             printf(" />\n");
03108         }
03109         else
03110         {
03111             printf("\t\t</testcase>\n");
03112         }
03113     }
03114     FCT_NLIST_FOREACH_END();
03115 
03116     /* print the std streams */
03117     first_out_line = 1;
03118     printf("\t\t<system-out>\n\t\t\t<![CDATA[");
03119     while ( (read_length = _fct_read(fct_stdout_pipe[0], std_buffer, 1024)) > 0)
03120     {
03121         if (first_out_line)
03122         {
03123             printf("\n");
03124             first_out_line = 0;
03125         }
03126         printf("%.*s", read_length, std_buffer);
03127     }
03128     printf("]]>\n\t\t</system-out>\n");
03129 
03130     first_out_line = 1;
03131     printf("\t\t<system-err>\n\t\t\t<![CDATA[");
03132     while ((read_length = _fct_read(fct_stderr_pipe[0], std_buffer, 1024)) > 0)
03133     {
03134         if (first_out_line)
03135         {
03136             printf("\n");
03137             first_out_line = 0;
03138         }
03139         printf("%.*s", read_length, std_buffer);
03140     }
03141     printf("]]>\n\t\t</system-err>\n");
03142 
03143     /* closing testsuite tag */
03144     printf("\t</testsuite>\n");
03145 }
03146 
03147 static void
03148 fct_junit_logger__on_fct_start(
03149     fct_logger_i *logger_,
03150     fct_logger_evt_t const *e
03151 )
03152 {
03153     fct_unused(logger_);
03154     fct_unused(e);
03155     printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
03156     printf("<testsuites>\n");
03157 }
03158 
03159 static void
03160 fct_junit_logger__on_fctx_end(
03161     fct_logger_i *logger_,
03162     fct_logger_evt_t const *e
03163 )
03164 {
03165     fct_unused(logger_);
03166     fct_unused(e);
03167     printf("</testsuites>\n");
03168 }
03169 
03170 static void
03171 fct_junit_logger__on_delete(
03172     fct_logger_i *logger_,
03173     fct_logger_evt_t const *e
03174 )
03175 {
03176     fct_junit_logger_t *logger = (fct_junit_logger_t*)logger_;
03177     fct_unused(e);
03178     free(logger);
03179     logger_ =NULL;
03180 }
03181 
03182 
03183 fct_junit_logger_t *
03184 fct_junit_logger_new(void)
03185 {
03186     fct_junit_logger_t *logger =
03187         (fct_junit_logger_t *)calloc(1, sizeof(fct_junit_logger_t));
03188     if ( logger == NULL )
03189     {
03190         return NULL;
03191     }
03192     fct_logger__init((fct_logger_i*)logger);
03193     logger->vtable.on_test_suite_start = fct_junit_logger__on_test_suite_start;
03194     logger->vtable.on_test_suite_end = fct_junit_logger__on_test_suite_end;
03195     logger->vtable.on_fctx_start = fct_junit_logger__on_fct_start;
03196     logger->vtable.on_fctx_end = fct_junit_logger__on_fctx_end;
03197     logger->vtable.on_delete = fct_junit_logger__on_delete;
03198     return logger;
03199 }
03200 
03201 
03202 /*
03203 ------------------------------------------------------------
03204 MACRO MAGIC
03205 ------------------------------------------------------------
03206 This is where the show begins!
03207 */
03208 
03209 /* This macro invokes a bunch of functions that need to be referenced in
03210 order to avoid  a "unreferenced local function has been removed" warning.
03211 The logical acrobatics below try and make it appear to the compiler that
03212 they are needed, but at runtime, only the cheap, first call is made. */
03213 #define FCT_REFERENCE_FUNCS() \
03214     {\
03215         int check = 0 && fctstr_ieq(NULL, NULL);\
03216         if ( check ) {\
03217             _fct_cmt("not to be executed");\
03218             (void)_fct_chk_empty_str(NULL);\
03219             (void)_fct_chk_full_str(NULL);\
03220             (void)fct_test__start_timer(NULL);\
03221             (void)fct_test__stop_timer(NULL);\
03222             (void)fct_ts_new(NULL);\
03223             (void)fct_ts__test_begin(NULL);\
03224             (void)fct_ts__add_test(NULL, NULL);\
03225             (void)fct_ts__test_end(NULL);\
03226             (void)fct_ts__inc_total_test_num(NULL);\
03227             (void)fct_ts__make_abort_test(NULL);\
03228             (void)fct_ts__setup_abort(NULL);\
03229             (void)fct_ts__setup_end(NULL);\
03230             (void)fct_ts__teardown_end(NULL);\
03231             (void)fct_ts__cnt_end(NULL);\
03232             (void)fct_ts__is_test_cnt(NULL, 0);\
03233             (void)fct_xchk_fn(0, "");\
03234             (void)fct_xchk2_fn(NULL, 0, "");\
03235             (void)fctkern__cl_parse(NULL);\
03236             (void)fctkern__add_ts(NULL, NULL);\
03237             (void)fctkern__pass_filter(NULL, NULL);\
03238             (void)fctkern__log_suite_start(NULL, NULL);\
03239             (void)fctkern__log_suite_end(NULL, NULL);\
03240             (void)fctkern__log_test_skip(NULL, NULL, NULL);\
03241             (void)fctkern__log_test_start(NULL, NULL);\
03242             (void)fctkern__log_test_end(NULL, NULL);\
03243             (void)fctstr_endswith(NULL,NULL);\
03244             (void)fctstr_iendswith(NULL,NULL);\
03245             (void)fctstr_ieq(NULL,NULL);\
03246             (void)fctstr_incl(NULL, NULL);\
03247             (void)fctstr_iincl(NULL, NULL);\
03248             (void)fctstr_iendswith(NULL,NULL);\
03249             (void)fctstr_istartswith(NULL,NULL);\
03250             (void)fctstr_clone_lower(NULL);\
03251             (void)fctstr_startswith(NULL,NULL);\
03252             (void)fctkern__init(NULL, 0, NULL);\
03253             (void)fctkern__cl_is(NULL, "");\
03254             (void)fctkern__cl_val2(NULL, NULL, NULL);\
03255             fctkern__log_suite_skip(NULL, NULL, NULL);\
03256             (void)fct_clp__is_param(NULL,NULL);\
03257             _fct_cmt("should never construct an object");\
03258             (void)fct_test_new(NULL);\
03259             (void)fct_ts__chk_cnt(NULL);\
03260         }\
03261     }
03262 
03263 
03264 #define FCT_INIT(_ARGC_, _ARGV_)                                    \
03265    fctkern_t  fctkern__;                                            \
03266    fctkern_t* fctkern_ptr__ = &fctkern__;                           \
03267    FCT_REFERENCE_FUNCS();                                           \
03268    if ( !fctkern__init(fctkern_ptr__, argc, (const char **)argv) ) {\
03269         (void)fprintf(                                              \
03270             stderr, "FATAL ERROR: Unable to initialize FCTX Kernel."\
03271         );                                                          \
03272         exit(EXIT_FAILURE);                                         \
03273    }                                                                \
03274 
03275 
03276 #define FCT_FINAL()                                                \
03277    fctkern_ptr__->ns.num_total_failed = fctkern__tst_cnt_failed(   \
03278             (fctkern_ptr__)                                        \
03279            );                                                      \
03280    fctkern__log_end(fctkern_ptr__);                                \
03281    fctkern__end(fctkern_ptr__);                                    \
03282    fctkern__final(fctkern_ptr__);                                  \
03283    FCT_ASSERT( !((int)fctkern_ptr__->ns.num_total_failed < 0)      \
03284                && "or we got truncated!");                         \
03285    if ( fctkern_ptr__->ns.num_total_failed ==                      \
03286         fctkern_ptr__->num_expected_failures) {                    \
03287        fctkern_ptr__->ns.num_total_failed = 0;                     \
03288    }                                                               \
03289    
03290 
03291 
03292 #define FCT_NUM_FAILED()       \
03293     fctkern_ptr__->ns.num_total_failed \
03294     
03295 
03296 
03297 /* Typically used internally only, this mentions to FCTX that you EXPECT
03298 to _NUM_FAILS_. If you the expected matches the actual, a 0 value is returned
03299 from the program. */
03300 #define FCT_EXPECTED_FAILURES(_NUM_FAILS_) \
03301     ((fctkern_ptr__->num_expected_failures = (_NUM_FAILS_)))
03302 
03303 
03304 #define FCT_BGN_FN(_FNNAME_)            \
03305     int _FNNAME_(int argc, char* argv[])\
03306     {                                   \
03307         FCT_INIT(argc, argv)
03308  
03309 #define FCT_END_FN() FCT_END()
03310 
03311 /* This defines our start. The fctkern__ is a kernal object
03312 that lives throughout the lifetime of our program. The
03313 fctkern_ptr__ makes it easier to abstract out macros.  */
03314 #define FCT_BGN() FCT_BGN_FN(main)
03315 
03316 
03317 /* Silence Intel complaints about unspecified operand order in user's code */
03318 #ifndef __INTEL_COMPILER
03319 # define FCT_END_WARNINGFIX_BGN
03320 # define FCT_END_WARNINGFIX_END
03321 #else
03322 # define FCT_END_WARNINGFIX_BGN _Pragma("warning(push,disable:981)");
03323 # define FCT_END_WARNINGFIX_END _Pragma("warning(pop)");
03324 #endif
03325 
03326 /* Ends the test suite by returning the number failed. The "chk_cnt" call is
03327 made in order allow strict compilers to pass when it encounters unreferenced
03328 functions. */
03329 #define FCT_END()             \
03330    {                          \
03331       FCT_END_WARNINGFIX_BGN  \
03332       FCT_FINAL();            \
03333       return FCT_NUM_FAILED();\
03334       FCT_END_WARNINGFIX_END  \
03335    }\
03336 }
03337 
03338 #define fctlog_install(_CUST_LOGGER_LIST_) \
03339     fctkern_ptr__->lt_usr = (_CUST_LOGGER_LIST_)
03340 
03341 /* Re-parses the command line options with the addition of user defined
03342 options. */
03343 #define fctcl_install(_CLO_INIT_) \
03344     {\
03345         fctkern_ptr__->cl_user_opts = (_CLO_INIT_);\
03346         _fct_cmt("Delay parse in order to allow for user customization.");\
03347         if ( !fctkern__cl_is_parsed((fctkern_ptr__)) ) {\
03348               int status = fctkern__cl_parse((fctkern_ptr__));\
03349               _fct_cmt("Need to parse command line before we start logger.");\
03350               fctkern__log_start((fctkern_ptr__));\
03351               switch( status ) {\
03352               case -1:\
03353               case 0:\
03354                   fctkern__final(fctkern_ptr__);\
03355                   exit( (status == 0) ? (EXIT_FAILURE) : (EXIT_SUCCESS) );\
03356                   break;\
03357               default:\
03358                   fct_pass();\
03359               }\
03360           }\
03361     }
03362 
03363 
03364 #define fctcl_is(_OPT_STR_) (fctkern__cl_is(fctkern_ptr__, (_OPT_STR_)))
03365 
03366 #define fctcl_val(_OPT_STR_) (fctcl_val2((_OPT_STR_), NULL))
03367 
03368 #define fctcl_val2(_OPT_STR_, _DEF_STR_) \
03369    (fctkern__cl_val2(fctkern_ptr__, (_OPT_STR_), (_DEF_STR_)))
03370 
03371 
03372 /* We delay the first parse of the command line until we get the first
03373 test fixture. This allows the user to possibly add their own parse
03374 specification. */
03375 #define FCT_FIXTURE_SUITE_BGN(_NAME_) \
03376    {\
03377       fctkern_ptr__->ns.ts_curr = fct_ts_new( #_NAME_ );\
03378       _fct_cmt("Delay parse in order to allow for user customization.");\
03379       if ( !fctkern__cl_is_parsed((fctkern_ptr__)) ) {\
03380           int status = fctkern__cl_parse((fctkern_ptr__));\
03381           _fct_cmt("Need to parse command line before we start logger.");\
03382           fctkern__log_start((fctkern_ptr__));\
03383           switch( status ) {\
03384           case -1:\
03385           case 0:\
03386               fct_ts__del((fctkern_ptr__->ns.ts_curr));\
03387               fctkern__final(fctkern_ptr__);\
03388               exit( (status == 0) ? (EXIT_FAILURE) : (EXIT_SUCCESS) );\
03389               break;\
03390           default:\
03391               fct_pass();\
03392           }\
03393       }\
03394       if ( fctkern_ptr__->ns.ts_curr == NULL ) {\
03395          fctkern__log_warn((fctkern_ptr__), "out of memory");\
03396       }\
03397       else\
03398       {\
03399          fctkern__log_suite_start((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
03400          for (;;)\
03401          {\
03402              fctkern_ptr__->ns.test_num = -1;\
03403              if ( fct_ts__is_ending_mode(fctkern_ptr__->ns.ts_curr) \
03404                   || fct_ts__is_abort_mode(fctkern_ptr__->ns.ts_curr) )\
03405              {\
03406                _fct_cmt("flag the test suite as complete.");\
03407                fct_ts__end(fctkern_ptr__->ns.ts_curr);\
03408                break;\
03409              }
03410 
03411 
03412 
03413 /*  Closes off a "Fixture" test suite. */
03414 #define FCT_FIXTURE_SUITE_END() \
03415              if ( fct_ts__is_cnt_mode(fctkern_ptr__->ns.ts_curr) )\
03416              {\
03417                 fct_ts__cnt_end(fctkern_ptr__->ns.ts_curr);\
03418              }\
03419           }\
03420           fctkern__add_ts((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
03421           fctkern__log_suite_end((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
03422           fct_ts__end(fctkern_ptr__->ns.ts_curr);\
03423           fctkern_ptr__->ns.ts_curr = NULL;\
03424           }\
03425       }
03426 
03427 #define FCT_FIXTURE_SUITE_BGN_IF(_CONDITION_, _NAME_) \
03428     fctkern_ptr__->ns.ts_is_skip_suite = !(_CONDITION_);\
03429     fctkern_ptr__->ns.ts_skip_cndtn = #_CONDITION_;\
03430     if ( fctkern_ptr__->ns.ts_is_skip_suite ) {\
03431        fctkern__log_suite_skip((fctkern_ptr__), #_CONDITION_, #_NAME_);\
03432     }\
03433     FCT_FIXTURE_SUITE_BGN(_NAME_);
03434 
03435 #define FCT_FIXTURE_SUITE_END_IF() \
03436     FCT_FIXTURE_SUITE_END();\
03437     fctkern_ptr__->ns.ts_is_skip_suite =0;\
03438     fctkern_ptr__->ns.ts_skip_cndtn =NULL;\
03439  
03440 #define FCT_SETUP_BGN()\
03441    if ( fct_ts__is_setup_mode(fctkern_ptr__->ns.ts_curr) ) {
03442 
03443 #define FCT_SETUP_END() \
03444    fct_ts__setup_end(fctkern_ptr__->ns.ts_curr); }
03445 
03446 #define FCT_TEARDOWN_BGN() \
03447    if ( fct_ts__is_teardown_mode(fctkern_ptr__->ns.ts_curr) ) {\
03448  
03449 #define FCT_TEARDOWN_END() \
03450    fct_ts__teardown_end(fctkern_ptr__->ns.ts_curr); \
03451    continue; \
03452    }
03453 
03454 /* Lets you create a test suite, where maybe you don't want a fixture. We
03455 do it by 'stubbing' out the setup/teardown logic. */
03456 #define FCT_SUITE_BGN(Name) \
03457    FCT_FIXTURE_SUITE_BGN(Name) {\
03458    FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\
03459    FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\
03460  
03461 #define FCT_SUITE_END() } FCT_FIXTURE_SUITE_END()
03462 
03463 #define FCT_SUITE_BGN_IF(_CONDITION_, _NAME_) \
03464     FCT_FIXTURE_SUITE_BGN_IF(_CONDITION_, (_NAME_)) {\
03465     FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\
03466     FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\
03467  
03468 #define FCT_SUITE_END_IF() } FCT_FIXTURE_SUITE_END_IF()
03469 
03470 typedef enum
03471 {
03472     FCT_TEST_END_FLAG_Default    = 0x0000,
03473     FCT_TEST_END_FLAG_ClearFail  = 0x0001
03474 } FCT_TEST_END_FLAG;
03475 
03476 
03477 #define FCT_TEST_BGN_IF(_CONDITION_, _NAME_) { \
03478     fctkern_ptr__->ns.test_is_skip = !(_CONDITION_);\
03479     fctkern_ptr__->ns.test_skip_cndtn = #_CONDITION_;\
03480     FCT_TEST_BGN(_NAME_) {\
03481  
03482 #define FCT_TEST_END_IF() \
03483     } FCT_TEST_END();\
03484     fctkern_ptr__->ns.test_is_skip = 0;\
03485     fctkern_ptr__->ns.test_skip_cndtn = NULL;\
03486     }
03487 
03488 
03489 /* Depending on whether or not we are counting the tests, we will have to
03490 first determine if the test is the "current" count. Then we have to determine
03491 if we can pass the filter. Finally we will execute everything so that when a
03492 check fails, we can "break" out to the end of the test. And in between all
03493 that we do a memory check and fail a test if we can't build a fct_test
03494 object (should be rare). */
03495 #define FCT_TEST_BGN(_NAME_) \
03496          {\
03497             fctkern_ptr__->ns.curr_test_name = #_NAME_;\
03498             ++(fctkern_ptr__->ns.test_num);\
03499             if ( fct_ts__is_cnt_mode(fctkern_ptr__->ns.ts_curr) )\
03500             {\
03501                fct_ts__inc_total_test_num(fctkern_ptr__->ns.ts_curr);\
03502             }\
03503             else if ( fct_ts__is_test_mode(fctkern_ptr__->ns.ts_curr) \
03504                       && fct_ts__is_test_cnt(fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.test_num) )\
03505             {\
03506                fct_ts__test_begin(fctkern_ptr__->ns.ts_curr);\
03507                if ( fctkern__pass_filter(fctkern_ptr__,  fctkern_ptr__->ns.curr_test_name ) )\
03508                {\
03509                   fctkern_ptr__->ns.curr_test = fct_test_new( fctkern_ptr__->ns.curr_test_name );\
03510                   if ( fctkern_ptr__->ns.curr_test  == NULL ) {\
03511                     fctkern__log_warn(fctkern_ptr__, "out of memory");\
03512                   } else if ( fctkern_ptr__->ns.ts_is_skip_suite \
03513                               || fctkern_ptr__->ns.test_is_skip ) {\
03514                        fct_ts__test_begin(fctkern_ptr__->ns.ts_curr);\
03515                        fctkern__log_test_skip(\
03516                             fctkern_ptr__,\
03517                             fctkern_ptr__->ns.curr_test_name,\
03518                             (fctkern_ptr__->ns.test_is_skip) ?\
03519                                 (fctkern_ptr__->ns.test_skip_cndtn) :\
03520                                 (fctkern_ptr__->ns.ts_skip_cndtn)\
03521                        );\
03522                        fct_ts__test_end(fctkern_ptr__->ns.ts_curr);\
03523                        continue;\
03524                  } else {\
03525                       fctkern__log_test_start(fctkern_ptr__, fctkern_ptr__->ns.curr_test);\
03526                       fct_test__start_timer(fctkern_ptr__->ns.curr_test);\
03527                       for (;;) \
03528                       {
03529 
03530 
03531 
03532 
03533 #define FCT_TEST_END() \
03534                          break;\
03535                       }\
03536                       fct_test__stop_timer(fctkern_ptr__->ns.curr_test);\
03537                  }\
03538                  fct_ts__add_test(fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.curr_test);\
03539                  fctkern__log_test_end(fctkern_ptr__, fctkern_ptr__->ns.curr_test);\
03540                }\
03541                fct_ts__test_end(fctkern_ptr__->ns.ts_curr);\
03542                continue;\
03543             }\
03544          }\
03545  
03546 
03547 
03548 /*
03549 ---------------------------------------------------------
03550 CHECKING MACROS
03551 ----------------------------------------------------------
03552 
03553 The chk variants will continue on while the req variants will abort
03554 a test if a chk condition fails. The req variants are useful when you
03555 no longer want to keep checking conditions because a critical condition
03556 is not being met. */
03557 
03558 
03559 /* To support older compilers that do not have macro variable argument lists
03560 we have to use a function. The macro manages to store away the line/file
03561 location into a global before it runs this function, a trick I picked up from
03562 the error handling in the APR library. The unfortunate thing is that we can
03563 not carry forth the actual test through a "stringize" operation, but if you
03564 wanted to do that you should use fct_chk. */
03565 
03566 static int fct_xchk_lineno =0;
03567 static char const *fct_xchk_file = NULL;
03568 static fct_test_t *fct_xchk_test = NULL;
03569 static fctkern_t *fct_xchk_kern =NULL;
03570 
03571 
03572 static int
03573 _fct_xchk_fn_varg(
03574     char const *condition,
03575     int is_pass,
03576     char const *format,
03577     va_list args
03578 )
03579 {
03580     fctchk_t *chk =NULL;
03581     chk = fctchk_new(
03582               is_pass,
03583               condition,
03584               fct_xchk_file,
03585               fct_xchk_lineno,
03586               format,
03587               args
03588           );
03589     if ( chk == NULL )
03590     {
03591         fctkern__log_warn(fct_xchk_kern, "out of memory (aborting test)");
03592         goto finally;
03593     }
03594 
03595     fct_test__add(fct_xchk_test, chk);
03596     fctkern__log_chk(fct_xchk_kern, chk);
03597 finally:
03598     fct_xchk_lineno =0;
03599     fct_xchk_file =NULL;
03600     fct_xchk_test =NULL;
03601     fct_xchk_kern =NULL;
03602     return is_pass;
03603 }
03604 
03605 
03606 static int
03607 fct_xchk2_fn(const char *condition, int is_pass, char const *format, ...)
03608 {
03609     int r =0;
03610     va_list args;
03611     va_start(args, format);
03612     r = _fct_xchk_fn_varg(condition, is_pass, format, args);
03613     va_end(args);
03614     return r;
03615 }
03616 
03617 
03618 static int
03619 fct_xchk_fn(int is_pass, char const *format, ...)
03620 {
03621     int r=0;
03622     va_list args;
03623     va_start(args, format);
03624     r = _fct_xchk_fn_varg("<none-from-xchk>", is_pass, format, args);
03625     va_end(args);
03626     return r;
03627 }
03628 
03629 
03630 /* Call this with the following argument list:
03631 
03632    fct_xchk(test_condition, format_str, ...)
03633 
03634 the bulk of this macro presets some globals to allow us to support
03635 variable argument lists on older compilers. The idea came from the APR
03636 libraries error checking routines. */
03637 #define fct_xchk  fct_xchk_kern = fctkern_ptr__,\
03638                   fct_xchk_test = fctkern_ptr__->ns.curr_test,\
03639                   fct_xchk_lineno =__LINE__,\
03640                   fct_xchk_file=__FILE__,\
03641                   fct_xchk_fn
03642 
03643 #define fct_xchk2  fct_xchk_kern = fctkern_ptr__,\
03644                    fct_xchk_test = fctkern_ptr__->ns.curr_test,\
03645                    fct_xchk_lineno =__LINE__,\
03646                    fct_xchk_file=__FILE__,\
03647                    fct_xchk2_fn
03648 
03649 
03650 /* This checks the condition and reports the condition as a string
03651 if it fails. */
03652 #define fct_chk(_CNDTN_)  (fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_))
03653 
03654 #define _fct_req(_CNDTN_)  \
03655     if ( !(fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_)) ) { break; }
03656 
03657 
03658 /* When in test mode, construct a mock test object for fct_xchk to operate
03659 with. If we fail a setup up, then we go directly to a teardown mode. */
03660 #define fct_req(_CNDTN_)                                                 \
03661     if ( fct_ts__is_test_mode(fctkern_ptr__->ns.ts_curr) ) {             \
03662        _fct_req((_CNDTN_));                                              \
03663     }                                                                    \
03664     else if ( fct_ts__is_setup_mode(fctkern_ptr__->ns.ts_curr)           \
03665               || fct_ts__is_teardown_mode(fctkern_ptr__->ns.ts_curr) ) { \
03666        fctkern_ptr__->ns.curr_test = fct_ts__make_abort_test(            \
03667             fctkern_ptr__->ns.ts_curr                                    \
03668             );                                                           \
03669        if ( !(fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_)) ) {                 \
03670            fct_ts__setup_abort(fctkern_ptr__->ns.ts_curr);               \
03671            fct_ts__add_test(                                             \
03672                 fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.curr_test   \
03673                 );                                                       \
03674        }                                                                 \
03675     } else {                                                             \
03676        assert("invalid condition for fct_req!");                         \
03677        _fct_req((_CNDTN_));                                              \
03678     }
03679 
03680 
03681 #define fct_chk_eq_dbl(V1, V2) \
03682     fct_xchk(\
03683         ((int)(fabs((V1)-(V2)) < DBL_EPSILON)),\
03684         "chk_eq_dbl: %f != %f",\
03685         (V1),\
03686         (V2)\
03687         )
03688 
03689 
03690 #define fct_chk_neq_dbl(V1, V2) \
03691     fct_xchk(\
03692         ((int)(fabs((V1)-(V2)) >= DBL_EPSILON)),\
03693         "chk_neq_dbl: %f == %f",\
03694         (V1),\
03695         (V2)\
03696         )
03697 
03698 
03699 #define fct_chk_eq_str(V1, V2) \
03700     fct_xchk(fctstr_eq((V1), (V2)),\
03701           "chk_eq_str: '%s' != '%s'",\
03702           (V1),\
03703           (V2)\
03704           )
03705 
03706 
03707 #define fct_chk_neq_str(V1, V2) \
03708     fct_xchk(!fctstr_eq((V1), (V2)),\
03709           "chk_neq_str: '%s' == '%s'",\
03710           (V1),\
03711           (V2)\
03712           )
03713 
03714 /* To quiet warnings with GCC, who think we are being silly and passing
03715 in NULL to strlen, we will filter the predicate through these little
03716 functions */
03717 static int
03718 _fct_chk_empty_str(char const *s)
03719 {
03720     if ( s == NULL )
03721     {
03722         return 1;
03723     }
03724     return strlen(s) ==0;
03725 }
03726 static int
03727 _fct_chk_full_str(char const *s)
03728 {
03729     if ( s == NULL )
03730     {
03731         return 0;
03732     }
03733     return strlen(s) >0;
03734 }
03735 
03736 
03737 #define fct_chk_empty_str(V) \
03738     fct_xchk(_fct_chk_empty_str((V)),\
03739              "string not empty: '%s'",\
03740              (V)\
03741              )
03742 
03743 #define fct_chk_full_str(V) \
03744     fct_xchk(_fct_chk_full_str((V)),\
03745              "string is full: '%s'",\
03746              (V)\
03747              )
03748 
03749 
03750 #define fct_chk_eq_istr(V1, V2) \
03751     fct_xchk(fctstr_ieq((V1), (V2)),\
03752           "chk_eq_str: '%s' != '%s'",\
03753           (V1),\
03754           (V2)\
03755           )
03756 
03757 
03758 #define fct_chk_neq_istr(V1, V2) \
03759     fct_xchk(!fctstr_ieq((V1), (V2)),\
03760           "chk_neq_str: '%s' == '%s'",\
03761           (V1),\
03762           (V2)\
03763           )
03764 
03765 
03766 #define fct_chk_endswith_str(STR, CHECK)\
03767     fct_xchk(fctstr_endswith((STR),(CHECK)),\
03768             "fct_chk_endswith_str: '%s' doesn't end with '%s'",\
03769             (STR),\
03770             (CHECK)\
03771             )
03772 
03773 
03774 #define fct_chk_iendswith_str(STR, CHECK)\
03775     fct_xchk(fctstr_iendswith((STR), (CHECK)),\
03776              "fch_chk_iendswith_str: '%s' doesn't end with '%s'.",\
03777              (STR),\
03778              (CHECK)\
03779              )
03780 
03781 #define fct_chk_excl_str(STR, CHECK_EXCLUDE) \
03782     fct_xchk(!fctstr_incl((STR), (CHECK_EXCLUDE)),\
03783           "fct_chk_excl_str: '%s' is included in '%s'",\
03784           (STR),\
03785           (CHECK_EXCLUDE)\
03786           )
03787 
03788 #define fct_chk_excl_istr(ISTR, ICHECK_EXCLUDE) \
03789     fct_xchk(!fctstr_iincl((ISTR), (ICHECK_EXCLUDE)),\
03790           "fct_chk_excl_istr (case insensitive): '%s' is "\
03791           "included in'%s'",\
03792           (ISTR),\
03793           (ICHECK_EXCLUDE)\
03794           )
03795 
03796 #define fct_chk_incl_str(STR, CHECK_INCLUDE) \
03797     fct_xchk(fctstr_incl((STR), (CHECK_INCLUDE)),\
03798           "fct_chk_incl_str: '%s' does not include '%s'",\
03799               (STR),\
03800           (CHECK_INCLUDE)\
03801           )
03802 
03803 
03804 #define fct_chk_incl_istr(ISTR, ICHECK_INCLUDE) \
03805     fct_xchk(fctstr_iincl((ISTR), (ICHECK_INCLUDE)),\
03806           "fct_chk_incl_istr (case insensitive): '%s' does "\
03807           "not include '%s'",\
03808               (ISTR),\
03809           (ICHECK_INCLUDE)\
03810           )
03811 
03812 
03813 #define fct_chk_startswith_str(STR, CHECK)\
03814     fct_xchk(fctstr_startswith((STR), (CHECK)),\
03815           "'%s' does not start with '%s'",\
03816           (STR),\
03817           (CHECK)\
03818     )
03819 
03820 
03821 #define fct_chk_startswith_istr(STR, CHECK)\
03822     fct_xchk(fctstr_istartswith((STR), (CHECK)),\
03823           "case insensitive check: '%s' does not start with '%s'",\
03824           (STR),\
03825           (CHECK)\
03826     )
03827 
03828 #define fct_chk_eq_int(V1, V2) \
03829     fct_xchk(\
03830         ((V1) == (V2)),\
03831         "chq_eq_int: %d != %d",\
03832         (V1),\
03833         (V2)\
03834         )
03835 
03836 
03837 #define fct_chk_neq_int(V1, V2) \
03838     fct_xchk(\
03839         ((V1) != (V2)),\
03840         "chq_neq_int: %d == %d",\
03841         (V1),\
03842         (V2)\
03843         )
03844 
03845 #define fct_chk_ex(EXCEPTION, CODE)   \
03846    {                                  \
03847       bool pass_chk_ex = false;       \
03848       try {                           \
03849           CODE;                       \
03850           pass_chk_ex = false;        \
03851       } catch ( EXCEPTION ) {         \
03852           pass_chk_ex = true;         \
03853       } catch ( ... ) {               \
03854           pass_chk_ex = false;        \
03855       }                               \
03856       fct_xchk(                       \
03857         pass_chk_ex,                  \
03858         "%s exception not generated", \
03859         #EXCEPTION                    \
03860       );                              \
03861    }                                  \
03862  
03863 /*
03864 ---------------------------------------------------------
03865 GUT CHECK MACROS
03866 ----------------------------------------------------------
03867 
03868 The following macros are used to help check the "guts" of
03869 the FCT, and to confirm that it all works according to spec.
03870 */
03871 
03872 /* Generates a message to STDERR and exits the application with a
03873 non-zero number. */
03874 #define _FCT_GUTCHK(_CNDTN_) \
03875    if ( !(_CNDTN_) ) {\
03876       fprintf(stderr, "gutchk fail: '"  #_CNDTN_ "' was not true.\n");\
03877       exit(1);\
03878    }\
03879    else {\
03880       fprintf(stdout, "gutchk pass:  '" #_CNDTN_ "'\n");\
03881    }
03882 
03883 /*
03884 ---------------------------------------------------------
03885 MULTI-FILE TEST SUITE MACROS
03886 ----------------------------------------------------------
03887 
03888 I struggled trying to figure this out in a way that was
03889 as simple as possible. I wanted to be able to define
03890 the test suite in one object file, then refer it within
03891 the other one within the minimum amount of typing.
03892 
03893 Unfortunately without resorting to some supermacro
03894 work, I could only find a happy comprimise.
03895 
03896 See test_multi.c for an example.
03897 */
03898 
03899 /* The following macros are used in your separate object
03900 file to define your test suite.  */
03901 
03902 
03903 #define FCTMF_FIXTURE_SUITE_BGN(NAME) \
03904         void NAME (fctkern_t *fctkern_ptr__) {\
03905         FCT_REFERENCE_FUNCS();\
03906         FCT_FIXTURE_SUITE_BGN( NAME ) {
03907 
03908 #define FCTMF_FIXTURE_SUITE_END() \
03909                 } FCT_FIXTURE_SUITE_END();\
03910         }
03911 
03912 #define FCTMF_SUITE_BGN(NAME) \
03913         void NAME (fctkern_t *fctkern_ptr__) {\
03914         FCT_REFERENCE_FUNCS();\
03915         FCT_SUITE_BGN( NAME ) {
03916 #define FCTMF_SUITE_END() \
03917        } FCT_SUITE_END(); \
03918    }
03919 
03920 
03921 /* Deprecated, no longer required. */
03922 #define FCTMF_SUITE_DEF(NAME)
03923 
03924 
03925 /* Executes a test suite defined by FCTMF_SUITE* */
03926 #define FCTMF_SUITE_CALL(NAME)  {\
03927     void NAME (fctkern_t *);\
03928     NAME (fctkern_ptr__);\
03929     }
03930 
03931 
03932 /*
03933 ---------------------------------------------------------
03934 FCT QUICK TEST API
03935 ----------------------------------------------------------
03936 The goal of these little macros is to try and get you
03937 up and running with a test as quick as possible.
03938 
03939 The basic idea is that there is one test per test suite.
03940 */
03941 
03942 #define FCT_QTEST_BGN(NAME) \
03943         FCT_SUITE_BGN(NAME) {\
03944                 FCT_TEST_BGN(NAME) {\
03945  
03946 #define FCT_QTEST_END() \
03947                 } FCT_TEST_END();\
03948         } FCT_SUITE_END();
03949 
03950 
03951 #define FCT_QTEST_BGN_IF(_CONDITION_, _NAME_) \
03952         FCT_SUITE_BGN(_NAME_) {\
03953                 FCT_TEST_BGN_IF(_CONDITION_, _NAME_) {\
03954  
03955 #define FCT_QTEST_END_IF() \
03956                 } FCT_TEST_END_IF();\
03957         } FCT_SUITE_END();
03958 
03959 #endif /* !FCT_INCLUDED__IMB */
Home |  Recent changes |  Search |  Glossary |  Sitemap |  Login