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