1 /*
2 ====================================================================
3 Copyright (c) 2008 Ian Blumel. All rights reserved.
4
5 FCTX (Fast C Test) Unit Testing Framework
6
7 Copyright (c) 2008, Ian Blumel (ian.blumel@gmail.com)
8 All rights reserved.
9
10 This license is based on the BSD License.
11
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
14 met:
15
16 * Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18
19 * Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in
21 the documentation and/or other materials provided with the
22 distribution.
23
24 * Neither the name of, Ian Blumel, nor the names of its
25 contributors may be used to endorse or promote products derived
26 from this software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
29 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
32 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
35 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ====================================================================
40
41 File: fct.h
42 */
43
44 #if !defined(FCT_INCLUDED__IMB)
45 #define FCT_INCLUDED__IMB
46
47 /* Configuration Values. You can over-ride these values in your own
48 header, then include this header. For example, in your file, myfct.h,
49
50 #define FCT_DEFAULT_LOGGER "standard"
51 #include "fct.h"
52
53 then if your unit tests included, myfct.h, you would default to work
54 with 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
109 because there is a inter-relationship between certain objects that
110 just can not be untwined. */
111 typedef struct _fct_logger_evt_t fct_logger_evt_t;
112 typedef struct _fct_logger_i fct_logger_i;
113 typedef struct _fct_logger_types_t fct_logger_types_t;
114 typedef struct _fct_standard_logger_t fct_standard_logger_t;
115 typedef struct _fct_junit_logger_t fct_junit_logger_t;
116 typedef struct _fct_minimal_logger_t fct_minimal_logger_t;
117 typedef struct _fctchk_t fctchk_t;
118 typedef struct _fct_test_t fct_test_t;
119 typedef struct _fct_ts_t fct_ts_t;
120 typedef struct _fctkern_t fctkern_t;
121
122 /* Forward declare some functions used throughout. */
123 static fct_logger_i*
124 fct_standard_logger_new(void);
125
126 static fct_logger_i*
127 fct_minimal_logger_new(void);
128
129 static fct_junit_logger_t *
130 fct_junit_logger_new(void);
131
132 static void
133 fct_logger__del(fct_logger_i *logger);
134
135 static void
136 fct_logger__on_chk(fct_logger_i *self, fctchk_t const *chk);
137
138 static void
139 fct_logger__on_test_start(fct_logger_i *logger, fct_test_t const *test);
140
141 static void
142 fct_logger__on_test_end(fct_logger_i *logger, fct_test_t *test);
143
144 static void
145 fct_logger__on_test_suite_start(fct_logger_i *logger, fct_ts_t const *ts);
146
147 static void
148 fct_logger__on_test_suite_end(fct_logger_i *logger, fct_ts_t const *ts);
149
150 static void
151 fct_logger__on_test_suite_skip(
152 fct_logger_i *logger,
153 char const *condition,
154 char const *name
155 );
156
157 static void
158 fct_logger__on_test_skip(
159 fct_logger_i *logger,
160 char const *condition,
161 char const *name
162 );
163
164
165 static void
166 fct_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
176 really only want to bother with this when we are "unwinding" the macros
177 for 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 --------------------------------------------------------
186 UTILITIES
187 --------------------------------------------------------
188 */
189
190
191 /* STDIO and STDERR redirect support */
192 #define FCT_PIPE_RESERVE_BYTES_DEFAULT 512
193 static int fct_stdout_pipe[2];
194 static int fct_stderr_pipe[2];
195 static int fct_saved_stdout;
196 static int fct_saved_stderr;
197
198 /* Platform indepedent pipe functions. TODO: Look to figure this out in a way
199 that 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
224 static void
fct_switch_std_to_buffer(int std_pipe[2],FILE * out,int fileno_,int * save_handle)225 fct_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
238 static void
fct_switch_std_to_std(FILE * out,int fileno_,int save_handle)239 fct_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
257 should be the length of DST plus the null-termintor. */
258 static void
fctstr_safe_cpy(char * dst,char const * src,size_t num)259 fctstr_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 */
273 static int
fct_vsnprintf(char * buffer,size_t buffer_len,char const * format,va_list args)274 fct_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. */
295 static int
fct_snprintf(char * buffer,size_t buffer_len,char const * format,...)296 fct_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
308 an out of memory condition. */
309 static char*
fctstr_clone(char const * s)310 fctstr_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. */
323 static char*
fctstr_clone_lower(char const * s)324 fctstr_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
344 against the test_str, to see if they both have the same starting
345 characters. If they do we return true, otherwise we return false. If the
346 prefix is a blank string or NULL, then it will return FCT_TRUE.*/
347 static nbool_t
fct_filter_pass(char const * prefix,char const * test_str)348 fct_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
393 http://publications.gbdirect.co.uk/c_book/chapter5/character_handling.html
394 */
395 static int
fctstr_eq(char const * s1,char const * s2)396 fctstr_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
419 static int
fctstr_ieq(char const * s1,char const * s2)420 fctstr_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
444 are handled, and NULL always INCLUDES NULL. This check is case
445 sensitive. If two strings point to the same place they are
446 included. */
447 static int
fctstr_incl(char const * str,char const * check_incl)448 fctstr_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. */
470 static int
fctstr_iincl(char const * str,char const * check_incl)471 fctstr_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
486 true. */
487 static int
fctstr_startswith(char const * str,char const * check)488 fctstr_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. */
506 static int
fctstr_istartswith(char const * str,char const * check)507 fctstr_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
521 check. Treats NULL as a blank string, and as such, will
522 pass the ends with (a blank string endswith a blank string). */
523 static int
fctstr_endswith(char const * str,char const * check)524 fctstr_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
555 static int
fctstr_iendswith(char const * str,char const * check)556 fctstr_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
589 STARTSWITH ........................................ END
590
591 effect. Assumes that the line will be maxwidth in characters. The
592 maxwidth can't be greater than FCT_DOTTED_MAX_LEN. */
593 #define FCT_DOTTED_MAX_LEN 256
594 static void
fct_dotted_line_start(size_t maxwidth,char const * startwith)595 fct_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
614 static void
fct_dotted_line_end(char const * endswith)615 fct_dotted_line_end(char const *endswith)
616 {
617 printf(" %s\n", endswith);
618 }
619
620
621 /*
622 --------------------------------------------------------
623 TIMER
624 --------------------------------------------------------
625 This is a low-res implementation at the moment.
626
627 We will improve this in the future, and isolate the
628 implementation from the rest of the code.
629 */
630
631 typedef struct _fct_timer_t fct_timer_t;
632 struct _fct_timer_t
633 {
634 clock_t start;
635 clock_t stop;
636 double duration;
637 };
638
639
640 static void
fct_timer__init(fct_timer_t * timer)641 fct_timer__init(fct_timer_t *timer)
642 {
643 FCT_ASSERT(timer != NULL);
644 memset(timer, 0, sizeof(fct_timer_t));
645 }
646
647
648 static void
fct_timer__start(fct_timer_t * timer)649 fct_timer__start(fct_timer_t *timer)
650 {
651 FCT_ASSERT(timer != NULL);
652 timer->start = clock();
653 }
654
655
656 static void
fct_timer__stop(fct_timer_t * timer)657 fct_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. */
666 static double
fct_timer__duration(fct_timer_t const * timer)667 fct_timer__duration(fct_timer_t const *timer)
668 {
669 FCT_ASSERT( timer != NULL );
670 return timer->duration;
671 }
672
673
674 /*
675 --------------------------------------------------------
676 GENERIC 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
684 at 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
688 to 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
709 the STL vector, where the array grows as more items are
710 appended. */
711 typedef struct _fct_nlist_t fct_nlist_t;
712 struct _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 };
723 typedef void (*fct_nlist_on_del_t)(void*);
724
725
726 /* Clears the contents of the list, and sets the list count to 0. The
727 actual count remains unchanged. If on_del is supplied it is executed
728 against each list element. */
729 static void
fct_nlist__clear(fct_nlist_t * list,fct_nlist_on_del_t on_del)730 fct_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
746 working with structures that live on the stack. */
747 static void
fct_nlist__final(fct_nlist_t * list,fct_nlist_on_del_t on_del)748 fct_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
756 static int
fct_nlist__init2(fct_nlist_t * list,size_t start_sz)757 fct_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.
783 Returns 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. */
789 static size_t
fct_nlist__size(fct_nlist_t const * list)790 fct_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. */
798 static void*
fct_nlist__at(fct_nlist_t const * list,size_t idx)799 fct_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
807 static void
fct_nlist__append(fct_nlist_t * list,void * itm)808 fct_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 -----------------------------------------------------------
834 A SINGLE CHECK
835 -----------------------------------------------------------
836 This defines a single check. It indicates what the check was,
837 and where it occurred. A "Test" object will have-a bunch
838 of "checks".
839 */
840
841 struct _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
865 static fctchk_t*
fctchk_new(int is_pass,char const * cndtn,char const * file,int lineno,char const * format,va_list args)866 fctchk_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
907 nothing. */
908 static void
fctchk__del(fctchk_t * chk)909 fctchk__del(fctchk_t *chk)
910 {
911 if ( chk == NULL )
912 {
913 return;
914 }
915 free( chk );
916 }
917
918
919 /*
920 -----------------------------------------------------------
921 A TEST
922 -----------------------------------------------------------
923 A suite will have-a list of tests. Where each test will have-a
924 list of failed and passed checks.
925 */
926
927 struct _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
949 static void
fct_test__del(fct_test_t * test)950 fct_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
962 static fct_test_t*
fct_test_new(char const * name)963 fct_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;
988 finally:
989 if ( !ok )
990 {
991 fct_test__del(test);
992 test =NULL;
993 }
994 return test;
995 }
996
997
998 static void
fct_test__start_timer(fct_test_t * test)999 fct_test__start_timer(fct_test_t *test)
1000 {
1001 FCT_ASSERT( test != NULL );
1002 fct_timer__start(&(test->timer));
1003 }
1004
1005
1006 static void
fct_test__stop_timer(fct_test_t * test)1007 fct_test__stop_timer(fct_test_t *test)
1008 {
1009 FCT_ASSERT( test != NULL );
1010 fct_timer__stop(&(test->timer));
1011 }
1012
1013
1014 static double
fct_test__duration(fct_test_t const * test)1015 fct_test__duration(fct_test_t const *test)
1016 {
1017 FCT_ASSERT( test != NULL );
1018 return fct_timer__duration(&(test->timer));
1019 }
1020
1021
1022 static nbool_t
fct_test__is_pass(fct_test_t const * test)1023 fct_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
1030 static void
fct_test__add(fct_test_t * test,fctchk_t * chk)1031 fct_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. */
1048 static size_t
fct_test__chk_cnt(fct_test_t const * test)1049 fct_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 -----------------------------------------------------------
1059 TEST SUITE (TS)
1060 -----------------------------------------------------------
1061 */
1062
1063
1064 /* The different types of 'modes' that a test suite can be in.
1065
1066 While the test suite is iterating through all the tests, its "State"
1067 can change from "setup mode", to "test mode" to "tear down" mode.
1068 These help to indicate what mode are currently in. Think of it as a
1069 basic FSM.
1070
1071 if the count was 0 end
1072 +--------->---------------------> ending_mode-----+-+
1073 | ^ |
1074 ^ | ^
1075 start | [if no more tests] |
1076 | | | |
1077 +-count_mode -> setup_mode -> test_mode -> teardown_mode->-+
1078 | ^ | |
1079 | +-----------<---------------+ |
1080 +----------->---[if fct_req fails]--------+
1081
1082 */
1083 enum 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. */
1095 typedef enum
1096 {
1097 fct_test_status_SUCCESS,
1098 fct_test_status_FAILURE
1099 } fct_test_status;
1100
1101
1102 struct _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
1130 there 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
1139 static void
fct_ts__del(fct_ts_t * ts)1140 fct_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
1150 static fct_ts_t *
fct_ts_new(char const * name)1151 fct_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
1165 static nbool_t
fct_ts__is_more_tests(fct_ts_t const * ts)1166 fct_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. */
1175 static void
fct_ts__test_begin(fct_ts_t * ts)1176 fct_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
1184 generation. */
1185 static void
fct_ts__add_test(fct_ts_t * ts,fct_test_t * test)1186 fct_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
1195 static void
fct_ts__test_end(fct_ts_t * ts)1196 fct_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. */
1205 static void
fct_ts__inc_total_test_num(fct_ts_t * ts)1206 fct_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
1216 setup mode. You must be already in setup mode for this to work! */
1217 static void
fct_ts__setup_end(fct_ts_t * ts)1218 fct_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
1227 static fct_test_t *
fct_ts__make_abort_test(fct_ts_t * ts)1228 fct_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). */
1237 static void
fct_ts__setup_abort(fct_ts_t * ts)1238 fct_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
1245 into setup mode (for the next 'iteration'). */
1246 static void
fct_ts__teardown_end(fct_ts_t * ts)1247 fct_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.
1268 Consider the special case when a test suite has NO tests in it, in
1269 that case we will have a current count that is zero, in which case
1270 we can skip right to 'ending'. */
1271 static void
fct_ts__cnt_end(fct_ts_t * ts)1272 fct_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
1288 static nbool_t
fct_ts__is_test_cnt(fct_ts_t const * ts,int test_num)1289 fct_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. */
1304 static size_t
fct_ts__tst_cnt(fct_ts_t const * ts)1305 fct_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. */
1317 static size_t
fct_ts__tst_cnt_passed(fct_ts_t const * ts)1318 fct_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. */
1338 static size_t
fct_ts__chk_cnt(fct_ts_t const * ts)1339 fct_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. */
1354 static double
fct_ts__duration(fct_ts_t const * ts)1355 fct_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 --------------------------------------------------------
1370 FCT COMMAND LINE OPTION INITIALIZATION (fctcl_init)
1371 --------------------------------------------------------
1372
1373 Structure used for command line initialization. To keep it clear that we do
1374 not delete the char*'s present on this structure.
1375 */
1376
1377
1378 typedef enum
1379 {
1380 FCTCL_STORE_UNDEFINED,
1381 FCTCL_STORE_TRUE,
1382 FCTCL_STORE_VALUE
1383 } fctcl_store_t;
1384
1385
1386 typedef 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 --------------------------------------------------------
1407 FCT COMMAND LINE OPTION (fctcl)
1408 --------------------------------------------------------
1409
1410 Specifies the command line configuration options. Use this
1411 to help initialize the fct_clp (command line parser).
1412 */
1413
1414
1415 /* Handy strings for storing "true" and "false". We can reference
1416 these strings throughout the parse operation and not have to
1417 worry about dealing with memory. */
1418 #define FCTCL_TRUE_STR "1"
1419
1420
1421 typedef 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
1441 static void
fctcl__del(fctcl_t * clo)1442 fctcl__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
1468 static fctcl_t*
fctcl_new2(fctcl_init_t const * clo_init)1469 fctcl_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;
1519 finally:
1520 if ( !ok )
1521 {
1522 fctcl__del(clone);
1523 clone = NULL;
1524 }
1525 return clone;
1526 }
1527
1528
1529 static int
fctcl__is_option(fctcl_t const * clo,char const * option)1530 fctcl__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 --------------------------------------------------------
1551 FCT COMMAND PARSER (fct_clp)
1552 --------------------------------------------------------
1553 */
1554
1555 #define FCT_CLP_MAX_ERR_MSG_LEN 256
1556
1557 typedef 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
1570 static void
fct_clp__final(fct_clp_t * clp)1571 fct_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. */
1579 static int
fct_clp__add_options(fct_clp_t * clp,fctcl_init_t const * options)1580 fct_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;
1595 finally:
1596 return ok;
1597 }
1598
1599 /* Returns false if we ran out of memory. */
1600 static int
fct_clp__init(fct_clp_t * clp,fctcl_init_t const * options)1601 fct_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;
1626 finally:
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
1636 fct_clp__get_error to figure out if something went awry. */
1637 static void
fct_clp__parse(fct_clp_t * clp,int argc,char const * argv[])1638 fct_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
1730 static fctcl_t const*
fct_clp__get_clo(fct_clp_t const * clp,char const * option)1731 fct_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.
1753 If the value wasn't parsed, the DEFAULT_VAL is returned instead. */
1754 static char const*
fct_clp__optval2(fct_clp_t * clp,char const * option,char const * default_val)1755 fct_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. */
1771 static int
fct_clp__is_param(fct_clp_t * clp,char const * param)1772 fct_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
1800 its 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.
1806 Use 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 --------------------------------------------------------
1814 FCT NAMESPACE
1815 --------------------------------------------------------
1816
1817 The macros below start to pollute the watch window with
1818 lots of "system" variables. This NAMESPACE is an
1819 attempt to hide all the "system" variables in one place.
1820 */
1821 typedef 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
1842 static void
fct_namespace_init(fct_namespace_t * ns)1843 fct_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 --------------------------------------------------------
1852 FCT KERNAL
1853 --------------------------------------------------------
1854
1855 The "fctkern" is a singleton that is defined throughout the
1856 system.
1857 */
1858
1859 struct _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"
1904 static 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
1930 typedef fct_logger_i* (*fct_logger_new_fn)(void);
1931 struct _fct_logger_types_t
1932 {
1933 char const *name;
1934 fct_logger_new_fn logger_new_fn;
1935 char const *desc;
1936 };
1937
1938 static 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
1963 static void
fctkern__add_logger(fctkern_t * nk,fct_logger_i * logger_owns)1964 fctkern__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
1972 static void
fctkern__write_help(fctkern_t * nk,FILE * out)1973 fctkern__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
2017 be executed or not. If the test starts with the same characters as
2018 the prefix, then it should be "runnable". The prefix filter must be
2019 a non-NULL, non-Blank string. */
2020 static void
fctkern__add_prefix_filter(fctkern_t * nk,char const * prefix_filter)2021 fctkern__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. */
2038 static void
fctkern__final(fctkern_t * nk)2039 fctkern__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
2056 static int
fctkern__cl_is(fctkern_t * nk,char const * opt_str)2057 fctkern__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
2066 at the command line, DEF_STR is returned (you can use NULL for the DEF_STR).
2067 The result returned should not be mofidied, and MAY even be the same pointer
2068 to DEF_STR. */
2069 static char const *
fctkern__cl_val2(fctkern_t * nk,char const * opt_str,char const * def_str)2070 fctkern__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.
2082 May return NULL if the name doesn't exist in the list. */
2083 static fct_logger_i*
fckern_sel_log(fct_logger_types_t * search,char const * sel_logger)2084 fckern_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
2100 static int
fctkern__cl_parse_config_logger(fctkern_t * nk)2101 fctkern__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
2132 set of options. Returns -1 if you are to abort with EXIT_SUCCESS, returns
2133 0 if you are to abort with EXIT_FAILURE and returns 1 if you are to continue. */
2134 static int
fctkern__cl_parse(fctkern_t * nk)2135 fctkern__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;
2193 finally:
2194 return status;
2195 }
2196
2197
2198
2199 /* Parses the command line and sets up the framework. The argc and argv
2200 should be directly from the program's main. */
2201 static int
fctkern__init(fctkern_t * nk,int argc,const char * argv[])2202 fctkern__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
2227 its contents. This way we can build up all kinds of summaries at the end
2228 of a run. */
2229 static void
fctkern__add_ts(fctkern_t * nk,fct_ts_t * ts)2230 fctkern__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
2239 this test suite. If there are no filters, we return FCT_TRUE always. */
2240 static nbool_t
fctkern__pass_filter(fctkern_t * nk,char const * test_name)2241 fctkern__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. */
2276 static size_t
fctkern__tst_cnt(fctkern_t const * nk)2277 fctkern__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. */
2291 static size_t
fctkern__tst_cnt_passed(fctkern_t const * nk)2292 fctkern__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)
2314 static size_t
fctkern__chk_cnt(fctkern_t const * nk)2315 fctkern__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
2334 static void
fctkern__log_suite_start(fctkern_t * nk,fct_ts_t const * ts)2335 fctkern__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
2347 static void
fctkern__log_suite_end(fctkern_t * nk,fct_ts_t const * ts)2348 fctkern__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
2360 static void
fctkern__log_suite_skip(fctkern_t * nk,char const * condition,char const * name)2361 fctkern__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
2375 static void
fctkern__log_test_skip(fctkern_t * nk,char const * condition,char const * name)2376 fctkern__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.
2387 a condition). */
2388 static void
fctkern__log_chk(fctkern_t * nk,fctchk_t const * chk)2389 fctkern__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. */
2402 static void
fctkern__log_warn(fctkern_t * nk,char const * warn)2403 fctkern__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. */
2416 static void
fctkern__log_test_start(fctkern_t * nk,fct_test_t const * test)2417 fctkern__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
2429 static void
fctkern__log_test_end(fctkern_t * nk,fct_test_t * test)2430 fctkern__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 -----------------------------------------------------------
2466 LOGGER INTERFACE
2467
2468 Defines an interface to a logging system. A logger
2469 must define the following functions in order to hook
2470 into the logging system.
2471
2472 See the "Standard Logger" and "Minimal Logger" as examples
2473 of the implementation.
2474 -----------------------------------------------------------
2475 */
2476
2477 /* Common event argument. The values of the each event may or may not be
2478 defined depending on the event in question. */
2479 struct _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
2491 typedef 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
2559 struct _fct_logger_i
2560 {
2561 _fct_logger_head;
2562 };
2563
2564
2565 static void
fct_logger__stub(fct_logger_i * l,fct_logger_evt_t const * e)2566 fct_logger__stub(fct_logger_i *l, fct_logger_evt_t const *e)
2567 {
2568 fct_unused(l);
2569 fct_unused(e);
2570 }
2571
2572
2573 static 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
2590 standard values. */
2591 static void
fct_logger__init(fct_logger_i * logger)2592 fct_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
2603 static void
fct_logger__del(fct_logger_i * logger)2604 fct_logger__del(fct_logger_i *logger)
2605 {
2606 if ( logger )
2607 {
2608 logger->vtable.on_delete(logger, &(logger->evt));
2609 }
2610 }
2611
2612
2613 static void
fct_logger__on_test_start(fct_logger_i * logger,fct_test_t const * test)2614 fct_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
2621 static void
fct_logger__on_test_end(fct_logger_i * logger,fct_test_t * test)2622 fct_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
2629 static void
fct_logger__on_test_suite_start(fct_logger_i * logger,fct_ts_t const * ts)2630 fct_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
2637 static void
fct_logger__on_test_suite_end(fct_logger_i * logger,fct_ts_t const * ts)2638 fct_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
2645 static void
fct_logger__on_test_suite_skip(fct_logger_i * logger,char const * condition,char const * name)2646 fct_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
2658 static void
fct_logger__on_test_skip(fct_logger_i * logger,char const * condition,char const * name)2659 fct_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
2671 static void
fct_logger__on_chk(fct_logger_i * logger,fctchk_t const * chk)2672 fct_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
2690 static void
fct_logger__on_warn(fct_logger_i * logger,char const * msg)2691 fct_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
2699 chk should be a failure before we call this, and the list is a list
2700 of char*'s that will eventually be free'd by the logger. */
2701 static void
fct_logger_record_failure(fctchk_t const * chk,fct_nlist_t * fail_list)2702 fct_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. */
2722 static void
fct_logger_print_failures(fct_nlist_t const * fail_list)2723 fct_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 -----------------------------------------------------------
2743 MINIMAL LOGGER
2744 -----------------------------------------------------------
2745
2746 At the moment the MINIMAL LOGGER is currently disabled. Hope
2747 to bring it back online soon. The only reason it is
2748 disabled is that we don't currently have the ability to specify
2749 loggers.
2750 */
2751
2752
2753 /* Minimal logger, reports the minimum amount of information needed
2754 to determine "something is happening". */
2755 struct _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
2763 static void
fct_minimal_logger__on_chk(fct_logger_i * self_,fct_logger_evt_t const * e)2764 fct_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
2782 static void
fct_minimal_logger__on_fctx_end(fct_logger_i * self_,fct_logger_evt_t const * e)2783 fct_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
2797 static void
fct_minimal_logger__on_delete(fct_logger_i * self_,fct_logger_evt_t const * e)2798 fct_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
2811 fct_logger_i*
fct_minimal_logger_new(void)2812 fct_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 -----------------------------------------------------------
2831 STANDARD LOGGER
2832 -----------------------------------------------------------
2833 */
2834
2835 struct _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
2851 them when the log "finishes" up. */
2852 static void
fct_standard_logger__on_chk(fct_logger_i * logger_,fct_logger_evt_t const * e)2853 fct_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
2867 static void
fct_standard_logger__on_test_skip(fct_logger_i * logger_,fct_logger_evt_t const * e)2868 fct_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
2885 static void
fct_standard_logger__on_test_start(fct_logger_i * logger_,fct_logger_evt_t const * e)2886 fct_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
2899 static void
fct_standard_logger__on_test_end(fct_logger_i * logger_,fct_logger_evt_t const * e)2900 fct_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
2912 static void
fct_standard_logger__on_fctx_start(fct_logger_i * logger_,fct_logger_evt_t const * e)2913 fct_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
2924 static void
fct_standard_logger__on_fctx_end(fct_logger_i * logger_,fct_logger_evt_t const * e)2925 fct_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
2968 static void
fct_standard_logger__on_delete(fct_logger_i * logger_,fct_logger_evt_t const * e)2969 fct_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
2982 static void
fct_standard_logger__on_warn(fct_logger_i * logger_,fct_logger_evt_t const * e)2983 fct_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
2993 fct_logger_i*
fct_standard_logger_new(void)2994 fct_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 -----------------------------------------------------------
3020 JUNIT LOGGER
3021 -----------------------------------------------------------
3022 */
3023
3024
3025 /* JUnit logger */
3026 struct _fct_junit_logger_t
3027 {
3028 _fct_logger_head;
3029 };
3030
3031
3032 static void
fct_junit_logger__on_test_suite_start(fct_logger_i * l,fct_logger_evt_t const * e)3033 fct_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
3045 static void
fct_junit_logger__on_test_suite_end(fct_logger_i * logger_,fct_logger_evt_t const * e)3046 fct_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
3147 static void
fct_junit_logger__on_fct_start(fct_logger_i * logger_,fct_logger_evt_t const * e)3148 fct_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
3159 static void
fct_junit_logger__on_fctx_end(fct_logger_i * logger_,fct_logger_evt_t const * e)3160 fct_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
3170 static void
fct_junit_logger__on_delete(fct_logger_i * logger_,fct_logger_evt_t const * e)3171 fct_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
3183 fct_junit_logger_t *
fct_junit_logger_new(void)3184 fct_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 ------------------------------------------------------------
3204 MACRO MAGIC
3205 ------------------------------------------------------------
3206 This is where the show begins!
3207 */
3208
3209 /* This macro invokes a bunch of functions that need to be referenced in
3210 order to avoid a "unreferenced local function has been removed" warning.
3211 The logical acrobatics below try and make it appear to the compiler that
3212 they 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
3298 to _NUM_FAILS_. If you the expected matches the actual, a 0 value is returned
3299 from 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
3312 that lives throughout the lifetime of our program. The
3313 fctkern_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
3327 made in order allow strict compilers to pass when it encounters unreferenced
3328 functions. */
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
3342 options. */
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
3373 test fixture. This allows the user to possibly add their own parse
3374 specification. */
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
3455 do 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
3470 typedef 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
3490 first determine if the test is the "current" count. Then we have to determine
3491 if we can pass the filter. Finally we will execute everything so that when a
3492 check fails, we can "break" out to the end of the test. And in between all
3493 that we do a memory check and fail a test if we can't build a fct_test
3494 object (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 ---------------------------------------------------------
3550 CHECKING MACROS
3551 ----------------------------------------------------------
3552
3553 The chk variants will continue on while the req variants will abort
3554 a test if a chk condition fails. The req variants are useful when you
3555 no longer want to keep checking conditions because a critical condition
3556 is not being met. */
3557
3558
3559 /* To support older compilers that do not have macro variable argument lists
3560 we have to use a function. The macro manages to store away the line/file
3561 location into a global before it runs this function, a trick I picked up from
3562 the error handling in the APR library. The unfortunate thing is that we can
3563 not carry forth the actual test through a "stringize" operation, but if you
3564 wanted to do that you should use fct_chk. */
3565
3566 static int fct_xchk_lineno =0;
3567 static char const *fct_xchk_file = NULL;
3568 static fct_test_t *fct_xchk_test = NULL;
3569 static fctkern_t *fct_xchk_kern =NULL;
3570
3571
3572 static int
_fct_xchk_fn_varg(char const * condition,int is_pass,char const * format,va_list args)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);
3597 finally:
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
3606 static int
fct_xchk2_fn(const char * condition,int is_pass,char const * format,...)3607 fct_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
3618 static int
fct_xchk_fn(int is_pass,char const * format,...)3619 fct_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
3634 the bulk of this macro presets some globals to allow us to support
3635 variable argument lists on older compilers. The idea came from the APR
3636 libraries 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
3651 if 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
3659 with. 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
3715 in NULL to strlen, we will filter the predicate through these little
3716 functions */
3717 static int
_fct_chk_empty_str(char const * s)3718 _fct_chk_empty_str(char const *s)
3719 {
3720 if ( s == NULL )
3721 {
3722 return 1;
3723 }
3724 return strlen(s) ==0;
3725 }
3726 static int
_fct_chk_full_str(char const * s)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 ---------------------------------------------------------
3865 GUT CHECK MACROS
3866 ----------------------------------------------------------
3867
3868 The following macros are used to help check the "guts" of
3869 the 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
3873 non-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 ---------------------------------------------------------
3885 MULTI-FILE TEST SUITE MACROS
3886 ----------------------------------------------------------
3887
3888 I struggled trying to figure this out in a way that was
3889 as simple as possible. I wanted to be able to define
3890 the test suite in one object file, then refer it within
3891 the other one within the minimum amount of typing.
3892
3893 Unfortunately without resorting to some supermacro
3894 work, I could only find a happy comprimise.
3895
3896 See test_multi.c for an example.
3897 */
3898
3899 /* The following macros are used in your separate object
3900 file 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 ---------------------------------------------------------
3934 FCT QUICK TEST API
3935 ----------------------------------------------------------
3936 The goal of these little macros is to try and get you
3937 up and running with a test as quick as possible.
3938
3939 The 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 */
3960