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