blob: c49abdaead390e3d6f18c51f983da6159e0e7c94 [file] [log] [blame]
Paul Bakkerc8cad6a2011-05-25 11:35:09 +00001/*
2====================================================================
3Copyright (c) 2008 Ian Blumel. All rights reserved.
4
5FCTX (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/* Configuration Values. You can over-ride these values in your own
48header, then include this header. For example, in your file, myfct.h,
49
50 #define FCT_DEFAULT_LOGGER "standard"
51 #include "fct.h"
52
53then if your unit tests included, myfct.h, you would default to work
54with a standard logger. */
55
56#if !defined(FCT_DEFAULT_LOGGER)
57# define FCT_DEFAULT_LOGGER "standard"
58#endif /* !FCT_DEFAULT_LOGGER */
59
60#define FCT_VERSION_MAJOR 1
61#define FCT_VERSION_MINOR 6
62#define FCT_VERSION_MICRO 1
63
64#define _FCT_QUOTEME(x) #x
65#define FCT_QUOTEME(x) _FCT_QUOTEME(x)
66
67#define FCT_VERSION_STR (FCT_QUOTEME(FCT_VERSION_MAJOR) "."\
68 FCT_QUOTEME(FCT_VERSION_MINOR) "."\
69 FCT_QUOTEME(FCT_VERSION_MICRO))
70
71#include <string.h>
72#include <assert.h>
73#include <stdarg.h>
74#include <stdlib.h>
75#include <stdio.h>
76#include <time.h>
77#include <float.h>
78#include <math.h>
79#include <ctype.h>
80
81#define FCT_MAX_NAME 256
82#define FCT_MAX_LOG_LINE 256
83
84#define nbool_t int
85#define FCT_TRUE 1
86#define FCT_FALSE 0
87
88#define FCTMIN(x, y) ( x < y) ? (x) : (y)
89
90#ifndef __INTEL_COMPILER
91/* Use regular assertions for non-Intel compilers */
92#define FCT_ASSERT(expr) assert(expr)
93#else
94/* Silence Intel warnings on assert(expr && "str") or assert("str") */
95#define FCT_ASSERT(expr) do { \
96 _Pragma("warning(push,disable:279)"); \
97 assert(expr); \
98 _Pragma("warning(pop)"); \
99 } while (0)
100#endif
101
102#if defined(__cplusplus)
103#define FCT_EXTERN_C extern "C"
104#else
105#define FCT_EXTERN_C
106#endif
107
108/* Forward declarations. The following forward declarations are required
109because there is a inter-relationship between certain objects that
110just can not be untwined. */
111typedef struct _fct_logger_evt_t fct_logger_evt_t;
112typedef struct _fct_logger_i fct_logger_i;
113typedef struct _fct_logger_types_t fct_logger_types_t;
114typedef struct _fct_standard_logger_t fct_standard_logger_t;
115typedef struct _fct_junit_logger_t fct_junit_logger_t;
116typedef struct _fct_minimal_logger_t fct_minimal_logger_t;
117typedef struct _fctchk_t fctchk_t;
118typedef struct _fct_test_t fct_test_t;
119typedef struct _fct_ts_t fct_ts_t;
120typedef struct _fctkern_t fctkern_t;
121
122/* Forward declare some functions used throughout. */
123static fct_logger_i*
124fct_standard_logger_new(void);
125
126static fct_logger_i*
127fct_minimal_logger_new(void);
128
129static fct_junit_logger_t *
130fct_junit_logger_new(void);
131
132static void
133fct_logger__del(fct_logger_i *logger);
134
135static void
136fct_logger__on_chk(fct_logger_i *self, fctchk_t const *chk);
137
138static void
139fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test);
140
141static void
142fct_logger__on_test_end(fct_logger_i *logger, fct_test_t *test);
143
144static void
145fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts);
146
147static void
148fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts);
149
150static void
151fct_logger__on_test_suite_skip(
152 fct_logger_i *logger,
153 char const *condition,
154 char const *name
155);
156
157static void
158fct_logger__on_test_skip(
159 fct_logger_i *logger,
160 char const *condition,
161 char const *name
162);
163
164
165static void
166fct_logger__on_warn(fct_logger_i *logger, char const *warn);
167
168
169
170/* Explicitly indicate a no-op */
171#define fct_pass()
172
173#define fct_unused(x) (void)(x)
174
175/* This is just a little trick to let me put comments inside of macros. I
176really only want to bother with this when we are "unwinding" the macros
177for debugging purposes. */
178#if defined(FCT_CONF_UNWIND)
179# define _fct_cmt(string) {char*_=string;}
180#else
181# define _fct_cmt(string)
182#endif
183
184/*
185--------------------------------------------------------
186UTILITIES
187--------------------------------------------------------
188*/
189
190
191/* STDIO and STDERR redirect support */
192#define FCT_PIPE_RESERVE_BYTES_DEFAULT 512
193static int fct_stdout_pipe[2];
194static int fct_stderr_pipe[2];
195static int fct_saved_stdout;
196static int fct_saved_stderr;
197
198/* Platform indepedent pipe functions. TODO: Look to figure this out in a way
199that follows the ISO C++ conformant naming convention. */
200#if defined(WIN32)
201# include <io.h>
202# include <fcntl.h>
203# define _fct_pipe(_PFDS_) \
204 _pipe((_PFDS_), FCT_PIPE_RESERVE_BYTES_DEFAULT, _O_TEXT)
205# define _fct_dup _dup
206# define _fct_dup2 _dup2
207# define _fct_close _close
208# define _fct_read _read
209/* Until I can figure a better way to do this, rely on magic numbers. */
210# define STDOUT_FILENO 1
211# define STDERR_FILENO 2
212#else
213# include <unistd.h>
214# define _fct_pipe pipe
215# define _fct_dup dup
216# define _fct_dup2 dup2
217# define _fct_close close
218# define _fct_read read
219#endif /* WIN32 */
220
221
222
223
224static void
225fct_switch_std_to_buffer(int std_pipe[2], FILE *out, int fileno_, int *save_handle)
226{
227 fflush(out);
228 *save_handle = _fct_dup(fileno_);
229 if ( _fct_pipe(std_pipe) != 0 )
230 {
231 exit(1);
232 }
233 _fct_dup2(std_pipe[1], fileno_);
234 _fct_close(std_pipe[1]);
235}
236
237
238static void
239fct_switch_std_to_std(FILE *out, int fileno_, int save_handle)
240{
241 fflush(out);
242 _fct_dup2(save_handle, fileno_);
243}
244
245
246#define FCT_SWITCH_STDOUT_TO_BUFFER() \
247 fct_switch_std_to_buffer(fct_stdout_pipe, stdout, STDOUT_FILENO, &fct_saved_stdout)
248#define FCT_SWITCH_STDOUT_TO_STDOUT() \
249 fct_switch_std_to_std(stdout, STDOUT_FILENO, fct_saved_stdout)
250#define FCT_SWITCH_STDERR_TO_BUFFER() \
251 fct_switch_std_to_buffer(fct_stderr_pipe, stderr, STDERR_FILENO, &fct_saved_stderr)
252#define FCT_SWITCH_STDERR_TO_STDERR() \
253 fct_switch_std_to_std(stderr, STDERR_FILENO, fct_saved_stderr)
254
255
256/* Utility for truncated, safe string copies. The NUM
257should be the length of DST plus the null-termintor. */
258static void
259fctstr_safe_cpy(char *dst, char const *src, size_t num)
260{
261 FCT_ASSERT( dst != NULL );
262 FCT_ASSERT( src != NULL );
263 FCT_ASSERT( num > 0 );
264#if defined(WIN32) && _MSC_VER >= 1400
265 strncpy_s(dst, num, src, _TRUNCATE);
266#else
267 strncpy(dst, src, num);
268#endif
269 dst[num-1] = '\0';
270}
271
272/* Isolate the vsnprintf implementation */
273static int
274fct_vsnprintf(char *buffer,
275 size_t buffer_len,
276 char const *format,
277 va_list args)
278{
279 int count =0;
280 /* Older microsoft compilers where not ANSI compliant with this
281 function and you had to use _vsnprintf. I will assume that newer
282 Microsoft Compilers start implementing vsnprintf. */
283#if defined(_MSC_VER) && (_MSC_VER < 1400)
284 count = _vsnprintf(buffer, buffer_len, format, args);
285#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
286 count = vsnprintf_s(buffer, buffer_len, _TRUNCATE, format, args);
287#else
288 count = vsnprintf(buffer, buffer_len, format, args);
289#endif
290 return count;
291}
292
293
294/* Isolate the snprintf implemenation. */
295static int
296fct_snprintf(char *buffer, size_t buffer_len, char const *format, ...)
297{
298 int count =0;
299 va_list args;
300 va_start(args, format);
301 count =fct_vsnprintf(buffer, buffer_len, format, args);
302 va_end(args);
303 return count;
304}
305
306
307/* Helper to for cloning strings on the heap. Returns NULL for
308an out of memory condition. */
309static char*
310fctstr_clone(char const *s)
311{
312 char *k =NULL;
313 size_t klen =0;
314 FCT_ASSERT( s != NULL && "invalid arg");
315 klen = strlen(s)+1;
316 k = (char*)malloc(sizeof(char)*klen+1);
317 fctstr_safe_cpy(k, s, klen);
318 return k;
319}
320
321
322/* Clones and returns a lower case version of the original string. */
323static char*
324fctstr_clone_lower(char const *s)
325{
326 char *k =NULL;
327 size_t klen =0;
328 size_t i;
329 if ( s == NULL )
330 {
331 return NULL;
332 }
333 klen = strlen(s)+1;
334 k = (char*)malloc(sizeof(char)*klen+1);
335 for ( i=0; i != klen; ++i )
336 {
337 k[i] = (char)tolower(s[i]);
338 }
339 return k;
340}
341
342
343/* A very, very simple "filter". This just compares the supplied prefix
344against the test_str, to see if they both have the same starting
345characters. If they do we return true, otherwise we return false. If the
346prefix is a blank string or NULL, then it will return FCT_TRUE.*/
347static nbool_t
348fct_filter_pass(char const *prefix, char const *test_str)
349{
350 nbool_t is_match = FCT_FALSE;
351 char const *prefix_p;
352 char const *test_str_p;
353
354 /* If you got nothing to test against, why test? */
355 FCT_ASSERT( test_str != NULL );
356
357 /* When the prefix is NULL or blank, we always return FCT_TRUE. */
358 if ( prefix == NULL || prefix[0] == '\0' )
359 {
360 return FCT_TRUE;
361 }
362
363 /* Iterate through both character arrays at the same time. We are
364 going to play a game and see if we can beat the house. */
365 for ( prefix_p = prefix, test_str_p = test_str;
366 *prefix_p != '\0' && *test_str_p != '\0';
367 ++prefix_p, ++test_str_p )
368 {
369 is_match = *prefix_p == *test_str_p;
370 if ( !is_match )
371 {
372 break; /* Quit the first time we don't match. */
373 }
374 }
375
376 /* If the iterator for the test_str is pointing at the null char, and
377 the iterator for the prefix string is not, then the prefix string is
378 larger than the actual test string, and therefore we failed to pass the
379 filter. */
380 if ( *test_str_p == '\0' && *prefix_p != '\0' )
381 {
382 return FCT_FALSE;
383 }
384
385 /* is_match will be set to the either FCT_TRUE if we kicked of the loop
386 early because our filter ran out of characters or FCT_FALSE if we
387 encountered a mismatch before our filter ran out of characters. */
388 return is_match;
389}
390
391
392/* Routine checks if two strings are equal. Taken from
393http://publications.gbdirect.co.uk/c_book/chapter5/character_handling.html
394*/
395static int
396fctstr_eq(char const *s1, char const *s2)
397{
398 if ( s1 == s2 )
399 {
400 return 1;
401 }
402 if ( (s1 == NULL && s2 != NULL)
403 || (s1 != NULL && s2 == NULL) )
404 {
405 return 0;
406 }
407 while (*s1 == *s2)
408 {
409 if (*s1 == '\0')
410 return 1;
411 s1++;
412 s2++;
413 }
414 /* Difference detected! */
415 return 0;
416}
417
418
419static int
420fctstr_ieq(char const *s1, char const *s2)
421{
422 if ( s1 == s2 )
423 {
424 return 1;
425 }
426 if ( (s1 == NULL && s2 != NULL)
427 || (s1 != NULL && s2 == NULL) )
428 {
429 return 0;
430 }
431 while (tolower(*s1) == tolower(*s2))
432 {
433 if (*s1 == '\0')
434 return 1;
435 s1++;
436 s2++;
437 }
438 /* Difference detected! */
439 return 0;
440}
441
442
443/* Returns 1 if the STR contains the CHECK_INCL substring. NULL's
444are handled, and NULL always INCLUDES NULL. This check is case
445sensitive. If two strings point to the same place they are
446included. */
447static int
448fctstr_incl(char const *str, char const *check_incl)
449{
450 static char const *blank_s = "";
451 char const *found = NULL;
452 if ( str == NULL )
453 {
454 str = blank_s;
455 }
456 if ( check_incl == NULL )
457 {
458 check_incl = blank_s;
459 }
460 if ( str == check_incl )
461 {
462 return 1;
463 }
464 found = strstr(str, check_incl);
465 return found != NULL;
466}
467
468
469/* Does a case insensitive include check. */
470static int
471fctstr_iincl(char const *str, char const *check_incl)
472{
473 /* Going to do this with a memory allocation to save coding
474 time. In the future this can be rewritten. Both clone_lower
475 and _incl are NULL tolerant. */
476 char *lstr = fctstr_clone_lower(str);
477 char *lcheck_incl = fctstr_clone_lower(check_incl);
478 int found = fctstr_incl(lstr, lcheck_incl);
479 free(lstr);
480 free(lcheck_incl);
481 return found;
482}
483
484
485/* Returns true if STR starts with CHECK. NULL and NULL is consider
486true. */
487static int
488fctstr_startswith(char const *str, char const *check)
489{
490 char const *sp;
491 if ( str == NULL && check == NULL )
492 {
493 return 1;
494 }
495 else if ( ((str == NULL) && (check != NULL))
496 || ((str != NULL) && (check == NULL)) )
497 {
498 return 0;
499 }
500 sp = strstr(str, check);
501 return sp == str;
502}
503
504
505/* Case insenstive variant of fctstr_startswith. */
506static int
507fctstr_istartswith(char const *str, char const *check)
508{
509 /* Taking the lazy approach for now. */
510 char *istr = fctstr_clone_lower(str);
511 char *icheck = fctstr_clone_lower(check);
512 /* TODO: check for memory. */
513 int startswith = fctstr_startswith(istr, icheck);
514 free(istr);
515 free(icheck);
516 return startswith;
517}
518
519
520/* Returns true if the given string ends with the given
521check. Treats NULL as a blank string, and as such, will
522pass the ends with (a blank string endswith a blank string). */
523static int
524fctstr_endswith(char const *str, char const *check)
525{
526 size_t check_i;
527 size_t str_i;
528 if ( str == NULL && check == NULL )
529 {
530 return 1;
531 }
532 else if ( ((str == NULL) && (check != NULL))
533 || ((str != NULL) && (check == NULL)) )
534 {
535 return 0;
536 }
537 check_i = strlen(check);
538 str_i = strlen(str);
539 if ( str_i < check_i )
540 {
541 return 0; /* Can't do it string is too small. */
542 }
543 for ( ; check_i != 0; --check_i, --str_i)
544 {
545 if ( str[str_i] != check[check_i] )
546 {
547 return 0; /* Found a case where they are not equal. */
548 }
549 }
550 /* Exahausted check against string, can only be true. */
551 return 1;
552}
553
554
555static int
556fctstr_iendswith(char const *str, char const *check)
557{
558 size_t check_i;
559 size_t str_i;
560 if ( str == NULL && check == NULL )
561 {
562 return 1;
563 }
564 else if ( ((str == NULL) && (check != NULL))
565 || ((str != NULL) && (check == NULL)) )
566 {
567 return 0;
568 }
569 check_i = strlen(check);
570 str_i = strlen(str);
571 if ( str_i < check_i )
572 {
573 return 0; /* Can't do it string is too small. */
574 }
575 for ( ; check_i != 0; --check_i, --str_i)
576 {
577 if ( tolower(str[str_i]) != tolower(check[check_i]) )
578 {
579 return 0; /* Found a case where they are not equal. */
580 }
581 }
582 /* Exahausted check against string, can only be true. */
583 return 1;
584}
585
586
587/* Use this with the _end variant to get the
588
589STARTSWITH ........................................ END
590
591effect. Assumes that the line will be maxwidth in characters. The
592maxwidth can't be greater than FCT_DOTTED_MAX_LEN. */
593#define FCT_DOTTED_MAX_LEN 256
594static void
595fct_dotted_line_start(size_t maxwidth, char const *startwith)
596{
597 char line[FCT_DOTTED_MAX_LEN];
598 size_t len =0;
599 size_t line_len =0;
600
601 memset(line, '.', sizeof(char)*maxwidth);
602 len = strlen(startwith);
603 line_len = FCTMIN(maxwidth-1, len);
604 memcpy(line, startwith, sizeof(char)*line_len);
605 if ( len < maxwidth-1)
606 {
607 line[len] = ' ';
608 }
609 line[maxwidth-1] = '\0';
610 fputs(line, stdout);
611}
612
613
614static void
615fct_dotted_line_end(char const *endswith)
616{
617 printf(" %s\n", endswith);
618}
619
620
621/*
622--------------------------------------------------------
623TIMER
624--------------------------------------------------------
625This is a low-res implementation at the moment.
626
627We will improve this in the future, and isolate the
628implementation from the rest of the code.
629*/
630
631typedef struct _fct_timer_t fct_timer_t;
632struct _fct_timer_t
633{
634 clock_t start;
635 clock_t stop;
636 double duration;
637};
638
639
640static void
641fct_timer__init(fct_timer_t *timer)
642{
643 FCT_ASSERT(timer != NULL);
644 memset(timer, 0, sizeof(fct_timer_t));
645}
646
647
648static void
649fct_timer__start(fct_timer_t *timer)
650{
651 FCT_ASSERT(timer != NULL);
652 timer->start = clock();
653}
654
655
656static void
657fct_timer__stop(fct_timer_t *timer)
658{
659 FCT_ASSERT(timer != NULL);
660 timer->stop = clock();
661 timer->duration = (double) (timer->stop - timer->start) / CLOCKS_PER_SEC;
662}
663
664
665/* Returns the time in seconds. */
666static double
667fct_timer__duration(fct_timer_t const *timer)
668{
669 FCT_ASSERT( timer != NULL );
670 return timer->duration;
671}
672
673
674/*
675--------------------------------------------------------
676GENERIC LIST
677--------------------------------------------------------
678*/
679
680/* For now we will just keep it at a linear growth rate. */
681#define FCT_LIST_GROWTH_FACTOR 2
682
683/* Starting size for the list, to keep it simple we will start
684at a reasonable size. */
685#define FCT_LIST_DEFAULT_START_SZ 8
686
687/* Helper macros for quickly iterating through a list. You should be able
688to do something like,
689
690 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, my_list)
691 {
692 fct_logger__on_blah(logger);
693 }
694 FCT_NLIST_FOREACH_END();
695
696*/
697#define FCT_NLIST_FOREACH_BGN(Type, Var, List)\
698{\
699 if ( List != NULL ) {\
700 size_t item_i##Var;\
701 size_t num_items##Var = fct_nlist__size(List);\
702 for( item_i##Var =0; item_i##Var != num_items##Var; ++item_i##Var )\
703 {\
704 Type Var = (Type) fct_nlist__at((List), item_i##Var);
705
706#define FCT_NLIST_FOREACH_END() }}}
707
708/* Used to manage a list of loggers. This works mostly like
709the STL vector, where the array grows as more items are
710appended. */
711typedef struct _fct_nlist_t fct_nlist_t;
712struct _fct_nlist_t
713{
714 /* Item's are stored as pointers to void. */
715 void **itm_list;
716
717 /* Indicates the number of element's in the array. */
718 size_t avail_itm_num;
719
720 /* Indicates the number of actually elements in the array. */
721 size_t used_itm_num;
722};
723typedef void (*fct_nlist_on_del_t)(void*);
724
725
726/* Clears the contents of the list, and sets the list count to 0. The
727actual count remains unchanged. If on_del is supplied it is executed
728against each list element. */
729static void
730fct_nlist__clear(fct_nlist_t *list, fct_nlist_on_del_t on_del)
731{
732 size_t itm_i__ =0;
733 FCT_ASSERT( list != NULL );
734 if ( on_del != NULL )
735 {
736 for ( itm_i__=0; itm_i__ != list->used_itm_num; ++itm_i__ )
737 {
738 on_del(list->itm_list[itm_i__]);
739 }
740 }
741 list->used_itm_num =0;
742}
743
744
745/* If you used init, then close with final. This is useful for
746working with structures that live on the stack. */
747static void
748fct_nlist__final(fct_nlist_t *list, fct_nlist_on_del_t on_del)
749{
750 FCT_ASSERT( list != NULL );
751 fct_nlist__clear(list, on_del);
752 free(list->itm_list);
753}
754
755
756static int
757fct_nlist__init2(fct_nlist_t *list, size_t start_sz)
758{
759 FCT_ASSERT( list != NULL );
760 if ( start_sz == 0 )
761 {
762 list->itm_list = NULL;
763 }
764 else
765 {
766 list->itm_list = (void**)malloc(sizeof(void*)*start_sz);
767 if ( list->itm_list == NULL )
768 {
769 return 0;
770 }
771 }
772 /* If these are both 0, then they are equal and that means
773 that the first append operation will allocate memory. The beauty
774 here is that if the list remains empty, then we save a malloc.
775 Empty lists are relatively common in FCT (consider an error list). */
776 list->avail_itm_num = start_sz;
777 list->used_itm_num =0;
778 return 1;
779}
780
781
782/* Initializes a list. Useful for populating existing structures.
783Returns 0 if there was an error allocating memory. Returns 1 otherwise. */
784#define fct_nlist__init(_LIST_PTR_) \
785 (fct_nlist__init2((_LIST_PTR_), FCT_LIST_DEFAULT_START_SZ))
786
787
788/* Returns the number of elements within the list. */
789static size_t
790fct_nlist__size(fct_nlist_t const *list)
791{
792 FCT_ASSERT( list != NULL );
793 return list->used_itm_num;
794}
795
796
797/* Returns the item at idx, asserts otherwise. */
798static void*
799fct_nlist__at(fct_nlist_t const *list, size_t idx)
800{
801 FCT_ASSERT( list != NULL );
802 FCT_ASSERT( idx < list->used_itm_num );
803 return list->itm_list[idx];
804}
805
806
807static void
808fct_nlist__append(fct_nlist_t *list, void *itm)
809{
810 FCT_ASSERT( list != NULL );
811 /* If we ran out of room, then the last increment should be equal to the
812 available space, in this case we need to grow a little more. If this
813 list started as size 0, then we should encounter the same effect as
814 "running out of room." */
815 if ( list->used_itm_num == list->avail_itm_num )
816 {
817 /* Use multiple and add, since the avail_itm_num could be 0. */
818 list->avail_itm_num = list->avail_itm_num*FCT_LIST_GROWTH_FACTOR+\
819 FCT_LIST_GROWTH_FACTOR;
820 list->itm_list = (void**)realloc(
821 list->itm_list, sizeof(void*)*list->avail_itm_num
822 );
823 FCT_ASSERT( list->itm_list != NULL && "memory check");
824 }
825
826 list->itm_list[list->used_itm_num] = itm;
827 ++(list->used_itm_num);
828}
829
830
831
832/*
833-----------------------------------------------------------
834A SINGLE CHECK
835-----------------------------------------------------------
836This defines a single check. It indicates what the check was,
837and where it occurred. A "Test" object will have-a bunch
838of "checks".
839*/
840
841struct _fctchk_t
842{
843 /* This string that represents the condition. */
844 char cndtn[FCT_MAX_LOG_LINE];
845
846 /* These indicate where the condition occurred. */
847 char file[FCT_MAX_LOG_LINE];
848
849 int lineno;
850
851 nbool_t is_pass;
852
853 /* This is a message that we can "format into", if
854 no format string is specified this should be
855 equivalent to the cntdn. */
856 char msg[FCT_MAX_LOG_LINE];
857};
858
859#define fctchk__is_pass(_CHK_) ((_CHK_)->is_pass)
860#define fctchk__file(_CHK_) ((_CHK_)->file)
861#define fctchk__lineno(_CHK_) ((_CHK_)->lineno)
862#define fctchk__cndtn(_CHK_) ((_CHK_)->cndtn)
863#define fctchk__msg(_CHK_) ((_CHK_)->msg)
864
865static fctchk_t*
866fctchk_new(int is_pass,
867 char const *cndtn,
868 char const *file,
869 int lineno,
870 char const *format,
871 va_list args)
872{
873 fctchk_t *chk = NULL;
874
875 FCT_ASSERT( cndtn != NULL );
876 FCT_ASSERT( file != NULL );
877 FCT_ASSERT( lineno > 0 );
878
879 chk = (fctchk_t*)calloc(1, sizeof(fctchk_t));
880 if ( chk == NULL )
881 {
882 return NULL;
883 }
884
885 fctstr_safe_cpy(chk->cndtn, cndtn, FCT_MAX_LOG_LINE);
886 fctstr_safe_cpy(chk->file, file, FCT_MAX_LOG_LINE);
887 chk->lineno = lineno;
888
889 chk->is_pass =is_pass;
890
891 if ( format != NULL )
892 {
893 fct_vsnprintf(chk->msg, FCT_MAX_LOG_LINE, format, args);
894 }
895 else
896 {
897 /* Default to make the condition be the message, if there was no format
898 specified. */
899 fctstr_safe_cpy(chk->msg, cndtn, FCT_MAX_LOG_LINE);
900 }
901
902 return chk;
903}
904
905
906/* Cleans up a "check" object. If the `chk` is NULL, this function does
907nothing. */
908static void
909fctchk__del(fctchk_t *chk)
910{
911 if ( chk == NULL )
912 {
913 return;
914 }
915 free( chk );
916}
917
918
919/*
920-----------------------------------------------------------
921A TEST
922-----------------------------------------------------------
923A suite will have-a list of tests. Where each test will have-a
924list of failed and passed checks.
925*/
926
927struct _fct_test_t
928{
929 /* List of failed and passed "checks" (fctchk_t). Two seperate
930 lists make it faster to determine how many checks passed and how
931 many checks failed. */
932 fct_nlist_t failed_chks;
933 fct_nlist_t passed_chks;
934
935 /* To store the test run time */
936 fct_timer_t timer;
937
938 /* The name of the test case. */
939 char name[FCT_MAX_NAME];
940};
941
942#define fct_test__name(_TEST_) ((_TEST_)->name)
943
944/* Clears the failed tests ... partly for internal testing. */
945#define fct_test__clear_failed(test) \
946 fct_nlist__clear(test->failed_chks, (fct_nlist_on_del_t)fctchk__del);\
947
948
949static void
950fct_test__del(fct_test_t *test)
951{
952 if (test == NULL )
953 {
954 return;
955 }
956 fct_nlist__final(&(test->passed_chks), (fct_nlist_on_del_t)fctchk__del);
957 fct_nlist__final(&(test->failed_chks), (fct_nlist_on_del_t)fctchk__del);
958 free(test);
959}
960
961
962static fct_test_t*
963fct_test_new(char const *name)
964{
965 nbool_t ok =FCT_FALSE;
966 fct_test_t *test =NULL;
967
968 test = (fct_test_t*)malloc(sizeof(fct_test_t));
969 if ( test == NULL )
970 {
971 return NULL;
972 }
973
974 fctstr_safe_cpy(test->name, name, FCT_MAX_NAME);
975
976 /* Failures are an exception, so lets not allocate up
977 the list until we need to. */
978 fct_nlist__init2(&(test->failed_chks), 0);
979 if (!fct_nlist__init(&(test->passed_chks)))
980 {
981 ok =FCT_FALSE;
982 goto finally;
983 }
984
985 fct_timer__init(&(test->timer));
986
987 ok =FCT_TRUE;
988finally:
989 if ( !ok )
990 {
991 fct_test__del(test);
992 test =NULL;
993 }
994 return test;
995}
996
997
998static void
999fct_test__start_timer(fct_test_t *test)
1000{
1001 FCT_ASSERT( test != NULL );
1002 fct_timer__start(&(test->timer));
1003}
1004
1005
1006static void
1007fct_test__stop_timer(fct_test_t *test)
1008{
1009 FCT_ASSERT( test != NULL );
1010 fct_timer__stop(&(test->timer));
1011}
1012
1013
1014static double
1015fct_test__duration(fct_test_t const *test)
1016{
1017 FCT_ASSERT( test != NULL );
1018 return fct_timer__duration(&(test->timer));
1019}
1020
1021
1022static nbool_t
1023fct_test__is_pass(fct_test_t const *test)
1024{
1025 FCT_ASSERT( test != NULL );
1026 return fct_nlist__size(&(test->failed_chks)) == 0;
1027}
1028
1029
1030static void
1031fct_test__add(fct_test_t *test, fctchk_t *chk)
1032{
1033
1034 FCT_ASSERT( test != NULL );
1035 FCT_ASSERT( chk != NULL );
1036
1037 if ( fctchk__is_pass(chk) )
1038 {
1039 fct_nlist__append(&(test->passed_chks), (void*)chk);
1040 }
1041 else
1042 {
1043 fct_nlist__append(&(test->failed_chks), (void*)chk);
1044 }
1045}
1046
1047/* Returns the number of checks made throughout the test. */
1048static size_t
1049fct_test__chk_cnt(fct_test_t const *test)
1050{
1051 FCT_ASSERT( test != NULL );
1052 return fct_nlist__size(&(test->failed_chks)) \
1053 + fct_nlist__size(&(test->passed_chks));
1054}
1055
1056
1057/*
1058-----------------------------------------------------------
1059TEST SUITE (TS)
1060-----------------------------------------------------------
1061*/
1062
1063
1064/* The different types of 'modes' that a test suite can be in.
1065
1066While the test suite is iterating through all the tests, its "State"
1067can change from "setup mode", to "test mode" to "tear down" mode.
1068These help to indicate what mode are currently in. Think of it as a
1069basic FSM.
1070
1071 if the count was 0 end
1072 +--------->---------------------> ending_mode-----+-+
1073 | ^ |
1074 ^ | ^
1075start | [if no more tests] |
1076 | | | |
1077 +-count_mode -> setup_mode -> test_mode -> teardown_mode->-+
1078 | ^ | |
1079 | +-----------<---------------+ |
1080 +----------->---[if fct_req fails]--------+
1081
1082*/
1083enum ts_mode
1084{
1085 ts_mode_cnt, /* To setup when done counting. */
1086 ts_mode_setup, /* To test when done setup. */
1087 ts_mode_teardown, /* To ending mode, when no more tests. */
1088 ts_mode_test, /* To tear down mode. */
1089 ts_mode_ending, /* To ... */
1090 ts_mode_end, /* .. The End. */
1091 ts_mode_abort /* Abort */
1092};
1093
1094/* Types of states the test could be in. */
1095typedef enum
1096{
1097 fct_test_status_SUCCESS,
1098 fct_test_status_FAILURE
1099} fct_test_status;
1100
1101
1102struct _fct_ts_t
1103{
1104 /* For counting our 'current' test number, and the total number of
1105 tests. */
1106 int curr_test_num;
1107 int total_test_num;
1108
1109 /* Keeps track of the current state of the object while it is walking
1110 through its "FSM" */
1111 enum ts_mode mode;
1112
1113 /* The name of the test suite. */
1114 char name[FCT_MAX_NAME];
1115
1116 /* List of tests that where executed within the test suite. */
1117 fct_nlist_t test_list;
1118};
1119
1120
1121#define fct_ts__is_setup_mode(ts) ((ts)->mode == ts_mode_setup)
1122#define fct_ts__is_teardown_mode(ts) ((ts)->mode == ts_mode_teardown)
1123#define fct_ts__is_test_mode(ts) ((ts)->mode == ts_mode_test)
1124#define fct_ts__is_ending_mode(ts) ((ts)->mode == ts_mode_ending)
1125#define fct_ts__is_end(ts) ((ts)->mode == ts_mode_end)
1126#define fct_ts__is_cnt_mode(ts) ((ts)->mode == ts_mode_cnt)
1127#define fct_ts__is_abort_mode(ts) ((ts)->mode == ts_mode_abort)
1128
1129/* This cndtn is set when we have iterated through all the tests, and
1130there was nothing more to do. */
1131#define fct_ts__ending(ts) ((ts)->mode = ts_mode_ending)
1132
1133/* Flag a test suite as complete. It will no longer accept any more tests. */
1134#define fct_ts__end(ts) ((ts)->mode = ts_mode_end)
1135
1136#define fct_ts__name(ts) ((ts)->name)
1137
1138
1139static void
1140fct_ts__del(fct_ts_t *ts)
1141{
1142 if ( ts == NULL )
1143 {
1144 return;
1145 }
1146 fct_nlist__final(&(ts->test_list), (fct_nlist_on_del_t)fct_test__del);
1147 free(ts);
1148}
1149
1150static fct_ts_t *
1151fct_ts_new(char const *name)
1152{
1153 fct_ts_t *ts =NULL;
1154 ts = (fct_ts_t*)calloc(1, sizeof(fct_ts_t));
1155 FCT_ASSERT( ts != NULL );
1156
1157 fctstr_safe_cpy(ts->name, name, FCT_MAX_NAME);
1158 ts->mode = ts_mode_cnt;
1159 fct_nlist__init(&(ts->test_list));
1160 return ts;
1161}
1162
1163
1164
1165static nbool_t
1166fct_ts__is_more_tests(fct_ts_t const *ts)
1167{
1168 FCT_ASSERT( ts != NULL );
1169 FCT_ASSERT( !fct_ts__is_end(ts) );
1170 return ts->curr_test_num < ts->total_test_num;
1171}
1172
1173
1174/* Indicates that we have started a test case. */
1175static void
1176fct_ts__test_begin(fct_ts_t *ts)
1177{
1178 FCT_ASSERT( !fct_ts__is_end(ts) );
1179 ++(ts->curr_test_num);
1180}
1181
1182
1183/* Takes OWNERSHIP of a test object, and warehouses it for later stat
1184generation. */
1185static void
1186fct_ts__add_test(fct_ts_t *ts, fct_test_t *test)
1187{
1188 FCT_ASSERT( ts != NULL && "invalid arg");
1189 FCT_ASSERT( test != NULL && "invalid arg");
1190 FCT_ASSERT( !fct_ts__is_end(ts) );
1191 fct_nlist__append(&(ts->test_list), test);
1192}
1193
1194
1195static void
1196fct_ts__test_end(fct_ts_t *ts)
1197{
1198 FCT_ASSERT( ts != NULL );
1199 /* After a test has completed, move to teardown mode. */
1200 ts->mode = ts_mode_teardown;
1201}
1202
1203
1204/* Increments the internal count by 1. */
1205static void
1206fct_ts__inc_total_test_num(fct_ts_t *ts)
1207{
1208 FCT_ASSERT( ts != NULL );
1209 FCT_ASSERT( fct_ts__is_cnt_mode(ts) );
1210 FCT_ASSERT( !fct_ts__is_end(ts) );
1211 ++(ts->total_test_num);
1212}
1213
1214
1215/* Flags the end of the setup, which implies we are going to move into
1216setup mode. You must be already in setup mode for this to work! */
1217static void
1218fct_ts__setup_end(fct_ts_t *ts)
1219{
1220 if ( ts->mode != ts_mode_abort )
1221 {
1222 ts->mode = ts_mode_test;
1223 }
1224}
1225
1226
1227static fct_test_t *
1228fct_ts__make_abort_test(fct_ts_t *ts)
1229{
1230 char setup_testname[FCT_MAX_LOG_LINE+1] = {'\0'};
1231 char const *suitename = fct_ts__name(ts);
1232 fct_snprintf(setup_testname, FCT_MAX_LOG_LINE, "setup_%s", suitename);
1233 return fct_test_new(setup_testname);
1234}
1235
1236/* Flags a pre-mature abort of a setup (like a failed fct_req). */
1237static void
1238fct_ts__setup_abort(fct_ts_t *ts)
1239{
1240 FCT_ASSERT( ts != NULL );
1241 ts->mode = ts_mode_abort;
1242}
1243
1244/* Flags the end of the teardown, which implies we are going to move
1245into setup mode (for the next 'iteration'). */
1246static void
1247fct_ts__teardown_end(fct_ts_t *ts)
1248{
1249 if ( ts->mode == ts_mode_abort )
1250 {
1251 return; /* Because we are aborting . */
1252 }
1253 /* We have to decide if we should keep on testing by moving into tear down
1254 mode or if we have reached the real end and should be moving into the
1255 ending mode. */
1256 if ( fct_ts__is_more_tests(ts) )
1257 {
1258 ts->mode = ts_mode_setup;
1259 }
1260 else
1261 {
1262 ts->mode = ts_mode_ending;
1263 }
1264}
1265
1266
1267/* Flags the end of the counting, and proceeding to the first setup.
1268Consider the special case when a test suite has NO tests in it, in
1269that case we will have a current count that is zero, in which case
1270we can skip right to 'ending'. */
1271static void
1272fct_ts__cnt_end(fct_ts_t *ts)
1273{
1274 FCT_ASSERT( ts != NULL );
1275 FCT_ASSERT( fct_ts__is_cnt_mode(ts) );
1276 FCT_ASSERT( !fct_ts__is_end(ts) );
1277 if (ts->total_test_num == 0 )
1278 {
1279 ts->mode = ts_mode_ending;
1280 }
1281 else
1282 {
1283 ts->mode = ts_mode_setup;
1284 }
1285}
1286
1287
1288static nbool_t
1289fct_ts__is_test_cnt(fct_ts_t const *ts, int test_num)
1290{
1291 FCT_ASSERT( ts != NULL );
1292 FCT_ASSERT( 0 <= test_num );
1293 FCT_ASSERT( test_num < ts->total_test_num );
1294 FCT_ASSERT( !fct_ts__is_end(ts) );
1295
1296 /* As we roll through the tests we increment the count. With this
1297 count we can decide if we need to execute a test or not. */
1298 return test_num == ts->curr_test_num;
1299}
1300
1301
1302/* Returns the # of tests on the FCT TS object. This is the actual
1303# of tests executed. */
1304static size_t
1305fct_ts__tst_cnt(fct_ts_t const *ts)
1306{
1307 FCT_ASSERT( ts != NULL );
1308 FCT_ASSERT(
1309 fct_ts__is_end(ts)
1310 && "can't count number of tests executed until the test suite ends"
1311 );
1312 return fct_nlist__size(&(ts->test_list));
1313}
1314
1315
1316/* Returns the # of tests in the TS object that passed. */
1317static size_t
1318fct_ts__tst_cnt_passed(fct_ts_t const *ts)
1319{
1320 size_t tally =0;
1321
1322 FCT_ASSERT( ts != NULL );
1323 FCT_ASSERT( fct_ts__is_end(ts) );
1324
1325 FCT_NLIST_FOREACH_BGN(fct_test_t*, test, &(ts->test_list))
1326 {
1327 if ( fct_test__is_pass(test) )
1328 {
1329 tally += 1;
1330 }
1331 }
1332 FCT_NLIST_FOREACH_END();
1333 return tally;
1334}
1335
1336
1337/* Returns the # of checks made throughout a test suite. */
1338static size_t
1339fct_ts__chk_cnt(fct_ts_t const *ts)
1340{
1341 size_t tally =0;
1342
1343 FCT_ASSERT( ts != NULL );
1344
1345 FCT_NLIST_FOREACH_BGN(fct_test_t *, test, &(ts->test_list))
1346 {
1347 tally += fct_test__chk_cnt(test);
1348 }
1349 FCT_NLIST_FOREACH_END();
1350 return tally;
1351}
1352
1353/* Currently the duration is simply a sum of all the tests. */
1354static double
1355fct_ts__duration(fct_ts_t const *ts)
1356{
1357 double tally =0.0;
1358 FCT_ASSERT( ts != NULL );
1359 FCT_NLIST_FOREACH_BGN(fct_test_t *, test, &(ts->test_list))
1360 {
1361 tally += fct_test__duration(test);
1362 }
1363 FCT_NLIST_FOREACH_END();
1364 return tally;
1365}
1366
1367
1368/*
1369--------------------------------------------------------
1370FCT COMMAND LINE OPTION INITIALIZATION (fctcl_init)
1371--------------------------------------------------------
1372
1373Structure used for command line initialization. To keep it clear that we do
1374not delete the char*'s present on this structure.
1375*/
1376
1377
1378typedef enum
1379{
1380 FCTCL_STORE_UNDEFINED,
1381 FCTCL_STORE_TRUE,
1382 FCTCL_STORE_VALUE
1383} fctcl_store_t;
1384
1385
1386typedef struct _fctcl_init_t
1387{
1388 /* What to parse for this option. --long versus -s. */
1389 char const *long_opt; /* i.e. --help */
1390 char const *short_opt; /* i.e. -h */
1391
1392 /* What action to take when the option is activated. */
1393 fctcl_store_t action;
1394
1395 /* The help string for the action. */
1396 char const *help;
1397} fctcl_init_t;
1398
1399
1400/* Use when defining the option list. */
1401#define FCTCL_INIT_NULL \
1402 {NULL, NULL, FCTCL_STORE_UNDEFINED, NULL}
1403
1404
1405/*
1406--------------------------------------------------------
1407FCT COMMAND LINE OPTION (fctcl)
1408--------------------------------------------------------
1409
1410Specifies the command line configuration options. Use this
1411to help initialize the fct_clp (command line parser).
1412*/
1413
1414
1415/* Handy strings for storing "true" and "false". We can reference
1416these strings throughout the parse operation and not have to
1417worry about dealing with memory. */
1418#define FCTCL_TRUE_STR "1"
1419
1420
1421typedef struct _fctcl_t
1422{
1423 /* What to parse for this option. --long versus -s. */
1424 char *long_opt; /* i.e. --help */
1425 char *short_opt; /* i.e. -h */
1426
1427 /* What action to take when the option is activated. */
1428 fctcl_store_t action;
1429
1430 /* The help string for the action. */
1431 char *help;
1432
1433 /* The result. */
1434 char *value;
1435} fctcl_t;
1436
1437
1438#define fctcl_new() ((fctcl_t*)calloc(1, sizeof(fctcl_t)))
1439
1440
1441static void
1442fctcl__del(fctcl_t *clo)
1443{
1444 if ( clo == NULL )
1445 {
1446 return;
1447 }
1448 if ( clo->long_opt )
1449 {
1450 free(clo->long_opt);
1451 }
1452 if ( clo->short_opt)
1453 {
1454 free(clo->short_opt);
1455 }
1456 if ( clo->value )
1457 {
1458 free(clo->value);
1459 }
1460 if ( clo->help )
1461 {
1462 free(clo->help);
1463 }
1464 free(clo);
1465}
1466
1467
1468static fctcl_t*
1469fctcl_new2(fctcl_init_t const *clo_init)
1470{
1471 fctcl_t *clone = NULL;
1472 int ok =0;
1473 clone = fctcl_new();
1474 if ( clone == NULL )
1475 {
1476 return NULL;
1477 }
1478 clone->action = clo_init->action;
1479 if ( clo_init->help == NULL )
1480 {
1481 clone->help = NULL;
1482 }
1483 else
1484 {
1485 clone->help = fctstr_clone(clo_init->help);
1486 if ( clone->help == NULL )
1487 {
1488 ok =0;
1489 goto finally;
1490 }
1491 }
1492 if ( clo_init->long_opt == NULL )
1493 {
1494 clone->long_opt = NULL;
1495 }
1496 else
1497 {
1498 clone->long_opt = fctstr_clone(clo_init->long_opt);
1499 if ( clone->long_opt == NULL )
1500 {
1501 ok = 0;
1502 goto finally;
1503 }
1504 }
1505 if ( clo_init->short_opt == NULL )
1506 {
1507 clone->short_opt = NULL;
1508 }
1509 else
1510 {
1511 clone->short_opt = fctstr_clone(clo_init->short_opt);
1512 if ( clone->short_opt == NULL )
1513 {
1514 ok =0;
1515 goto finally;
1516 }
1517 }
1518 ok = 1;
1519finally:
1520 if ( !ok )
1521 {
1522 fctcl__del(clone);
1523 clone = NULL;
1524 }
1525 return clone;
1526}
1527
1528
1529static int
1530fctcl__is_option(fctcl_t const *clo, char const *option)
1531{
1532 FCT_ASSERT( clo != NULL );
1533 if ( option == NULL )
1534 {
1535 return 0;
1536 }
1537 return ((clo->long_opt != NULL
1538 && fctstr_eq(clo->long_opt, option))
1539 ||
1540 (clo->short_opt != NULL
1541 && fctstr_eq(clo->short_opt, option))
1542 );
1543}
1544
1545
1546#define fctcl__set_value(_CLO_, _VAL_) \
1547 (_CLO_)->value = fctstr_clone((_VAL_));
1548
1549/*
1550--------------------------------------------------------
1551FCT COMMAND PARSER (fct_clp)
1552--------------------------------------------------------
1553*/
1554
1555#define FCT_CLP_MAX_ERR_MSG_LEN 256
1556
1557typedef struct _fct_clp_t
1558{
1559 /* List of command line options. */
1560 fct_nlist_t clo_list;
1561
1562 /* List of parameters (not options). */
1563 fct_nlist_t param_list;
1564
1565 char error_msg[FCT_CLP_MAX_ERR_MSG_LEN];
1566 int is_error;
1567} fct_clp_t;
1568
1569
1570static void
1571fct_clp__final(fct_clp_t *clp)
1572{
1573 fct_nlist__final(&(clp->clo_list), (fct_nlist_on_del_t)fctcl__del);
1574 fct_nlist__final(&(clp->param_list), (fct_nlist_on_del_t)free);
1575}
1576
1577
1578/* Add an configuration options. */
1579static int
1580fct_clp__add_options(fct_clp_t *clp, fctcl_init_t const *options)
1581{
1582 fctcl_init_t const *pclo =NULL;
1583 int ok;
1584 for ( pclo = options; pclo->action != FCTCL_STORE_UNDEFINED; ++pclo )
1585 {
1586 fctcl_t *cpy = fctcl_new2(pclo);
1587 if ( cpy == NULL )
1588 {
1589 ok = 0;
1590 goto finally;
1591 }
1592 fct_nlist__append(&(clp->clo_list), (void*)cpy);
1593 }
1594 ok =1;
1595finally:
1596 return ok;
1597}
1598
1599/* Returns false if we ran out of memory. */
1600static int
1601fct_clp__init(fct_clp_t *clp, fctcl_init_t const *options)
1602{
1603 int ok =0;
1604 FCT_ASSERT( clp != NULL );
1605 /* It is just much saner to manage a clone of the options. Then we know
1606 who is in charge of the memory. */
1607 ok = fct_nlist__init(&(clp->clo_list));
1608 if ( !ok )
1609 {
1610 goto finally;
1611 }
1612 if ( options != NULL )
1613 {
1614 ok = fct_clp__add_options(clp, options);
1615 if ( !ok )
1616 {
1617 goto finally;
1618 }
1619 }
1620 ok = fct_nlist__init(&(clp->param_list));
1621 if ( !ok )
1622 {
1623 goto finally;
1624 }
1625 ok =1;
1626finally:
1627 if ( !ok )
1628 {
1629 fct_clp__final(clp);
1630 }
1631 return ok;
1632}
1633
1634
1635/* Parses the command line arguments. Use fct_clp__is_error and
1636fct_clp__get_error to figure out if something went awry. */
1637static void
1638fct_clp__parse(fct_clp_t *clp, int argc, char const *argv[])
1639{
1640 int argi =1;
1641 int is_option =0;
1642 char *arg =NULL;
1643 char *token =NULL;
1644 char *next_token =NULL;
1645
1646 clp->error_msg[0] = '\0';
1647 clp->is_error =0;
1648
1649 while ( argi < argc )
1650 {
1651 is_option =0;
1652 token =NULL;
1653 next_token = NULL;
1654 arg = fctstr_clone(argv[argi]);
1655
1656#if defined(_MSC_VER) && _MSC_VER > 1300
1657 token = strtok_s(arg, "=", &next_token);
1658#else
1659 token = strtok(arg, "=");
1660 next_token = strtok(NULL, "=");
1661#endif
1662
1663 FCT_NLIST_FOREACH_BGN(fctcl_t*, pclo, &(clp->clo_list))
1664 {
1665 /* Need to reset for each search. strtok below is destructive. */
1666 if ( fctcl__is_option(pclo, token) )
1667 {
1668 is_option =1;
1669 if ( pclo->action == FCTCL_STORE_VALUE )
1670 {
1671 /* If this is --xxxx=value then the next strtok should succeed.
1672 Otherwise, we need to chew up the next argument. */
1673 if ( next_token != NULL && strlen(next_token) > 0 )
1674 {
1675 fctcl__set_value(pclo, next_token);
1676 }
1677 else
1678 {
1679 ++argi; /* Chew up the next value */
1680 if ( argi >= argc )
1681 {
1682 /* error */
1683 fct_snprintf(
1684 clp->error_msg,
1685 FCT_CLP_MAX_ERR_MSG_LEN,
1686 "missing argument for %s",
1687 token
1688 );
1689 clp->is_error =1;
1690 break;
1691 }
1692 fctcl__set_value(pclo, argv[argi]);
1693 }
1694 }
1695 else if (pclo->action == FCTCL_STORE_TRUE)
1696 {
1697 fctcl__set_value(pclo, FCTCL_TRUE_STR);
1698 }
1699 else
1700 {
1701 FCT_ASSERT("undefined action requested");
1702 }
1703 break; /* No need to parse this argument further. */
1704 }
1705 }
1706 FCT_NLIST_FOREACH_END();
1707 /* If we have an error, exit. */
1708 if ( clp->is_error )
1709 {
1710 break;
1711 }
1712 /* If we walked through all the options, and didn't find
1713 anything, then we must have a parameter. Forget the fact that
1714 an unknown option will be treated like a parameter... */
1715 if ( !is_option )
1716 {
1717 fct_nlist__append(&(clp->param_list), arg);
1718 arg =NULL; /* Owned by the nlist */
1719 }
1720 ++argi;
1721 if ( arg != NULL )
1722 {
1723 free(arg);
1724 arg =NULL;
1725 }
1726 }
1727}
1728
1729
1730static fctcl_t const*
1731fct_clp__get_clo(fct_clp_t const *clp, char const *option)
1732{
1733 fctcl_t const *found =NULL;
1734
1735 FCT_NLIST_FOREACH_BGN(fctcl_t const*, pclo, &(clp->clo_list))
1736 {
1737 if ( fctcl__is_option(pclo, option) )
1738 {
1739 found = pclo;
1740 break;
1741 }
1742 }
1743 FCT_NLIST_FOREACH_END();
1744 return found;
1745}
1746
1747
1748#define fct_clp__optval(_CLP_, _OPTION_) \
1749 fct_clp__optval2((_CLP_), (_OPTION_), NULL)
1750
1751
1752/* Returns the value parsed at the command line, and equal to OPTION.
1753If the value wasn't parsed, the DEFAULT_VAL is returned instead. */
1754static char const*
1755fct_clp__optval2(fct_clp_t *clp, char const *option, char const *default_val)
1756{
1757 fctcl_t const *clo =NULL;
1758 FCT_ASSERT( clp != NULL );
1759 FCT_ASSERT( option != NULL );
1760 clo = fct_clp__get_clo(clp, option);
1761 if ( clo == NULL || clo->value == NULL)
1762 {
1763 return default_val;
1764 }
1765 return clo->value;
1766}
1767
1768
1769
1770/* Mainly used for unit tests. */
1771static int
1772fct_clp__is_param(fct_clp_t *clp, char const *param)
1773{
1774 if ( clp == NULL || param == NULL )
1775 {
1776 return 0;
1777 }
1778 FCT_NLIST_FOREACH_BGN(char *, aparam, &(clp->param_list))
1779 {
1780 if ( fctstr_eq(aparam, param) )
1781 {
1782 return 1;
1783 }
1784 }
1785 FCT_NLIST_FOREACH_END();
1786 return 0;
1787}
1788
1789
1790#define fct_clp__is_error(_CLP_) ((_CLP_)->is_error)
1791#define fct_clp__get_error(_CLP_) ((_CLP_)->error_msg);
1792
1793#define fct_clp__num_clo(_CLP_) \
1794 (fct_nlist__size(&((_CLP_)->clo_list)))
1795
1796#define fct_clp__param_cnt(_CLP_) \
1797 (fct_nlist__size(&((_CLP_)->param_list)))
1798
1799/* Returns a *reference* to the parameter at _IDX_. Do not modify
1800its contents. */
1801#define fct_clp__param_at(_CLP_, _IDX_) \
1802 ((char const*)fct_nlist__at(&((_CLP_)->param_list), (_IDX_)))
1803
1804
1805/* Returns true if the given option was on the command line.
1806Use either the long or short option name to check against. */
1807#define fct_clp__is(_CLP_, _OPTION_) \
1808 (fct_clp__optval((_CLP_), (_OPTION_)) != NULL)
1809
1810
1811
1812/*
1813--------------------------------------------------------
1814FCT NAMESPACE
1815--------------------------------------------------------
1816
1817The macros below start to pollute the watch window with
1818lots of "system" variables. This NAMESPACE is an
1819attempt to hide all the "system" variables in one place.
1820*/
1821typedef struct _fct_namespace_t
1822{
1823 /* The currently active test suite. */
1824 fct_ts_t *ts_curr;
1825 int ts_is_skip_suite;
1826 char const *ts_skip_cndtn;
1827
1828 /* Current test name. */
1829 char const* curr_test_name;
1830 fct_test_t *curr_test;
1831 const char *test_skip_cndtn;
1832 int test_is_skip;
1833
1834 /* Counts the number of tests in a test suite. */
1835 int test_num;
1836
1837 /* Set at the end of the test suites. */
1838 size_t num_total_failed;
1839} fct_namespace_t;
1840
1841
1842static void
1843fct_namespace_init(fct_namespace_t *ns)
1844{
1845 FCT_ASSERT( ns != NULL && "invalid argument!");
1846 memset(ns, 0, sizeof(fct_namespace_t));
1847}
1848
1849
1850/*
1851--------------------------------------------------------
1852FCT KERNAL
1853--------------------------------------------------------
1854
1855The "fctkern" is a singleton that is defined throughout the
1856system.
1857*/
1858
1859struct _fctkern_t
1860{
1861 /* Holds variables used throughout MACRO MAGIC. In order to reduce
1862 the "noise" in the watch window during a debug trace. */
1863 fct_namespace_t ns;
1864
1865 /* Command line parsing. */
1866 fct_clp_t cl_parser;
1867
1868 /* Hold onto the command line arguments. */
1869 int cl_argc;
1870 char const **cl_argv;
1871 /* Track user options. */
1872 fctcl_init_t const *cl_user_opts;
1873
1874 /* Tracks the delay parsing. */
1875 int cl_is_parsed;
1876
1877 /* This is an list of loggers that can be used in the fct system. */
1878 fct_nlist_t logger_list;
1879
1880 /* Array of custom types, you have built-in system ones and you
1881 have optionally supplied user ones.. */
1882 fct_logger_types_t *lt_usr;
1883 fct_logger_types_t *lt_sys;
1884
1885 /* This is a list of prefix's that can be used to determine if a
1886 test is should be run or not. */
1887 fct_nlist_t prefix_list;
1888
1889 /* This is a list of test suites that where generated throughout the
1890 testing process. */
1891 fct_nlist_t ts_list;
1892
1893 /* Records what we expect to fail. */
1894 size_t num_expected_failures;
1895};
1896
1897
1898#define FCT_OPT_VERSION "--version"
1899#define FCT_OPT_VERSION_SHORT "-v"
1900#define FCT_OPT_HELP "--help"
1901#define FCT_OPT_HELP_SHORT "-h"
1902#define FCT_OPT_LOGGER "--logger"
1903#define FCT_OPT_LOGGER_SHORT "-l"
1904static fctcl_init_t FCT_CLP_OPTIONS[] =
1905{
1906 /* Totally unsafe, since we are assuming we can clean out this data,
1907 what I need to do is have an "initialization" object, full of
1908 const objects. But for now, this should work. */
1909 {
1910 FCT_OPT_VERSION,
1911 FCT_OPT_VERSION_SHORT,
1912 FCTCL_STORE_TRUE,
1913 "Displays the FCTX version number and exits."
1914 },
1915 {
1916 FCT_OPT_HELP,
1917 FCT_OPT_HELP_SHORT,
1918 FCTCL_STORE_TRUE,
1919 "Shows this help."
1920 },
1921 {
1922 FCT_OPT_LOGGER,
1923 FCT_OPT_LOGGER_SHORT,
1924 FCTCL_STORE_VALUE,
1925 NULL
1926 },
1927 FCTCL_INIT_NULL /* Sentinel */
1928};
1929
1930typedef fct_logger_i* (*fct_logger_new_fn)(void);
1931struct _fct_logger_types_t
1932{
1933 char const *name;
1934 fct_logger_new_fn logger_new_fn;
1935 char const *desc;
1936};
1937
1938static fct_logger_types_t FCT_LOGGER_TYPES[] =
1939{
1940 {
1941 "standard",
1942 (fct_logger_new_fn)fct_standard_logger_new,
1943 "the basic fctx logger"
1944 },
1945 {
1946 "minimal",
1947 (fct_logger_new_fn)fct_minimal_logger_new,
1948 "the least amount of logging information."
1949 },
1950 {
1951 "junit",
1952 (fct_logger_new_fn)fct_junit_logger_new,
1953 "junit compatable xml"
1954 },
1955 {NULL, (fct_logger_new_fn)NULL, NULL} /* Sentinel */
1956};
1957
1958
1959/* Returns the number of filters defined for the fct kernal. */
1960#define fctkern__filter_cnt(_NK_) (fct_nlist__size(&((_NK_)->prefix_list)))
1961
1962
1963static void
1964fctkern__add_logger(fctkern_t *nk, fct_logger_i *logger_owns)
1965{
1966 FCT_ASSERT(nk != NULL && "invalid arg");
1967 FCT_ASSERT(logger_owns != NULL && "invalid arg");
1968 fct_nlist__append(&(nk->logger_list), logger_owns);
1969}
1970
1971
1972static void
1973fctkern__write_help(fctkern_t *nk, FILE *out)
1974{
1975 fct_clp_t *clp = &(nk->cl_parser);
1976 fprintf(out, "test.exe [options] prefix_filter ...\n\n");
1977 FCT_NLIST_FOREACH_BGN(fctcl_t*, clo, &(clp->clo_list))
1978 {
1979 if ( clo->short_opt != NULL )
1980 {
1981 fprintf(out, "%s, %s\n", clo->short_opt, clo->long_opt);
1982 }
1983 else
1984 {
1985 fprintf(out, "%s\n", clo->long_opt);
1986 }
1987 if ( !fctstr_ieq(clo->long_opt, FCT_OPT_LOGGER) )
1988 {
1989 /* For now lets not get to fancy with the text wrapping. */
1990 fprintf(out, " %s\n", clo->help);
1991 }
1992 else
1993 {
1994 fct_logger_types_t *types[2];
1995 int type_i;
1996 fct_logger_types_t *itr;
1997 types[0] = nk->lt_sys;
1998 types[1] = nk->lt_usr;
1999 fputs(" Sets the logger. The types of loggers currently "
2000 "available are,\n", out);
2001 for (type_i =0; type_i != 2; ++type_i )
2002 {
2003 for ( itr=types[type_i]; itr && itr->name != NULL; ++itr )
2004 {
2005 fprintf(out, " =%s : %s\n", itr->name, itr->desc);
2006 }
2007 }
2008 fprintf(out, " default is '%s'.\n", FCT_DEFAULT_LOGGER);
2009 }
2010 }
2011 FCT_NLIST_FOREACH_END();
2012 fputs("\n", out);
2013}
2014
2015
2016/* Appends a prefix filter that is used to determine if a test can
2017be executed or not. If the test starts with the same characters as
2018the prefix, then it should be "runnable". The prefix filter must be
2019a non-NULL, non-Blank string. */
2020static void
2021fctkern__add_prefix_filter(fctkern_t *nk, char const *prefix_filter)
2022{
2023 char *filter =NULL;
2024 size_t filter_len =0;
2025 FCT_ASSERT( nk != NULL && "invalid arg" );
2026 FCT_ASSERT( prefix_filter != NULL && "invalid arg" );
2027 FCT_ASSERT( strlen(prefix_filter) > 0 && "invalid arg" );
2028 /* First we make a copy of the prefix, then we store it away
2029 in our little list. */
2030 filter_len = strlen(prefix_filter);
2031 filter = (char*)malloc(sizeof(char)*(filter_len+1));
2032 fctstr_safe_cpy(filter, prefix_filter, filter_len+1);
2033 fct_nlist__append(&(nk->prefix_list), (void*)filter);
2034}
2035
2036
2037/* Cleans up the contents of a fctkern. NULL does nothing. */
2038static void
2039fctkern__final(fctkern_t *nk)
2040{
2041 if ( nk == NULL )
2042 {
2043 return;
2044 }
2045 fct_clp__final(&(nk->cl_parser));
2046 fct_nlist__final(&(nk->logger_list), (fct_nlist_on_del_t)fct_logger__del);
2047 /* The prefix list is a list of malloc'd strings. */
2048 fct_nlist__final(&(nk->prefix_list), (fct_nlist_on_del_t)free);
2049 fct_nlist__final(&(nk->ts_list), (fct_nlist_on_del_t)fct_ts__del);
2050}
2051
2052
2053#define fctkern__cl_is_parsed(_NK_) ((_NK_)->cl_is_parsed)
2054
2055
2056static int
2057fctkern__cl_is(fctkern_t *nk, char const *opt_str)
2058{
2059 FCT_ASSERT( opt_str != NULL );
2060 return opt_str[0] != '\0'
2061 && fct_clp__is(&(nk->cl_parser), opt_str);
2062}
2063
2064
2065/* Returns the command line value given by OPT_STR. If OPT_STR was not defined
2066at the command line, DEF_STR is returned (you can use NULL for the DEF_STR).
2067The result returned should not be mofidied, and MAY even be the same pointer
2068to DEF_STR. */
2069static char const *
2070fctkern__cl_val2(fctkern_t *nk, char const *opt_str, char const *def_str)
2071{
2072 FCT_ASSERT( opt_str != NULL );
2073 if ( nk == NULL )
2074 {
2075 return NULL;
2076 }
2077 return fct_clp__optval2(&(nk->cl_parser), opt_str, def_str);
2078}
2079
2080
2081/* Selects a logger from the list based on the selection name.
2082May return NULL if the name doesn't exist in the list. */
2083static fct_logger_i*
2084fckern_sel_log(fct_logger_types_t *search, char const *sel_logger)
2085{
2086 fct_logger_types_t *iter;
2087 FCT_ASSERT(search != NULL);
2088 FCT_ASSERT(sel_logger != NULL);
2089 FCT_ASSERT(strlen(sel_logger) > 0);
2090 for ( iter = search; iter->name != NULL; ++iter)
2091 {
2092 if ( fctstr_ieq(iter->name, sel_logger) )
2093 {
2094 return iter->logger_new_fn();
2095 }
2096 }
2097 return NULL;
2098}
2099
2100static int
2101fctkern__cl_parse_config_logger(fctkern_t *nk)
2102{
2103 fct_logger_i *logger =NULL;
2104 char const *sel_logger =NULL;
2105 char const *def_logger =FCT_DEFAULT_LOGGER;
2106 sel_logger = fctkern__cl_val2(nk, FCT_OPT_LOGGER, def_logger);
2107 FCT_ASSERT(sel_logger != NULL && "should never be NULL");
2108 /* First search the user selected types, then search the
2109 built-in types. */
2110 if ( nk->lt_usr != NULL )
2111 {
2112 logger = fckern_sel_log(nk->lt_usr, sel_logger);
2113 }
2114 if ( nk->lt_sys != NULL && logger == NULL )
2115 {
2116 logger = fckern_sel_log(nk->lt_sys, sel_logger);
2117 }
2118 if ( logger == NULL )
2119 {
2120 /* No logger configured, you must have supplied an invalid selection. */
2121 fprintf(stderr, "error: unknown logger selected - '%s'", sel_logger);
2122 return 0;
2123 }
2124 fctkern__add_logger(nk, logger);
2125 logger = NULL; /* owned by nk. */
2126 return 1;
2127}
2128
2129
2130
2131/* Call this if you want to (re)parse the command line options with a new
2132set of options. Returns -1 if you are to abort with EXIT_SUCCESS, returns
21330 if you are to abort with EXIT_FAILURE and returns 1 if you are to continue. */
2134static int
2135fctkern__cl_parse(fctkern_t *nk)
2136{
2137 int status =0;
2138 size_t num_params =0;
2139 size_t param_i =0;
2140 if ( nk == NULL )
2141 {
2142 return 0;
2143 }
2144 if ( nk->cl_user_opts != NULL )
2145 {
2146 if ( !fct_clp__add_options(&(nk->cl_parser), nk->cl_user_opts) )
2147 {
2148 status =0;
2149 goto finally;
2150 }
2151 }
2152 /* You want to add the "house options" after the user defined ones. The
2153 options are stored as a list so it means that any option listed after
2154 the above ones won't get parsed. */
2155 if ( !fct_clp__add_options(&(nk->cl_parser), FCT_CLP_OPTIONS) )
2156 {
2157 status =0;
2158 goto finally;
2159 }
2160 fct_clp__parse(&(nk->cl_parser), nk->cl_argc, nk->cl_argv);
2161 if ( fct_clp__is_error(&(nk->cl_parser)) )
2162 {
2163 char *err = fct_clp__get_error(&(nk->cl_parser));
2164 fprintf(stderr, "error: %s", err);
2165 status =0;
2166 goto finally;
2167 }
2168 num_params = fct_clp__param_cnt(&(nk->cl_parser));
2169 for ( param_i =0; param_i != num_params; ++param_i )
2170 {
2171 char const *param = fct_clp__param_at(&(nk->cl_parser), param_i);
2172 fctkern__add_prefix_filter(nk, param);
2173 }
2174 if ( fctkern__cl_is(nk, FCT_OPT_VERSION) )
2175 {
2176 (void)printf("Built using FCTX version %s.\n", FCT_VERSION_STR);
2177 status = -1;
2178 goto finally;
2179 }
2180 if ( fctkern__cl_is(nk, FCT_OPT_HELP) )
2181 {
2182 fctkern__write_help(nk, stdout);
2183 status = -1;
2184 goto finally;
2185 }
2186 if ( !fctkern__cl_parse_config_logger(nk) )
2187 {
2188 status = -1;
2189 goto finally;
2190 }
2191 status =1;
2192 nk->cl_is_parsed =1;
2193finally:
2194 return status;
2195}
2196
2197
2198
2199/* Parses the command line and sets up the framework. The argc and argv
2200should be directly from the program's main. */
2201static int
2202fctkern__init(fctkern_t *nk, int argc, const char *argv[])
2203{
2204 if ( argc == 0 && argv == NULL )
2205 {
2206 return 0;
2207 }
2208 memset(nk, 0, sizeof(fctkern_t));
2209 fct_clp__init(&(nk->cl_parser), NULL);
2210 fct_nlist__init(&(nk->logger_list));
2211 nk->lt_usr = NULL; /* Supplied via 'install' mechanics. */
2212 nk->lt_sys = FCT_LOGGER_TYPES;
2213 fct_nlist__init2(&(nk->prefix_list), 0);
2214 fct_nlist__init2(&(nk->ts_list), 0);
2215 nk->cl_is_parsed =0;
2216 /* Save a copy of the arguments. We do a delay parse of the command
2217 line arguments in order to allow the client code to optionally configure
2218 the command line parser.*/
2219 nk->cl_argc = argc;
2220 nk->cl_argv = argv;
2221 fct_namespace_init(&(nk->ns));
2222 return 1;
2223}
2224
2225
2226/* Takes OWNERSHIP of the test suite after we have finished executing
2227its contents. This way we can build up all kinds of summaries at the end
2228of a run. */
2229static void
2230fctkern__add_ts(fctkern_t *nk, fct_ts_t *ts)
2231{
2232 FCT_ASSERT( nk != NULL );
2233 FCT_ASSERT( ts != NULL );
2234 fct_nlist__append(&(nk->ts_list), ts);
2235}
2236
2237
2238/* Returns FCT_TRUE if the supplied test_name passes the filters set on
2239this test suite. If there are no filters, we return FCT_TRUE always. */
2240static nbool_t
2241fctkern__pass_filter(fctkern_t *nk, char const *test_name)
2242{
2243 size_t prefix_i =0;
2244 size_t prefix_list_size =0;
2245 FCT_ASSERT( nk != NULL && "invalid arg");
2246 FCT_ASSERT( test_name != NULL );
2247 FCT_ASSERT( strlen(test_name) > 0 );
2248 prefix_list_size = fctkern__filter_cnt(nk);
2249 /* If there is no filter list, then we return FCT_TRUE always. */
2250 if ( prefix_list_size == 0 )
2251 {
2252 return FCT_TRUE;
2253 }
2254 /* Iterate through the prefix filter list, and see if we have
2255 anything that does not pass. All we require is ONE item that
2256 passes the test in order for us to succeed here. */
2257 for ( prefix_i = 0; prefix_i != prefix_list_size; ++prefix_i )
2258 {
2259 char const *prefix = (char const*)fct_nlist__at(
2260 &(nk->prefix_list), prefix_i
2261 );
2262 nbool_t pass = fct_filter_pass(prefix, test_name);
2263 if ( pass )
2264 {
2265 return FCT_TRUE;
2266 }
2267 }
2268 /* Otherwise, we never managed to find a prefix that satisfied the
2269 supplied test name. Therefore we have failed to pass to the filter
2270 list test. */
2271 return FCT_FALSE;
2272}
2273
2274
2275/* Returns the number of tests that were performed. */
2276static size_t
2277fctkern__tst_cnt(fctkern_t const *nk)
2278{
2279 size_t tally =0;
2280 FCT_ASSERT( nk != NULL );
2281 FCT_NLIST_FOREACH_BGN(fct_ts_t *, ts, &(nk->ts_list))
2282 {
2283 tally += fct_ts__tst_cnt(ts);
2284 }
2285 FCT_NLIST_FOREACH_END();
2286 return tally;
2287}
2288
2289
2290/* Returns the number of tests that passed. */
2291static size_t
2292fctkern__tst_cnt_passed(fctkern_t const *nk)
2293{
2294 size_t tally =0;
2295 FCT_ASSERT( nk != NULL );
2296
2297 FCT_NLIST_FOREACH_BGN(fct_ts_t*, ts, &(nk->ts_list))
2298 {
2299 tally += fct_ts__tst_cnt_passed(ts);
2300 }
2301 FCT_NLIST_FOREACH_END();
2302
2303 return tally;
2304}
2305
2306
2307/* Returns the number of tests that failed. */
2308#define fctkern__tst_cnt_failed(nk) \
2309 (fctkern__tst_cnt(nk) - fctkern__tst_cnt_passed(nk))
2310
2311
2312/* Returns the number of checks made throughout the entire test. */
2313#if defined(FCT_USE_TEST_COUNT)
2314static size_t
2315fctkern__chk_cnt(fctkern_t const *nk)
2316{
2317 size_t tally =0;
2318 FCT_ASSERT( nk != NULL );
2319
2320 FCT_NLIST_FOREACH_BGN(fct_ts_t *, ts, &(nk->ts_list))
2321 {
2322 tally += fct_ts__chk_cnt(ts);
2323 }
2324 FCT_NLIST_FOREACH_END();
2325 return tally;
2326}
2327#endif /* FCT_USE_TEST_COUNT */
2328
2329
2330/* Indicates the very end of all the tests. */
2331#define fctkern__end(nk) /* unused */
2332
2333
2334static void
2335fctkern__log_suite_start(fctkern_t *nk, fct_ts_t const *ts)
2336{
2337 FCT_ASSERT( nk != NULL );
2338 FCT_ASSERT( ts != NULL );
2339 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2340 {
2341 fct_logger__on_test_suite_start(logger, ts);
2342 }
2343 FCT_NLIST_FOREACH_END();
2344}
2345
2346
2347static void
2348fctkern__log_suite_end(fctkern_t *nk, fct_ts_t const *ts)
2349{
2350 FCT_ASSERT( nk != NULL );
2351 FCT_ASSERT( ts != NULL );
2352 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2353 {
2354 fct_logger__on_test_suite_end(logger, ts);
2355 }
2356 FCT_NLIST_FOREACH_END();
2357}
2358
2359
2360static void
2361fctkern__log_suite_skip(fctkern_t *nk, char const *condition, char const *name)
2362{
2363 if ( nk == NULL )
2364 {
2365 return;
2366 }
2367 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2368 {
2369 fct_logger__on_test_suite_skip(logger, condition, name);
2370 }
2371 FCT_NLIST_FOREACH_END();
2372}
2373
2374
2375static void
2376fctkern__log_test_skip(fctkern_t *nk, char const *condition, char const *name)
2377{
2378 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2379 {
2380 fct_logger__on_test_skip(logger, condition, name);
2381 }
2382 FCT_NLIST_FOREACH_END();
2383}
2384
2385
2386/* Use this for displaying information about a "Check" (i.e.
2387a condition). */
2388static void
2389fctkern__log_chk(fctkern_t *nk, fctchk_t const *chk)
2390{
2391 FCT_ASSERT( nk != NULL );
2392 FCT_ASSERT( chk != NULL );
2393 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2394 {
2395 fct_logger__on_chk(logger, chk);
2396 }
2397 FCT_NLIST_FOREACH_END();
2398}
2399
2400
2401/* Use this for displaying warning messages. */
2402static void
2403fctkern__log_warn(fctkern_t *nk, char const *warn)
2404{
2405 FCT_ASSERT( nk != NULL );
2406 FCT_ASSERT( warn != NULL );
2407 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2408 {
2409 fct_logger__on_warn(logger, warn);
2410 }
2411 FCT_NLIST_FOREACH_END();
2412}
2413
2414
2415/* Called whenever a test is started. */
2416static void
2417fctkern__log_test_start(fctkern_t *nk, fct_test_t const *test)
2418{
2419 FCT_ASSERT( nk != NULL );
2420 FCT_ASSERT( test != NULL );
2421 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2422 {
2423 fct_logger__on_test_start(logger, test);
2424 }
2425 FCT_NLIST_FOREACH_END();
2426}
2427
2428
2429static void
2430fctkern__log_test_end(fctkern_t *nk, fct_test_t *test)
2431{
2432 FCT_ASSERT( nk != NULL );
2433 FCT_ASSERT( test != NULL );
2434 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &(nk->logger_list))
2435 {
2436 fct_logger__on_test_end(logger, test);
2437 }
2438 FCT_NLIST_FOREACH_END();
2439}
2440
2441
2442#define fctkern__log_start(_NK_) \
2443 {\
2444 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &((_NK_)->logger_list))\
2445 {\
2446 fct_logger__on_fctx_start(logger, (_NK_));\
2447 }\
2448 FCT_NLIST_FOREACH_END();\
2449 }
2450
2451
2452#define fctkern__log_end(_NK_) \
2453 {\
2454 FCT_NLIST_FOREACH_BGN(fct_logger_i*, logger, &((_NK_)->logger_list))\
2455 {\
2456 fct_logger__on_fctx_end(logger, (_NK_));\
2457 }\
2458 FCT_NLIST_FOREACH_END();\
2459 }
2460
2461
2462
2463
2464/*
2465-----------------------------------------------------------
2466LOGGER INTERFACE
2467
2468Defines an interface to a logging system. A logger
2469must define the following functions in order to hook
2470into the logging system.
2471
2472See the "Standard Logger" and "Minimal Logger" as examples
2473of the implementation.
2474-----------------------------------------------------------
2475*/
2476
2477/* Common event argument. The values of the each event may or may not be
2478defined depending on the event in question. */
2479struct _fct_logger_evt_t
2480{
2481 fctkern_t const *kern;
2482 fctchk_t const *chk;
2483 fct_test_t const *test;
2484 fct_ts_t const *ts;
2485 char const *msg;
2486 char const *cndtn;
2487 char const *name;
2488};
2489
2490
2491typedef struct _fct_logger_i_vtable_t
2492{
2493 /* 1
2494 * Fired when an "fct_chk*" (check) function is completed. The event
2495 * will contain a reference to the "chk" object created.
2496 * */
2497 void (*on_chk)(fct_logger_i *logger, fct_logger_evt_t const *e);
2498
2499 /* 2
2500 * Fired when a test starts and before any checks are made. The
2501 * event will have its "test" object set. */
2502 void (*on_test_start)(
2503 fct_logger_i *logger,
2504 fct_logger_evt_t const *e
2505 );
2506 /* 3 */
2507 void (*on_test_end)(
2508 fct_logger_i *logger,
2509 fct_logger_evt_t const *e
2510 );
2511 /* 4 */
2512 void (*on_test_suite_start)(
2513 fct_logger_i *logger,
2514 fct_logger_evt_t const *e
2515 );
2516 /* 5 */
2517 void (*on_test_suite_end)(
2518 fct_logger_i *logger,
2519 fct_logger_evt_t const *e
2520 );
2521 /* 6 */
2522 void (*on_fctx_start)(
2523 fct_logger_i *logger,
2524 fct_logger_evt_t const *e
2525 );
2526 /* 7 */
2527 void (*on_fctx_end)(
2528 fct_logger_i *logger,
2529 fct_logger_evt_t const *e
2530 );
2531 /* 8
2532 Called when the logger object must "clean up". */
2533 void (*on_delete)(
2534 fct_logger_i *logger,
2535 fct_logger_evt_t const *e
2536 );
2537 /* 9 */
2538 void (*on_warn)(
2539 fct_logger_i *logger,
2540 fct_logger_evt_t const *e
2541 );
2542 /* -- new in 1.2 -- */
2543 /* 10 */
2544 void (*on_test_suite_skip)(
2545 fct_logger_i *logger,
2546 fct_logger_evt_t const *e
2547 );
2548 /* 11 */
2549 void (*on_test_skip)(
2550 fct_logger_i *logger,
2551 fct_logger_evt_t const *e
2552 );
2553} fct_logger_i_vtable_t;
2554
2555#define _fct_logger_head \
2556 fct_logger_i_vtable_t vtable; \
2557 fct_logger_evt_t evt
2558
2559struct _fct_logger_i
2560{
2561 _fct_logger_head;
2562};
2563
2564
2565static void
2566fct_logger__stub(fct_logger_i *l, fct_logger_evt_t const *e)
2567{
2568 fct_unused(l);
2569 fct_unused(e);
2570}
2571
2572
2573static fct_logger_i_vtable_t fct_logger_default_vtable =
2574{
2575 fct_logger__stub, /* 1. on_chk */
2576 fct_logger__stub, /* 2. on_test_start */
2577 fct_logger__stub, /* 3. on_test_end */
2578 fct_logger__stub, /* 4. on_test_suite_start */
2579 fct_logger__stub, /* 5. on_test_suite_end */
2580 fct_logger__stub, /* 6. on_fctx_start */
2581 fct_logger__stub, /* 7. on_fctx_end */
2582 fct_logger__stub, /* 8. on_delete */
2583 fct_logger__stub, /* 9. on_warn */
2584 fct_logger__stub, /* 10. on_test_suite_skip */
2585 fct_logger__stub, /* 11. on_test_skip */
2586};
2587
2588
2589/* Initializes the elements of a logger interface so they are at their
2590standard values. */
2591static void
2592fct_logger__init(fct_logger_i *logger)
2593{
2594 FCT_ASSERT( logger != NULL );
2595 memcpy(
2596 &(logger->vtable),
2597 &fct_logger_default_vtable,
2598 sizeof(fct_logger_i_vtable_t)
2599 );
2600 memset(&(logger->evt),0, sizeof(fct_logger_evt_t));
2601}
2602
2603static void
2604fct_logger__del(fct_logger_i *logger)
2605{
2606 if ( logger )
2607 {
2608 logger->vtable.on_delete(logger, &(logger->evt));
2609 }
2610}
2611
2612
2613static void
2614fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test)
2615{
2616 logger->evt.test = test;
2617 logger->vtable.on_test_start(logger, &(logger->evt));
2618}
2619
2620
2621static void
2622fct_logger__on_test_end(fct_logger_i *logger, fct_test_t *test)
2623{
2624 logger->evt.test = test;
2625 logger->vtable.on_test_end(logger, &(logger->evt));
2626}
2627
2628
2629static void
2630fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts)
2631{
2632 logger->evt.ts = ts;
2633 logger->vtable.on_test_suite_start(logger, &(logger->evt));
2634}
2635
2636
2637static void
2638fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts)
2639{
2640 logger->evt.ts = ts;
2641 logger->vtable.on_test_suite_end(logger, &(logger->evt));
2642}
2643
2644
2645static void
2646fct_logger__on_test_suite_skip(
2647 fct_logger_i *logger,
2648 char const *condition,
2649 char const *name
2650)
2651{
2652 logger->evt.cndtn = condition;
2653 logger->evt.name = name;
2654 logger->vtable.on_test_suite_skip(logger, &(logger->evt));
2655}
2656
2657
2658static void
2659fct_logger__on_test_skip(
2660 fct_logger_i *logger,
2661 char const *condition,
2662 char const *name
2663)
2664{
2665 logger->evt.cndtn = condition;
2666 logger->evt.name = name;
2667 logger->vtable.on_test_skip(logger, &(logger->evt));
2668}
2669
2670
2671static void
2672fct_logger__on_chk(fct_logger_i *logger, fctchk_t const *chk)
2673{
2674 logger->evt.chk = chk;
2675 logger->vtable.on_chk(logger, &(logger->evt));
2676}
2677
2678/* When we start all our tests. */
2679#define fct_logger__on_fctx_start(LOGGER, KERN) \
2680 (LOGGER)->evt.kern = (KERN);\
2681 (LOGGER)->vtable.on_fctx_start((LOGGER), &((LOGGER)->evt));
2682
2683
2684/* When we have reached the end of ALL of our testing. */
2685#define fct_logger__on_fctx_end(LOGGER, KERN) \
2686 (LOGGER)->evt.kern = (KERN);\
2687 (LOGGER)->vtable.on_fctx_end((LOGGER), &((LOGGER)->evt));
2688
2689
2690static void
2691fct_logger__on_warn(fct_logger_i *logger, char const *msg)
2692{
2693 logger->evt.msg = msg;
2694 logger->vtable.on_warn(logger, &(logger->evt));
2695}
2696
2697
2698/* Commmon routine to record strings representing failures. The
2699chk should be a failure before we call this, and the list is a list
2700of char*'s that will eventually be free'd by the logger. */
2701static void
2702fct_logger_record_failure(fctchk_t const* chk, fct_nlist_t* fail_list)
2703{
2704 /* For now we will truncate the string to some set amount, later
2705 we can work out a dynamic string object. */
2706 char *str = (char*)malloc(sizeof(char)*FCT_MAX_LOG_LINE);
2707 FCT_ASSERT( str != NULL );
2708 fct_snprintf(
2709 str,
2710 FCT_MAX_LOG_LINE,
2711 "%s(%d):\n %s",
2712 fctchk__file(chk),
2713 fctchk__lineno(chk),
2714 fctchk__msg(chk)
2715 );
2716 /* Append it to the listing ... */
2717 fct_nlist__append(fail_list, (void*)str);
2718}
2719
2720
2721/* Another common routine, to print the failures at the end of a run. */
2722static void
2723fct_logger_print_failures(fct_nlist_t const *fail_list)
2724{
2725 puts(
2726 "\n----------------------------------------------------------------------------\n"
2727 );
2728 puts("FAILED TESTS\n\n");
2729 FCT_NLIST_FOREACH_BGN(char *, cndtn_str, fail_list)
2730 {
2731 printf("%s\n", cndtn_str);
2732 }
2733 FCT_NLIST_FOREACH_END();
2734
2735 puts("\n");
2736}
2737
2738
2739
2740
2741/*
2742-----------------------------------------------------------
2743MINIMAL LOGGER
2744-----------------------------------------------------------
2745
2746At the moment the MINIMAL LOGGER is currently disabled. Hope
2747to bring it back online soon. The only reason it is
2748disabled is that we don't currently have the ability to specify
2749loggers.
2750*/
2751
2752
2753/* Minimal logger, reports the minimum amount of information needed
2754to determine "something is happening". */
2755struct _fct_minimal_logger_t
2756{
2757 _fct_logger_head;
2758 /* A list of char*'s that needs to be cleaned up. */
2759 fct_nlist_t failed_cndtns_list;
2760};
2761
2762
2763static void
2764fct_minimal_logger__on_chk(
2765 fct_logger_i *self_,
2766 fct_logger_evt_t const *e
2767)
2768{
2769 fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
2770 if ( fctchk__is_pass(e->chk) )
2771 {
2772 fputs(".", stdout);
2773 }
2774 else
2775 {
2776 fputs("x", stdout);
2777 fct_logger_record_failure(e->chk, &(self->failed_cndtns_list));
2778
2779 }
2780}
2781
2782static void
2783fct_minimal_logger__on_fctx_end(
2784 fct_logger_i *self_,
2785 fct_logger_evt_t const *e
2786)
2787{
2788 fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
2789 fct_unused(e);
2790 if ( fct_nlist__size(&(self->failed_cndtns_list)) >0 )
2791 {
2792 fct_logger_print_failures(&(self->failed_cndtns_list));
2793 }
2794}
2795
2796
2797static void
2798fct_minimal_logger__on_delete(
2799 fct_logger_i *self_,
2800 fct_logger_evt_t const *e
2801)
2802{
2803 fct_minimal_logger_t *self = (fct_minimal_logger_t*)self_;
2804 fct_unused(e);
2805 fct_nlist__final(&(self->failed_cndtns_list), free);
2806 free(self);
2807
2808}
2809
2810
2811fct_logger_i*
2812fct_minimal_logger_new(void)
2813{
2814 fct_minimal_logger_t *self = (fct_minimal_logger_t*)\
2815 calloc(1,sizeof(fct_minimal_logger_t));
2816 if ( self == NULL )
2817 {
2818 return NULL;
2819 }
2820 fct_logger__init((fct_logger_i*)self);
2821 self->vtable.on_chk = fct_minimal_logger__on_chk;
2822 self->vtable.on_fctx_end = fct_minimal_logger__on_fctx_end;
2823 self->vtable.on_delete = fct_minimal_logger__on_delete;
2824 fct_nlist__init2(&(self->failed_cndtns_list), 0);
2825 return (fct_logger_i*)self;
2826}
2827
2828
2829/*
2830-----------------------------------------------------------
2831STANDARD LOGGER
2832-----------------------------------------------------------
2833*/
2834
2835struct _fct_standard_logger_t
2836{
2837 _fct_logger_head;
2838
2839 /* Start time. For now we use the low-accuracy time_t version. */
2840 fct_timer_t timer;
2841
2842 /* A list of char*'s that needs to be cleaned up. */
2843 fct_nlist_t failed_cndtns_list;
2844};
2845
2846
2847#define FCT_STANDARD_LOGGER_MAX_LINE 68
2848
2849
2850/* When a failure occurrs, we will record the details so we can display
2851them when the log "finishes" up. */
2852static void
2853fct_standard_logger__on_chk(
2854 fct_logger_i *logger_,
2855 fct_logger_evt_t const *e
2856)
2857{
2858 fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
2859 /* Only record failures. */
2860 if ( !fctchk__is_pass(e->chk) )
2861 {
2862 fct_logger_record_failure(e->chk, &(logger->failed_cndtns_list));
2863 }
2864}
2865
2866
2867static void
2868fct_standard_logger__on_test_skip(
2869 fct_logger_i* logger_,
2870 fct_logger_evt_t const *e
2871)
2872{
2873 char const *condition = e->cndtn;
2874 char const *name = e->name;
2875 char msg[256] = {'\0'};
2876 fct_unused(logger_);
2877 fct_unused(condition);
2878 fct_snprintf(msg, sizeof(msg), "%s (%s)", name, condition);
2879 msg[sizeof(msg)-1] = '\0';
2880 fct_dotted_line_start(FCT_STANDARD_LOGGER_MAX_LINE, msg);
2881 fct_dotted_line_end("- SKIP -");
2882}
2883
2884
2885static void
2886fct_standard_logger__on_test_start(
2887 fct_logger_i *logger_,
2888 fct_logger_evt_t const *e
2889)
2890{
2891 fct_unused(logger_);
2892 fct_dotted_line_start(
2893 FCT_STANDARD_LOGGER_MAX_LINE,
2894 fct_test__name(e->test)
2895 );
2896}
2897
2898
2899static void
2900fct_standard_logger__on_test_end(
2901 fct_logger_i *logger_,
2902 fct_logger_evt_t const *e
2903)
2904{
2905 nbool_t is_pass;
2906 fct_unused(logger_);
2907 is_pass = fct_test__is_pass(e->test);
2908 fct_dotted_line_end((is_pass) ? "PASS" : "FAIL ***" );
2909}
2910
2911
2912static void
2913fct_standard_logger__on_fctx_start(
2914 fct_logger_i *logger_,
2915 fct_logger_evt_t const *e
2916)
2917{
2918 fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
2919 fct_unused(e);
2920 fct_timer__start(&(logger->timer));
2921}
2922
2923
2924static void
2925fct_standard_logger__on_fctx_end(
2926 fct_logger_i *logger_,
2927 fct_logger_evt_t const *e
2928)
2929{
2930 fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
2931 nbool_t is_success =1;
2932 double elasped_time =0;
2933 size_t num_tests =0;
2934 size_t num_passed =0;
2935
2936 fct_timer__stop(&(logger->timer));
2937
2938 is_success = fct_nlist__size(&(logger->failed_cndtns_list)) ==0;
2939
2940 if ( !is_success )
2941 {
2942 fct_logger_print_failures(&(logger->failed_cndtns_list));
2943 }
2944 puts(
2945 "\n----------------------------------------------------------------------------\n"
2946 );
2947 num_tests = fctkern__tst_cnt(e->kern);
2948 num_passed = fctkern__tst_cnt_passed(e->kern);
2949 printf(
2950 "%s (%lu/%lu tests",
2951 (is_success) ? "PASSED" : "FAILED",
2952 (unsigned long) num_passed,
2953 (unsigned long) num_tests
2954 );
2955 elasped_time = fct_timer__duration(&(logger->timer));
2956 if ( elasped_time > 0.0000001 )
2957 {
2958 printf(" in %.6fs)\n", elasped_time);
2959 }
2960 else
2961 {
2962 /* Don't bother displaying the time to execute. */
2963 puts(")\n");
2964 }
2965}
2966
2967
2968static void
2969fct_standard_logger__on_delete(
2970 fct_logger_i *logger_,
2971 fct_logger_evt_t const *e
2972)
2973{
2974 fct_standard_logger_t *logger = (fct_standard_logger_t*)logger_;
2975 fct_unused(e);
2976 fct_nlist__final(&(logger->failed_cndtns_list), free);
2977 free(logger);
2978 logger_ =NULL;
2979}
2980
2981
2982static void
2983fct_standard_logger__on_warn(
2984 fct_logger_i* logger_,
2985 fct_logger_evt_t const *e
2986)
2987{
2988 fct_unused(logger_);
2989 (void)printf("WARNING: %s", e->msg);
2990}
2991
2992
2993fct_logger_i*
2994fct_standard_logger_new(void)
2995{
2996 fct_standard_logger_t *logger = (fct_standard_logger_t *)calloc(
2997 1, sizeof(fct_standard_logger_t)
2998 );
2999 if ( logger == NULL )
3000 {
3001 return NULL;
3002 }
3003 fct_logger__init((fct_logger_i*)logger);
3004 logger->vtable.on_chk = fct_standard_logger__on_chk;
3005 logger->vtable.on_test_start = fct_standard_logger__on_test_start;
3006 logger->vtable.on_test_end = fct_standard_logger__on_test_end;
3007 logger->vtable.on_fctx_start = fct_standard_logger__on_fctx_start;
3008 logger->vtable.on_fctx_end = fct_standard_logger__on_fctx_end;
3009 logger->vtable.on_delete = fct_standard_logger__on_delete;
3010 logger->vtable.on_warn = fct_standard_logger__on_warn;
3011 logger->vtable.on_test_skip = fct_standard_logger__on_test_skip;
3012 fct_nlist__init2(&(logger->failed_cndtns_list), 0);
3013 fct_timer__init(&(logger->timer));
3014 return (fct_logger_i*)logger;
3015}
3016
3017
3018/*
3019-----------------------------------------------------------
3020JUNIT LOGGER
3021-----------------------------------------------------------
3022*/
3023
3024
3025/* JUnit logger */
3026struct _fct_junit_logger_t
3027{
3028 _fct_logger_head;
3029};
3030
3031
3032static void
3033fct_junit_logger__on_test_suite_start(
3034 fct_logger_i *l,
3035 fct_logger_evt_t const *e
3036)
3037{
3038 fct_unused(l);
3039 fct_unused(e);
3040 FCT_SWITCH_STDOUT_TO_BUFFER();
3041 FCT_SWITCH_STDERR_TO_BUFFER();
3042}
3043
3044
3045static void
3046fct_junit_logger__on_test_suite_end(
3047 fct_logger_i *logger_,
3048 fct_logger_evt_t const *e
3049)
3050{
3051 fct_ts_t const *ts = e->ts; /* Test Suite */
3052 nbool_t is_pass;
3053 double elasped_time = 0;
3054 char std_buffer[1024];
3055 int read_length;
3056 int first_out_line;
3057
3058 fct_unused(logger_);
3059
3060 elasped_time = fct_ts__duration(ts);
3061
3062 FCT_SWITCH_STDOUT_TO_STDOUT();
3063 FCT_SWITCH_STDERR_TO_STDERR();
3064
3065 /* opening testsuite tag */
3066 printf("\t<testsuite errors=\"%lu\" failures=\"0\" tests=\"%lu\" "
3067 "name=\"%s\" time=\"%.4f\">\n",
3068 (unsigned long) fct_ts__tst_cnt(ts)
3069 - fct_ts__tst_cnt_passed(ts),
3070 (unsigned long) fct_ts__tst_cnt(ts),
3071 fct_ts__name(ts),
3072 elasped_time);
3073
3074 FCT_NLIST_FOREACH_BGN(fct_test_t*, test, &(ts->test_list))
3075 {
3076 is_pass = fct_test__is_pass(test);
3077
3078 /* opening testcase tag */
3079 if (is_pass)
3080 {
3081 printf("\t\t<testcase name=\"%s\" time=\"%.3f\"",
3082 fct_test__name(test),
3083 fct_test__duration(test)
3084 );
3085 }
3086 else
3087 {
3088 printf("\t\t<testcase name=\"%s\" time=\"%.3f\">\n",
3089 fct_test__name(test),
3090 fct_test__duration(test)
3091 );
3092 }
3093
3094 FCT_NLIST_FOREACH_BGN(fctchk_t*, chk, &(test->failed_chks))
3095 {
3096 /* error tag */
3097 printf("\t\t\t<error message=\"%s\" "
3098 "type=\"fctx\">", chk->msg);
3099 printf("file:%s, line:%d", chk->file, chk->lineno);
3100 printf("</error>\n");
3101 }
3102 FCT_NLIST_FOREACH_END();
3103
3104 /* closing testcase tag */
3105 if (is_pass)
3106 {
3107 printf(" />\n");
3108 }
3109 else
3110 {
3111 printf("\t\t</testcase>\n");
3112 }
3113 }
3114 FCT_NLIST_FOREACH_END();
3115
3116 /* print the std streams */
3117 first_out_line = 1;
3118 printf("\t\t<system-out>\n\t\t\t<![CDATA[");
3119 while ( (read_length = _fct_read(fct_stdout_pipe[0], std_buffer, 1024)) > 0)
3120 {
3121 if (first_out_line)
3122 {
3123 printf("\n");
3124 first_out_line = 0;
3125 }
3126 printf("%.*s", read_length, std_buffer);
3127 }
3128 printf("]]>\n\t\t</system-out>\n");
3129
3130 first_out_line = 1;
3131 printf("\t\t<system-err>\n\t\t\t<![CDATA[");
3132 while ((read_length = _fct_read(fct_stderr_pipe[0], std_buffer, 1024)) > 0)
3133 {
3134 if (first_out_line)
3135 {
3136 printf("\n");
3137 first_out_line = 0;
3138 }
3139 printf("%.*s", read_length, std_buffer);
3140 }
3141 printf("]]>\n\t\t</system-err>\n");
3142
3143 /* closing testsuite tag */
3144 printf("\t</testsuite>\n");
3145}
3146
3147static void
3148fct_junit_logger__on_fct_start(
3149 fct_logger_i *logger_,
3150 fct_logger_evt_t const *e
3151)
3152{
3153 fct_unused(logger_);
3154 fct_unused(e);
3155 printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
3156 printf("<testsuites>\n");
3157}
3158
3159static void
3160fct_junit_logger__on_fctx_end(
3161 fct_logger_i *logger_,
3162 fct_logger_evt_t const *e
3163)
3164{
3165 fct_unused(logger_);
3166 fct_unused(e);
3167 printf("</testsuites>\n");
3168}
3169
3170static void
3171fct_junit_logger__on_delete(
3172 fct_logger_i *logger_,
3173 fct_logger_evt_t const *e
3174)
3175{
3176 fct_junit_logger_t *logger = (fct_junit_logger_t*)logger_;
3177 fct_unused(e);
3178 free(logger);
3179 logger_ =NULL;
3180}
3181
3182
3183fct_junit_logger_t *
3184fct_junit_logger_new(void)
3185{
3186 fct_junit_logger_t *logger =
3187 (fct_junit_logger_t *)calloc(1, sizeof(fct_junit_logger_t));
3188 if ( logger == NULL )
3189 {
3190 return NULL;
3191 }
3192 fct_logger__init((fct_logger_i*)logger);
3193 logger->vtable.on_test_suite_start = fct_junit_logger__on_test_suite_start;
3194 logger->vtable.on_test_suite_end = fct_junit_logger__on_test_suite_end;
3195 logger->vtable.on_fctx_start = fct_junit_logger__on_fct_start;
3196 logger->vtable.on_fctx_end = fct_junit_logger__on_fctx_end;
3197 logger->vtable.on_delete = fct_junit_logger__on_delete;
3198 return logger;
3199}
3200
3201
3202/*
3203------------------------------------------------------------
3204MACRO MAGIC
3205------------------------------------------------------------
3206This is where the show begins!
3207*/
3208
3209/* This macro invokes a bunch of functions that need to be referenced in
3210order to avoid a "unreferenced local function has been removed" warning.
3211The logical acrobatics below try and make it appear to the compiler that
3212they are needed, but at runtime, only the cheap, first call is made. */
3213#define FCT_REFERENCE_FUNCS() \
3214 {\
3215 int check = 0 && fctstr_ieq(NULL, NULL);\
3216 if ( check ) {\
3217 _fct_cmt("not to be executed");\
3218 (void)_fct_chk_empty_str(NULL);\
3219 (void)_fct_chk_full_str(NULL);\
3220 (void)fct_test__start_timer(NULL);\
3221 (void)fct_test__stop_timer(NULL);\
3222 (void)fct_ts_new(NULL);\
3223 (void)fct_ts__test_begin(NULL);\
3224 (void)fct_ts__add_test(NULL, NULL);\
3225 (void)fct_ts__test_end(NULL);\
3226 (void)fct_ts__inc_total_test_num(NULL);\
3227 (void)fct_ts__make_abort_test(NULL);\
3228 (void)fct_ts__setup_abort(NULL);\
3229 (void)fct_ts__setup_end(NULL);\
3230 (void)fct_ts__teardown_end(NULL);\
3231 (void)fct_ts__cnt_end(NULL);\
3232 (void)fct_ts__is_test_cnt(NULL, 0);\
3233 (void)fct_xchk_fn(0, "");\
3234 (void)fct_xchk2_fn(NULL, 0, "");\
3235 (void)fctkern__cl_parse(NULL);\
3236 (void)fctkern__add_ts(NULL, NULL);\
3237 (void)fctkern__pass_filter(NULL, NULL);\
3238 (void)fctkern__log_suite_start(NULL, NULL);\
3239 (void)fctkern__log_suite_end(NULL, NULL);\
3240 (void)fctkern__log_test_skip(NULL, NULL, NULL);\
3241 (void)fctkern__log_test_start(NULL, NULL);\
3242 (void)fctkern__log_test_end(NULL, NULL);\
3243 (void)fctstr_endswith(NULL,NULL);\
3244 (void)fctstr_iendswith(NULL,NULL);\
3245 (void)fctstr_ieq(NULL,NULL);\
3246 (void)fctstr_incl(NULL, NULL);\
3247 (void)fctstr_iincl(NULL, NULL);\
3248 (void)fctstr_iendswith(NULL,NULL);\
3249 (void)fctstr_istartswith(NULL,NULL);\
3250 (void)fctstr_clone_lower(NULL);\
3251 (void)fctstr_startswith(NULL,NULL);\
3252 (void)fctkern__init(NULL, 0, NULL);\
3253 (void)fctkern__cl_is(NULL, "");\
3254 (void)fctkern__cl_val2(NULL, NULL, NULL);\
3255 fctkern__log_suite_skip(NULL, NULL, NULL);\
3256 (void)fct_clp__is_param(NULL,NULL);\
3257 _fct_cmt("should never construct an object");\
3258 (void)fct_test_new(NULL);\
3259 (void)fct_ts__chk_cnt(NULL);\
3260 }\
3261 }
3262
3263
3264#define FCT_INIT(_ARGC_, _ARGV_) \
3265 fctkern_t fctkern__; \
3266 fctkern_t* fctkern_ptr__ = &fctkern__; \
3267 FCT_REFERENCE_FUNCS(); \
3268 if ( !fctkern__init(fctkern_ptr__, argc, (const char **)argv) ) {\
3269 (void)fprintf( \
3270 stderr, "FATAL ERROR: Unable to initialize FCTX Kernel."\
3271 ); \
3272 exit(EXIT_FAILURE); \
3273 } \
3274
3275
3276#define FCT_FINAL() \
3277 fctkern_ptr__->ns.num_total_failed = fctkern__tst_cnt_failed( \
3278 (fctkern_ptr__) \
3279 ); \
3280 fctkern__log_end(fctkern_ptr__); \
3281 fctkern__end(fctkern_ptr__); \
3282 fctkern__final(fctkern_ptr__); \
3283 FCT_ASSERT( !((int)fctkern_ptr__->ns.num_total_failed < 0) \
3284 && "or we got truncated!"); \
3285 if ( fctkern_ptr__->ns.num_total_failed == \
3286 fctkern_ptr__->num_expected_failures) { \
3287 fctkern_ptr__->ns.num_total_failed = 0; \
3288 } \
3289
3290
3291
3292#define FCT_NUM_FAILED() \
3293 fctkern_ptr__->ns.num_total_failed \
3294
3295
3296
3297/* Typically used internally only, this mentions to FCTX that you EXPECT
3298to _NUM_FAILS_. If you the expected matches the actual, a 0 value is returned
3299from the program. */
3300#define FCT_EXPECTED_FAILURES(_NUM_FAILS_) \
3301 ((fctkern_ptr__->num_expected_failures = (_NUM_FAILS_)))
3302
3303
3304#define FCT_BGN_FN(_FNNAME_) \
3305 int _FNNAME_(int argc, char* argv[])\
3306 { \
3307 FCT_INIT(argc, argv)
3308
3309#define FCT_END_FN() FCT_END()
3310
3311/* This defines our start. The fctkern__ is a kernal object
3312that lives throughout the lifetime of our program. The
3313fctkern_ptr__ makes it easier to abstract out macros. */
3314#define FCT_BGN() FCT_BGN_FN(main)
3315
3316
3317/* Silence Intel complaints about unspecified operand order in user's code */
3318#ifndef __INTEL_COMPILER
3319# define FCT_END_WARNINGFIX_BGN
3320# define FCT_END_WARNINGFIX_END
3321#else
3322# define FCT_END_WARNINGFIX_BGN _Pragma("warning(push,disable:981)");
3323# define FCT_END_WARNINGFIX_END _Pragma("warning(pop)");
3324#endif
3325
3326/* Ends the test suite by returning the number failed. The "chk_cnt" call is
3327made in order allow strict compilers to pass when it encounters unreferenced
3328functions. */
3329#define FCT_END() \
3330 { \
3331 FCT_END_WARNINGFIX_BGN \
3332 FCT_FINAL(); \
3333 return FCT_NUM_FAILED();\
3334 FCT_END_WARNINGFIX_END \
3335 }\
3336}
3337
3338#define fctlog_install(_CUST_LOGGER_LIST_) \
3339 fctkern_ptr__->lt_usr = (_CUST_LOGGER_LIST_)
3340
3341/* Re-parses the command line options with the addition of user defined
3342options. */
3343#define fctcl_install(_CLO_INIT_) \
3344 {\
3345 fctkern_ptr__->cl_user_opts = (_CLO_INIT_);\
3346 _fct_cmt("Delay parse in order to allow for user customization.");\
3347 if ( !fctkern__cl_is_parsed((fctkern_ptr__)) ) {\
3348 int status = fctkern__cl_parse((fctkern_ptr__));\
3349 _fct_cmt("Need to parse command line before we start logger.");\
3350 fctkern__log_start((fctkern_ptr__));\
3351 switch( status ) {\
3352 case -1:\
3353 case 0:\
3354 fctkern__final(fctkern_ptr__);\
3355 exit( (status == 0) ? (EXIT_FAILURE) : (EXIT_SUCCESS) );\
3356 break;\
3357 default:\
3358 fct_pass();\
3359 }\
3360 }\
3361 }
3362
3363
3364#define fctcl_is(_OPT_STR_) (fctkern__cl_is(fctkern_ptr__, (_OPT_STR_)))
3365
3366#define fctcl_val(_OPT_STR_) (fctcl_val2((_OPT_STR_), NULL))
3367
3368#define fctcl_val2(_OPT_STR_, _DEF_STR_) \
3369 (fctkern__cl_val2(fctkern_ptr__, (_OPT_STR_), (_DEF_STR_)))
3370
3371
3372/* We delay the first parse of the command line until we get the first
3373test fixture. This allows the user to possibly add their own parse
3374specification. */
3375#define FCT_FIXTURE_SUITE_BGN(_NAME_) \
3376 {\
3377 fctkern_ptr__->ns.ts_curr = fct_ts_new( #_NAME_ );\
3378 _fct_cmt("Delay parse in order to allow for user customization.");\
3379 if ( !fctkern__cl_is_parsed((fctkern_ptr__)) ) {\
3380 int status = fctkern__cl_parse((fctkern_ptr__));\
3381 _fct_cmt("Need to parse command line before we start logger.");\
3382 fctkern__log_start((fctkern_ptr__));\
3383 switch( status ) {\
3384 case -1:\
3385 case 0:\
3386 fct_ts__del((fctkern_ptr__->ns.ts_curr));\
3387 fctkern__final(fctkern_ptr__);\
3388 exit( (status == 0) ? (EXIT_FAILURE) : (EXIT_SUCCESS) );\
3389 break;\
3390 default:\
3391 fct_pass();\
3392 }\
3393 }\
3394 if ( fctkern_ptr__->ns.ts_curr == NULL ) {\
3395 fctkern__log_warn((fctkern_ptr__), "out of memory");\
3396 }\
3397 else\
3398 {\
3399 fctkern__log_suite_start((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
3400 for (;;)\
3401 {\
3402 fctkern_ptr__->ns.test_num = -1;\
3403 if ( fct_ts__is_ending_mode(fctkern_ptr__->ns.ts_curr) \
3404 || fct_ts__is_abort_mode(fctkern_ptr__->ns.ts_curr) )\
3405 {\
3406 _fct_cmt("flag the test suite as complete.");\
3407 fct_ts__end(fctkern_ptr__->ns.ts_curr);\
3408 break;\
3409 }
3410
3411
3412
3413/* Closes off a "Fixture" test suite. */
3414#define FCT_FIXTURE_SUITE_END() \
3415 if ( fct_ts__is_cnt_mode(fctkern_ptr__->ns.ts_curr) )\
3416 {\
3417 fct_ts__cnt_end(fctkern_ptr__->ns.ts_curr);\
3418 }\
3419 }\
3420 fctkern__add_ts((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
3421 fctkern__log_suite_end((fctkern_ptr__), fctkern_ptr__->ns.ts_curr);\
3422 fct_ts__end(fctkern_ptr__->ns.ts_curr);\
3423 fctkern_ptr__->ns.ts_curr = NULL;\
3424 }\
3425 }
3426
3427#define FCT_FIXTURE_SUITE_BGN_IF(_CONDITION_, _NAME_) \
3428 fctkern_ptr__->ns.ts_is_skip_suite = !(_CONDITION_);\
3429 fctkern_ptr__->ns.ts_skip_cndtn = #_CONDITION_;\
3430 if ( fctkern_ptr__->ns.ts_is_skip_suite ) {\
3431 fctkern__log_suite_skip((fctkern_ptr__), #_CONDITION_, #_NAME_);\
3432 }\
3433 FCT_FIXTURE_SUITE_BGN(_NAME_);
3434
3435#define FCT_FIXTURE_SUITE_END_IF() \
3436 FCT_FIXTURE_SUITE_END();\
3437 fctkern_ptr__->ns.ts_is_skip_suite =0;\
3438 fctkern_ptr__->ns.ts_skip_cndtn =NULL;\
3439
3440#define FCT_SETUP_BGN()\
3441 if ( fct_ts__is_setup_mode(fctkern_ptr__->ns.ts_curr) ) {
3442
3443#define FCT_SETUP_END() \
3444 fct_ts__setup_end(fctkern_ptr__->ns.ts_curr); }
3445
3446#define FCT_TEARDOWN_BGN() \
3447 if ( fct_ts__is_teardown_mode(fctkern_ptr__->ns.ts_curr) ) {\
3448
3449#define FCT_TEARDOWN_END() \
3450 fct_ts__teardown_end(fctkern_ptr__->ns.ts_curr); \
3451 continue; \
3452 }
3453
3454/* Lets you create a test suite, where maybe you don't want a fixture. We
3455do it by 'stubbing' out the setup/teardown logic. */
3456#define FCT_SUITE_BGN(Name) \
3457 FCT_FIXTURE_SUITE_BGN(Name) {\
3458 FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\
3459 FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\
3460
3461#define FCT_SUITE_END() } FCT_FIXTURE_SUITE_END()
3462
3463#define FCT_SUITE_BGN_IF(_CONDITION_, _NAME_) \
3464 FCT_FIXTURE_SUITE_BGN_IF(_CONDITION_, (_NAME_)) {\
3465 FCT_SETUP_BGN() {_fct_cmt("stubbed"); } FCT_SETUP_END()\
3466 FCT_TEARDOWN_BGN() {_fct_cmt("stubbed");} FCT_TEARDOWN_END()\
3467
3468#define FCT_SUITE_END_IF() } FCT_FIXTURE_SUITE_END_IF()
3469
3470typedef enum
3471{
3472 FCT_TEST_END_FLAG_Default = 0x0000,
3473 FCT_TEST_END_FLAG_ClearFail = 0x0001
3474} FCT_TEST_END_FLAG;
3475
3476
3477#define FCT_TEST_BGN_IF(_CONDITION_, _NAME_) { \
3478 fctkern_ptr__->ns.test_is_skip = !(_CONDITION_);\
3479 fctkern_ptr__->ns.test_skip_cndtn = #_CONDITION_;\
3480 FCT_TEST_BGN(_NAME_) {\
3481
3482#define FCT_TEST_END_IF() \
3483 } FCT_TEST_END();\
3484 fctkern_ptr__->ns.test_is_skip = 0;\
3485 fctkern_ptr__->ns.test_skip_cndtn = NULL;\
3486 }
3487
3488
3489/* Depending on whether or not we are counting the tests, we will have to
3490first determine if the test is the "current" count. Then we have to determine
3491if we can pass the filter. Finally we will execute everything so that when a
3492check fails, we can "break" out to the end of the test. And in between all
3493that we do a memory check and fail a test if we can't build a fct_test
3494object (should be rare). */
3495#define FCT_TEST_BGN(_NAME_) \
3496 {\
3497 fctkern_ptr__->ns.curr_test_name = #_NAME_;\
3498 ++(fctkern_ptr__->ns.test_num);\
3499 if ( fct_ts__is_cnt_mode(fctkern_ptr__->ns.ts_curr) )\
3500 {\
3501 fct_ts__inc_total_test_num(fctkern_ptr__->ns.ts_curr);\
3502 }\
3503 else if ( fct_ts__is_test_mode(fctkern_ptr__->ns.ts_curr) \
3504 && fct_ts__is_test_cnt(fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.test_num) )\
3505 {\
3506 fct_ts__test_begin(fctkern_ptr__->ns.ts_curr);\
3507 if ( fctkern__pass_filter(fctkern_ptr__, fctkern_ptr__->ns.curr_test_name ) )\
3508 {\
3509 fctkern_ptr__->ns.curr_test = fct_test_new( fctkern_ptr__->ns.curr_test_name );\
3510 if ( fctkern_ptr__->ns.curr_test == NULL ) {\
3511 fctkern__log_warn(fctkern_ptr__, "out of memory");\
3512 } else if ( fctkern_ptr__->ns.ts_is_skip_suite \
3513 || fctkern_ptr__->ns.test_is_skip ) {\
3514 fct_ts__test_begin(fctkern_ptr__->ns.ts_curr);\
3515 fctkern__log_test_skip(\
3516 fctkern_ptr__,\
3517 fctkern_ptr__->ns.curr_test_name,\
3518 (fctkern_ptr__->ns.test_is_skip) ?\
3519 (fctkern_ptr__->ns.test_skip_cndtn) :\
3520 (fctkern_ptr__->ns.ts_skip_cndtn)\
3521 );\
3522 fct_ts__test_end(fctkern_ptr__->ns.ts_curr);\
3523 continue;\
3524 } else {\
3525 fctkern__log_test_start(fctkern_ptr__, fctkern_ptr__->ns.curr_test);\
3526 fct_test__start_timer(fctkern_ptr__->ns.curr_test);\
3527 for (;;) \
3528 {
3529
3530
3531
3532
3533#define FCT_TEST_END() \
3534 break;\
3535 }\
3536 fct_test__stop_timer(fctkern_ptr__->ns.curr_test);\
3537 }\
3538 fct_ts__add_test(fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.curr_test);\
3539 fctkern__log_test_end(fctkern_ptr__, fctkern_ptr__->ns.curr_test);\
3540 }\
3541 fct_ts__test_end(fctkern_ptr__->ns.ts_curr);\
3542 continue;\
3543 }\
3544 }\
3545
3546
3547
3548/*
3549---------------------------------------------------------
3550CHECKING MACROS
3551----------------------------------------------------------
3552
3553The chk variants will continue on while the req variants will abort
3554a test if a chk condition fails. The req variants are useful when you
3555no longer want to keep checking conditions because a critical condition
3556is not being met. */
3557
3558
3559/* To support older compilers that do not have macro variable argument lists
3560we have to use a function. The macro manages to store away the line/file
3561location into a global before it runs this function, a trick I picked up from
3562the error handling in the APR library. The unfortunate thing is that we can
3563not carry forth the actual test through a "stringize" operation, but if you
3564wanted to do that you should use fct_chk. */
3565
3566static int fct_xchk_lineno =0;
3567static char const *fct_xchk_file = NULL;
3568static fct_test_t *fct_xchk_test = NULL;
3569static fctkern_t *fct_xchk_kern =NULL;
3570
3571
3572static int
3573_fct_xchk_fn_varg(
3574 char const *condition,
3575 int is_pass,
3576 char const *format,
3577 va_list args
3578)
3579{
3580 fctchk_t *chk =NULL;
3581 chk = fctchk_new(
3582 is_pass,
3583 condition,
3584 fct_xchk_file,
3585 fct_xchk_lineno,
3586 format,
3587 args
3588 );
3589 if ( chk == NULL )
3590 {
3591 fctkern__log_warn(fct_xchk_kern, "out of memory (aborting test)");
3592 goto finally;
3593 }
3594
3595 fct_test__add(fct_xchk_test, chk);
3596 fctkern__log_chk(fct_xchk_kern, chk);
3597finally:
3598 fct_xchk_lineno =0;
3599 fct_xchk_file =NULL;
3600 fct_xchk_test =NULL;
3601 fct_xchk_kern =NULL;
3602 return is_pass;
3603}
3604
3605
3606static int
3607fct_xchk2_fn(const char *condition, int is_pass, char const *format, ...)
3608{
3609 int r =0;
3610 va_list args;
3611 va_start(args, format);
3612 r = _fct_xchk_fn_varg(condition, is_pass, format, args);
3613 va_end(args);
3614 return r;
3615}
3616
3617
3618static int
3619fct_xchk_fn(int is_pass, char const *format, ...)
3620{
3621 int r=0;
3622 va_list args;
3623 va_start(args, format);
3624 r = _fct_xchk_fn_varg("<none-from-xchk>", is_pass, format, args);
3625 va_end(args);
3626 return r;
3627}
3628
3629
3630/* Call this with the following argument list:
3631
3632 fct_xchk(test_condition, format_str, ...)
3633
3634the bulk of this macro presets some globals to allow us to support
3635variable argument lists on older compilers. The idea came from the APR
3636libraries error checking routines. */
3637#define fct_xchk fct_xchk_kern = fctkern_ptr__,\
3638 fct_xchk_test = fctkern_ptr__->ns.curr_test,\
3639 fct_xchk_lineno =__LINE__,\
3640 fct_xchk_file=__FILE__,\
3641 fct_xchk_fn
3642
3643#define fct_xchk2 fct_xchk_kern = fctkern_ptr__,\
3644 fct_xchk_test = fctkern_ptr__->ns.curr_test,\
3645 fct_xchk_lineno =__LINE__,\
3646 fct_xchk_file=__FILE__,\
3647 fct_xchk2_fn
3648
3649
3650/* This checks the condition and reports the condition as a string
3651if it fails. */
3652#define fct_chk(_CNDTN_) (fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_))
3653
3654#define _fct_req(_CNDTN_) \
3655 if ( !(fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_)) ) { break; }
3656
3657
3658/* When in test mode, construct a mock test object for fct_xchk to operate
3659with. If we fail a setup up, then we go directly to a teardown mode. */
3660#define fct_req(_CNDTN_) \
3661 if ( fct_ts__is_test_mode(fctkern_ptr__->ns.ts_curr) ) { \
3662 _fct_req((_CNDTN_)); \
3663 } \
3664 else if ( fct_ts__is_setup_mode(fctkern_ptr__->ns.ts_curr) \
3665 || fct_ts__is_teardown_mode(fctkern_ptr__->ns.ts_curr) ) { \
3666 fctkern_ptr__->ns.curr_test = fct_ts__make_abort_test( \
3667 fctkern_ptr__->ns.ts_curr \
3668 ); \
3669 if ( !(fct_xchk((_CNDTN_) ? 1 : 0, #_CNDTN_)) ) { \
3670 fct_ts__setup_abort(fctkern_ptr__->ns.ts_curr); \
3671 fct_ts__add_test( \
3672 fctkern_ptr__->ns.ts_curr, fctkern_ptr__->ns.curr_test \
3673 ); \
3674 } \
3675 } else { \
3676 assert("invalid condition for fct_req!"); \
3677 _fct_req((_CNDTN_)); \
3678 }
3679
3680
3681#define fct_chk_eq_dbl(V1, V2) \
3682 fct_xchk(\
3683 ((int)(fabs((V1)-(V2)) < DBL_EPSILON)),\
3684 "chk_eq_dbl: %f != %f",\
3685 (V1),\
3686 (V2)\
3687 )
3688
3689
3690#define fct_chk_neq_dbl(V1, V2) \
3691 fct_xchk(\
3692 ((int)(fabs((V1)-(V2)) >= DBL_EPSILON)),\
3693 "chk_neq_dbl: %f == %f",\
3694 (V1),\
3695 (V2)\
3696 )
3697
3698
3699#define fct_chk_eq_str(V1, V2) \
3700 fct_xchk(fctstr_eq((V1), (V2)),\
3701 "chk_eq_str: '%s' != '%s'",\
3702 (V1),\
3703 (V2)\
3704 )
3705
3706
3707#define fct_chk_neq_str(V1, V2) \
3708 fct_xchk(!fctstr_eq((V1), (V2)),\
3709 "chk_neq_str: '%s' == '%s'",\
3710 (V1),\
3711 (V2)\
3712 )
3713
3714/* To quiet warnings with GCC, who think we are being silly and passing
3715in NULL to strlen, we will filter the predicate through these little
3716functions */
3717static int
3718_fct_chk_empty_str(char const *s)
3719{
3720 if ( s == NULL )
3721 {
3722 return 1;
3723 }
3724 return strlen(s) ==0;
3725}
3726static int
3727_fct_chk_full_str(char const *s)
3728{
3729 if ( s == NULL )
3730 {
3731 return 0;
3732 }
3733 return strlen(s) >0;
3734}
3735
3736
3737#define fct_chk_empty_str(V) \
3738 fct_xchk(_fct_chk_empty_str((V)),\
3739 "string not empty: '%s'",\
3740 (V)\
3741 )
3742
3743#define fct_chk_full_str(V) \
3744 fct_xchk(_fct_chk_full_str((V)),\
3745 "string is full: '%s'",\
3746 (V)\
3747 )
3748
3749
3750#define fct_chk_eq_istr(V1, V2) \
3751 fct_xchk(fctstr_ieq((V1), (V2)),\
3752 "chk_eq_str: '%s' != '%s'",\
3753 (V1),\
3754 (V2)\
3755 )
3756
3757
3758#define fct_chk_neq_istr(V1, V2) \
3759 fct_xchk(!fctstr_ieq((V1), (V2)),\
3760 "chk_neq_str: '%s' == '%s'",\
3761 (V1),\
3762 (V2)\
3763 )
3764
3765
3766#define fct_chk_endswith_str(STR, CHECK)\
3767 fct_xchk(fctstr_endswith((STR),(CHECK)),\
3768 "fct_chk_endswith_str: '%s' doesn't end with '%s'",\
3769 (STR),\
3770 (CHECK)\
3771 )
3772
3773
3774#define fct_chk_iendswith_str(STR, CHECK)\
3775 fct_xchk(fctstr_iendswith((STR), (CHECK)),\
3776 "fch_chk_iendswith_str: '%s' doesn't end with '%s'.",\
3777 (STR),\
3778 (CHECK)\
3779 )
3780
3781#define fct_chk_excl_str(STR, CHECK_EXCLUDE) \
3782 fct_xchk(!fctstr_incl((STR), (CHECK_EXCLUDE)),\
3783 "fct_chk_excl_str: '%s' is included in '%s'",\
3784 (STR),\
3785 (CHECK_EXCLUDE)\
3786 )
3787
3788#define fct_chk_excl_istr(ISTR, ICHECK_EXCLUDE) \
3789 fct_xchk(!fctstr_iincl((ISTR), (ICHECK_EXCLUDE)),\
3790 "fct_chk_excl_istr (case insensitive): '%s' is "\
3791 "included in'%s'",\
3792 (ISTR),\
3793 (ICHECK_EXCLUDE)\
3794 )
3795
3796#define fct_chk_incl_str(STR, CHECK_INCLUDE) \
3797 fct_xchk(fctstr_incl((STR), (CHECK_INCLUDE)),\
3798 "fct_chk_incl_str: '%s' does not include '%s'",\
3799 (STR),\
3800 (CHECK_INCLUDE)\
3801 )
3802
3803
3804#define fct_chk_incl_istr(ISTR, ICHECK_INCLUDE) \
3805 fct_xchk(fctstr_iincl((ISTR), (ICHECK_INCLUDE)),\
3806 "fct_chk_incl_istr (case insensitive): '%s' does "\
3807 "not include '%s'",\
3808 (ISTR),\
3809 (ICHECK_INCLUDE)\
3810 )
3811
3812
3813#define fct_chk_startswith_str(STR, CHECK)\
3814 fct_xchk(fctstr_startswith((STR), (CHECK)),\
3815 "'%s' does not start with '%s'",\
3816 (STR),\
3817 (CHECK)\
3818 )
3819
3820
3821#define fct_chk_startswith_istr(STR, CHECK)\
3822 fct_xchk(fctstr_istartswith((STR), (CHECK)),\
3823 "case insensitive check: '%s' does not start with '%s'",\
3824 (STR),\
3825 (CHECK)\
3826 )
3827
3828#define fct_chk_eq_int(V1, V2) \
3829 fct_xchk(\
3830 ((V1) == (V2)),\
3831 "chq_eq_int: %d != %d",\
3832 (V1),\
3833 (V2)\
3834 )
3835
3836
3837#define fct_chk_neq_int(V1, V2) \
3838 fct_xchk(\
3839 ((V1) != (V2)),\
3840 "chq_neq_int: %d == %d",\
3841 (V1),\
3842 (V2)\
3843 )
3844
3845#define fct_chk_ex(EXCEPTION, CODE) \
3846 { \
3847 bool pass_chk_ex = false; \
3848 try { \
3849 CODE; \
3850 pass_chk_ex = false; \
3851 } catch ( EXCEPTION ) { \
3852 pass_chk_ex = true; \
3853 } catch ( ... ) { \
3854 pass_chk_ex = false; \
3855 } \
3856 fct_xchk( \
3857 pass_chk_ex, \
3858 "%s exception not generated", \
3859 #EXCEPTION \
3860 ); \
3861 } \
3862
3863/*
3864---------------------------------------------------------
3865GUT CHECK MACROS
3866----------------------------------------------------------
3867
3868The following macros are used to help check the "guts" of
3869the FCT, and to confirm that it all works according to spec.
3870*/
3871
3872/* Generates a message to STDERR and exits the application with a
3873non-zero number. */
3874#define _FCT_GUTCHK(_CNDTN_) \
3875 if ( !(_CNDTN_) ) {\
3876 fprintf(stderr, "gutchk fail: '" #_CNDTN_ "' was not true.\n");\
3877 exit(1);\
3878 }\
3879 else {\
3880 fprintf(stdout, "gutchk pass: '" #_CNDTN_ "'\n");\
3881 }
3882
3883/*
3884---------------------------------------------------------
3885MULTI-FILE TEST SUITE MACROS
3886----------------------------------------------------------
3887
3888I struggled trying to figure this out in a way that was
3889as simple as possible. I wanted to be able to define
3890the test suite in one object file, then refer it within
3891the other one within the minimum amount of typing.
3892
3893Unfortunately without resorting to some supermacro
3894work, I could only find a happy comprimise.
3895
3896See test_multi.c for an example.
3897*/
3898
3899/* The following macros are used in your separate object
3900file to define your test suite. */
3901
3902
3903#define FCTMF_FIXTURE_SUITE_BGN(NAME) \
3904 void NAME (fctkern_t *fctkern_ptr__) {\
3905 FCT_REFERENCE_FUNCS();\
3906 FCT_FIXTURE_SUITE_BGN( NAME ) {
3907
3908#define FCTMF_FIXTURE_SUITE_END() \
3909 } FCT_FIXTURE_SUITE_END();\
3910 }
3911
3912#define FCTMF_SUITE_BGN(NAME) \
3913 void NAME (fctkern_t *fctkern_ptr__) {\
3914 FCT_REFERENCE_FUNCS();\
3915 FCT_SUITE_BGN( NAME ) {
3916#define FCTMF_SUITE_END() \
3917 } FCT_SUITE_END(); \
3918 }
3919
3920
3921/* Deprecated, no longer required. */
3922#define FCTMF_SUITE_DEF(NAME)
3923
3924
3925/* Executes a test suite defined by FCTMF_SUITE* */
3926#define FCTMF_SUITE_CALL(NAME) {\
3927 void NAME (fctkern_t *);\
3928 NAME (fctkern_ptr__);\
3929 }
3930
3931
3932/*
3933---------------------------------------------------------
3934FCT QUICK TEST API
3935----------------------------------------------------------
3936The goal of these little macros is to try and get you
3937up and running with a test as quick as possible.
3938
3939The basic idea is that there is one test per test suite.
3940*/
3941
3942#define FCT_QTEST_BGN(NAME) \
3943 FCT_SUITE_BGN(NAME) {\
3944 FCT_TEST_BGN(NAME) {\
3945
3946#define FCT_QTEST_END() \
3947 } FCT_TEST_END();\
3948 } FCT_SUITE_END();
3949
3950
3951#define FCT_QTEST_BGN_IF(_CONDITION_, _NAME_) \
3952 FCT_SUITE_BGN(_NAME_) {\
3953 FCT_TEST_BGN_IF(_CONDITION_, _NAME_) {\
3954
3955#define FCT_QTEST_END_IF() \
3956 } FCT_TEST_END_IF();\
3957 } FCT_SUITE_END();
3958
3959#endif /* !FCT_INCLUDED__IMB */