- Added CMake makefiles as alternative to regular Makefiles.
 - Added preliminary Code Coverage tests for AES, ARC4, Base64, MPI, SHA-family, MD-family and  HMAC-SHA-family.

diff --git a/tests/fct.h b/tests/fct.h
new file mode 100644
index 0000000..f6c1251
--- /dev/null
+++ b/tests/fct.h
@@ -0,0 +1,1688 @@
+/*

+====================================================================

+Copyright (c) 2008 Ian Blumel.  All rights reserved.

+

+FCT (Fast C Test) Unit Testing Framework

+

+Copyright (c) 2008, Ian Blumel (ian.blumel@gmail.com)

+All rights reserved.

+

+This license is based on the BSD License.

+

+Redistribution and use in source and binary forms, with or without

+modification, are permitted provided that the following conditions are

+met:

+

+    * Redistributions of source code must retain the above copyright

+    notice, this list of conditions and the following disclaimer.

+    

+    * Redistributions in binary form must reproduce the above copyright

+    notice, this list of conditions and the following disclaimer in

+    the documentation and/or other materials provided with the

+    distribution.

+

+    * Neither the name of, Ian Blumel, nor the names of its

+    contributors may be used to endorse or promote products derived

+    from this software without specific prior written permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS

+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED

+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A

+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER

+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,

+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF

+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+====================================================================

+

+File: fct.h

+*/

+

+#if !defined(FCT_INCLUDED__IMB)

+#define FCT_INCLUDED__IMB

+

+#define FCT_VERSION_STR   "1.0.2"

+#define FCT_VERSION_MAJOR 1

+#define FCT_VERSION_MINOR 0

+#define FCT_VERSION_MICRO 2

+

+/* Define this to remove unneeded WIN32 warnings. We will undefine this at

+the end of the file so as not to interfere with your build. */

+#if defined(WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)

+#  define _CRT_SECURE_NO_WARNINGS

+#endif

+

+#include <string.h>

+#include <assert.h>

+#include <stdarg.h>

+#include <stdlib.h>

+#include <stdio.h>

+#include <time.h>

+#include <float.h>

+#include <math.h>

+

+#define FCT_MAX_NAME           256

+#define FCT_MAX_LOG_LINE       256

+

+#define nbool_t int

+#define FCT_TRUE   1

+#define FCT_FALSE  0

+

+/* Forward declarations. The following forward declarations are required

+because there is a inter-relationship between certain objects that 

+just can not be untwined. */

+typedef struct _fct_logger_i fct_logger_i;

+typedef struct _fct_standard_logger_t fct_standard_logger_t;

+typedef struct _fct_minimal_logger_t fct_minimal_logger_t;

+typedef struct _fctchk_t fctchk_t;

+typedef struct _fct_test_t fct_test_t;

+typedef struct _fct_ts_t fct_ts_t;

+typedef struct _fctkern_t fctkern_t;

+

+/* Forward declare some functions used throughout. */

+static fct_standard_logger_t *

+fct_standard_logger__new(void);

+

+static void

+fct_logger__del(fct_logger_i *logger);

+

+static void

+fct_logger__on_cndtn(fct_logger_i *self, fctchk_t const *chk);

+

+static void

+fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test);

+

+static void

+fct_logger__on_test_end(fct_logger_i *logger, fct_test_t const *test);

+

+static void

+fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts);

+

+static void

+fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts);

+

+static void

+fct_logger__on_fct_start(fct_logger_i *logger, fctkern_t const *kern);

+

+static void

+fct_logger__on_fct_end(fct_logger_i *logger, fctkern_t const *kern);

+

+

+

+/* Explicitly indicate a no-op */

+#define fct_pass()    

+

+#define fct_unused(x)   ((void) (x));

+

+/* This is just a little trick to let me put comments inside of macros. I

+really only want to bother with this when we are "unwinding" the macros

+for debugging purposes. */

+#if defined(FCT_CONF_UNWIND)

+#	define _fct_cmt(string)		{char*_=string;} 

+#else

+#	define _fct_cmt(string)

+#endif

+

+/* 

+-------------------------------------------------------- 

+UTILITIES

+-------------------------------------------------------- 

+*/

+

+/* Utility for truncated, safe string copies. */

+static void

+fct_safe_str_cpy(char *dst, char const *src, size_t num)

+{

+   assert( dst != NULL );

+   assert( src != NULL );

+   assert( num > 0 );

+   strncpy(dst, src, num);

+   dst[num-1] = '\0';

+}

+

+/* Isolate the snprintf implemenation. */

+int 

+fct_snprintf(char *buffer, size_t buffer_len, char *format, ...)

+{

+   int count =0;

+   va_list args;

+   va_start(args, format);

+   count =vsnprintf(buffer, buffer_len, format, args);

+   va_end(args);

+   return count;

+}

+

+/* A very, very simple "filter". This just compares the supplied prefix 

+against the test_str, to see if they both have the same starting 

+characters. If they do we return true, otherwise we return false. If the

+prefix is a blank string or NULL, then it will return FCT_TRUE.*/

+static nbool_t

+fct_filter_pass(char const *prefix, char const *test_str)

+{

+   nbool_t is_match = FCT_FALSE;

+   char const *prefix_p;

+   char const *test_str_p;

+

+   /* If you got nothing to test against, why test? */

+   assert( test_str != NULL );

+

+   /* When the prefix is NULL or blank, we always return FCT_TRUE. */

+   if ( prefix == NULL  || prefix[0] == '\0' ) 

+   { 

+      return FCT_TRUE;

+   }

+     

+   /* Iterate through both character arrays at the same time. We are

+   going to play a game and see if we can beat the house. */

+   for ( prefix_p = prefix, test_str_p = test_str; 

+         *prefix_p != '\0' && *test_str_p != '\0'; 

+         ++prefix_p, ++test_str_p )

+   {

+      is_match = *prefix_p == *test_str_p;

+      if ( !is_match ) 

+      {

+         break;   /* Quit the first time we don't match. */

+      }

+   }

+   

+   /* If the iterator for the test_str is pointing at the null char, and

+   the iterator for the prefix string is not, then the prefix string is 

+   larger than the actual test string, and therefore we failed to pass the

+   filter. */

+   if ( *test_str_p == '\0' && *prefix_p != '\0' )

+   {

+      return FCT_FALSE;

+   }

+

+   /* is_match will be set to the either FCT_TRUE if we kicked of the loop

+   early because our filter ran out of characters or FCT_FALSE if we 

+   encountered a mismatch before our filter ran out of characters. */

+   return is_match;

+}

+

+/* Returns true if two reals are equal. */

+nbool_t 

+fct_real_eq(double v1, double v2)

+{

+   return (nbool_t)(fabs(v1 - v2) < DBL_EPSILON);

+}

+

+/* 

+-------------------------------------------------------- 

+TIMER

+-------------------------------------------------------- 

+*/

+

+typedef struct _fct_timer_t fct_timer_t;

+struct _fct_timer_t {

+    clock_t start;

+    clock_t stop;

+    double duration;

+};

+

+

+static void

+fct_timer__init(fct_timer_t *timer) {

+    assert(timer != NULL);

+    memset(timer, 0, sizeof(fct_timer_t));

+}

+

+

+static void

+fct_timer__start(fct_timer_t *timer) {

+    assert(timer != NULL);

+    timer->start = clock();

+}

+

+

+static void

+fct_timer__stop(fct_timer_t *timer) {

+    assert(timer != NULL);

+    timer->stop = clock();

+    timer->duration = (double) (timer->stop - timer->start) / CLOCKS_PER_SEC;

+}

+

+

+/* Returns the time in seconds. */

+static double

+fct_timer__duration(fct_timer_t *timer) {

+    assert( timer != NULL );

+    return timer->duration;   

+}

+

+

+/* 

+-------------------------------------------------------- 

+GENERIC LIST

+-------------------------------------------------------- 

+*/

+

+/* For now we will just keep it at a linear growth rate. */

+#define FCT_LIST_GROWTH_FACTOR   2

+

+/* Starting size for the list, to keep it simple we will start

+at a reasonable size. */

+#define FCT_LIST_START_SIZE      2

+

+/* Helper macros for quickly iterating through a list. You should be able

+to do something like,

+

+  NLIST_FOREACH_BGN(fct_logger_i*, logger, my_list)

+  {

+     fct_logger__on_blah(logger);

+  }

+  NLIST_FOREACH_END();

+

+*/

+#define NLIST_FOREACH_BGN(Type, Var, List)\

+{\

+   if ( List != NULL ) {\

+      size_t item_i##Var;\

+      size_t num_items##Var = nlist__size(List);\

+      for( item_i##Var =0; item_i##Var != num_items##Var; ++item_i##Var )\

+      {\

+         Type Var = (Type) nlist__at((List), item_i##Var);

+

+#define NLIST_FOREACH_END() }}}

+

+/* Used to manage a list of loggers. This works mostly like

+the STL vector, where the array grows as more items are 

+appended. */

+typedef struct _nlist_t nlist_t;

+struct _nlist_t

+{ 

+   /* Item's are stored as pointers to void. */

+   void **itm_list;

+   

+   /* Indicates the number of element's in the array. */

+   size_t avail_itm_num;

+

+   /* Indicates the number of actually elements in the array. */

+   size_t used_itm_num;

+};

+

+static nlist_t *

+nlist_new(void)

+{

+   nlist_t *list = (nlist_t*)calloc(1, sizeof(nlist_t));

+   assert( list != NULL && "memory check");

+

+   list->itm_list = (void**)malloc(sizeof(void*)*FCT_LIST_START_SIZE);

+   assert( list->itm_list != NULL && "memory check");

+

+   list->avail_itm_num =FCT_LIST_START_SIZE;

+   list->used_itm_num =0;

+   return list;

+}

+

+typedef void (*on_del_t)(void*);

+

+/* Cleans up list, and applies `on_del` to each item in the list. 

+If on_del is NULL, it will not be applied. If `list` is NULL this

+function does nothing. */

+static void

+nlist__del(nlist_t *list, on_del_t on_del)

+{

+   size_t itm_i =0;

+

+   if ( list == NULL ) { return; }

+

+   /* Walk through the list applying the destroy function, if it was 

+   defined. */

+   if ( on_del != NULL )

+   {

+      for ( itm_i =0; itm_i != list->used_itm_num; ++itm_i )

+      {

+         on_del(list->itm_list[itm_i]);

+      }

+   }

+

+   free(list->itm_list);

+   free(list);

+}

+

+

+/* Returns the number of elements within the list. */

+static size_t

+nlist__size(nlist_t const *list)

+{

+   assert( list != NULL );

+   return list->used_itm_num;

+}

+

+

+/* Returns the item at idx, asserts otherwise. */

+static void*

+nlist__at(nlist_t const *list, size_t idx)

+{

+   assert( list != NULL );

+   assert( idx < list->used_itm_num );

+   return list->itm_list[idx];

+}

+

+

+static void

+nlist__append(nlist_t *list, void *itm)

+{

+   assert( list != NULL );

+   assert( list->itm_list != NULL );

+   assert( list->avail_itm_num != 0 );

+

+   /* If we ran out of room, then the last increment should be equal to the

+   available space, in this case we need to grow a little more. */

+   if ( list->used_itm_num == list->avail_itm_num )

+   {

+      list->avail_itm_num = list->avail_itm_num*FCT_LIST_GROWTH_FACTOR;

+      list->itm_list = (void**)realloc(

+         list->itm_list, sizeof(void*)*list->avail_itm_num

+         );

+      assert( list->itm_list != NULL && "memory check");

+   }

+

+   list->itm_list[list->used_itm_num] = itm;

+   ++(list->used_itm_num);

+}

+

+

+

+/*

+-----------------------------------------------------------

+A SINGLE CHECK

+-----------------------------------------------------------

+This defines a single check. It indicates what the check was,

+and where it occurred. A "Test" object will have-a bunch

+of "checks".

+*/

+

+struct _fctchk_t {

+   /* This string that represents the condition. */

+   char cndtn[FCT_MAX_LOG_LINE];

+

+   /* These indicate where the condition occurred. */

+   char file[FCT_MAX_LOG_LINE];

+

+   int lineno;

+

+   nbool_t is_pass;

+};

+

+#define fctchk__is_pass(_CHK_) ((_CHK_)->is_pass)

+#define fctchk__file(_CHK_)    ((_CHK_)->file)

+#define fctchk__lineno(_CHK_)  ((_CHK_)->lineno)

+#define fctchk__cndtn(_CHK_)   ((_CHK_)->cndtn)

+

+

+static fctchk_t*

+fctchk_new(char const *cndtn, char const *file, int lineno, nbool_t is_pass)

+{

+   fctchk_t *chk = NULL;

+

+   assert( cndtn != NULL );

+   assert( file != NULL );

+   assert( lineno > 0 );

+   

+   chk = (fctchk_t*)calloc(1, sizeof(fctchk_t));

+   assert( chk != NULL && "out of memory");

+   if ( chk == NULL ) { return NULL; }

+

+   fct_safe_str_cpy(chk->cndtn, cndtn, FCT_MAX_LOG_LINE);

+   fct_safe_str_cpy(chk->file, file, FCT_MAX_LOG_LINE);

+   chk->lineno = lineno;

+

+   chk->is_pass =is_pass;

+

+   return chk;

+}

+

+

+/* Cleans up a "check" object. If the `chk` is NULL, this function does 

+nothing. */

+static void

+fctchk__del(fctchk_t *chk)

+{

+   if ( chk == NULL ) { return; }

+   free( chk );

+}

+

+

+/*

+-----------------------------------------------------------

+A TEST

+-----------------------------------------------------------

+A suite will have-a list of tests. Where each test will have-a

+list of failed and passed checks.

+*/

+

+struct _fct_test_t {

+   /* List of failed and passed "checks" (fctchk_t). Two seperate

+   lists make it faster to determine how many checks passed and how

+   many checks failed. */

+   nlist_t *failed_chks;

+   nlist_t *passed_chks;

+

+   /* The name of the test case. */

+   char name[FCT_MAX_NAME];

+};

+

+#define fct_test__name(_TEST_) ((_TEST_)->name)

+

+static fct_test_t*

+fct_test_new(char const *name) {

+   fct_test_t *test =NULL;

+

+   test = (fct_test_t*)malloc(sizeof(fct_test_t));

+   assert( test != NULL && "out of memory");

+   

+   fct_safe_str_cpy(test->name, name, FCT_MAX_NAME);

+     

+   test->failed_chks = nlist_new();

+   test->passed_chks = nlist_new();

+   assert( test->failed_chks != NULL && "out of memory");

+   assert( test->passed_chks != NULL && "out of memory");

+

+   return test;

+}

+

+

+static nbool_t

+fct_test__is_pass(fct_test_t const *test)

+{

+   assert( test != NULL );

+   return nlist__size(test->failed_chks) == 0;   

+}

+

+

+static void

+fct_test__add(fct_test_t *test, fctchk_t *chk)

+{

+

+   assert( test != NULL );

+   assert( chk != NULL );

+

+   if ( fctchk__is_pass(chk) )

+   {

+      nlist__append(test->passed_chks, (void*)chk);

+   }

+   else

+   {

+      nlist__append(test->failed_chks, (void*)chk);

+   }

+}

+

+/* Returns the number of checks made throughout the test. */

+static int

+fct_test__chk_cnt(fct_test_t const *test)

+{

+   assert( test != NULL );

+   return nlist__size(test->failed_chks) + nlist__size(test->passed_chks);

+}

+

+

+static void

+fct_test__del(fct_test_t *test)

+{

+   if (test == NULL ) { return; }

+   nlist__del(test->passed_chks, (on_del_t)fctchk__del);

+   nlist__del(test->failed_chks, (on_del_t)fctchk__del);

+   free(test);

+}

+

+

+/* 

+-----------------------------------------------------------

+TEST SUITE (TS)

+-----------------------------------------------------------

+*/

+

+

+/* The different types of 'modes' that a test suite can be in.

+

+While the test suite is iterating through all the tests, its "State"

+can change from "setup mode", to "test mode" to "tear down" mode. 

+These help to indicate what mode are currently in. Think of it as a 

+basic FSM.

+

+            if the count was 0                               end

+           +--------->---------------------> ending_mode-----+

+           |                                       ^

+           ^                                       |

+start      |                              [if no more tests]

+  |        |                                       |      

+  +-count_mode -> setup_mode -> test_mode -> teardown_mode

+                      ^                           |                         

+                      +-----------<---------------+ 

+*/    

+enum ts_mode {

+   ts_mode_cnt,         /* To setup when done counting. */

+   ts_mode_setup,       /* To test when done setup. */

+   ts_mode_teardown,    /* To ending mode, when no more tests. */

+   ts_mode_test,        /* To tear down mode. */

+   ts_mode_ending,      /* To ... */

+   ts_mode_end          /* .. The End. */

+};

+

+/* Types of modes the test could be in. */

+typedef enum {

+   fct_test_status_SUCCESS,

+   fct_test_status_FAILURE

+} fct_test_status;

+

+

+struct _fct_ts_t {

+   /* For counting our 'current' test number, and the total number of 

+   tests. */

+   int  curr_test_num;

+   int  total_test_num;

+

+   /* Keeps track of the current state of the object while it is walking

+   through its "FSM" */

+   enum ts_mode mode;

+

+   /* The name of the test suite. */

+   char name[FCT_MAX_NAME];

+

+   /* List of tests that where executed within the test suite. */

+   nlist_t *test_list;

+};

+

+

+#define fct_ts__is_setup_mode(ts)     ((ts)->mode == ts_mode_setup)

+#define fct_ts__is_teardown_mode(ts)  ((ts)->mode == ts_mode_teardown)

+#define fct_ts__is_test_mode(ts)      ((ts)->mode == ts_mode_test)

+#define fct_ts__is_ending_mode(ts)    ((ts)->mode == ts_mode_ending)

+#define fct_ts__is_end(ts)            ((ts)->mode == ts_mode_end)

+#define fct_ts__is_cnt_mode(ts)       ((ts)->mode == ts_mode_cnt)

+#define fct_ts__name(ts)              ((ts)->name)

+

+

+static fct_ts_t *

+fct_ts_new(char const *name) {

+   fct_ts_t *ts =NULL;

+   ts = (fct_ts_t*)calloc(1, sizeof(fct_ts_t));

+   assert( ts != NULL );

+

+   fct_safe_str_cpy(ts->name, name, FCT_MAX_NAME);

+   ts->mode = ts_mode_cnt;

+

+   ts->test_list = nlist_new();

+   assert( ts->test_list != NULL && "no memory");

+

+   return ts;

+}

+

+static void

+fct_ts__del(fct_ts_t *ts) {

+   if ( ts == NULL ) { return; }

+   free(ts);

+}

+

+/* Flag a test suite as complete. It will no longer accept any more tests. */

+#define fct_ts__end(_TS_)  ((_TS_)->mode == ts_mode_end)

+

+

+static nbool_t

+fct_ts__is_more_tests(fct_ts_t const *ts) {

+   assert( ts != NULL );

+   assert( !fct_ts__is_end(ts) );

+   return ts->curr_test_num < ts->total_test_num;

+}

+

+

+/* Indicates that we have started a test case. */

+static void

+fct_ts__test_begin(fct_ts_t *ts) {

+   assert( !fct_ts__is_end(ts) );

+   ++(ts->curr_test_num);

+}

+

+

+/* Takes OWNERSHIP of a test object, and warehouses it for later stat

+generation. */

+static void

+fct_ts__add_test(fct_ts_t *ts, fct_test_t *test) {

+   assert( ts != NULL && "invalid arg");

+   assert( test != NULL && "invalid arg");

+   assert( !fct_ts__is_end(ts) );

+   nlist__append(ts->test_list, test);

+}

+

+

+static void

+fct_ts__test_end(fct_ts_t *ts) {

+   assert( ts != NULL );

+   assert( fct_ts__is_test_mode(ts) && "not in test mode, can't end!" );

+

+   /* After a test has completed, move to teardown mode. */

+   ts->mode = ts_mode_teardown;

+}

+

+

+/* Increments the internal count by 1. */

+static void

+fct_ts__inc_total_test_num(fct_ts_t *ts)

+{

+   assert( ts != NULL );

+   assert( fct_ts__is_cnt_mode(ts) );

+   assert( !fct_ts__is_end(ts) );

+   ++(ts->total_test_num);

+}

+

+

+/* Flags the end of the setup, which implies we are going to move into

+setup mode. You must be already in setup mode for this to work! */

+static void

+fct_ts__setup_end(fct_ts_t *ts)

+{

+   assert( fct_ts__is_setup_mode(ts) );

+   assert( !fct_ts__is_end(ts) );

+   ts->mode = ts_mode_test;

+}

+

+

+/* This cndtn is set when we have iterated through all the tests, and

+there was nothing more to do. */

+static void

+fct_ts__ending(fct_ts_t *ts)

+{

+   // We can only go from 'test-mode' to 'end-down' mode.

+   assert( fct_ts__is_test_mode(ts) );

+   assert( !fct_ts__is_end(ts) );

+   ts->mode = ts_mode_ending;

+}

+

+

+/* Flags the end of the teardown, which implies we are going to move

+into setup mode (for the next 'iteration'). */

+static void

+fct_ts__teardown_end(fct_ts_t *ts)

+{

+    assert( fct_ts__is_teardown_mode(ts) );

+    assert( !fct_ts__is_end(ts) );

+    /* We have to decide if we should keep on testing by moving into tear down 

+    mode or if we have reached the real end and should be moving into the 

+    ending mode. */

+    if ( fct_ts__is_more_tests(ts) ) {

+        ts->mode = ts_mode_setup;

+    }

+    else {

+        ts->mode = ts_mode_ending;

+    }

+}

+

+

+/* Flags the end of the counting, and proceeding to the first setup. 

+Consider the special case when a test suite has NO tests in it, in

+that case we will have a current count that is zero, in which case

+we can skip right to 'ending'. */

+static void

+fct_ts__cnt_end(fct_ts_t *ts)

+{

+   assert( ts != NULL );

+   assert( fct_ts__is_cnt_mode(ts) );

+   assert( !fct_ts__is_end(ts) );

+   if (ts->total_test_num == 0  ) {

+      ts->mode = ts_mode_ending;

+   }

+   else {

+      ts->mode = ts_mode_setup;

+   }

+}

+

+

+static nbool_t

+fct_ts__is_test_cnt(fct_ts_t const *ts, int test_num)

+{

+   assert( ts != NULL );

+   assert( 0 <= test_num );

+   assert( test_num < ts->total_test_num );

+   assert( !fct_ts__is_end(ts) );

+

+   /* As we roll through the tests we increment the count. With this

+   count we can decide if we need to execute a test or not. */

+   return test_num == ts->curr_test_num;

+}

+

+

+/* Returns the # of tests on the FCT TS object. This is the actual

+# of tests executed. */

+static int

+fct_ts__tst_cnt(fct_ts_t const *ts)

+{

+   assert( ts != NULL );

+   assert( !fct_ts__is_end(ts) );

+   return nlist__size(ts->test_list);

+}

+

+

+/* Returns the # of tests in the TS object that passed. */

+static int

+fct_ts__tst_cnt_passed(fct_ts_t const *ts)

+{

+   int tally =0;

+

+   assert( ts != NULL );

+   assert( !fct_ts__is_end(ts) );

+

+   NLIST_FOREACH_BGN(fct_test_t*, test, ts->test_list)

+   {

+      if ( fct_test__is_pass(test) )

+      {

+         tally += 1;

+      }

+   }

+   NLIST_FOREACH_END();

+   return tally;

+}

+

+

+/* Returns the # of checks made throughout a test suite. */

+static int

+fct_ts__chk_cnt(fct_ts_t const *ts)

+{

+   int tally =0;

+

+   assert( ts != NULL );

+   

+   NLIST_FOREACH_BGN(fct_test_t *, test, ts->test_list)

+   {

+      tally += fct_test__chk_cnt(test);

+   }

+   NLIST_FOREACH_END();

+   return tally;

+}

+

+

+/* 

+-------------------------------------------------------- 

+FCT KERNAL

+-------------------------------------------------------- 

+

+The "fctkern" is a singleton that is defined throughout the 

+system. 

+*/

+

+struct _fctkern_t {

+   /* This is an list of loggers that can be used in the fct system. 

+   You/ can attach _MAX_LOGGERS to any framework. */

+   nlist_t *logger_list;

+

+   /* This is a list of prefix's that can be used to determine if a 

+   test is should be run or not. */

+   nlist_t *prefix_list;

+

+   /* This is a list of test suites that where generated throughout the

+   testing process. */

+   nlist_t *ts_list;

+};

+

+

+/* Returns the number of filters defined for the fct kernal. */

+#define fctkern__filter_cnt(_NK_) (nlist__size((_NK_)->prefix_list))

+

+

+static void

+fctkern__add_logger(fctkern_t *fct, fct_logger_i *logger_owns)

+{

+   assert(fct != NULL && "invalid arg");

+   assert(logger_owns != NULL && "invalid arg");

+   nlist__append(fct->logger_list, logger_owns);

+   assert( fct->logger_list != NULL && "memory check");

+}

+

+/* Appends a prefix filter that is used to determine if a test can

+be executed or not. If the test starts with the same characters as

+the prefix, then it should be "runnable". The prefix filter must be

+a non-NULL, non-Blank string. */

+static void

+fctkern__add_prefix_filter(fctkern_t const *fct, char const *prefix_filter)

+{

+   char *filter =NULL;

+   int filter_len =0;

+

+   assert( fct != NULL && "invalid arg" );

+   assert( prefix_filter != NULL && "invalid arg" );

+   assert( strlen(prefix_filter) > 0 && "invalid arg" );

+

+   /* First we make a copy of the prefix, then we store it away

+   in our little list. */

+   filter_len = strlen(prefix_filter);

+   filter = (char*)malloc(sizeof(char)*(filter_len+1));

+   strncpy(filter, prefix_filter, filter_len);

+   filter[filter_len] = '\0';

+

+   nlist__append(fct->prefix_list, (void*)filter);

+}

+

+

+/* Parses the command line and sets up the framework. The argc and argv 

+should be directly from the program's  main. */

+static void

+fctkern_init(fctkern_t *nk, int argc, char *argv[])

+{

+   fct_logger_i *standard_logger = NULL;

+   int arg_i =0;

+

+   assert( nk != NULL );

+

+   memset(nk, 0, sizeof(fctkern_t));

+

+   nk->logger_list = nlist_new();

+   nk->prefix_list = nlist_new();

+   nk->ts_list = nlist_new();

+

+   /* Low-budget memory check for now. */

+   assert( nk->logger_list != NULL );

+   assert( nk->prefix_list != NULL );

+   assert( nk->ts_list != NULL );

+

+   standard_logger = (fct_logger_i*) fct_standard_logger__new();

+   assert( standard_logger != NULL && "no memory!");

+

+   fctkern__add_logger(nk, standard_logger);   

+   standard_logger = NULL;   /* Owned by the nk list. */

+

+   /* Our basic parser. For now we just take each 'argv' and assume

+   that it is a prefix filter. Notice we start at argument 1, since

+   we don't care about the *name* of the program. */

+   for ( arg_i =1; arg_i < argc; ++arg_i )

+   {

+      fctkern__add_prefix_filter(nk, argv[arg_i]);

+   }

+}

+

+

+/* Takes OWNERSHIP of the test suite after we have finished executing

+its contents. This way we can build up all kinds of summaries at the end

+of a run. */

+static void

+fctkern__add_ts(fctkern_t *nk, fct_ts_t *ts) {

+   assert( nk != NULL );

+   assert( ts != NULL );

+   nlist__append(nk->ts_list, ts);

+}

+

+

+

+/* Returns FCT_TRUE if the supplied test_name passes the filters set on

+this test suite. If there are no filters, we return FCT_TRUE always. */

+static nbool_t

+fctkern__pass_filter(fctkern_t *nk, char const *test_name) {

+   int prefix_i =0;

+   int prefix_list_size =0;

+

+   assert( nk != NULL && "invalid arg");

+   assert( test_name != NULL );

+   assert( strlen(test_name) > 0 );

+

+   prefix_list_size = fctkern__filter_cnt(nk);

+   

+   /* If there is no filter list, then we return FCT_TRUE always. */

+   if ( prefix_list_size == 0 ) {

+      return FCT_TRUE;

+   }   

+

+   /* Iterate through the prefix filter list, and see if we have

+   anything that does not pass. All we require is ONE item that

+   passes the test in order for us to succeed here. */

+   for ( prefix_i = 0; prefix_i != prefix_list_size; ++prefix_i ) {

+      char const *prefix = (char const*)nlist__at(nk->prefix_list, prefix_i);

+      nbool_t pass = fct_filter_pass(prefix, test_name);

+      if ( pass ) {

+         return FCT_TRUE;

+      }

+   }

+

+   /* Otherwise, we never managed to find a prefix that satisfied the 

+   supplied test name. Therefore we have failed to pass to the filter 

+   list test. */

+   return FCT_FALSE;

+}

+

+

+/* Returns the number of tests that were performed. */

+static int

+fctkern__tst_cnt(fctkern_t const *nk)

+{

+   int tally =0;

+   assert( nk != NULL );

+

+   NLIST_FOREACH_BGN(fct_ts_t *, ts, nk->ts_list)

+   {

+      tally += fct_ts__tst_cnt(ts);

+   }

+   NLIST_FOREACH_END();

+   return tally;

+}

+

+/* Returns the number of tests that passed. */

+static int

+fctkern__tst_cnt_passed(fctkern_t const *nk)

+{

+   int tally =0;

+   assert( nk != NULL );

+

+   NLIST_FOREACH_BGN(fct_ts_t*, ts, nk->ts_list)

+   {

+      tally += fct_ts__tst_cnt_passed(ts);

+   }

+   NLIST_FOREACH_END();

+

+   return tally;

+}

+

+

+/* Returns the number of tests that failed. */

+static int

+fctkern__tst_cnt_failed(fctkern_t const *nk)

+{

+   /* Keep it simple for now and just do a little math. */

+   int total =0;

+   int passed =0;

+   int failed =0;

+

+   assert( nk != NULL );

+

+   total = fctkern__tst_cnt(nk);

+   passed = fctkern__tst_cnt_passed(nk);

+

+   failed = total - passed;

+

+   return failed;

+}

+

+

+/* Returns the number of checks made throughout the entire test. */

+static int

+fctkern__chk_cnt(fctkern_t const *nk)

+{

+   int tally =0;

+   assert( nk != NULL );

+

+   NLIST_FOREACH_BGN(fct_ts_t *, ts, nk->ts_list)

+   {

+      tally += fct_ts__chk_cnt(ts);

+   }

+   NLIST_FOREACH_END();

+   return tally;

+}

+

+

+/* Indicates the very end of all the tests. */

+static void

+fctkern__end(fctkern_t *fct)

+{

+   fct_unused(fct);

+}

+

+

+/* Cleans up the contents of a fctkern. NULL does nothing. */

+static void

+fctkern__final(fctkern_t *fct) 

+{

+   if ( fct == NULL ) { return; }

+

+   nlist__del(fct->logger_list, (on_del_t)fct_logger__del);

+

+   /* The prefix list is a list of malloc'd strings. */

+   nlist__del(fct->prefix_list, (on_del_t)free);

+

+   nlist__del(fct->ts_list, (on_del_t)fct_ts__del);

+}

+

+

+static void

+fctkern__log_suite_start(fctkern_t *kern, fct_ts_t const *ts)

+{

+   assert( kern != NULL );

+   assert( ts != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_test_suite_start(logger, ts);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+static void

+fctkern__log_suite_end(fctkern_t *kern, fct_ts_t const *ts)

+{

+   assert( kern != NULL );

+   assert( ts != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_test_suite_end(logger, ts);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+static void

+fctkern__log_chk(fctkern_t *kern, fctchk_t const *chk)

+{

+   assert( kern != NULL );

+   assert( chk != NULL );

+  

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_cndtn(logger, chk);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+/* Called whenever a test is started. */

+static void

+fctkern__log_test_start(fctkern_t *kern, fct_test_t const *test)

+{

+   assert( kern != NULL );

+   assert( test != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_test_start(logger, test);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+static void

+fctkern__log_test_end(fctkern_t *kern, fct_test_t const *test)

+{

+   assert( kern != NULL );

+   assert( test != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_test_end(logger, test);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+static void

+fctkern__log_start(fctkern_t *kern)

+{

+   assert( kern != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_fct_start(logger, kern);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+static void

+fctkern__log_end(fctkern_t *kern)

+{

+   assert( kern != NULL );

+   NLIST_FOREACH_BGN(fct_logger_i*, logger, kern->logger_list)

+   {

+      fct_logger__on_fct_end(logger, kern);

+   }

+   NLIST_FOREACH_END();

+}

+

+

+/*

+-----------------------------------------------------------

+LOGGER INTERFACE

+

+Defines an interface to a logging system. A logger 

+must define the following functions in order to hook 

+into the logging system.

+

+See the "Standard Logger" and "Minimal Logger" as examples

+of the implementation.

+-----------------------------------------------------------

+*/

+

+typedef void (*fct_logger_on_cndtn_fn)(fct_logger_i *self, 

+                                       fctchk_t const *chk);

+#define _fct_logger_head \

+   fct_logger_on_cndtn_fn on_cndtn;\

+   void (*on_test_start)(fct_logger_i *logger, fct_test_t const *test);\

+   void (*on_test_end)(fct_logger_i *logger, fct_test_t const *test);\

+   void (*on_test_suite_start)(fct_logger_i *logger, fct_ts_t const *ts);\

+   void (*on_test_suite_end)(fct_logger_i *logger, fct_ts_t const *ts);\

+   void (*on_fct_start)(fct_logger_i *logger, fctkern_t const *kern);\

+   void (*on_fct_end)(fct_logger_i *logger, fctkern_t const *kern);\

+   void (*on_delete)(fct_logger_i *logger)\

+

+struct _fct_logger_i {

+   _fct_logger_head;

+};

+

+

+/* Initializes the elements of a logger interface so they are at their 

+standard values. */

+static void

+fct_logger__init(fct_logger_i *logger)

+{

+   assert( logger != NULL );

+   logger->on_cndtn =NULL;

+   logger->on_test_start =NULL;

+   logger->on_test_end =NULL;

+   logger->on_test_suite_start =NULL;

+   logger->on_test_suite_end =NULL;

+   logger->on_fct_start =NULL;

+   logger->on_fct_end =NULL;

+   logger->on_delete =NULL;

+}

+

+

+static void

+fct_logger__del(fct_logger_i *logger)

+{

+   if ( logger == NULL ) { return; }

+   if ( logger->on_delete) { logger->on_delete(logger); }

+}

+

+

+static void

+fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test)

+{

+   assert( logger != NULL && "invalid arg");

+   assert( test != NULL && "invalid arg");

+

+   if ( logger->on_test_start != NULL )

+   {

+      logger->on_test_start(logger, test);

+   }

+}

+

+

+static void

+fct_logger__on_test_end(fct_logger_i *logger, fct_test_t const *test)

+{

+   assert( logger != NULL && "invalid arg");

+   assert( test != NULL && "invalid arg");

+

+   if ( logger->on_test_end != NULL )

+   {

+      logger->on_test_end(logger, test);

+   }

+}

+

+

+static void

+fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts)

+{

+   assert( logger != NULL && "invalid arg");

+   assert( ts != NULL && "invalid arg");

+

+   if ( logger->on_test_suite_start != NULL )

+   {

+      logger->on_test_suite_start(logger, ts);

+   }

+}

+

+

+static void

+fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts)

+{

+   assert( logger != NULL && "invalid arg");

+   assert( ts != NULL && "invalid arg");

+

+   if ( logger->on_test_suite_end != NULL )

+   {

+      logger->on_test_suite_end(logger, ts);

+   }

+}

+

+

+static void

+fct_logger__on_cndtn(fct_logger_i *logger, fctchk_t const *chk)

+{

+   assert( logger != NULL && "invalid arg");

+   assert( chk != NULL && "invalid arg");

+

+   if ( logger->on_cndtn ) 

+   {

+      logger->on_cndtn(logger, chk);

+   }

+}                        

+

+

+/* When we start all our tests. */

+static void

+fct_logger__on_fct_start(fct_logger_i *logger, fctkern_t const *kern)

+{

+   assert( logger != NULL );

+   assert( kern != NULL );

+

+   if ( logger->on_fct_start != NULL ) 

+   {

+      logger->on_fct_start(logger, kern);

+   }

+}

+

+

+/* When we have reached the end of ALL of our testing. */

+static void

+fct_logger__on_fct_end(fct_logger_i *logger, fctkern_t const *kern)

+{

+   assert( logger != NULL );

+   assert( kern != NULL );

+

+   if ( logger->on_fct_end )

+   {

+      logger->on_fct_end(logger, kern);

+   }

+}

+

+

+

+/*

+-----------------------------------------------------------

+MINIMAL LOGGER

+-----------------------------------------------------------

+*/

+

+/* Minimal logger, reports the minimum amount of information needed

+to determine "something is happening". */

+struct _fct_minimal_logger_t {

+   _fct_logger_head;

+};

+

+

+static void 

+fct_minimal_logger__on_cndtn(fct_logger_i *self, fctchk_t const *chk)

+{

+   fct_unused(self);   

+   printf(fctchk__is_pass(chk) ? "." : "!");

+}

+

+

+static void

+fct_minimal_logger__del(fct_logger_i *self)

+{

+   free(self);

+}

+

+

+static fct_minimal_logger_t *

+fct_minimal_logger__new(void)

+{

+   fct_minimal_logger_t *self = (fct_minimal_logger_t*)\

+				calloc(1,sizeof(fct_minimal_logger_t));

+   if ( self == NULL ) { return NULL; }

+

+   fct_logger__init((fct_logger_i*)self);

+

+   self->on_cndtn = fct_minimal_logger__on_cndtn;

+   self->on_delete = fct_minimal_logger__del;

+   return self;

+}

+

+

+/*

+-----------------------------------------------------------

+STANDARD LOGGER

+-----------------------------------------------------------

+*/

+

+struct _fct_standard_logger_t {

+   _fct_logger_head;

+

+   /* Start time. For now we use the low-accuracy time_t version. */

+   fct_timer_t timer;

+

+   /* A list of char*'s that needs to be cleaned up. */

+   nlist_t *failed_cndtns_list;

+};

+

+

+/* When a failure occurrs, we will record the details so we can display

+them when the log "finishes" up. */

+static void

+fct_standard_logger__on_cndtn(fct_logger_i *logger_, fctchk_t const *chk)

+{

+   fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;

+   

+   assert( logger != NULL );

+   assert( chk != NULL );

+

+   /* Only record failures. */

+   if ( !fctchk__is_pass(chk) )

+   {

+      /* For now we will truncate the string to some set amount, later

+      we can work out a dynamic string object. */

+      char *str = (char*)malloc(sizeof(char)*FCT_MAX_LOG_LINE);

+      assert( str != NULL );

+      

+      fct_snprintf(

+         str, 

+         FCT_MAX_LOG_LINE, 

+         "%s(%d): %s", 

+         fctchk__file(chk),

+         fctchk__lineno(chk),

+         fctchk__cndtn(chk)

+         );

+

+      /* Append it to the listing ... */

+      nlist__append(logger->failed_cndtns_list, (void*)str);

+   }  

+}

+

+

+static void

+fct_standard_logger__on_test_start(fct_logger_i *logger_, 

+                                   fct_test_t const *test)

+{

+   fct_unused(logger_);

+   printf("%s ... ", fct_test__name(test));

+}

+

+

+static void

+fct_standard_logger__on_test_end(fct_logger_i *logger_, 

+                                   fct_test_t const *test)

+{

+   nbool_t is_pass;

+   fct_unused(logger_);

+

+   is_pass = fct_test__is_pass(test);

+   printf("%s\n", (is_pass) ? "PASS" : "FAIL" );

+}

+

+

+static void

+fct_standard_logger__on_test_suite_start(fct_logger_i *logger_, 

+                                         fct_ts_t const *ts)

+{

+   fct_unused(logger_);

+   fct_unused(ts);

+}

+

+

+static void

+fct_standard_logger__on_test_suite_end(fct_logger_i *logger_, 

+                                         fct_ts_t const *ts)

+{

+   fct_unused(logger_);

+   fct_unused(ts);

+}

+

+

+static void

+fct_standard_logger__on_fct_start(fct_logger_i *logger_, 

+                                  fctkern_t const *nk)

+{

+   fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;

+   fct_unused(nk);

+   fct_timer__start(&(logger->timer));

+}

+

+

+static void

+fct_standard_logger__on_fct_end(fct_logger_i *logger_, fctkern_t const *nk)

+{

+   fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;

+   nbool_t is_success =1;

+   double elasped_time =0;

+   int num_tests =0;

+   int num_passed =0;

+

+   fct_timer__stop(&(logger->timer));

+     

+   is_success = nlist__size(logger->failed_cndtns_list) ==0;

+

+   if (  !is_success )

+   {

+      printf("\n--------------------------------------------------------\n");

+      printf("FAILED TESTS\n\n");

+

+      NLIST_FOREACH_BGN(char *, cndtn_str, logger->failed_cndtns_list)

+      {

+         printf("%s\n", cndtn_str);

+      }

+      NLIST_FOREACH_END();

+

+      printf("\n");

+   }

+

+   printf("\n--------------------------------------------------------\n");

+

+   num_tests = fctkern__tst_cnt(nk);

+   num_passed = fctkern__tst_cnt_passed(nk);

+

+   printf(

+      "%s (%d/%d tests", 

+      (is_success) ? "PASSED" : "FAILED",

+      num_passed,

+      num_tests

+   );

+

+   elasped_time = fct_timer__duration(&(logger->timer));

+   if ( elasped_time > 0.0000001 )

+   {

+      printf(" in %.6fs)\n", elasped_time);

+   }

+   else

+   {

+      /* Don't bother displaying the time to execute. */

+      printf(")\n");

+   }

+}

+

+

+static void

+fct_standard_logger__del(fct_logger_i *logger_)

+{

+   fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;

+

+   NLIST_FOREACH_BGN(char *, cndtn_str, logger->failed_cndtns_list)

+   {

+      free(cndtn_str);

+   }

+   NLIST_FOREACH_END();

+

+   free(logger);

+   logger_ =NULL;

+}

+

+

+fct_standard_logger_t *

+fct_standard_logger__new(void)

+{

+   fct_standard_logger_t *logger = (fct_standard_logger_t *)calloc(

+		   1, sizeof(fct_standard_logger_t)

+		   );

+   if ( logger == NULL ) 

+   { 

+      return NULL; 

+   }

+   fct_logger__init((fct_logger_i*)logger);

+   logger->on_cndtn = fct_standard_logger__on_cndtn;

+   logger->on_test_start = fct_standard_logger__on_test_start;

+   logger->on_test_end = fct_standard_logger__on_test_end;

+   logger->on_test_suite_start = fct_standard_logger__on_test_suite_start;

+   logger->on_test_suite_end = fct_standard_logger__on_test_suite_end;

+   logger->on_fct_start = fct_standard_logger__on_fct_start;

+   logger->on_fct_end = fct_standard_logger__on_fct_end;

+   logger->on_delete = fct_standard_logger__del;

+

+   logger->failed_cndtns_list = nlist_new();

+   assert( logger->failed_cndtns_list != NULL );

+   

+   fct_timer__init(&(logger->timer));

+

+   return logger;

+}

+

+

+

+/*

+------------------------------------------------------------

+MAGIC MACROS

+------------------------------------------------------------

+*/

+

+#define FCT_BGN() \

+int \

+main(int argc, char *argv[])\

+{\

+   fctkern_t fctkern__;\

+   fctkern_init(&fctkern__, argc, argv);\

+   fctkern__log_start(&fctkern__);

+

+

+#define FCT_END()\

+   {\

+      int num_failed__ =0;\

+      num_failed__ = fctkern__tst_cnt_failed((&fctkern__));\

+      fctkern__log_end(&fctkern__);\

+      fctkern__end(&fctkern__);\

+      fctkern__final(&fctkern__);\

+      return num_failed__;\

+   }\

+}

+

+#define FCT_FIXTURE_SUITE_BGN(_NAME_) \

+   {\

+      fct_ts_t *ts__ = fct_ts_new( #_NAME_ );\

+      fctkern__log_suite_start((&fctkern__), ts__);\

+      for (;;)\

+      {\

+         int fct_test_num__ = -1;\

+         _fct_cmt("Strict compiler warnings will complain in 'blank' suites.")\

+         _fct_cmt("so we are going to do a 'noop' to trick them.")\

+         fct_test_num__ = fct_test_num__;\

+         if ( fct_ts__is_ending_mode(ts__) )\

+         {\

+            _fct_cmt("flag the test suite as complete.");\

+            fct_ts__end(ts__);\

+            break;\

+         }

+

+

+/*  Closes off a "Fixture" test suite. */

+#define FCT_FIXTURE_SUITE_END() \

+         if ( fct_ts__is_cnt_mode(ts__) )\

+         {\

+            fct_ts__cnt_end(ts__);\

+         }\

+      }\

+      fctkern__add_ts((&fctkern__), ts__);\

+      fctkern__log_suite_end((&fctkern__), ts__);\

+      ts__ = NULL;\

+   }

+

+

+

+#define FCT_SETUP_BGN()\

+   if ( fct_ts__is_setup_mode(ts__) ) {

+

+#define FCT_SETUP_END() \

+   fct_ts__setup_end(ts__); }

+

+#define FCT_TEARDOWN_BGN() \

+   if ( fct_ts__is_teardown_mode(ts__) ) {\

+

+#define FCT_TEARDOWN_END() \

+   fct_ts__teardown_end(ts__); \

+   continue; \

+   }

+

+/* Lets you create a test suite, where maybe you don't want a fixture. We

+do it by 'stubbing' out the setup/teardown logic. */

+#define FCT_SUITE_BGN(Name) \

+   FCT_FIXTURE_SUITE_BGN(Name) {\

+   FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\

+   FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\

+

+#define FCT_SUITE_END() } FCT_FIXTURE_SUITE_END()

+

+/* Depending on whether or not we are counting the tests, we will have to 

+first determine if the test is the "current" count. Then we have to determine

+if we can pass the filter. Finally we will execute everything so that when a 

+check fails, we can "break" out to the end of the test. */

+#define FCT_TEST_BGN(_NAME_) \

+         {\

+            char const *test_name__ = #_NAME_;\

+            ++fct_test_num__;\

+            if ( fct_ts__is_cnt_mode(ts__) )\

+            {\

+               fct_ts__inc_total_test_num(ts__);\

+            }\

+            else if ( fct_ts__is_test_mode(ts__) \

+                      && fct_ts__is_test_cnt(ts__, fct_test_num__) )\

+            {\

+               int is_pass__;\

+               is_pass__ = FCT_FALSE;\

+               fct_ts__test_begin(ts__);\

+               if ( fctkern__pass_filter(&fctkern__,  test_name__ ) )\

+               {\

+                  fct_test_t *test__ = fct_test_new( test_name__ );\

+                  fctkern__log_test_start(&fctkern__, test__);\

+                  for (;;) \

+                  {

+

+#define FCT_TEST_END() \

+                     break;\

+                  }\

+               fct_ts__add_test(ts__, test__);\

+               fctkern__log_test_end(&fctkern__, test__);\

+               }\

+               fct_ts__test_end(ts__);\

+               continue;\

+            }\

+         }

+

+

+

+/*

+---------------------------------------------------------

+CHECKING MACROS

+---------------------------------------------------------- 

+

+For now we only have the one "positive" check macro. In the future I plan

+to add more macros that check for different types of common conditions.

+*/

+

+#define fct_chk(_CNDTN_) \

+   {\

+      fctchk_t *chk =NULL;\

+      is_pass__ = (_CNDTN_);\

+      chk = fctchk_new(#_CNDTN_, __FILE__, __LINE__, is_pass__);\

+      fct_test__add(test__, chk);\

+      fctkern__log_chk(&fctkern__, chk);\

+      if ( !is_pass__ ) { break; }\

+   }

+

+

+/*

+---------------------------------------------------------

+GUT CHECK MACROS

+---------------------------------------------------------- 

+

+The following macros are used to help check the "guts" of

+the FCT, and to confirm that it all works according to spec.

+*/

+

+/* Generates a message to STDERR and exits the application with a 

+non-zero number. */

+#define _FCT_GUTCHK(_CNDTN_) \

+   if ( !(_CNDTN_) ) {\

+      fprintf(stderr, "gutchk fail: '"  #_CNDTN_ "' was not true.\n");\

+      exit(1);\

+   }\

+   else {\

+      fprintf(stdout, "gutchk pass:  '" #_CNDTN_ "'\n");\

+   }

+      

+

+/*

+---------------------------------------------------------

+CLOSING STATEMENTS

+---------------------------------------------------------- 

+*/

+

+/* This is defined at the start of the file. We are undefining it

+here so it doesn't conflict with existing. */

+#if defined(WIN32)

+#   undef _CRT_SECURE_NO_WARNINGS

+#endif

+

+#endif /* !FCT_INCLUDED__IMB */