LCOV - code coverage report
Current view: top level - unit_tests - clove-unit.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 43.7 % 1930 844
Test Date: 2025-08-24 13:31:38 Functions: 51.8 % 224 116

            Line data    Source code
       1              : /*
       2              :  * clove-unit
       3              :  * v2.4.6
       4              :  * Single-Header Unit Testing library for C/C++
       5              :  * https://github.com/fdefelici/clove-unit
       6              :  *
       7              :  */
       8              : #ifndef __CLOVE_H
       9              : #define __CLOVE_H
      10              : 
      11              : #define __CLOVE_VERSION_MAJOR 2
      12              : #define __CLOVE_VERSION_MINOR 4
      13              : #define __CLOVE_VERSION_PATCH 6
      14              : #define __CLOVE_VERSION "2.4.6"
      15              : 
      16              : //Preventing "unknown-pragmas" warning on GCC <= 12 for '#pragma region' usage
      17              : //NOTE1: GCC and G++ v13+ support '#pragma region' by the way.
      18              : //NOTE2: This workaround doesn't work for G++ version <= 12 because of a bug 
      19              : //       that has been addressed only in G++ v13 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431)
      20              : #if defined(__GNUC__) && __GNUC__ <= 12 // GNU Unknown Pragma Fix: START
      21              : #pragma GCC diagnostic push
      22              : #pragma GCC diagnostic ignored "-Wunknown-pragmas"
      23              : #endif 
      24              : 
      25              : #pragma region PRIVATE
      26              : 
      27              : #pragma region PRIVATE - Target Init
      28              : #ifdef __linux
      29              : #ifndef _GNU_SOURCE
      30              : #define _GNU_SOURCE
      31              : #endif //_GNU_SOURCE
      32              : #endif //__linux
      33              : 
      34              : #ifdef __cplusplus
      35              : #define __CLOVE_EXTERN_C extern "C"
      36              : #else
      37              : #define __CLOVE_EXTERN_C
      38              : #endif //__cplusplus
      39              : #pragma endregion // Target Init
      40              : 
      41              : #pragma region PRIVATE - DECLARATION
      42              : #pragma region PRIVATE - Utils Decl
      43              : #include <stdio.h>
      44              : __CLOVE_EXTERN_C void  __clove_utils_empty_funct(void);
      45              : 
      46              : extern char* __clove_exec_abs_path;
      47              : extern char* __clove_exec_abs_basepath;
      48              : __CLOVE_EXTERN_C const char* __clove_utils_get_exec_abs_path(void);
      49              : __CLOVE_EXTERN_C const char* __clove_utils_get_exec_abs_basepath(void);
      50              : 
      51              : //Switch implementation for pointer types
      52              : #define __CLOVE_SWITCH_BEG(X) \
      53              :     { \
      54              :         size_t* expr = (size_t*)(size_t)X; \
      55              :         if (false)  { }
      56              : #define __CLOVE_SWITCH_CASE(Y) \
      57              :     else if (expr == (size_t*)(size_t)Y)
      58              : #define __CLOVE_SWITCH_DEFAULT() \
      59              :     else 
      60              : #define __CLOVE_SWITCH_END() }
      61              : 
      62              : //Custom suppressing "unused parameter" warnings for multi-compilers
      63              : #define __CLOVE_UNUSED_VAR(x) (void)(x)
      64              : 
      65              : #define __CLOVE_MACRO_COMBINE_INTERNAL(A, B) A##B
      66              : #define __CLOVE_MACRO_COMBINE(A, B) __CLOVE_MACRO_COMBINE_INTERNAL(A, B)
      67              : #pragma endregion // Utils Decl
      68              : 
      69              : #pragma region PRIVATE - Math Decl
      70              : //mainly math header operations re-implemented to avoid explicit linking to math library on unix os (with option -lm).
      71              : __CLOVE_EXTERN_C unsigned int __clove_math_powi(unsigned int base, unsigned int exp);
      72              : __CLOVE_EXTERN_C float __clove_math_decimalf(unsigned char precision);
      73              : __CLOVE_EXTERN_C double __clove_math_decimald(unsigned char precision);
      74              : #pragma endregion
      75              : 
      76              : #pragma region PRIVATE - Path Decl
      77              : #include <stdbool.h>
      78              : 
      79              : #ifdef _WIN32
      80              : #define __CLOVE_PATH_SEPARATOR '\\'
      81              : #define __CLOVE_PATH_SEPARATOR_STR "\\"
      82              : #else 
      83              : #define __CLOVE_PATH_SEPARATOR '/'
      84              : #define __CLOVE_PATH_SEPARATOR_STR "/"
      85              : #endif //_WIN32
      86              : 
      87              : __CLOVE_EXTERN_C char* __clove_path_concat(const char* path1, const char* path2, const char separator);
      88              : __CLOVE_EXTERN_C const char* __clove_path_relative(const char* abs_path, const char* base_path);
      89              : __CLOVE_EXTERN_C char* __clove_path_rel_to_abs_exec_path(const char* rel_path);
      90              : __CLOVE_EXTERN_C bool __clove_path_is_relative(const char* path);
      91              : __CLOVE_EXTERN_C bool __clove_path_is_absolute(const char* path);
      92              : __CLOVE_EXTERN_C void __clove_path_to_os(char* path);
      93              : __CLOVE_EXTERN_C char* __clove_path_basepath(const char* path);
      94              : __CLOVE_EXTERN_C bool __clove_path_exists(const char* path);
      95              : __CLOVE_EXTERN_C char* __clove_path_to_absolute(const char* path);
      96              : #pragma endregion // Path Decl
      97              : 
      98              : #pragma region PRIVATE - Memory Decl
      99              : __CLOVE_EXTERN_C void* __clove_memory_malloc(size_t size);
     100              : __CLOVE_EXTERN_C void* __clove_memory_calloc(size_t size);
     101              : __CLOVE_EXTERN_C void* __clove_memory_realloc(void* source, size_t size);
     102              : __CLOVE_EXTERN_C bool __clove_memory_memcpy(void* dest, size_t dest_size, const void* src, size_t src_size);
     103              : __CLOVE_EXTERN_C bool __clove_memory_memset(void* dest, size_t size, unsigned char value);
     104              : __CLOVE_EXTERN_C void __clove_memory_free(void* source);
     105              : 
     106              : #define __CLOVE_MEMORY_MALLOC_TYPE_N(TYPE, COUNT) (TYPE*)__clove_memory_malloc(sizeof(TYPE) * COUNT)
     107              : #define __CLOVE_MEMORY_MALLOC_TYPE(TYPE) __CLOVE_MEMORY_MALLOC_TYPE_N(TYPE, 1)
     108              : 
     109              : #define __CLOVE_MEMORY_CALLOC_TYPE_N(TYPE, COUNT) (TYPE*)__clove_memory_calloc(sizeof(TYPE) * COUNT)
     110              : #define __CLOVE_MEMORY_CALLOC_TYPE(TYPE) __CLOVE_MEMORY_CALLOC_TYPE_N(TYPE, 1)
     111              : #pragma endregion //Memory Decl
     112              : 
     113              : #pragma region PRIVATE - Console Decl
     114              : #include <stdarg.h>
     115              : __CLOVE_EXTERN_C void __clove_console_printf(const char* format, ...);
     116              : __CLOVE_EXTERN_C void __clove_console_vprintf(const char* format, va_list args);
     117              : __CLOVE_EXTERN_C void __clove_console_write(const char* str);
     118              : __CLOVE_EXTERN_C void __clove_console_writeline(const char* str);
     119              : #pragma endregion //Console Decl
     120              : 
     121              : #pragma region PRIVATE - File Decl
     122              : #include <stdarg.h>
     123              : __CLOVE_EXTERN_C FILE* __clove_file_open(const char* path, const char* mode);
     124              : __CLOVE_EXTERN_C void __clove_file_close(FILE* file);
     125              : __CLOVE_EXTERN_C void __clove_file_printf(FILE* file, const char* format, ...);
     126              : __CLOVE_EXTERN_C void __clove_file_vprintf(FILE* file, const char* format, va_list args);
     127              : __CLOVE_EXTERN_C void __clove_file_write(FILE* file, const char* str);
     128              : __CLOVE_EXTERN_C void __clove_file_writeline(FILE* file, const char* str);
     129              : #pragma endregion //File Decl
     130              : 
     131              : #pragma region PRIVATE - String Decl
     132              : #include <stdbool.h>
     133              : __CLOVE_EXTERN_C bool __clove_string_equal(const char* str1, const char* str2);
     134              : __CLOVE_EXTERN_C bool __clove_string_equal_any(const char* str1, size_t count, ...);
     135              : __CLOVE_EXTERN_C bool __clove_string_startswith(const char* str1, const char* prefix);
     136              : __CLOVE_EXTERN_C bool __clove_string_endswith(const char* str1, const char* suffix);
     137              : __CLOVE_EXTERN_C bool __clove_string_strncmp(const char* str1, const char* str2, size_t count);
     138              : __CLOVE_EXTERN_C bool __clove_string_strcpy(char* dest, size_t dest_size, const char* source);
     139              : __CLOVE_EXTERN_C bool __clove_string_strncpy(char* dest, size_t dest_size, const char* source, size_t count);
     140              : __CLOVE_EXTERN_C bool __clove_string_strcat(char* dest, size_t dest_size, const char* source);
     141              : __CLOVE_EXTERN_C bool __clove_string_strncat(char* dest, size_t dest_size, const char* source, size_t count);
     142              : __CLOVE_EXTERN_C char* __clove_string_strdup(const char* str);
     143              : __CLOVE_EXTERN_C void __clove_string_sprintf(char* dest, size_t dest_size, const char* format, ...);
     144              : __CLOVE_EXTERN_C void __clove_string_vsprintf(char* dest, size_t dest_size, const char* format, va_list args);
     145              : __CLOVE_EXTERN_C size_t __clove_string_length(const char* str);
     146              : __CLOVE_EXTERN_C const char* __clove_string_strstr(const char* str1, const char* str2);
     147              : __CLOVE_EXTERN_C bool __clove_string_contains(const char* string, const char* contained);
     148              : __CLOVE_EXTERN_C char* __clove_string_escape(const char* string);
     149              : __CLOVE_EXTERN_C char* __clove_string_csv_escape(const char* string);
     150              : __CLOVE_EXTERN_C void __clove_string_ellipse(const char* string, size_t str_len, size_t pos, char* out, size_t out_size);
     151              : __CLOVE_EXTERN_C void __clove_string_replace_char(char* path, char find, char replace);
     152              : __CLOVE_EXTERN_C void __clove_string_pad_right(char* dest, size_t dest_size, size_t str_target_len);
     153              : __CLOVE_EXTERN_C int  __clove_string_last_indexof(const char* source, char character);
     154              : #pragma endregion // String Decl
     155              : 
     156              : #pragma region PRIVATE - String View Decl
     157              : #include <stdbool.h>
     158              : typedef struct __clove_string_view_t  {
     159              :     const char* begin;
     160              :     size_t length;
     161              : } __clove_string_view_t;
     162              : 
     163              : __CLOVE_EXTERN_C __clove_string_view_t __clove_string_view_from_offs(const char* source, size_t begin_offset, size_t end_offset);
     164              : __CLOVE_EXTERN_C __clove_string_view_t __clove_string_view_from_be(const char* begin, const char* end);
     165              : __CLOVE_EXTERN_C __clove_string_view_t __clove_string_view_from_len(const char* begin, size_t length);
     166              : __CLOVE_EXTERN_C __clove_string_view_t __clove_string_view_from_str(const char* str);
     167              : __CLOVE_EXTERN_C size_t __clove_string_view_length(const __clove_string_view_t* view);
     168              : __CLOVE_EXTERN_C bool __clove_string_view_equals(const __clove_string_view_t* view1, const __clove_string_view_t* view2);
     169              : __CLOVE_EXTERN_C bool __clove_string_view_ncmp(const __clove_string_view_t* view1, const __clove_string_view_t* view2, size_t count);
     170              : __CLOVE_EXTERN_C bool __clove_string_view_endswith(const __clove_string_view_t* view, const __clove_string_view_t* suffix);
     171              : __CLOVE_EXTERN_C bool __clove_string_view_nendswith(const __clove_string_view_t* view, const __clove_string_view_t* suffix, size_t suffix_begin_offset);
     172              : __CLOVE_EXTERN_C bool __clove_string_view_strequals(const __clove_string_view_t* view, const char* str);
     173              : __CLOVE_EXTERN_C const char* __clove_string_view_begin(const __clove_string_view_t* view);
     174              : __CLOVE_EXTERN_C const char* __clove_string_view_end(const __clove_string_view_t* view);
     175              : __CLOVE_EXTERN_C char* __clove_string_view_as_string(const __clove_string_view_t* view);
     176              : __CLOVE_EXTERN_C char __clove_string_view_at(const __clove_string_view_t* view, size_t index);
     177              : __CLOVE_EXTERN_C bool __clove_string_view_contains(const __clove_string_view_t* view, const __clove_string_view_t* fixture);
     178              : #pragma endregion // String View Decl
     179              : 
     180              : #pragma region PRIVATE - Time Decl
     181              : typedef enum __clove_time_translation_e {
     182              :     __CLOVE_TIME_TRANSL_NANOS_PER_SEC = 1000000000, //1 BILLION
     183              :     __CLOVE_TIME_TRANSL_MILLIS_PER_SEC = 1000,
     184              :     __CLOVE_TIME_TRANSL_NANOS_PER_MILLIS = 1000000 //1 MILLION
     185              : } __clove_time_translation_e;
     186              : 
     187              : typedef struct __clove_time_t {
     188              :     long long seconds;
     189              :     long long nanos_after_seconds;
     190              : } __clove_time_t;
     191              : 
     192              : __CLOVE_EXTERN_C __clove_time_t __clove_time_now(void);
     193              : __CLOVE_EXTERN_C __clove_time_t __clove_time_sub(__clove_time_t* t1, __clove_time_t* t2);
     194              : __CLOVE_EXTERN_C __clove_time_t __clove_time_sum(__clove_time_t* t1, __clove_time_t* t2);
     195              : __CLOVE_EXTERN_C unsigned long long __clove_time_to_millis(__clove_time_t* t);
     196              : __CLOVE_EXTERN_C unsigned long long __clove_time_to_nanos(__clove_time_t* t);
     197              : #pragma endregion // Time Decl
     198              : 
     199              : #pragma region PRIVATE - Stack Decl
     200              : //Stack isn't generalized. By now just managing size_t items by implementing Iterative QuickSort
     201              : typedef struct __clove_stack_t {
     202              :     unsigned char* items;
     203              :     size_t capacity;
     204              :     size_t count;
     205              :     size_t item_size;
     206              : } __clove_stack_t;
     207              : 
     208              : __CLOVE_EXTERN_C void __clove_stack_init(__clove_stack_t* stack, size_t initial_capacity);
     209              : __CLOVE_EXTERN_C bool __clove_stack_is_empty(__clove_stack_t* stack);
     210              : __CLOVE_EXTERN_C void __clove_stack_push(__clove_stack_t* stack, size_t item);
     211              : __CLOVE_EXTERN_C size_t __clove_stack_pop(__clove_stack_t* stack);
     212              : __CLOVE_EXTERN_C void __clove_stack_free(__clove_stack_t* stack);
     213              : #pragma endregion // Stack Decl
     214              : 
     215              : #pragma region PRIVATE - Vector Decl
     216              : typedef struct __clove_vector_params_t {
     217              :     size_t item_size;
     218              :     size_t initial_capacity;
     219              :     void (*item_ctor)(void*);
     220              :     void (*item_dtor)(void*);
     221              : } __clove_vector_params_t;
     222              : 
     223              : typedef struct __clove_vector_t {
     224              :     unsigned char* items;
     225              :     size_t capacity;
     226              :     size_t count;
     227              :     size_t item_size;
     228              :     void (*item_ctor)(void*);
     229              :     void (*item_dtor)(void*);
     230              :     void* swap_temp;
     231              : } __clove_vector_t;
     232              : 
     233              : __CLOVE_EXTERN_C __clove_vector_params_t __clove_vector_params_defaulted(size_t item_size);
     234              : __CLOVE_EXTERN_C __clove_vector_t __clove_vector_null(void);
     235              : __CLOVE_EXTERN_C void __clove_vector_init(__clove_vector_t* vector, __clove_vector_params_t* params);
     236              : __CLOVE_EXTERN_C size_t __clove_vector_count(const __clove_vector_t* vector);
     237              : __CLOVE_EXTERN_C bool __clove_vector_is_empty(const __clove_vector_t* vector);
     238              : __CLOVE_EXTERN_C void* __clove_vector_add_slot(__clove_vector_t* vector);
     239              : __CLOVE_EXTERN_C void __clove_vector_add_all(__clove_vector_t* vector, const __clove_vector_t* other);
     240              : __CLOVE_EXTERN_C void* __clove_vector_get(const __clove_vector_t* vector, size_t index);
     241              : __CLOVE_EXTERN_C void __clove_vector_set(__clove_vector_t* vector, size_t index, void* item);
     242              : __CLOVE_EXTERN_C void __clove_vector_free(__clove_vector_t* vector);
     243              : __CLOVE_EXTERN_C void __clove_vector_swap(__clove_vector_t* vector, size_t index1, size_t index2);
     244              : __CLOVE_EXTERN_C size_t __clove_vector_quicksort_partition(__clove_vector_t* vector, int (*comparator)(void*, void*), size_t start_index, size_t end_index);
     245              : __CLOVE_EXTERN_C void __clove_vector_quicksort_iterative(__clove_vector_t* vector, int (*comparator)(void*, void*), size_t start_index, size_t end_index);
     246              : __CLOVE_EXTERN_C void __clove_vector_sort(__clove_vector_t* vector, int (*comparator)(void*, void*));
     247              : __CLOVE_EXTERN_C void __clove_vector_collection_dtor(void* vector);
     248              : 
     249              : #define __CLOVE_VECTOR_INIT(VECTOR_PTR, TYPE) \
     250              :     __clove_vector_params_t __CLOVE_MACRO_COMBINE(params,__LINE__) = __clove_vector_params_defaulted(sizeof(TYPE)); \
     251              :     __clove_vector_init(VECTOR_PTR, &__CLOVE_MACRO_COMBINE(params,__LINE__));
     252              : 
     253              : #define __CLOVE_VECTOR_INIT_CAPACITY(VECTOR_PTR, TYPE, CAPACITY) \
     254              :     __clove_vector_params_t __CLOVE_MACRO_COMBINE(params,__LINE__) = __clove_vector_params_defaulted(sizeof(TYPE)); \
     255              :     __CLOVE_MACRO_COMBINE(params,__LINE__).initial_capacity = CAPACITY; \
     256              :     __clove_vector_init(VECTOR_PTR, &__CLOVE_MACRO_COMBINE(params,__LINE__));
     257              : 
     258              : #define __CLOVE_VECTOR_INIT_PARAMS(VECTOR_PTR, PARAMS) \
     259              :     __clove_vector_params_t __CLOVE_MACRO_COMBINE(params,__LINE__) = PARAMS; \
     260              :     __clove_vector_init(VECTOR_PTR, &__CLOVE_MACRO_COMBINE(params,__LINE__));
     261              : 
     262              : #define __CLOVE_VECTOR_ADD(VECTOR_PTR, TYPE, ITEM) \
     263              :     TYPE* __CLOVE_MACRO_COMBINE(__vector_slot,__LINE__) = (TYPE*)__clove_vector_add_slot(VECTOR_PTR); \
     264              :     *__CLOVE_MACRO_COMBINE(__vector_slot,__LINE__) = ITEM;
     265              : 
     266              : #define __CLOVE_VECTOR_FOREACH(VECTOR_PTR, TYPE, NAME, BODY) \
     267              :     for(size_t __CLOVE_MACRO_COMBINE(__CLOVE_MACRO_COMBINE(vector_index_,NAME), __LINE__)=0; __CLOVE_MACRO_COMBINE(__CLOVE_MACRO_COMBINE(vector_index_,NAME), __LINE__) < __clove_vector_count(VECTOR_PTR); ++__CLOVE_MACRO_COMBINE(__CLOVE_MACRO_COMBINE(vector_index_,NAME), __LINE__)) { \
     268              :         TYPE* NAME = (TYPE*)__clove_vector_get(VECTOR_PTR, __CLOVE_MACRO_COMBINE(__CLOVE_MACRO_COMBINE(vector_index_,NAME), __LINE__)); \
     269              :         BODY \
     270              :     }
     271              : 
     272              : #define __CLOVE_VECTOR_FOR(VECTOR_PTR, TYPE, NAME, INDEX, BODY) \
     273              :     for(size_t INDEX=0; INDEX < __clove_vector_count(VECTOR_PTR); ++INDEX) { \
     274              :         TYPE* NAME = (TYPE*)__clove_vector_get(VECTOR_PTR, INDEX); \
     275              :         BODY \
     276              :     }
     277              : 
     278              : #define __CLOVE_VECTOR_FREE(VECTOR_PTR) \
     279              :     __clove_vector_free(VECTOR_PTR);
     280              : 
     281              : #pragma endregion // Vector Decl
     282              : 
     283              : #pragma region PRIVATE - Map Decl
     284              : typedef struct __clove_map_node_t {
     285              :     char*       key;
     286              :     size_t      key_size;
     287              :     void*       value;
     288              :     struct __clove_map_node_t* next;
     289              : } __clove_map_node_t;
     290              : 
     291              : typedef struct __clove_map_params_t {
     292              :     size_t initial_hash_size;
     293              :     size_t (*hash_funct)(void*, size_t);
     294              :     void   (*item_dtor)(void*);
     295              : } __clove_map_params_t;
     296              : 
     297              : typedef struct __clove_map_t {
     298              :     size_t                   count;
     299              :     __clove_map_node_t**     hashmap; 
     300              :     size_t                   hashmap_size;
     301              :     size_t                   (*hash_funct)(void*, size_t);
     302              :     void                     (*item_dtor)(void*);
     303              : } __clove_map_t;
     304              : 
     305              : size_t __clove_map_hash_djb33x(void *key, size_t keylen);
     306              : __clove_map_params_t __clove_map_params_defaulted(void);
     307              : void __clove_map_init(__clove_map_t* map, __clove_map_params_t* params);
     308              : void __clove_map_free(__clove_map_t* map);
     309              : size_t __clove_map_count(__clove_map_t* map);
     310              : void __clove_map_put(__clove_map_t* dict, const char* key, void* value);
     311              : void* __clove_map_get(__clove_map_t* map, const char* key);
     312              : bool __clove_map_has_key(__clove_map_t* map, const char* key);
     313              : 
     314              : #define __CLOVE_MAP_INIT(MAP_PTR) \
     315              :     __clove_map_params_t __CLOVE_MACRO_COMBINE(params,__LINE__) = __clove_map_params_defaulted(); \
     316              :     __clove_map_init(MAP_PTR, &__CLOVE_MACRO_COMBINE(params,__LINE__));
     317              : 
     318              : #define __CLOVE_MAP_INIT_PARAMS(MAP_PTR, PARAMS) \
     319              :     __clove_map_params_t __CLOVE_MACRO_COMBINE(params,__LINE__) = PARAMS; \
     320              :     __clove_map_init(MAP_PTR, &__CLOVE_MACRO_COMBINE(params,__LINE__));
     321              : 
     322              : #pragma endregion // Map Decl
     323              : 
     324              : #pragma region PRIVATE - CommandLine Decl
     325              : #include <stdbool.h>
     326              : typedef struct __clove_cmdline_t {
     327              :     int arg_index;
     328              :     int argc;
     329              :     const char** argv;
     330              :     __clove_map_t map;
     331              : } __clove_cmdline_t;
     332              : 
     333              : typedef enum __clove_cmdline_errno_t {
     334              :     __CLOVE_CMD_ERRNO_UNMANAGED = -1,
     335              :     __CLOVE_CMD_ERRNO_OK = 0,
     336              :     __CLOVE_CMD_ERRNO_GENERIC = 1,
     337              :     __CLOVE_CMD_ERRNO_INVALID_PARAM = 2,
     338              : } __clove_cmdline_errno_t;
     339              : 
     340              : __CLOVE_EXTERN_C void __clove_cmdline_init(__clove_cmdline_t* cmdline, const char** argv, int argc);
     341              : __CLOVE_EXTERN_C void __clove_cmdline_free(__clove_cmdline_t* cmdline);
     342              : __CLOVE_EXTERN_C bool __clove_cmdline_next_opt(__clove_cmdline_t* cmdline, const char** opt_out);
     343              : __CLOVE_EXTERN_C bool __clove_cmdline_next_arg(__clove_cmdline_t* cmdline, const char** arg_out);
     344              : __CLOVE_EXTERN_C bool __clove_cmdline_has_opt(__clove_cmdline_t* cmdline, const char* opt);
     345              : __CLOVE_EXTERN_C bool __clove_cmdline_has_any_opt(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2);
     346              : __CLOVE_EXTERN_C const char* __clove_cmdline_get_opt_value(__clove_cmdline_t* cmdline, const char* opt);
     347              : __CLOVE_EXTERN_C const char* __clove_cmdline_get_any_opt_value(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2);
     348              : __CLOVE_EXTERN_C const char* __clove_cmdline_get_any_opt_value_defaulted(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2, const char* default_value);
     349              : __CLOVE_EXTERN_C const __clove_vector_t* __clove_cmdline_get_opt_values(__clove_cmdline_t* cmdline, const char* opt);
     350              : __CLOVE_EXTERN_C void __clove_cmdline_add_opt(__clove_cmdline_t* cmd, const char* opt, const char* value);
     351              : //Command Handlers
     352              :  typedef __clove_cmdline_errno_t (*__clove_cmdline_handler_f)(__clove_cmdline_t*);
     353              : __CLOVE_EXTERN_C __clove_cmdline_errno_t __clove_cmdline_handle_help(__clove_cmdline_t* cmd);
     354              : __CLOVE_EXTERN_C __clove_cmdline_errno_t __clove_cmdline_handle_version(__clove_cmdline_t* cmd);
     355              : __CLOVE_EXTERN_C __clove_cmdline_errno_t __clove_cmdline_handle_run_tests(__clove_cmdline_t* cmd);
     356              : __CLOVE_EXTERN_C __clove_cmdline_errno_t __clove_cmdline_handle_default(__clove_cmdline_t* cmd);
     357              : __CLOVE_EXTERN_C void __clove_cmdline_create_test_expr(__clove_cmdline_t* cmd, const char* opt1, const char* opt2, __clove_vector_t* out_expressions);
     358              : #pragma endregion // CommandLine Decl
     359              : 
     360              : #pragma region PRIVATE - Test Decl
     361              : typedef union __clove_generic_u {
     362              :     bool               _bool;
     363              :     char               _char;
     364              :     int                _int;
     365              :     unsigned int       _uint;
     366              :     long               _long;
     367              :     unsigned long      _ulong;
     368              :     long long          _llong;
     369              :     unsigned long long _ullong;
     370              :     size_t             _sizet;
     371              :     float              _float;
     372              :     double             _double;
     373              :     char* _string;
     374              :     void* _ptr;
     375              : } __clove_generic_u;
     376              : 
     377              : /* TODO: Delete in favor of a crazy custom implementation of string enum... (See below)
     378              : typedef enum __clove_generic_type_e {
     379              :     __CLOVE_GENERIC_BOOL = 1,
     380              :     __CLOVE_GENERIC_CHAR = 2,
     381              :     __CLOVE_GENERIC_INT = 3,
     382              :     __CLOVE_GENERIC_UINT = 4,
     383              :     __CLOVE_GENERIC_LONG = 5,
     384              :     __CLOVE_GENERIC_ULONG = 6,
     385              :     __CLOVE_GENERIC_LLONG = 7,
     386              :     __CLOVE_GENERIC_ULLONG = 8,
     387              :     __CLOVE_GENERIC_FLOAT = 9,
     388              :     __CLOVE_GENERIC_DOUBLE = 10,
     389              :     __CLOVE_GENERIC_STRING = 11,
     390              :     __CLOVE_GENERIC_PTR = 12
     391              : } __clove_generic_type_e;
     392              : 
     393              : typedef enum __clove_assert_check_e {
     394              :     __CLOVE_ASSERT_EQ = 1,
     395              :     __CLOVE_ASSERT_NE = 2,
     396              :     __CLOVE_ASSERT_FAIL = 3
     397              : } __clove_assert_check_e;
     398              : 
     399              : typedef enum __clove_test_result_e {
     400              :     __CLOVE_TEST_RESULT_PASSED = 1,
     401              :     __CLOVE_TEST_RESULT_FAILED = 2,
     402              :     __CLOVE_TEST_RESULT_SKIPPED = 3
     403              : } __clove_test_result_e;
     404              : */
     405              : 
     406              : /* Custom String Enum for Generic Type */
     407              : typedef const char* __clove_generic_type_e;
     408              : extern const char* __CLOVE_GENERIC_BOOL;
     409              : extern const char* __CLOVE_GENERIC_CHAR;
     410              : extern const char* __CLOVE_GENERIC_INT;
     411              : extern const char* __CLOVE_GENERIC_UINT;
     412              : extern const char* __CLOVE_GENERIC_LONG;
     413              : extern const char* __CLOVE_GENERIC_ULONG;
     414              : extern const char* __CLOVE_GENERIC_LLONG;
     415              : extern const char* __CLOVE_GENERIC_ULLONG;
     416              : extern const char* __CLOVE_GENERIC_SIZET;
     417              : extern const char* __CLOVE_GENERIC_FLOAT;
     418              : extern const char* __CLOVE_GENERIC_DOUBLE;
     419              : extern const char* __CLOVE_GENERIC_STRING;
     420              : extern const char* __CLOVE_GENERIC_PTR;
     421              : #define __CLOVE_GENERIC_TYPE_E_DECL() \
     422              :     const char* __CLOVE_GENERIC_BOOL = "BOOL"; \
     423              :     const char* __CLOVE_GENERIC_CHAR   = "CHAR"; \
     424              :     const char* __CLOVE_GENERIC_INT    = "INT"; \
     425              :     const char* __CLOVE_GENERIC_UINT   = "UINT"; \
     426              :     const char* __CLOVE_GENERIC_LONG   = "LONG"; \
     427              :     const char* __CLOVE_GENERIC_ULONG  = "ULONG"; \
     428              :     const char* __CLOVE_GENERIC_LLONG  = "LLONG"; \
     429              :     const char* __CLOVE_GENERIC_ULLONG = "ULLONG"; \
     430              :     const char* __CLOVE_GENERIC_SIZET  = "SIZET"; \
     431              :     const char* __CLOVE_GENERIC_FLOAT  = "FLOAT"; \
     432              :     const char* __CLOVE_GENERIC_DOUBLE = "DOUBLE"; \
     433              :     const char* __CLOVE_GENERIC_STRING = "STRING"; \
     434              :     const char* __CLOVE_GENERIC_PTR    = "PTR"; 
     435              :     
     436              : /* Custom String Enum for Assert Check */
     437              : typedef const char*  __clove_assert_check_e;
     438              : extern const char* __CLOVE_ASSERT_EQ;
     439              : extern const char* __CLOVE_ASSERT_NE;
     440              : extern const char* __CLOVE_ASSERT_LT;
     441              : extern const char* __CLOVE_ASSERT_LTE;
     442              : extern const char* __CLOVE_ASSERT_GT;
     443              : extern const char* __CLOVE_ASSERT_GTE;
     444              : extern const char* __CLOVE_ASSERT_FAIL;
     445              : #define __CLOVE_ASSERT_CHECK_E_DECL() \
     446              :     const char* __CLOVE_ASSERT_EQ   = "EQ";\
     447              :     const char* __CLOVE_ASSERT_NE   = "NE";\
     448              :     const char* __CLOVE_ASSERT_GT   = "GT";\
     449              :     const char* __CLOVE_ASSERT_GTE  = "GTE";\
     450              :     const char* __CLOVE_ASSERT_LT   = "LT";\
     451              :     const char* __CLOVE_ASSERT_LTE  = "LTE";\
     452              :     const char* __CLOVE_ASSERT_FAIL = "FAIL";
     453              : 
     454              : /* Custom String Enum for Test Result */
     455              : typedef const char* __clove_test_result_e;
     456              : extern const char* __CLOVE_TEST_RESULT_PASSED;
     457              : extern const char* __CLOVE_TEST_RESULT_SKIPPED;
     458              : extern const char* __CLOVE_TEST_RESULT_FAILED;
     459              : #define __CLOVE_TEST_RESULT_E_DECL() \
     460              :     const char* __CLOVE_TEST_RESULT_PASSED  = "PASS";\
     461              :     const char* __CLOVE_TEST_RESULT_FAILED  = "FAIL";\
     462              :     const char* __CLOVE_TEST_RESULT_SKIPPED = "SKIP";
     463              : 
     464              : typedef struct __clove_test_t {
     465              :     char* name;
     466              :     void (*funct)(struct __clove_test_t*);
     467              :     __clove_test_result_e result;
     468              :     __clove_time_t duration;
     469              :     const char* file_name;
     470              :     bool dry_run;
     471              :     size_t funct_line;
     472              :     struct {
     473              :         size_t line;
     474              :         __clove_assert_check_e assert;
     475              :         __clove_generic_type_e data_type;
     476              :         __clove_generic_u expected;
     477              :         __clove_generic_u actual;
     478              :         unsigned char floating_precision; //Just used for float/double to represent a decimal digit.
     479              :         //TODO Eventually refactor to a data struct to represent expected/actual and encapsulate also __clove_generic_u.
     480              :     } issue;
     481              : } __clove_test_t;
     482              : 
     483              : __CLOVE_EXTERN_C void __clove_vector_test_ctor(void* test);
     484              : __CLOVE_EXTERN_C void __clove_vector_test_dtor(void* test_ptr);
     485              : #pragma endregion // Test Decl
     486              : 
     487              : #pragma region PRIVATE - Suite Decl
     488              : typedef struct __clove_suite_t {
     489              :     char* name;
     490              :     __clove_vector_t tests;
     491              :     size_t test_count;
     492              :     struct {
     493              :         void (*setup_once)(void);
     494              :         void (*teardown_once)(void);
     495              :         void (*setup)(void);
     496              :         void (*teardown)(void);
     497              :     } fixtures;
     498              :     struct {
     499              :         __clove_time_t duration;
     500              :         size_t passed_count;
     501              :         size_t failed_count;
     502              :         size_t skipped_count;
     503              :     } issue;
     504              : 
     505              : } __clove_suite_t;
     506              : 
     507              : __CLOVE_EXTERN_C void __clove_vector_suite_ctor(void* suite_ptr);
     508              : __CLOVE_EXTERN_C void __clove_vector_suite_dtor(void* suite_ptr);
     509              : #pragma endregion
     510              : 
     511              : #pragma region PRIVATE - Assert Decl
     512              : #define __CLOVE_ASSERT_GUARD \
     513              :     if (_this->result == __CLOVE_TEST_RESULT_FAILED) { return; }\
     514              :     if (_this->file_name == NULL) _this->file_name = __FILE__; \
     515              :     _this->issue.line = __LINE__;
     516              : 
     517              : #define __CLOVE_ASSERT_INTEGER_CHECK(mode, exp, act, type, field, test) \
     518              :     bool pass_scenario = false;\
     519              :     if (check_mode == __CLOVE_ASSERT_EQ)       { pass_scenario = exp == act; }\
     520              :     else if (check_mode == __CLOVE_ASSERT_NE)  { pass_scenario = exp != act; }\
     521              :     else if (check_mode == __CLOVE_ASSERT_GT)  { pass_scenario = exp >  act; }\
     522              :     else if (check_mode == __CLOVE_ASSERT_GTE) { pass_scenario = exp >= act; }\
     523              :     else if (check_mode == __CLOVE_ASSERT_LT)  { pass_scenario = exp <  act; }\
     524              :     else if (check_mode == __CLOVE_ASSERT_LTE) { pass_scenario = exp <= act; }\
     525              :     if (pass_scenario) _this->result =  __CLOVE_TEST_RESULT_PASSED;\
     526              :     else { \
     527              :         _this->result =  __CLOVE_TEST_RESULT_FAILED;\
     528              :         _this->issue.assert = mode;\
     529              :         _this->issue.data_type = type;\
     530              :         _this->issue.expected.field = exp;\
     531              :         _this->issue.actual.field = act;\
     532              :     }
     533              : 
     534              : __CLOVE_EXTERN_C void __clove_assert_fail(__clove_test_t* _this);
     535              : __CLOVE_EXTERN_C void __clove_assert_pass(__clove_test_t* _this);
     536              : __CLOVE_EXTERN_C void __clove_assert_int(__clove_assert_check_e check_mode, int expected, int result, __clove_test_t* _this);
     537              : __CLOVE_EXTERN_C void __clove_assert_uint(__clove_assert_check_e check_mode, unsigned int expected, unsigned int result, __clove_test_t* _this);
     538              : __CLOVE_EXTERN_C void __clove_assert_long(__clove_assert_check_e check_mode, long expected, long result, __clove_test_t* _this);
     539              : __CLOVE_EXTERN_C void __clove_assert_ulong(__clove_assert_check_e check_mode, unsigned long expected, unsigned long result, __clove_test_t* _this);
     540              : __CLOVE_EXTERN_C void __clove_assert_llong(__clove_assert_check_e check_mode, long long expected, long long result, __clove_test_t* _this);
     541              : __CLOVE_EXTERN_C void __clove_assert_ullong(__clove_assert_check_e check_mode, unsigned long long expected, unsigned long long result, __clove_test_t* _this);
     542              : __CLOVE_EXTERN_C void __clove_assert_sizet(__clove_assert_check_e check_mode, size_t expected, size_t result, __clove_test_t* _this);
     543              : __CLOVE_EXTERN_C void __clove_assert_char(__clove_assert_check_e check_mode, char expected, char result, __clove_test_t* _this);
     544              : __CLOVE_EXTERN_C void __clove_assert_bool(__clove_assert_check_e check_mode, bool expected, bool result, __clove_test_t* _this);
     545              : __CLOVE_EXTERN_C void __clove_assert_null(__clove_assert_check_e check_mode, void* expected, void* result, __clove_test_t* _this);
     546              : __CLOVE_EXTERN_C void __clove_assert_ptr(__clove_assert_check_e check_mode, void* expected, void* result, __clove_test_t* _this);
     547              : __CLOVE_EXTERN_C void __clove_assert_float(__clove_assert_check_e check_mode, float expected, float result, unsigned char precision, __clove_test_t* _this);
     548              : __CLOVE_EXTERN_C void __clove_assert_double(__clove_assert_check_e check_mode, double expected, double result, unsigned char precision, __clove_test_t* _this);
     549              : __CLOVE_EXTERN_C void __clove_assert_string(__clove_assert_check_e check_mode, const char* expected, const char* result, __clove_test_t* _this);
     550              : #pragma endregion // Assert Decl
     551              : 
     552              : #pragma region PRIVATE - Stream Decl
     553              : typedef struct __clove_stream_t {
     554              :     bool (*open)(struct __clove_stream_t* _this);
     555              :     void (*close)(struct __clove_stream_t* _this);
     556              :     void (*writef)(struct __clove_stream_t* _this, const char* format, ...);
     557              :     void (*seek)(struct __clove_stream_t* _this, long offset, int origin);
     558              :     bool (*has_ansi_support)(struct __clove_stream_t* _this);
     559              :     void (*free)(struct __clove_stream_t* _this);
     560              : } __clove_stream_t;
     561              : 
     562              : typedef struct __clove_stream_console_t {
     563              :     __clove_stream_t base;
     564              : } __clove_stream_console_t;
     565              : 
     566              : __CLOVE_EXTERN_C __clove_stream_console_t* __clove_stream_console_new(void);
     567              : __CLOVE_EXTERN_C bool __clove_stream_console_open(__clove_stream_t* stream);
     568              : __CLOVE_EXTERN_C void __clove_stream_console_close(__clove_stream_t* stream);
     569              : __CLOVE_EXTERN_C void __clove_stream_console_writef(__clove_stream_t* stream, const char* format, ...);
     570              : __CLOVE_EXTERN_C void __clove_stream_console_seek(__clove_stream_t* stream, long offset, int origin);
     571              : __CLOVE_EXTERN_C bool __clove_stream_console_has_ansi_support(struct __clove_stream_t* _this);
     572              : __CLOVE_EXTERN_C void __clove_stream_console_free(__clove_stream_t* stream);
     573              : 
     574              : #include <stdio.h> 
     575              : typedef struct __clove_stream_file_t {
     576              :     __clove_stream_t base;
     577              :      const char* file_path;
     578              :     FILE* file; //No way to forward declaring FILE. The only way should be to use void*
     579              : } __clove_stream_file_t;
     580              : 
     581              : __CLOVE_EXTERN_C __clove_stream_file_t* __clove_stream_file_new(const char* file_path);
     582              : __CLOVE_EXTERN_C bool __clove_stream_file_open(__clove_stream_t* stream);
     583              : __CLOVE_EXTERN_C void __clove_stream_file_close(__clove_stream_t* stream);
     584              : __CLOVE_EXTERN_C void __clove_stream_file_writef(__clove_stream_t* stream, const char* format, ...);
     585              : __CLOVE_EXTERN_C void __clove_stream_file_seek(__clove_stream_t* stream, long offset, int origin);
     586              : __CLOVE_EXTERN_C bool __clove_stream_file_has_ansi_support(struct __clove_stream_t* _this);
     587              : __CLOVE_EXTERN_C void __clove_stream_file_free(__clove_stream_t* stream);
     588              : 
     589              : //In Memory Stream
     590              : typedef struct __clove_stream_memory_t {
     591              :     __clove_stream_t base;
     592              :     __clove_vector_t lines;
     593              : } __clove_stream_memory_t;
     594              : 
     595              : __CLOVE_EXTERN_C __clove_stream_memory_t* __clove_stream_memory_new(void);
     596              : __CLOVE_EXTERN_C bool __clove_stream_memory_open(__clove_stream_t* stream);
     597              : __CLOVE_EXTERN_C void __clove_stream_memory_close(__clove_stream_t* stream);
     598              : __CLOVE_EXTERN_C void __clove_stream_memory_writef(__clove_stream_t* stream, const char* format, ...);
     599              : __CLOVE_EXTERN_C void __clove_stream_memory_seek(__clove_stream_t* stream, long offset, int origin);
     600              : __CLOVE_EXTERN_C bool __clove_stream_memory_has_ansi_support(struct __clove_stream_t* _this);
     601              : __CLOVE_EXTERN_C void __clove_stream_memory_free(__clove_stream_t* stream);
     602              : __CLOVE_EXTERN_C char* __clove_stream_memory_get_line(__clove_stream_memory_t* mem_stream, size_t index);
     603              : __CLOVE_EXTERN_C char* __clove_stream_memory_as_string(__clove_stream_memory_t* mem_stream);
     604              : #pragma endregion //Stream Decl
     605              : 
     606              : #pragma region PRIVATE - Report Decl
     607              : typedef struct __clove_report_t {
     608              :     void (*start)(struct __clove_report_t* _this, __clove_vector_t* suites, size_t test_count);
     609              :     void (*end)(struct __clove_report_t* _this, size_t passed, size_t skipped, size_t failed);
     610              :     void (*begin_suite)(struct __clove_report_t* _this, __clove_suite_t* suite, size_t index);
     611              :     void (*end_suite)(struct __clove_report_t* _this, __clove_suite_t* suite, size_t index);
     612              :     void (*end_test)(struct __clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number);
     613              :     void (*free)(struct __clove_report_t* _this);
     614              : } __clove_report_t;
     615              : 
     616              : typedef struct __clove_test_expr_t {
     617              :     __clove_string_view_t suite_view;
     618              :     __clove_string_view_t test_view;
     619              : } __clove_test_expr_t;
     620              : 
     621              : typedef enum __clove_report_detail_e {
     622              :     __CLOVE_REPORT_DETAIL__NONE = 0,
     623              :     __CLOVE_REPORT_DETAIL__FAILED = 1,
     624              :     __CLOVE_REPORT_DETAIL__FAILED_SKIPPED = 2,
     625              :     __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED = 3,
     626              : } __clove_report_detail_e;
     627              : 
     628              : typedef struct __clove_report_params_t {
     629              :     const char* tests_base_path;
     630              :     __clove_report_detail_e report_detail;
     631              : } __clove_report_params_t;
     632              : 
     633              : __CLOVE_EXTERN_C void __clove_test_expr_init(__clove_test_expr_t* expr,  const char* expr_str);
     634              : __CLOVE_EXTERN_C bool __clove_test_expr_validate_vw(const __clove_string_view_t* match, const __clove_string_view_t* view);
     635              : __CLOVE_EXTERN_C bool __clove_test_expr_validate(__clove_test_expr_t* expr, const __clove_string_view_t* suite, const __clove_string_view_t* test);
     636              : #pragma endregion
     637              : 
     638              : #pragma region PRIVATE - RunTests Report Pretty Decl
     639              : #include <stdbool.h>
     640              : typedef struct __clove_report_pretty_t {
     641              :     __clove_report_t base;
     642              :     __clove_stream_t* stream;
     643              :     __clove_report_params_t* params;
     644              :     __clove_time_t start_time;
     645              :     unsigned int max_test_digits;
     646              :     size_t max_suite_and_test_name_size;
     647              :     size_t test_count;
     648              :     struct {
     649              :         const char* info;
     650              :         const char* warn;
     651              :         const char* erro;
     652              :         const char* pass;
     653              :         const char* skip;
     654              :         const char* fail;
     655              :     } labels;
     656              : } __clove_report_pretty_t;
     657              : __clove_report_pretty_t* __clove_report_run_tests_pretty_new(__clove_stream_t* stream, __clove_report_params_t* params);
     658              : __CLOVE_EXTERN_C void __clove_report_pretty_free(__clove_report_t* report);
     659              : __CLOVE_EXTERN_C void __clove_report_pretty_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count);
     660              : __CLOVE_EXTERN_C void __clove_report_pretty_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     661              : __CLOVE_EXTERN_C void __clove_report_pretty_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     662              : __CLOVE_EXTERN_C void __clove_report_pretty_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number);
     663              : __CLOVE_EXTERN_C void __clove_report_pretty_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed);
     664              : __CLOVE_EXTERN_C void __clove_report_pretty_string_ellipse(const char* exp, size_t exp_len, const char* act, size_t act_len, char* exp_short, char* act_short, size_t short_size);
     665              : #define __CLOVE_STRING_LENGTH 256
     666              : #define __PRETTY_PRINT_FAIL_ASSERT_MSG(buffer, buffer_size, assert, exp, act, print_type) \
     667              : { \
     668              :     char phrase_format[40] = {0}; \
     669              :     if (assert == __CLOVE_ASSERT_EQ)      __clove_string_sprintf(phrase_format, sizeof(phrase_format), "expected [%s] but was [%s]", print_type, print_type); \
     670              :     else if(assert == __CLOVE_ASSERT_NE)  __clove_string_sprintf(phrase_format, sizeof(phrase_format), "not expected [%s] but was [%s]", print_type, print_type); \
     671              :     else if(assert == __CLOVE_ASSERT_GT)  __clove_string_sprintf(phrase_format, sizeof(phrase_format), "expected [%s > %s] but wasn't", print_type, print_type); \
     672              :     else if(assert == __CLOVE_ASSERT_GTE) __clove_string_sprintf(phrase_format, sizeof(phrase_format), "expected [%s >= %s] but wasn't", print_type, print_type); \
     673              :     else if(assert == __CLOVE_ASSERT_LT) __clove_string_sprintf(phrase_format, sizeof(phrase_format),  "expected [%s < %s] but wasn't", print_type, print_type); \
     674              :     else if(assert == __CLOVE_ASSERT_LTE) __clove_string_sprintf(phrase_format, sizeof(phrase_format), "expected [%s <= %s] but wasn't", print_type, print_type); \
     675              :     __clove_string_sprintf(buffer, buffer_size, phrase_format, exp, act); \
     676              : }
     677              : #pragma endregion
     678              : 
     679              : #pragma region PRIVATE - RunTests Report CSV Decl
     680              : #include <stdbool.h>
     681              : typedef struct __clove_report_run_tests_csv_t {
     682              :     __clove_report_t base;
     683              :     __clove_stream_t* stream;
     684              :      __clove_report_params_t* params;
     685              : } __clove_report_run_tests_csv_t;
     686              : __clove_report_run_tests_csv_t* __clove_report_run_tests_csv_new(__clove_stream_t* stream,  __clove_report_params_t* params);
     687              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_free(__clove_report_t* report);
     688              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count);
     689              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     690              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     691              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number);
     692              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed);
     693              : __CLOVE_EXTERN_C void __clove_report_run_tests_csv_print_data(__clove_report_run_tests_csv_t* _this, __clove_test_t* test, __clove_generic_u* data);
     694              : #pragma endregion
     695              : 
     696              : #pragma region PRIVATE - Report Json Decl
     697              : typedef struct __clove_report_json_t {
     698              :     __clove_report_t base;
     699              :     __clove_stream_t* stream;
     700              :     __clove_report_params_t* params;
     701              :     const char* clove_version;
     702              :     const char* json_schema;
     703              :     __clove_suite_t* current_suite;
     704              :     bool is_first_suite_test;
     705              :     size_t suite_tests_counter;
     706              :     size_t suite_tests_number;
     707              :     size_t suite_count;
     708              :     size_t test_count;
     709              :     __clove_vector_t cached_suites;
     710              :     bool is_realtime_scenario;
     711              :     bool is_reporting_enabled;
     712              : } __clove_report_json_t;
     713              : 
     714              : __CLOVE_EXTERN_C __clove_report_json_t* __clove_report_run_tests_json_new(__clove_stream_t* stream, __clove_report_params_t* params);
     715              : __CLOVE_EXTERN_C void __clove_report_json_free(__clove_report_t* report);
     716              : __CLOVE_EXTERN_C void __clove_report_json_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count);
     717              : __CLOVE_EXTERN_C void __clove_report_json_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     718              : __CLOVE_EXTERN_C void __clove_report_json_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index);
     719              : __CLOVE_EXTERN_C void __clove_report_json_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed);
     720              : __CLOVE_EXTERN_C void __clove_report_json_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number);
     721              : __CLOVE_EXTERN_C void __clove_report_json_print_data(__clove_report_json_t* _this, __clove_test_t* test, __clove_generic_u* data);
     722              : #pragma endregion
     723              : 
     724              : #pragma region PRIVATE - Report List Test Decl
     725              : typedef struct __clove_report_list_tests_t {
     726              :     void (*begin)(struct __clove_report_list_tests_t* _this, size_t suite_count, size_t test_count);
     727              :     void (*begin_suite)(struct __clove_report_list_tests_t* _this, __clove_suite_t* suite, size_t index);
     728              :     void (*begin_test)(struct __clove_report_list_tests_t* _this, __clove_test_t* test, size_t index);
     729              :     void (*end_test)(struct __clove_report_list_tests_t* _this, __clove_test_t* test, size_t index);
     730              :     void (*end_suite)(struct __clove_report_list_tests_t* _this, __clove_suite_t* suite, size_t index);
     731              :     void (*end)(struct __clove_report_list_tests_t* _this);
     732              :     void (*free)(struct __clove_report_list_tests_t* _this);
     733              : } __clove_report_list_tests_t;
     734              : 
     735              : typedef struct __clove_report_list_tests_pretty_t {
     736              :    __clove_report_list_tests_t base;
     737              :    __clove_stream_t* stream;
     738              :    __clove_report_params_t* params;
     739              :    const char* suite_format;
     740              :    const char* test_format;
     741              :    bool is_suite_first_test;
     742              :    __clove_suite_t* current_suite;
     743              : } __clove_report_list_tests_pretty_t;
     744              : 
     745              : __clove_report_list_tests_pretty_t* __clove_report_list_tests_pretty_new(__clove_stream_t* stream, __clove_report_params_t* params);
     746              : void __clove_report_list_tests_pretty_free(__clove_report_list_tests_t* _this);
     747              : void __clove_report_list_tests_pretty_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count);
     748              : void __clove_report_list_tests_pretty_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     749              : void __clove_report_list_tests_pretty_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     750              : void __clove_report_list_tests_pretty_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     751              : void __clove_report_list_tests_pretty_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     752              : void __clove_report_list_tests_pretty_end(__clove_report_list_tests_t* _this);
     753              : 
     754              : typedef struct __clove_report_list_tests_csv_t {
     755              :    __clove_report_list_tests_t base;
     756              :    __clove_stream_t* stream;
     757              :    __clove_report_params_t* params;
     758              :    __clove_suite_t* current_suite;
     759              : } __clove_report_list_tests_csv_t;
     760              : 
     761              : __clove_report_list_tests_csv_t* __clove_report_list_tests_csv_new(__clove_stream_t* stream, __clove_report_params_t* params);
     762              : void __clove_report_list_tests_csv_free(__clove_report_list_tests_t* _this);
     763              : void __clove_report_list_tests_csv_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count);
     764              : void __clove_report_list_tests_csv_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     765              : void __clove_report_list_tests_csv_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     766              : void __clove_report_list_tests_csv_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     767              : void __clove_report_list_tests_csv_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     768              : void __clove_report_list_tests_csv_end(__clove_report_list_tests_t* _this);
     769              : 
     770              : typedef struct __clove_report_list_tests_json_t {
     771              :    __clove_report_list_tests_t base;
     772              :    __clove_stream_t* stream;
     773              :    __clove_report_params_t* params;
     774              :    __clove_suite_t* current_suite;
     775              :    const char* clove_version;
     776              :    const char* json_schema;
     777              :    size_t suite_count;
     778              :    bool is_suite_first_test;
     779              : } __clove_report_list_tests_json_t;
     780              : 
     781              : __clove_report_list_tests_json_t* __clove_report_list_tests_json_new(__clove_stream_t* stream, __clove_report_params_t* params);
     782              : void __clove_report_list_tests_json_free(__clove_report_list_tests_t* _this);
     783              : void __clove_report_list_tests_json_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count);
     784              : void __clove_report_list_tests_json_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     785              : void __clove_report_list_tests_json_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index);
     786              : void __clove_report_list_tests_json_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     787              : void __clove_report_list_tests_json_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index);
     788              : void __clove_report_list_tests_json_end(__clove_report_list_tests_t* _this);
     789              : 
     790              : int __clove_cmd_list_test_execute(__clove_suite_t* suites, size_t suite_count, size_t test_count, __clove_report_list_tests_t* report);
     791              : #pragma endregion
     792              : 
     793              : #pragma region PRIVATE - Autodiscovery Decl
     794              : #include <stdbool.h>
     795              : typedef struct __clove_symbols_context_t {
     796              :     __clove_vector_t suites;
     797              :     size_t suites_count;
     798              :     size_t tests_count;
     799              :     const char* prefix;
     800              :     size_t prefix_length;
     801              :     const __clove_vector_t* includes;
     802              :     const __clove_vector_t* excludes;
     803              : } __clove_symbols_context_t;
     804              : 
     805              : typedef struct __clove_symbols_function_t {
     806              :     char* name;
     807              :     //Using union just to avoid explicit casting from object ptr to function ptr 'void* to void(*)()'
     808              :     //which emit warning using -Wpedantic flag with GCC compiler.
     809              :     union {
     810              :         void* obj_ptr;
     811              :         void (*fun_ptr)(void);
     812              :     };
     813              : } __clove_symbols_function_t;
     814              : 
     815              : __CLOVE_EXTERN_C bool __clove_symbols_function_validate(__clove_string_view_t* suite, __clove_string_view_t* type, __clove_string_view_t* name, __clove_symbols_context_t* context);
     816              : __CLOVE_EXTERN_C void __clove_symbols_function_collect(__clove_symbols_function_t exported_funct, __clove_symbols_context_t* context);
     817              : //For each OS / symbols table format
     818              : __CLOVE_EXTERN_C typedef void (*__clove_symbols_function_action)(__clove_symbols_function_t, __clove_symbols_context_t* context);
     819              : __CLOVE_EXTERN_C int __clove_symbols_for_each_function_by_prefix(__clove_symbols_context_t* context, __clove_symbols_function_action action);
     820              : #pragma endregion //Autodiscovery Decl
     821              : 
     822              : #pragma region PRIVATE - Run Decl
     823              : __CLOVE_EXTERN_C int __clove_runner_auto(int argc, char* argv[]);
     824              : __CLOVE_EXTERN_C int __clove_run_tests_with_report(__clove_report_t* report, __clove_vector_t* includes, __clove_vector_t* excludes);
     825              : __CLOVE_EXTERN_C int __clove_exec_suites(__clove_vector_t* suites, size_t test_count, __clove_report_t* report);
     826              : __CLOVE_EXTERN_C void __clove_exec_suite(__clove_suite_t* suite, size_t test_counter, size_t* passed, size_t* failed, size_t* skipped, __clove_report_t* report);
     827              : #pragma endregion // Run Decl
     828              : 
     829              : #pragma region PRIVATE - Api Decl
     830              : #ifdef _WIN32
     831              : #define __CLOVE_API_EXPORT __CLOVE_EXTERN_C __declspec(dllexport)
     832              : #else 
     833              : #define __CLOVE_API_EXPORT __CLOVE_EXTERN_C
     834              : #endif //_WIN32
     835              : 
     836              : //Note: Not exported for windows (symbol limit 65535). Even "extern c" directive is not needed
     837              : //      Furthermore using prefix __clove_symint__ so that this kind of function is excluded from Symbol Discovery
     838              : #define __CLOVE_SUITE_METHOD_INTERNAL_DECL_2(suite, title, param) void __clove_symint___##suite##___##title(param)
     839              : #define __CLOVE_SUITE_METHOD_INTERNAL_DECL_1(suite, name, param) __CLOVE_SUITE_METHOD_INTERNAL_DECL_2(suite, name, param)
     840              : #define __CLOVE_SUITE_METHOD_INTERNAL_INVOKE_2(suite, title, param) __clove_symint___##suite##___##title(param)
     841              : #define __CLOVE_SUITE_METHOD_INTERNAL_INVOKE_1(suite, title, param) __CLOVE_SUITE_METHOD_INTERNAL_INVOKE_2(suite, title, param)
     842              : 
     843              : #define __CLOVE_SUITE_METHOD_DECL_2(suite, title, param) __CLOVE_API_EXPORT void __clove_sym___##suite##___##title(param)
     844              : #define __CLOVE_SUITE_METHOD_DECL_1(suite, name, param) __CLOVE_SUITE_METHOD_DECL_2(suite, name, param)
     845              : 
     846              : #define __CLOVE_SUITE_SETUP_ONCE_AUTO() __CLOVE_SUITE_METHOD_DECL_1( CLOVE_SUITE_NAME, 11_setuponce, void)
     847              : #define __CLOVE_SUITE_TEARDOWN_ONCE_AUTO() __CLOVE_SUITE_METHOD_DECL_1( CLOVE_SUITE_NAME, 12_teardownonce, void)
     848              : #define __CLOVE_SUITE_SETUP_AUTO() __CLOVE_SUITE_METHOD_DECL_1( CLOVE_SUITE_NAME, 13_setup, void)
     849              : #define __CLOVE_SUITE_TEARDOWN_AUTO() __CLOVE_SUITE_METHOD_DECL_1( CLOVE_SUITE_NAME, 14_teardown, void)
     850              : #define __CLOVE_TEST_AUTO(title) \
     851              :     __CLOVE_SUITE_METHOD_INTERNAL_DECL_1( CLOVE_SUITE_NAME, 21_ ## title, __clove_test_t *_this); \
     852              :     __CLOVE_SUITE_METHOD_DECL_1( CLOVE_SUITE_NAME, 20_ ## title, __clove_test_t *_this) {\
     853              :         _this->file_name = __FILE__; \
     854              :         _this->funct_line = __LINE__; \
     855              :         if (_this->dry_run) return; \
     856              :         __CLOVE_SUITE_METHOD_INTERNAL_INVOKE_1(CLOVE_SUITE_NAME, 21_ ## title, _this); \
     857              :     } \
     858              :     __CLOVE_SUITE_METHOD_INTERNAL_DECL_1( CLOVE_SUITE_NAME, 21_ ## title, __clove_test_t *_this)
     859              : #pragma endregion
     860              : 
     861              : #pragma endregion // DECLARATION
     862              : 
     863              : #pragma region PRIVATE - IMPLEMENTATION
     864              : #ifdef CLOVE_IMPLEMENTATION
     865              : #pragma region PRIVATE - Utils Impl
     866              : #include <string.h>
     867              : #include <stdio.h>
     868            0 : void __clove_utils_empty_funct(void) { }
     869              : 
     870            1 : const char* __clove_utils_get_exec_abs_path(void) {
     871            1 :     return __clove_exec_abs_path;
     872              : }
     873              : 
     874            0 : const char* __clove_utils_get_exec_abs_basepath(void) {
     875            0 :     return __clove_exec_abs_basepath;
     876              : }
     877              : 
     878              : #pragma endregion // Utils Impl
     879              : 
     880              : #pragma region PRIVATE - Math Impl
     881              : #include <math.h>
     882            0 : unsigned int __clove_math_powi(unsigned int base, unsigned int exp) {
     883            0 :     unsigned int result = 1;
     884            0 :     for(unsigned int i=0; i < exp; ++i) {
     885            0 :         result *= base;
     886              :     }
     887            0 :     return result;
     888              : }
     889              : 
     890            0 : float __clove_math_decimalf(unsigned char precision) {
     891            0 :     unsigned int divider = __clove_math_powi(10, precision);
     892            0 :     return 1.0f / (float)divider;
     893              : }
     894              : 
     895            0 : double __clove_math_decimald(unsigned char precision) {
     896            0 :     unsigned int divider = __clove_math_powi(10, precision);
     897            0 :     return 1.0 / (double)divider;
     898              : }
     899              : #pragma endregion
     900              : 
     901              : #pragma region PRIVATE - Path Impl
     902              : #include <string.h>
     903              : #include <stdbool.h>
     904              : #include <stdlib.h>
     905              : #include <limits.h>
     906              : #include <sys/stat.h> 
     907              : 
     908              : #ifdef _WIN32
     909              :     #define __CLOVE_PATH_MAX_LEN _MAX_PATH
     910              : #else 
     911              :     #define __CLOVE_PATH_MAX_LEN PATH_MAX
     912              : #endif //_WIN32
     913              : 
     914            0 : char*  __clove_path_concat(const char* path1, const char* path2, const char separator) {
     915            0 :     size_t count = __clove_string_length(path1) + 1 + __clove_string_length(path2) + 1;
     916            0 :     char* path = __CLOVE_MEMORY_CALLOC_TYPE_N(char, count);
     917              : 
     918            0 :     __clove_string_strcat(path, count, path1);
     919            0 :     __clove_string_strncat(path, count, &separator, 1);
     920            0 :     __clove_string_strcat(path, count, path2);
     921              : 
     922            0 :     __clove_string_replace_char(path, '/', separator);
     923            0 :     __clove_string_replace_char(path, '\\', separator);
     924              : 
     925            0 :     return path;
     926              : }
     927              : 
     928           31 : const char* __clove_path_relative(const char* abs_path, const char* base_path) {
     929           31 :     if (!__clove_string_startswith(abs_path, base_path)) return abs_path;
     930              : 
     931            0 :     size_t base_path_length = __clove_string_length(base_path);
     932            0 :     const char* result = abs_path + base_path_length;
     933            0 :     if (__clove_string_startswith(result, __CLOVE_PATH_SEPARATOR_STR)) {
     934            0 :         result += 1;
     935              :     }
     936            0 :     return result;
     937              : }
     938              : 
     939            0 : char* __clove_path_rel_to_abs_exec_path(const char* rel_path) {
     940            0 :     const char* base_path = __clove_utils_get_exec_abs_basepath();
     941            0 :     char* abs_path = __clove_path_concat(base_path, rel_path, __CLOVE_PATH_SEPARATOR);
     942            0 :     return abs_path;
     943              : }
     944              : 
     945            0 : bool __clove_path_is_relative(const char* path) {
     946            0 :     if (__clove_string_startswith(path, "\\")) return false; //windows (match the main unit)
     947            0 :     if (__clove_string_length(path) > 2 && path[1] == ':') return false;    //windows (contains unit:)
     948            0 :     if (__clove_string_startswith(path, "/")) return false;  //unix or Windows
     949            0 :     return true;
     950              : }
     951              : 
     952            0 : bool __clove_path_is_absolute(const char* path) {
     953            0 :     return !__clove_path_is_relative(path);
     954              : }
     955              : 
     956            2 : void __clove_path_to_os(char* path) {
     957            2 :     __clove_string_replace_char(path, '/', __CLOVE_PATH_SEPARATOR);
     958            2 :     __clove_string_replace_char(path, '\\', __CLOVE_PATH_SEPARATOR);
     959            2 : }
     960              : 
     961            1 : char* __clove_path_basepath(const char* path) {    
     962              :     char temp_path[__CLOVE_PATH_MAX_LEN];
     963            1 :     __clove_string_strcpy(temp_path, sizeof(temp_path), path);
     964              : 
     965              :     //Remove last path separator character if any
     966            1 :     bool last_char_is_win = __clove_string_endswith(path, "\\");
     967            1 :     bool last_char_is_uni = __clove_string_endswith(path, "/");
     968            1 :     if (last_char_is_win || last_char_is_uni) {
     969            0 :         size_t last_index = __clove_string_length(temp_path) - 1;
     970            0 :         temp_path[last_index] = '\0'; 
     971              :     }
     972              :     
     973              :     // Find the last path separator character in the input path.
     974            1 :     int last_char_win = __clove_string_last_indexof(temp_path, '\\');
     975            1 :     int last_char_uni = __clove_string_last_indexof(temp_path, '/'); //or unix or win eventually
     976            1 :     int last_char_index = last_char_win > last_char_uni ? last_char_win : last_char_uni;
     977              :     
     978              :     // If there are no separators in the path, return the current directory path.
     979            1 :     char* result = NULL;
     980            1 :     if (last_char_index < 0)  { 
     981              :         static char dot_path[3] = { '.', __CLOVE_PATH_SEPARATOR, '\0' };
     982            0 :         result = __clove_string_strdup(dot_path);
     983              :     } else {
     984              :         // Calculate base path length based on the position of the last path separator.
     985            1 :         size_t base_length = ((size_t)last_char_index) + 1;
     986            1 :         char* base_path = __CLOVE_MEMORY_CALLOC_TYPE_N(char, base_length);
     987            1 :         __clove_string_strncpy(base_path, base_length, temp_path, base_length - 1);
     988            1 :         __clove_path_to_os(base_path);
     989            1 :         result = base_path;
     990              :     }
     991              : 
     992            1 :     return result;
     993              : }
     994              : 
     995            1 : bool __clove_path_exists(const char* path) {
     996              :     struct stat buffer;
     997            1 :     return stat(path, &buffer) == 0;   
     998              : }
     999              : 
    1000            1 : char* __clove_path_to_absolute(const char* rel_path) {
    1001            1 :     char* result = NULL;
    1002              : #if _WIN32
    1003              :     result = __CLOVE_MEMORY_MALLOC_TYPE_N(char, _MAX_PATH);
    1004              :     
    1005              :     char* discarded = _fullpath(result, rel_path, _MAX_PATH );
    1006              :     __CLOVE_UNUSED_VAR(discarded); //fix "warning C6031: Return value ignored: '_fullpath'."
    1007              : #else
    1008            1 :     result = __CLOVE_MEMORY_MALLOC_TYPE_N(char, PATH_MAX);
    1009            1 :     if (__clove_path_exists(rel_path)) {
    1010            1 :         realpath(rel_path, result); // NULL
    1011              :     } else {
    1012            0 :         if (__clove_path_is_absolute(rel_path)) {
    1013            0 :             __clove_string_strcpy(result, PATH_MAX, rel_path);
    1014              :         } else { //relative
    1015            0 :             realpath(".", result); //getcwd
    1016            0 :             if (!__clove_string_endswith(result, "/")) {
    1017            0 :                 __clove_string_strcat(result, PATH_MAX, "/");
    1018              :             }
    1019            0 :             if (__clove_string_startswith(rel_path, "./")) {
    1020            0 :                 rel_path = rel_path + 2;
    1021              :             }
    1022              :             
    1023            0 :             __clove_string_strcat(result, PATH_MAX, rel_path);
    1024              :         }       
    1025              :     }
    1026              : 
    1027              : /*
    1028              :     //case where rel_path not really exists on fs
    1029              :     //(in this case only the first subpath of the rel_path is added by realpath)
    1030              :     if (!__clove_string_endswith(result, rel_path)) {
    1031              :         if (__clove_path_is_absolute(rel_path)) {
    1032              :             __clove_string_strcpy(result, PATH_MAX, rel_path);
    1033              :         } else { //relative
    1034              :             realpath(".", result);
    1035              :             if (!__clove_string_endswith(result, "/")) {
    1036              :                 __clove_string_strcat(result, PATH_MAX, "/");
    1037              :             }
    1038              :             __clove_string_strcat(result, PATH_MAX, rel_path);
    1039              :         }       
    1040              :     }
    1041              : */
    1042              : #endif 
    1043            1 :     return result;
    1044              : }
    1045              : #pragma endregion // Path Impl
    1046              : 
    1047              : #pragma region PRIVATE - Console Impl
    1048              : #include <stdio.h>
    1049              : #include <stdarg.h>
    1050            0 : void __clove_console_printf(const char* format, ...) {
    1051              :     va_list args;
    1052            0 :     va_start(args, format);
    1053            0 :     __clove_console_vprintf(format, args);
    1054            0 :     va_end(args);
    1055            0 : }
    1056           46 : void __clove_console_vprintf(const char* format, va_list args) {
    1057           46 :      vprintf(format, args);
    1058           46 : }
    1059            0 : void __clove_console_write(const char* str) {
    1060            0 :     __clove_console_printf("%s", str);
    1061            0 : }
    1062            0 : void __clove_console_writeline(const char* str) {
    1063            0 :     __clove_console_printf("%s\n", str);
    1064            0 : }
    1065              : #pragma endregion //Console Impl
    1066              : 
    1067              : #pragma region PRIVATE - File Impl
    1068            0 : FILE* __clove_file_open(const char* path, const char* mode) {
    1069              : #ifdef _WIN32
    1070              :     FILE* file;
    1071              :     fopen_s(&file, path, mode);
    1072              :     return file;
    1073              : #else
    1074            0 :     return fopen(path, mode);
    1075              : #endif
    1076              : }
    1077              : 
    1078            0 : void __clove_file_close(FILE* file) {
    1079            0 :     if (file) fclose(file);
    1080            0 : }
    1081              : 
    1082            0 : void __clove_file_printf(FILE* file, const char* format, ...) {
    1083              :     va_list args;
    1084            0 :     va_start(args, format);
    1085            0 :     __clove_file_vprintf(file, format, args);
    1086            0 :     va_end(args);
    1087            0 : }
    1088              : 
    1089            0 : void __clove_file_vprintf(FILE* file, const char* format, va_list args) {
    1090            0 :     vfprintf(file, format, args);
    1091            0 : }
    1092              : 
    1093            0 : void __clove_file_write(FILE* file, const char* str) {
    1094            0 :     __clove_file_printf(file, "%s", str);
    1095            0 : }
    1096              : 
    1097            0 : void __clove_file_writeline(FILE* file, const char* str) {
    1098            0 :     __clove_file_printf(file, "%s\n", str);
    1099            0 : }
    1100              : #pragma endregion //File Impl
    1101              : 
    1102              : 
    1103              : #pragma region PRIVATE - Memory Impl
    1104              : #include <string.h>
    1105           58 : void* __clove_memory_malloc(size_t size) {
    1106           58 :     return malloc(size);
    1107              : }
    1108              : 
    1109           24 : void* __clove_memory_calloc(size_t size) {
    1110           24 :     return calloc(1, size);
    1111              : }
    1112              : 
    1113            6 : void* __clove_memory_realloc(void* source, size_t size) {
    1114            6 :     return realloc(source, size);
    1115              : }
    1116              : 
    1117          228 : bool __clove_memory_memcpy(void* dest, size_t dest_size, const void* src, size_t src_size) {
    1118              : #ifdef _WIN32
    1119              :     return memcpy_s(dest, dest_size, src, src_size) == 0;
    1120              : #else
    1121              :     __CLOVE_UNUSED_VAR(dest_size);
    1122          228 :     return memcpy(dest, src, src_size) != NULL;
    1123              : #endif
    1124              : }
    1125              : 
    1126           82 : bool __clove_memory_memset(void* dest, size_t size, unsigned char value) {
    1127           82 :     return memset(dest, value, size) != NULL;
    1128              : }
    1129              : 
    1130          106 : void __clove_memory_free(void* source)
    1131              : {
    1132          106 :     free(source);
    1133          106 : }
    1134              : 
    1135              : #pragma endregion //Memory Impl
    1136              : 
    1137              : #pragma region PRIVATE - String Impl
    1138              : #include <string.h>
    1139              : #include <stdlib.h>
    1140              : #include <stdarg.h>
    1141              : #include <stdio.h>
    1142           12 : bool __clove_string_equal(const char* str1, const char* str2) {
    1143           12 :     return strcmp(str1, str2) == 0;
    1144              : }
    1145              : 
    1146            2 : bool __clove_string_equal_any(const char* str1, size_t count, ...) {
    1147              :     va_list args;
    1148            2 :     va_start(args, count); 
    1149            2 :     bool result = false;
    1150            4 :     for(size_t i=0; i < count; ++i) {
    1151            4 :         const char* arg = va_arg(args, const char*);
    1152            4 :         if (__clove_string_equal(str1, arg)) {
    1153            2 :             result = true;
    1154            2 :             break;
    1155              :         }
    1156              :     }
    1157            2 :     va_end(args);
    1158            2 :     return result;
    1159              : }
    1160              : 
    1161              : 
    1162           31 : bool __clove_string_startswith(const char* str1, const char* prefix) {
    1163           31 :     if (!str1 || !prefix) return false;
    1164           31 :     size_t prefix_len = __clove_string_length(prefix);
    1165           31 :     if (prefix_len == 0) {
    1166           31 :         size_t str_len = __clove_string_length(str1);
    1167           31 :         if (str_len == 0) return true;
    1168           31 :         else return false;
    1169              :     }
    1170            0 :     return __clove_string_strncmp(str1, prefix, prefix_len);
    1171              : }
    1172              : 
    1173            2 : bool __clove_string_endswith(const char* str, const char* suffix) {
    1174            2 :     if (!str || !suffix) return false;
    1175            2 :     size_t str_len = __clove_string_length(str);
    1176            2 :     size_t suf_len = __clove_string_length(suffix);
    1177            2 :     if (suf_len >  str_len) return false;
    1178            2 :     return __clove_string_strncmp(str + str_len - suf_len, suffix, suf_len);
    1179              : }
    1180              : 
    1181          217 : bool __clove_string_strncmp(const char* str1, const char* str2, size_t count) {
    1182          217 :     return strncmp(str1, str2, count) == 0;
    1183              : }
    1184              : 
    1185            1 : bool __clove_string_strcpy(char* dest, size_t dest_size, const char* source) {
    1186              : #ifdef _WIN32
    1187              :     return strcpy_s(dest, dest_size, source) == 0;
    1188              : #else
    1189              :     __CLOVE_UNUSED_VAR(dest_size);
    1190            1 :     return strcpy(dest, source) != NULL;
    1191              : #endif
    1192              : }
    1193              : 
    1194           43 : bool __clove_string_strncpy(char* dest, size_t dest_size, const char* source, size_t count) {
    1195              : #ifdef _WIN32
    1196              :     return strncpy_s(dest, dest_size, source, count) == 0;
    1197              : #else
    1198              :     __CLOVE_UNUSED_VAR(dest_size);
    1199           43 :     return strncpy(dest, source, count) != NULL;
    1200              : #endif
    1201              : }
    1202              : 
    1203            0 : bool __clove_string_strcat(char* dest, size_t dest_size, const char* source) {
    1204              : #ifdef _WIN32
    1205              :     return strcat_s(dest, dest_size, source) == 0;
    1206              : #else
    1207              :     __CLOVE_UNUSED_VAR(dest_size);
    1208            0 :     return strcat(dest, source) != NULL;
    1209              : #endif
    1210              : }
    1211              : 
    1212            0 : bool __clove_string_strncat(char* dest, size_t dest_size, const char* source, size_t count) {
    1213              : #ifdef _WIN32
    1214              :     return strncat_s(dest, dest_size, source, count) == 0;
    1215              : #else
    1216              :     __CLOVE_UNUSED_VAR(dest_size);
    1217            0 :     return strncat(dest, source, count) != NULL;
    1218              : #endif
    1219              : }
    1220              : 
    1221           24 : char* __clove_string_strdup(const char* str) {
    1222              : #ifdef _WIN32
    1223              :     return _strdup(str);
    1224              : #else
    1225           24 :     return strdup(str);
    1226              : #endif
    1227              : }
    1228              : 
    1229           78 : void __clove_string_sprintf(char* dest, size_t dest_size, const char* format, ...) {
    1230              :     va_list args;
    1231           78 :     va_start(args, format);
    1232              : #ifdef _WIN32
    1233              :     vsnprintf_s(dest, dest_size, dest_size, format, args);
    1234              : #else
    1235           78 :     vsnprintf(dest, dest_size, format, args);
    1236              : #endif
    1237           78 :     va_end(args);
    1238           78 : }
    1239              : 
    1240            0 : void __clove_string_vsprintf(char* dest, size_t dest_size, const char* format, va_list args) {
    1241              : #ifdef _WIN32
    1242              :     vsnprintf_s(dest, dest_size, dest_size, format, args);
    1243              : #else
    1244            0 :     vsnprintf(dest, dest_size, format, args);
    1245              : #endif
    1246            0 : }
    1247              : 
    1248          483 : size_t __clove_string_length(const char* str) {
    1249          483 :     return strlen(str);
    1250              : }
    1251              : 
    1252           45 : const char* __clove_string_strstr(const char* str1, const char* str2) {
    1253           45 :     return strstr(str1, str2);
    1254              : }
    1255              : 
    1256            0 : bool __clove_string_contains(const char* str, const char* contained) {
    1257            0 :     return __clove_string_strstr(str, contained) != NULL;
    1258              : }
    1259              : 
    1260           22 : char* __clove_string_escape(const char* string) {
    1261           22 :     size_t str_len = __clove_string_length(string);
    1262           22 :     size_t esc_len = str_len * 2 + 1; //worst case where each char needs escape
    1263           22 :     char* escaped = __CLOVE_MEMORY_CALLOC_TYPE_N(char, esc_len);
    1264              : 
    1265           22 :     size_t esc_index = 0;
    1266           75 :     for (size_t str_index = 0; str_index < str_len; ++str_index) {
    1267           53 :         char c = string[str_index];
    1268           53 :         switch (c)
    1269              :         {
    1270            0 :         case '\b':
    1271            0 :             escaped[esc_index++] = '\\';
    1272            0 :             escaped[esc_index] = 'b';
    1273            0 :             break;
    1274            0 :         case '\f':
    1275            0 :             escaped[esc_index++] = '\\';
    1276            0 :             escaped[esc_index] = 'f';
    1277            0 :             break;
    1278            0 :         case '\n':
    1279            0 :             escaped[esc_index++] = '\\';
    1280            0 :             escaped[esc_index] = 'n';
    1281            0 :             break;
    1282            0 :         case '\r':
    1283            0 :             escaped[esc_index++] = '\\';
    1284            0 :             escaped[esc_index] = 'r';
    1285            0 :             break;
    1286            0 :         case '\t':
    1287            0 :             escaped[esc_index++] = '\\';
    1288            0 :             escaped[esc_index] = 't';
    1289            0 :             break;
    1290            0 :         case '"':
    1291            0 :             escaped[esc_index++] = '\\';
    1292            0 :             escaped[esc_index] = '"';
    1293            0 :             break;
    1294            0 :         case '\\':
    1295            0 :             escaped[esc_index++] = '\\';
    1296            0 :             escaped[esc_index] = '\\';
    1297            0 :             break;
    1298           53 :         default:
    1299           53 :             escaped[esc_index] = c;
    1300           53 :             break;
    1301              :         }
    1302           53 :         esc_index++;
    1303              :     }
    1304           22 :     return escaped;
    1305              : }
    1306              : 
    1307            0 : char* __clove_string_csv_escape(const char* string) {
    1308            0 :     size_t str_len = __clove_string_length(string);
    1309            0 :     size_t esc_len = str_len * 2 + 2 + 1; //worst case where each char need escape + 2 for string who need to be enclosed in double quotes
    1310            0 :     char* escaped = __CLOVE_MEMORY_CALLOC_TYPE_N(char, esc_len);
    1311              : 
    1312            0 :     bool has_comma = false;
    1313            0 :     if (__clove_string_contains(string, ","))  has_comma = true;
    1314              : 
    1315            0 :     size_t esc_index = has_comma ? 1 : 0;
    1316            0 :     for (size_t str_index = 0; str_index < str_len; ++str_index) {
    1317            0 :         char c = string[str_index];
    1318            0 :         switch (c)
    1319              :         {
    1320            0 :         case '\b':
    1321            0 :             escaped[esc_index++] = '\\';
    1322            0 :             escaped[esc_index] = 'b';
    1323            0 :             break;
    1324            0 :         case '\f':
    1325            0 :             escaped[esc_index++] = '\\';
    1326            0 :             escaped[esc_index] = 'f';
    1327            0 :             break;
    1328            0 :         case '\n':
    1329            0 :             escaped[esc_index++] = '\\';
    1330            0 :             escaped[esc_index] = 'n';
    1331            0 :             break;
    1332            0 :         case '\r':
    1333            0 :             escaped[esc_index++] = '\\';
    1334            0 :             escaped[esc_index] = 'r';
    1335            0 :             break;
    1336            0 :         case '\t':
    1337            0 :             escaped[esc_index++] = '\\';
    1338            0 :             escaped[esc_index] = 't';
    1339            0 :             break;
    1340            0 :         case '"':
    1341            0 :             escaped[esc_index++] = '"'; //csv escape char for double quote
    1342            0 :             escaped[esc_index] = '"';
    1343            0 :             break;
    1344            0 :         case '\\':
    1345            0 :             escaped[esc_index++] = '\\';
    1346            0 :             escaped[esc_index] = '\\';
    1347            0 :             break;
    1348            0 :         default:
    1349            0 :             escaped[esc_index] = c;
    1350            0 :             break;
    1351              :         }
    1352            0 :         esc_index++;
    1353              :     }
    1354              : 
    1355            0 :     if (has_comma) {
    1356            0 :         escaped[0] = '"';
    1357            0 :         escaped[esc_index] = '"';
    1358              :     }
    1359              : 
    1360            0 :     return escaped;
    1361              : }
    1362              : 
    1363            0 : void __clove_string_ellipse(const char* string, size_t str_len, size_t pos, char* out, size_t out_size) {
    1364            0 :     if (str_len == 1) {
    1365            0 :         out[0] = '\0';
    1366            0 :         return;
    1367              :     }
    1368            0 :     if (str_len <= out_size-1) {
    1369            0 :         __clove_string_strcpy(out, out_size, string);
    1370            0 :         return;
    1371              :     }
    1372              : 
    1373            0 :     bool left_ellipse = false;
    1374            0 :     bool right_ellipse = false;
    1375            0 :     if (pos >= 4) {
    1376            0 :         left_ellipse = true;
    1377              :     }
    1378              : 
    1379            0 :     if (str_len-1 - pos >= 4) {
    1380            0 :         right_ellipse = true;
    1381              :     }
    1382              : 
    1383            0 :     size_t out_start = 0;
    1384            0 :     size_t start_index = 0;
    1385            0 :     size_t out_end = out_size - 1;
    1386              : 
    1387            0 :     if (left_ellipse) {
    1388            0 :         out_start = 3;
    1389            0 :         start_index = right_ellipse ? pos - 3 : str_len - 12;
    1390            0 :         out[0] = '.'; out[1] = '.'; out[2] = '.';
    1391              :     }
    1392              : 
    1393            0 :     if (right_ellipse) {
    1394            0 :         out_end -= 3;
    1395            0 :         out[out_end] = '.'; out[out_end + 1] = '.'; out[out_end + 2] = '.';
    1396              :     }
    1397            0 :     out[out_size - 1] = '\0';
    1398              : 
    1399            0 :     size_t to_copy = out_end - out_start;
    1400              : 
    1401              :     //Copia stringa
    1402            0 :     for (size_t i = 0; i < to_copy; ++i) {
    1403            0 :         out[out_start + i] = string[start_index + i];
    1404              :     }
    1405              : }
    1406              : 
    1407            4 : void __clove_string_replace_char(char* str, char src_chr, char dst_chr) {
    1408            4 :     size_t size = __clove_string_length(str);
    1409          100 :     for (size_t i = 0; i < size; ++i) {
    1410           96 :         if (str[i] == src_chr) {
    1411            7 :             str[i] = dst_chr;
    1412              :         }
    1413              :     }
    1414            4 : }
    1415              : 
    1416           41 : void __clove_string_pad_right(char* dest, size_t dest_size, size_t str_target_len) {    
    1417              :     //capped by dest buffer size, taking account space of null terminator
    1418           41 :     if (str_target_len >= dest_size) str_target_len = dest_size - 1; 
    1419              : 
    1420           41 :     size_t str_len = __clove_string_length(dest);
    1421              : 
    1422              :     //Compute padding length avoiding negative result
    1423           41 :     size_t pad_len = 0;
    1424           41 :     if (str_target_len > str_len) pad_len = str_target_len - str_len;
    1425              : 
    1426           41 :     char* pad_beg = dest + str_len;
    1427           41 :     char* pad_end = dest + str_len + pad_len;
    1428              :     
    1429           41 :     __clove_memory_memset(pad_beg , pad_len, '.');
    1430           41 :     *pad_end = '\0';
    1431           41 : }
    1432              : 
    1433            2 : int __clove_string_last_indexof(const char* source, char character) {
    1434            2 :     const char* char_ptr = strrchr(source, character);
    1435            2 :     if (char_ptr == NULL) return -1;
    1436            1 :     return (int)(char_ptr - source);
    1437              : }
    1438              : 
    1439              : #pragma endregion //String Impl
    1440              : 
    1441              : #pragma region PRIVATE - String View Impl
    1442              : #include <stdlib.h>
    1443          135 : __clove_string_view_t __clove_string_view_from_offs(const char* source, size_t begin_offset, size_t end_offset) {
    1444              :     __clove_string_view_t v;
    1445          135 :     v.begin = source + begin_offset;
    1446          135 :     v.length = end_offset - begin_offset + 1;
    1447          135 :     return v;
    1448              : }
    1449              : 
    1450           45 : __clove_string_view_t __clove_string_view_from_be(const char* begin, const char* end) {
    1451           45 :     return __clove_string_view_from_offs(begin, 0, end - begin);
    1452              : }
    1453              : 
    1454           45 : __clove_string_view_t __clove_string_view_from_len(const char* begin, size_t length) {
    1455           45 :     return __clove_string_view_from_offs(begin, 0, length-1);
    1456              : }
    1457              : 
    1458           45 : __clove_string_view_t __clove_string_view_from_str(const char* str) {
    1459           45 :     return __clove_string_view_from_offs(str, 0, __clove_string_length(str) - 1);
    1460              : }
    1461              : 
    1462          215 : size_t __clove_string_view_length(const __clove_string_view_t* view) {
    1463          215 :     return view->length;
    1464              : }
    1465              : 
    1466            0 : const char* __clove_string_view_begin(const __clove_string_view_t* view) {
    1467            0 :     return view->begin;
    1468              : }
    1469              : 
    1470           45 : const char* __clove_string_view_end(const __clove_string_view_t* view) {
    1471           45 :     return view->begin + view->length - 1;
    1472              : }
    1473              : 
    1474           44 : bool __clove_string_view_equals(const __clove_string_view_t* view1, const __clove_string_view_t* view2) {
    1475           44 :     if (view1->length != view2->length) return false;
    1476           44 :     return strncmp(view1->begin, view2->begin, view1->length) == 0;  //richiamare ncmp
    1477              : }
    1478              : 
    1479            0 : bool __clove_string_view_ncmp(const __clove_string_view_t* view1, const __clove_string_view_t* view2, size_t count) {
    1480            0 :     return __clove_string_strncmp(view1->begin, view2->begin, count);
    1481              : }
    1482              : 
    1483            0 : bool __clove_string_view_endswith(const __clove_string_view_t* view, const __clove_string_view_t* suffix) {
    1484            0 :     if (suffix->length > view->length) return false;
    1485              : 
    1486            0 :     const char* end = __clove_string_view_end(view);
    1487            0 :     const char* beg = end - suffix->length+1;
    1488            0 :     return __clove_string_strncmp(beg, suffix->begin, suffix->length);
    1489              : }
    1490              : 
    1491            0 : bool __clove_string_view_nendswith(const __clove_string_view_t* view, const __clove_string_view_t* suffix, size_t suffix_begin_offset) {
    1492            0 :     __clove_string_view_t suffix_with_offset = __clove_string_view_from_be(suffix->begin + suffix_begin_offset, __clove_string_view_end(suffix));
    1493            0 :     return __clove_string_view_endswith(view, &suffix_with_offset);
    1494              : }
    1495              : 
    1496          215 : bool __clove_string_view_strequals(const __clove_string_view_t* view, const char* str) {
    1497          215 :     size_t length = __clove_string_view_length(view);
    1498          215 :     if (__clove_string_length(str) != length) return false;
    1499          215 :     return __clove_string_strncmp(view->begin, str, length);
    1500              : }
    1501              : 
    1502           42 : char* __clove_string_view_as_string(const __clove_string_view_t* view) {
    1503           42 :     char* str = (char*)__clove_memory_malloc(view->length + 1); //size+1 for null terminator
    1504           42 :     __clove_string_strncpy(str, view->length + 1, view->begin, view->length);
    1505           42 :     str[view->length] = '\0'; //maybe could be avoided?!
    1506           42 :     return str;
    1507              : }
    1508              : 
    1509            0 : char __clove_string_view_at(const __clove_string_view_t* view, size_t index) {
    1510            0 :     return view->begin[index]; //No index check, preserving undefined behaviour
    1511              : }
    1512              : 
    1513            0 : bool __clove_string_view_contains(const __clove_string_view_t* view, const __clove_string_view_t* fixture) {
    1514            0 :     if (fixture->length > view->length) return false;
    1515            0 :     size_t residual_length = view->length;
    1516            0 :     size_t index = 0;
    1517            0 :     while(fixture->length <= residual_length) { 
    1518            0 :         if (__clove_string_strncmp(view->begin + index, fixture->begin, fixture->length)) return true;
    1519            0 :         residual_length--;
    1520            0 :         index++;
    1521              :     }
    1522            0 :     return false;
    1523              : }
    1524              : #pragma endregion // String View Impl
    1525              : 
    1526              : #pragma region PRIVATE - Time Impl
    1527           43 : __clove_time_t __clove_time_sub(__clove_time_t* t1, __clove_time_t* t2) {
    1528              :     __clove_time_t result;
    1529           43 :     result.seconds = t1->seconds - t2->seconds;
    1530           43 :     result.nanos_after_seconds = t1->nanos_after_seconds - t2->nanos_after_seconds;
    1531           43 :     if (result.seconds > 0 && result.nanos_after_seconds < 0) {
    1532            0 :         result.seconds--;
    1533            0 :         result.nanos_after_seconds += __CLOVE_TIME_TRANSL_NANOS_PER_SEC;
    1534              :     }
    1535           43 :     else if (result.seconds < 0 && result.nanos_after_seconds > 0) {
    1536            0 :         result.seconds++;
    1537            0 :         result.nanos_after_seconds -= __CLOVE_TIME_TRANSL_NANOS_PER_SEC;
    1538              :     }
    1539           43 :     return result;
    1540              : }
    1541              : 
    1542            0 : __clove_time_t __clove_time_sum(__clove_time_t* t1, __clove_time_t* t2) {
    1543              :     __clove_time_t result;
    1544            0 :     result.seconds = t1->seconds + t2->seconds;
    1545            0 :     result.nanos_after_seconds = t1->nanos_after_seconds + t2->nanos_after_seconds;
    1546            0 :     if (result.nanos_after_seconds >= __CLOVE_TIME_TRANSL_NANOS_PER_SEC) {
    1547            0 :         result.seconds++;
    1548            0 :         result.nanos_after_seconds -= __CLOVE_TIME_TRANSL_NANOS_PER_SEC;
    1549              :     }
    1550            0 :     return result;
    1551              : }
    1552              : 
    1553            1 : unsigned long long __clove_time_to_millis(__clove_time_t* t) {
    1554            1 :     unsigned long long result = 0;
    1555            1 :     result += t->seconds * __CLOVE_TIME_TRANSL_MILLIS_PER_SEC;
    1556            1 :     result += t->nanos_after_seconds / __CLOVE_TIME_TRANSL_NANOS_PER_MILLIS;
    1557            1 :     return result;
    1558              : }
    1559              : 
    1560           10 : unsigned long long __clove_time_to_nanos(__clove_time_t* t) {
    1561           10 :     unsigned long long result = 0;
    1562           10 :     result += t->seconds * __CLOVE_TIME_TRANSL_NANOS_PER_SEC;
    1563           10 :     result += t->nanos_after_seconds;
    1564           10 :     return result;
    1565              : }
    1566              : 
    1567              : #ifdef _WIN32
    1568              : #include <windows.h>
    1569              : #include <time.h>
    1570              : __clove_time_t __clove_time_now(void) {
    1571              :     static bool first_time = true;
    1572              :     static LARGE_INTEGER count_per_sec;
    1573              :     __clove_time_t result;
    1574              :     result.seconds = 0;
    1575              :     result.nanos_after_seconds = 0;
    1576              : 
    1577              :     if (first_time) {
    1578              :         first_time = false;
    1579              :         if (QueryPerformanceFrequency(&count_per_sec) == 0) {
    1580              :             return result;
    1581              :         }
    1582              :     }
    1583              : 
    1584              :     LARGE_INTEGER count;
    1585              :     if (QueryPerformanceCounter(&count) == 0) {
    1586              :         return result;
    1587              :     }
    1588              : 
    1589              :     result.seconds = count.QuadPart / count_per_sec.QuadPart;
    1590              :     result.nanos_after_seconds = ((count.QuadPart % count_per_sec.QuadPart) * __CLOVE_TIME_TRANSL_NANOS_PER_SEC) / count_per_sec.QuadPart;
    1591              :     return result;
    1592              : }
    1593              : #else 
    1594              : #include <time.h>
    1595              : #include <unistd.h>
    1596           86 : __clove_time_t __clove_time_now(void) {
    1597              :     struct timespec time_data;
    1598           86 :     clock_gettime(CLOCK_REALTIME, &time_data);
    1599              : 
    1600              :     __clove_time_t result;
    1601           86 :     result.seconds = time_data.tv_sec;
    1602           86 :     result.nanos_after_seconds = time_data.tv_nsec;
    1603           86 :     return result;
    1604              : }
    1605              : #endif //_WIN32
    1606              : #pragma endregion // Time Impl
    1607              : 
    1608              : #pragma region PRIVATE - Stack Impl
    1609              : #include <stdbool.h>
    1610              : #include <stdlib.h>
    1611            1 : void __clove_stack_init(__clove_stack_t* stack, size_t initial_capacity) {
    1612            1 :     stack->capacity = initial_capacity;
    1613            1 :     stack->count = 0;
    1614            1 :     stack->item_size = sizeof(size_t);
    1615            1 :     stack->items = (unsigned char*)__clove_memory_malloc(stack->item_size * stack->capacity);
    1616            1 : }
    1617              : 
    1618           60 : bool __clove_stack_is_empty(__clove_stack_t* stack) {
    1619           60 :     return stack->count == 0;
    1620              : }
    1621              : 
    1622          118 : void __clove_stack_push(__clove_stack_t* stack, size_t item) {
    1623          118 :     if (stack->count == stack->capacity) {
    1624            0 :         stack->capacity *= 2;
    1625            0 :         stack->items = (unsigned char*)__clove_memory_realloc(stack->items, stack->item_size * stack->capacity);
    1626              :     }
    1627          118 :     size_t byte_index = stack->count * stack->item_size;
    1628          118 :     size_t* item_ptr = (size_t*)&(stack->items[byte_index]);
    1629          118 :     *item_ptr = item;
    1630          118 :     stack->count++;
    1631          118 : }
    1632              : 
    1633          118 : size_t __clove_stack_pop(__clove_stack_t* stack) {
    1634          118 :     if (stack->count == 0) return 0; //shouldn't happen
    1635              : 
    1636          118 :     size_t byte_index = (stack->count - 1) * stack->item_size;
    1637          118 :     size_t* item_ptr = (size_t*)&(stack->items[byte_index]);
    1638          118 :     stack->count--;
    1639          118 :     return *item_ptr;
    1640              : }
    1641              : 
    1642            1 : void __clove_stack_free(__clove_stack_t* stack) {
    1643            1 :     if (!stack) return;
    1644            1 :     __clove_memory_free(stack->items);
    1645            1 :     stack->items = NULL;
    1646            1 :     stack->capacity = 0;
    1647            1 :     stack->count = 0;
    1648            1 :     stack->item_size = 0;
    1649              : }
    1650              : #pragma endregion // Stack Impl
    1651              : 
    1652              : #pragma region PRIVATE - Vector Impl
    1653              : #include <stdlib.h>
    1654              : #include <stdint.h>
    1655            5 : __clove_vector_params_t __clove_vector_params_defaulted(size_t item_size) {
    1656              :     __clove_vector_params_t params;
    1657            5 :     params.item_size = item_size;
    1658            5 :     params.initial_capacity = 10;
    1659            5 :     params.item_ctor = NULL;
    1660            5 :     params.item_dtor = NULL;
    1661            5 :     return params;
    1662              : }
    1663              : 
    1664            2 : __clove_vector_t __clove_vector_null(void) {
    1665              :     __clove_vector_t v;
    1666            2 :     v.capacity = 0;
    1667            2 :     v.item_size = 0;
    1668            2 :     v.count = 0;
    1669            2 :     v.items = NULL;
    1670            2 :     v.item_ctor = NULL;
    1671            2 :     v.item_dtor = NULL;
    1672            2 :     v.swap_temp = NULL;
    1673            2 :     return v;
    1674              : }
    1675              : 
    1676            5 : void __clove_vector_init(__clove_vector_t* vector, __clove_vector_params_t* params) {
    1677            5 :     vector->capacity = params->initial_capacity;
    1678            5 :     vector->count = 0;
    1679            5 :     vector->item_size = params->item_size;
    1680            5 :     vector->items = (unsigned char*)__clove_memory_malloc(vector->item_size * vector->capacity);
    1681            5 :     vector->item_ctor = params->item_ctor;
    1682            5 :     vector->item_dtor = params->item_dtor;
    1683            5 :     vector->swap_temp = __clove_memory_malloc(vector->item_size);
    1684            5 : }
    1685              : 
    1686           98 : size_t __clove_vector_count(const __clove_vector_t* vector) {
    1687           98 :     return vector->count;
    1688              : }
    1689              : 
    1690           90 : bool __clove_vector_is_empty(const __clove_vector_t* vector) {
    1691           90 :     return vector->count == 0;
    1692              : }
    1693              : 
    1694           93 : void* __clove_vector_add_slot(__clove_vector_t* vector) {
    1695           93 :     if (vector->count == vector->capacity) {
    1696            6 :         vector->capacity *= 2;
    1697            6 :         vector->items = (unsigned char*)__clove_memory_realloc(vector->items, vector->item_size * vector->capacity);
    1698              :     }
    1699           93 :     size_t byte_index = vector->count * vector->item_size;
    1700           93 :     vector->count++;
    1701           93 :     void* item = (void*)&(vector->items[byte_index]);
    1702           93 :     if (vector->item_ctor) vector->item_ctor(item);
    1703           93 :     return item;
    1704              : }
    1705              : 
    1706            0 : void __clove_vector_add_all(__clove_vector_t* vector, const __clove_vector_t* other) {
    1707            0 :     if (vector->item_size != other->item_size) return;
    1708              :     
    1709            0 :     size_t vector_free_slots = vector->capacity - vector->count;
    1710            0 :     if (vector_free_slots < other->count)
    1711              :     {
    1712            0 :         vector->capacity = vector->count + other->count;
    1713            0 :         vector->items = (unsigned char*)__clove_memory_realloc(vector->items, vector->item_size * vector->capacity);
    1714              :     }
    1715              :     
    1716            0 :     size_t byte_index = vector->count * vector->item_size;
    1717              :     
    1718            0 :     void* dest = (void*)&(vector->items[byte_index]);
    1719            0 :     size_t dest_size = (vector->capacity - vector->count) * vector->item_size;
    1720            0 :     void* src = other->items;
    1721            0 :     size_t src_size =  other->count * other->item_size;
    1722            0 :     __clove_memory_memcpy(dest, dest_size, src, src_size);
    1723              :     
    1724            0 :     vector->count += other->count;
    1725              : }
    1726              : 
    1727         1074 : void* __clove_vector_get(const __clove_vector_t* vector, size_t index) {
    1728              :     //if (index < 0) return NULL; //can never happen because of size_t
    1729         1074 :     if (index >= vector->count) return NULL;
    1730         1074 :     size_t byte_index = index * vector->item_size;
    1731         1074 :     return (void*)&(vector->items[byte_index]);
    1732              : }
    1733              : 
    1734          152 : void __clove_vector_set(__clove_vector_t* vector, size_t index, void* item) {
    1735          152 :     void* found = __clove_vector_get(vector, index);
    1736          152 :     if (!found) return;
    1737          152 :     __clove_memory_memcpy(found, vector->item_size, item, vector->item_size);
    1738              : }
    1739              : 
    1740            7 : void __clove_vector_free(__clove_vector_t* vector) {
    1741            7 :     if (vector->item_dtor) {
    1742           44 :         for (size_t i = 0; i < vector->count; ++i) {
    1743           42 :             void* item = __clove_vector_get(vector, i);
    1744           42 :             vector->item_dtor(item);
    1745              :         }
    1746            2 :         vector->item_dtor = NULL;
    1747              :     }
    1748              : 
    1749            7 :     if (vector->items) {
    1750            5 :         __clove_memory_free(vector->items);
    1751            5 :         vector->items = NULL;
    1752              :     }
    1753              : 
    1754            7 :     if (vector->swap_temp) {
    1755            5 :         __clove_memory_free(vector->swap_temp);
    1756            5 :         vector->swap_temp = NULL;
    1757              :     }
    1758            7 :     vector->capacity = 0;
    1759            7 :     vector->count = 0;
    1760            7 : }
    1761              : 
    1762           76 : void __clove_vector_swap(__clove_vector_t* vector, size_t index1, size_t index2) {
    1763           76 :     void* curr = __clove_vector_get(vector, index1);
    1764           76 :     void* next = __clove_vector_get(vector, index2);
    1765           76 :     if (!curr || !next) return;
    1766           76 :     __clove_memory_memcpy(vector->swap_temp, vector->item_size, curr, vector->item_size);
    1767           76 :     __clove_vector_set(vector, index1, next);
    1768           76 :     __clove_vector_set(vector, index2, vector->swap_temp);
    1769              : }
    1770              : 
    1771              : //QuickSort
    1772           29 : size_t __clove_vector_quicksort_partition(__clove_vector_t* vector, int (*comparator)(void*, void*), size_t start_index, size_t end_index) {
    1773           29 :     size_t pivot_index = start_index;
    1774           29 :     size_t left_index = start_index;
    1775           29 :     size_t right_index = end_index;
    1776              : 
    1777           29 :     void* item = NULL;
    1778           29 :     void* pivot = NULL;
    1779           73 :     while (left_index < right_index) {
    1780              :         //Moving pivot to right
    1781           61 :         bool item_is_gte = true;
    1782          225 :         while (item_is_gte && pivot_index < right_index) {
    1783          164 :             item = __clove_vector_get(vector, right_index);
    1784          164 :             pivot = __clove_vector_get(vector, pivot_index);
    1785          164 :             item_is_gte = (comparator(item, pivot) >= 0);
    1786          164 :             if (item_is_gte) right_index--;
    1787              :         }
    1788              : 
    1789           61 :         if (pivot_index != right_index) {
    1790           44 :             __clove_vector_swap(vector, pivot_index, right_index);
    1791           44 :             pivot_index = right_index;
    1792              :         }
    1793              : 
    1794           61 :         if (left_index == right_index) break;
    1795              : 
    1796              :         //Moving pivot to left
    1797           44 :         bool item_is_lte = true;
    1798          177 :         while (item_is_lte && pivot_index > left_index) {
    1799          133 :             item = __clove_vector_get(vector, left_index);
    1800          133 :             pivot = __clove_vector_get(vector, pivot_index);
    1801          133 :             item_is_lte = (comparator(item, pivot) <= 0);
    1802          133 :             if (item_is_lte) left_index++;
    1803              :         }
    1804              : 
    1805           44 :         if (pivot_index != left_index) {
    1806           32 :             __clove_vector_swap(vector, pivot_index, left_index);
    1807           32 :             pivot_index = left_index;
    1808              :         }
    1809              :     }
    1810           29 :     return pivot_index;
    1811              : }
    1812              : 
    1813            1 : void __clove_vector_quicksort_iterative(__clove_vector_t* vector, int (*comparator)(void*, void*), size_t start_index, size_t end_index) {
    1814              :     __clove_stack_t index_pairs_stack;
    1815            1 :     __clove_stack_init(&index_pairs_stack, vector->count);
    1816              : 
    1817            1 :     __clove_stack_push(&index_pairs_stack, start_index);
    1818            1 :     __clove_stack_push(&index_pairs_stack, end_index);
    1819              : 
    1820           60 :     while (!__clove_stack_is_empty(&index_pairs_stack)) {
    1821           59 :         end_index = __clove_stack_pop(&index_pairs_stack);
    1822           59 :         start_index = __clove_stack_pop(&index_pairs_stack);
    1823              : 
    1824           59 :         if (start_index >= end_index) continue;
    1825              : 
    1826              :         //find a pivot and put it in the right position
    1827           29 :         size_t pivot_index = __clove_vector_quicksort_partition(vector, comparator, start_index, end_index);
    1828              : 
    1829              :         //left array indexes
    1830           29 :         if (pivot_index != 0) { //protect size_t overflow (for instance, this happens for already sorted items)
    1831           29 :             __clove_stack_push(&index_pairs_stack, start_index);
    1832           29 :             __clove_stack_push(&index_pairs_stack, pivot_index - 1);
    1833              :         }
    1834              : 
    1835              :         //right array indexes
    1836           29 :         if (pivot_index != SIZE_MAX) { //protect size_t overflow (for symmetry)
    1837           29 :             __clove_stack_push(&index_pairs_stack, pivot_index + 1);
    1838           29 :             __clove_stack_push(&index_pairs_stack, end_index);
    1839              :         }
    1840              :     }
    1841            1 :     __clove_stack_free(&index_pairs_stack);
    1842            1 : }
    1843              : 
    1844            1 : void __clove_vector_sort(__clove_vector_t* vector, int (*comparator)(void*, void*)) {
    1845            1 :     if (vector->count <= 1) return;
    1846            1 :     __clove_vector_quicksort_iterative(vector, comparator, 0, vector->count - 1);
    1847              : }
    1848              : 
    1849            1 : void __clove_vector_collection_dtor(void* vector) {
    1850            1 :     __clove_vector_t* vector_ptr = (__clove_vector_t*)vector;
    1851            1 :     __clove_vector_free(vector_ptr);
    1852            1 : }
    1853              : #pragma endregion // Vector Impl
    1854              : 
    1855              : #pragma region PRIVATE - Map Impl
    1856              : #include <stdlib.h>
    1857              : // Bernstein classic hash
    1858           25 : size_t __clove_map_hash_djb33x(void *key, size_t keylen) {
    1859           25 :     size_t hash = 5381;
    1860           25 :     unsigned char *key_as_num = (unsigned char *)key;
    1861          132 :     for (size_t i = 0; i < keylen; i++) {
    1862          107 :         hash = ((hash << 5) + hash) ^ key_as_num[i];
    1863              :     }
    1864           25 :     return hash;
    1865              : }
    1866              : 
    1867            1 : __clove_map_params_t __clove_map_params_defaulted(void) 
    1868              : {
    1869              :     __clove_map_params_t params;
    1870            1 :     params.initial_hash_size = 10;
    1871            1 :     params.hash_funct = __clove_map_hash_djb33x;
    1872            1 :     params.item_dtor = NULL;
    1873            1 :     return params;
    1874              : }
    1875              : 
    1876            1 : void __clove_map_init(__clove_map_t* map, __clove_map_params_t* params) {
    1877            1 :     map->hashmap_size = params->initial_hash_size;
    1878            1 :     map->hashmap = __CLOVE_MEMORY_CALLOC_TYPE_N(__clove_map_node_t*, map->hashmap_size);
    1879            1 :     map->hash_funct = params->hash_funct;
    1880            1 :     map->item_dtor = params->item_dtor;
    1881            1 :     map->count = 0;
    1882            1 : }
    1883              : 
    1884            1 : void __clove_map_free(__clove_map_t* map) {
    1885           11 :     for(size_t i=0; i < map->hashmap_size; ++i) {
    1886           10 :         if (!map->hashmap[i]) continue;
    1887            1 :         __clove_map_node_t* node = map->hashmap[i];
    1888              : 
    1889            1 :         __clove_map_node_t* current = node;
    1890            2 :         while(current) {
    1891            1 :             __clove_map_node_t* next = current->next;
    1892              : 
    1893            1 :             __clove_memory_free(current->key);
    1894            1 :             if (map->item_dtor) {
    1895              :                 //if dtor set, means map become owner of the item (and its memory)
    1896            1 :                 map->item_dtor(current->value);
    1897            1 :                 __clove_memory_free(current->value);
    1898              :             }
    1899            1 :             __clove_memory_free(current);
    1900              : 
    1901            1 :             current = next;
    1902              :         }
    1903              :     }
    1904            1 :     __clove_memory_free(map->hashmap);
    1905            1 :     map->hashmap = NULL;
    1906            1 :     map->hashmap_size = 0;
    1907            1 :     map->count = 0;
    1908            1 : }
    1909              : 
    1910            0 : size_t __clove_map_count(__clove_map_t* map) {
    1911            0 :     return map->count;
    1912              : }
    1913              : 
    1914           16 : bool __clove_map_has_key(__clove_map_t* map, const char* key) {
    1915           16 :     size_t key_size = __clove_string_length(key);
    1916           16 :     size_t hash = __clove_map_hash_djb33x((void*)key, key_size);
    1917           16 :     size_t hash_index = hash % map->hashmap_size;
    1918              : 
    1919           16 :     __clove_map_node_t* node = map->hashmap[hash_index];
    1920           16 :     while(node) {
    1921            1 :         if (__clove_string_equal(key, node->key)) return true;
    1922            0 :         node = node->next;
    1923              :     }
    1924           15 :     return false;
    1925              : }
    1926              : 
    1927            1 : void __clove_map_put(__clove_map_t* dict, const char* key, void* value) {
    1928            1 :     size_t key_size = __clove_string_length(key);
    1929            1 :     size_t hash = dict->hash_funct((void*)key, key_size);
    1930            1 :     size_t hash_index = hash % dict->hashmap_size;
    1931              :     //Scenario 1: hash(Key) not present
    1932            1 :     if (!dict->hashmap[hash_index]) {
    1933            1 :         __clove_map_node_t* node = __CLOVE_MEMORY_MALLOC_TYPE(__clove_map_node_t);
    1934            1 :         node->key = __clove_string_strdup(key);
    1935            1 :         node->key_size = key_size;
    1936            1 :         node->value = value;
    1937            1 :         node->next = NULL;
    1938              : 
    1939            1 :         dict->hashmap[hash_index] = node;
    1940            1 :         dict->count++;
    1941              :     } else { //Scenario 2: hash(Key) already present 
    1942            0 :         __clove_map_node_t* node = dict->hashmap[hash_index];
    1943            0 :         __clove_map_node_t* last = NULL;
    1944              :         
    1945              :         //Scenario 2.1: key already exists
    1946            0 :         while(node) {
    1947            0 :             last = node;
    1948            0 :             if (node->key_size == key_size && __clove_string_equal(key, node->key)) {
    1949            0 :                 node->value = value;
    1950            0 :                 return;
    1951              :             }
    1952            0 :             node = node->next;
    1953              :         }
    1954              : 
    1955              :         //Scenario 2.2: key not exists
    1956            0 :         __clove_map_node_t* new_node = __CLOVE_MEMORY_MALLOC_TYPE(__clove_map_node_t);
    1957            0 :         new_node->key = __clove_string_strdup(key);
    1958            0 :         new_node->key_size = key_size;
    1959            0 :         new_node->value = value;
    1960            0 :         new_node->next = NULL;
    1961              : 
    1962            0 :         last->next = new_node;
    1963            0 :         dict->count++;
    1964              :     }
    1965              : 
    1966              : }
    1967              : 
    1968            8 : void* __clove_map_get(__clove_map_t* map, const char* key) {
    1969            8 :     size_t key_size = __clove_string_length(key);
    1970            8 :     size_t hash = map->hash_funct((void*)key, key_size);
    1971            8 :     size_t hash_index = hash % map->hashmap_size;
    1972              : 
    1973            8 :     __clove_map_node_t* node = map->hashmap[hash_index];
    1974            9 :     while(node) {
    1975            1 :         if (__clove_string_equal(key, node->key)) return node->value;
    1976            1 :         node = node->next;
    1977              :     }
    1978            8 :     return NULL;
    1979              : }
    1980              : #pragma endregion // Map Impl
    1981              : 
    1982              : #pragma region PRIVATE - CommandLine Impl
    1983              : #include <stdbool.h>
    1984              : #include <string.h>
    1985            1 : bool __clove_cmdline_next_opt(__clove_cmdline_t* cmdline, const char** opt_out) {
    1986            2 :    while(cmdline->arg_index < cmdline->argc) {
    1987            0 :         const char* current = cmdline->argv[cmdline->arg_index];
    1988            0 :         cmdline->arg_index++;
    1989            0 :         if (__clove_string_startswith(current, "--") && __clove_string_length(current) > 3) {
    1990            0 :             *opt_out = current + 2;
    1991            0 :             return true;
    1992            0 :         } else if (__clove_string_startswith(current, "-") && __clove_string_length(current) == 2) {
    1993            0 :             *opt_out = current + 1;
    1994            0 :             return true;
    1995              :         }
    1996              :    }
    1997            1 :    return false;
    1998              : }
    1999              : 
    2000            0 : bool __clove_cmdline_next_arg(__clove_cmdline_t* cmdline, const char** arg_out) {
    2001            0 :     if (cmdline->arg_index >= cmdline->argc) return false;
    2002            0 :     const char* arg = cmdline->argv[cmdline->arg_index];
    2003            0 :     if (__clove_string_startswith(arg, "-")) return false; 
    2004            0 :     *arg_out = arg;
    2005            0 :     cmdline->arg_index++;
    2006            0 :     return true;
    2007              : }
    2008              : 
    2009            1 : void __clove_cmdline_init(__clove_cmdline_t* cmd, const char** argv, int argc) {
    2010            1 :     cmd->argv = argv;
    2011            1 :     cmd->argc = argc;
    2012            1 :     cmd->arg_index = 1;
    2013              : 
    2014            1 :     __clove_map_params_t params = __clove_map_params_defaulted();
    2015            1 :     params.item_dtor = __clove_vector_collection_dtor;
    2016            1 :     __clove_map_init(&cmd->map, &params);
    2017              : 
    2018              :     const char* opt;
    2019            1 :     while(__clove_cmdline_next_opt(cmd, &opt)) {
    2020            0 :         const char* arg = NULL;
    2021            0 :         __clove_cmdline_next_arg(cmd, &arg);
    2022            0 :         __clove_cmdline_add_opt(cmd, opt, arg);
    2023              :     }
    2024            1 : }
    2025              : 
    2026            1 : void __clove_cmdline_free(__clove_cmdline_t* cmd) {
    2027            1 :     __clove_map_free(&(cmd->map));
    2028            1 :     cmd->argv = NULL;
    2029            1 :     cmd->argc = 0;
    2030            1 :     cmd->arg_index = 0;
    2031            1 : }
    2032              : 
    2033            1 : void __clove_cmdline_add_opt(__clove_cmdline_t* cmd, const char* opt, const char* value) {
    2034              :     __clove_vector_t* values;
    2035            1 :     if (__clove_map_has_key(&(cmd->map), opt)) {
    2036            0 :         values = (__clove_vector_t*)__clove_map_get(&(cmd->map), opt);
    2037              :     } else {
    2038            1 :         values = __CLOVE_MEMORY_MALLOC_TYPE(__clove_vector_t);
    2039            1 :         __CLOVE_VECTOR_INIT(values, char*);
    2040            1 :         __clove_map_put(&(cmd->map), opt, values);
    2041              :     }
    2042            1 :     const char* *slot = (const char* *)__clove_vector_add_slot(values);
    2043            1 :     *slot = value;
    2044            1 : }
    2045              : 
    2046           15 : bool __clove_cmdline_has_opt(__clove_cmdline_t* cmdline, const char* opt) {
    2047           15 :     return __clove_map_has_key(&(cmdline->map), opt);
    2048              : }
    2049            8 : const char* __clove_cmdline_get_opt_value(__clove_cmdline_t* cmdline, const char* opt) {
    2050            8 :     const __clove_vector_t* values = __clove_cmdline_get_opt_values(cmdline, opt);
    2051            8 :     if (!values || __clove_vector_count(values) == 0) return NULL;
    2052            0 :     return *(char**)__clove_vector_get(values, 0);
    2053              : }
    2054            8 : const __clove_vector_t* __clove_cmdline_get_opt_values(__clove_cmdline_t* cmdline, const char* opt) {
    2055            8 :     return (__clove_vector_t*)__clove_map_get(&(cmdline->map), opt);
    2056              : }
    2057              : 
    2058            6 : bool __clove_cmdline_has_any_opt(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2) {
    2059            6 :     return __clove_cmdline_has_opt(cmdline, opt1) || __clove_cmdline_has_opt(cmdline, opt2);
    2060              : }
    2061              : 
    2062            4 : const char* __clove_cmdline_get_any_opt_value(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2) {
    2063            4 :     const char* result = __clove_cmdline_get_opt_value(cmdline, opt1);
    2064            4 :     if (result) return result;
    2065            4 :     return __clove_cmdline_get_opt_value(cmdline, opt2);
    2066              : }
    2067              : 
    2068            4 : const char* __clove_cmdline_get_any_opt_value_defaulted(__clove_cmdline_t* cmdline, const char* opt1, const char* opt2, const char* default_value) {
    2069            4 :     const char* result = __clove_cmdline_get_any_opt_value(cmdline, opt1, opt2);
    2070            4 :     if (result) return result;
    2071            4 :     return default_value;
    2072              : }
    2073              : 
    2074            1 : __clove_cmdline_errno_t __clove_cmdline_handle_help(__clove_cmdline_t* cmd) {
    2075            1 :     if (!__clove_cmdline_has_any_opt(cmd, "h", "help")) return __CLOVE_CMD_ERRNO_UNMANAGED;    
    2076            0 :     printf("CLove-Unit v%s\n", __CLOVE_VERSION); 
    2077            0 :     printf("usage:\n");
    2078            0 :     printf("%*s<executable> [options]\n", 3," ");
    2079            0 :     printf("where options are:\n");
    2080            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"<no-options>",             5," ", "Run all tests producing a 'pretty' print report (default behavior).");
    2081            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-b, --base-path",          5," ", "Base path for test sources. Allow to shorten test file paths when running/listing tests.");
    2082            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-d, --run-detail <level>", 5," ", "Control Run Tests report detail level: '1' (failed), '2' (failed+skipped), '3' (passed+failed+skipped). Default is '3'.");
    2083            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-e, --exclude <expr>",     5," ", "Suite/Test expression to be excluded. Works when running/listing tests.");
    2084            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-h, --help",               5," ", "Display usage information.");
    2085            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-i, --include <expr>",     5," ", "Suite/Test expression to be included. Works when running/listing tests.");
    2086            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-l, --list-tests",         5," ", "List all/matching test cases in 'pretty' format (default).");
    2087            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-o, --output <stream>",    5," ", "Specify output stream for a report: 'stdout' (default) or <file path>.");
    2088            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-r, --report <format>",    5," ", "Specify a report format when running tests: 'pretty', 'csv', 'json'.");
    2089            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-t, --run-tests",          5," ", "Execute all/matching test cases (same as <no-options>).");
    2090            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-v, --version",            5," ", "Show CLove-Unit version.");
    2091            0 :     printf("%*s%-*s%*s%s\n", 3," ", 30,"-x, --error-on-test-fail", 5," ", "Run Tests process will end with error in case of test failure. Default is to end the process successfully.");
    2092            0 :     printf("\n");
    2093            0 :     printf("For detailed usage please look at the README in https://github.com/fdefelici/clove-unit.\n");
    2094            0 :     return __CLOVE_CMD_ERRNO_OK;
    2095              : }
    2096              : 
    2097            1 : __clove_cmdline_errno_t __clove_cmdline_handle_version(__clove_cmdline_t* cmd) {
    2098            1 :     if (!__clove_cmdline_has_any_opt(cmd, "v", "version")) return __CLOVE_CMD_ERRNO_UNMANAGED;
    2099            0 :     printf("%s", __CLOVE_VERSION); //to avoid new_line character(s)
    2100            0 :     return __CLOVE_CMD_ERRNO_OK;
    2101              : }
    2102              : 
    2103            2 : __clove_cmdline_errno_t __clove_cmdline_handle_run_tests(__clove_cmdline_t* cmd) {
    2104            2 :     if (!__clove_cmdline_has_any_opt(cmd, "t", "run-tests")) return __CLOVE_CMD_ERRNO_UNMANAGED;
    2105              :     
    2106            1 :     const char* opt_report = __clove_cmdline_get_any_opt_value_defaulted(cmd, "r", "report", "pretty");
    2107            1 :     if (!__clove_string_equal_any(opt_report, 3, "pretty", "json", "csv")) return __CLOVE_CMD_ERRNO_INVALID_PARAM;
    2108              :     
    2109            1 :     const char* opt_detail = __clove_cmdline_get_any_opt_value_defaulted(cmd, "d", "run-detail", "3");
    2110            1 :     if (!__clove_string_equal_any(opt_detail, 3, "1", "2", "3")) return __CLOVE_CMD_ERRNO_INVALID_PARAM;    
    2111              :     
    2112            1 :     const char* opt_out = __clove_cmdline_get_any_opt_value_defaulted(cmd, "o", "output", "stdout");
    2113            1 :     const char* opt_base_path = __clove_cmdline_get_any_opt_value_defaulted(cmd, "b", "base-path", "");
    2114            1 :     const bool opt_enable_error = __clove_cmdline_has_any_opt(cmd, "x", "error-on-test-fail");
    2115              : 
    2116              :      __clove_vector_t includes;
    2117            1 :     __clove_cmdline_create_test_expr(cmd, "i", "include", &includes);
    2118              : 
    2119              :     __clove_vector_t excludes;
    2120            1 :     __clove_cmdline_create_test_expr(cmd, "e", "exclude", &excludes);
    2121              :     
    2122              :     //Select stream
    2123              :     __clove_stream_t* stream;
    2124            1 :     if (__clove_string_equal(opt_out, "stdout")) {
    2125            1 :         stream = (__clove_stream_t*)__clove_stream_console_new();
    2126              :     } else { // file path
    2127              :         const char* report_path;
    2128            0 :         if (__clove_path_is_relative(opt_out)) {
    2129            0 :             report_path = __clove_path_rel_to_abs_exec_path(opt_out);
    2130              :         }
    2131              :         else {
    2132            0 :             report_path = opt_out;
    2133              :         } 
    2134            0 :         stream = (__clove_stream_t*)__clove_stream_file_new(report_path);
    2135              :     }
    2136              : 
    2137              :     //Select Report
    2138              :     __clove_report_params_t report_params;
    2139              :     
    2140              :     //ensure base path is in os format
    2141            1 :     char* base_path_fixed = __clove_string_strdup(opt_base_path);
    2142            1 :     __clove_path_to_os(base_path_fixed);    
    2143            1 :     report_params.tests_base_path = base_path_fixed;
    2144              : 
    2145            1 :     if (__clove_string_equal(opt_detail, "1")) 
    2146            0 :         report_params.report_detail = __CLOVE_REPORT_DETAIL__FAILED;
    2147            1 :     else if (__clove_string_equal(opt_detail, "2"))
    2148            0 :         report_params.report_detail = __CLOVE_REPORT_DETAIL__FAILED_SKIPPED;
    2149            1 :     else if (__clove_string_equal(opt_detail, "3"))
    2150            1 :         report_params.report_detail = __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED;
    2151              : 
    2152              :     __clove_report_t* report;
    2153            1 :     if (__clove_string_equal("json", opt_report)) {
    2154            0 :         report = (__clove_report_t*)__clove_report_run_tests_json_new(stream, &report_params);
    2155            1 :     } else if (__clove_string_equal("pretty", opt_report)) {
    2156            1 :         report = (__clove_report_t*)__clove_report_run_tests_pretty_new(stream, &report_params);
    2157            0 :     } else if (__clove_string_equal("csv", opt_report)) {
    2158            0 :         report = (__clove_report_t*)__clove_report_run_tests_csv_new(stream, &report_params);
    2159              :     } else {
    2160              :         //Just to avoid compile warnings. This can never happen because of validation did before.
    2161            0 :         return __CLOVE_CMD_ERRNO_UNMANAGED;
    2162              :     }
    2163              :     
    2164              :     //Run report
    2165            1 :     int run_result = __clove_run_tests_with_report(report, &includes, &excludes);
    2166              :     
    2167              :     //Clean
    2168            1 :     report->free(report);
    2169            1 :     stream->free(stream);
    2170            1 :     __clove_vector_free(&includes);
    2171            1 :     __clove_vector_free(&excludes);
    2172            1 :     __clove_memory_free(base_path_fixed);
    2173              : 
    2174              :     //Result
    2175            1 :     if (run_result == 1) return __CLOVE_CMD_ERRNO_GENERIC;
    2176            1 :     if (run_result == 2 && opt_enable_error) return __CLOVE_CMD_ERRNO_GENERIC;
    2177            1 :     return __CLOVE_CMD_ERRNO_OK;
    2178              : }
    2179              : 
    2180            1 : __clove_cmdline_errno_t __clove_cmdline_handle_default(__clove_cmdline_t* cmd) {
    2181            1 :     __clove_cmdline_add_opt(cmd, "t", NULL);
    2182            1 :     return __clove_cmdline_handle_run_tests(cmd);
    2183              : }
    2184              : 
    2185            1 : __clove_cmdline_errno_t __clove_cmdline_handle_list_tests(__clove_cmdline_t* cmd) {
    2186            1 :     if (!__clove_cmdline_has_any_opt(cmd, "l", "list-tests")) return __CLOVE_CMD_ERRNO_UNMANAGED;
    2187              :     
    2188            0 :     const char* opt_report = __clove_cmdline_get_any_opt_value_defaulted(cmd, "r", "report", "pretty");
    2189            0 :     if (!__clove_string_equal_any(opt_report, 3, "pretty", "json", "csv")) return __CLOVE_CMD_ERRNO_INVALID_PARAM;    
    2190              :     
    2191            0 :     const char* opt_out = __clove_cmdline_get_any_opt_value_defaulted(cmd, "o", "output", "stdout");
    2192            0 :     const char* opt_base_path = __clove_cmdline_get_any_opt_value_defaulted(cmd, "b", "base-path", "");
    2193              : 
    2194              :      __clove_vector_t includes;
    2195            0 :     __clove_cmdline_create_test_expr(cmd, "i", "include", &includes);
    2196              : 
    2197              :     __clove_vector_t excludes;
    2198            0 :     __clove_cmdline_create_test_expr(cmd, "e", "exclude", &excludes);
    2199              : 
    2200              :     //ensure base path is in os format
    2201            0 :     char* base_path_os = __clove_string_strdup(opt_base_path);
    2202            0 :     __clove_path_to_os(base_path_os);    
    2203              :     __clove_report_params_t report_params;
    2204            0 :     report_params.tests_base_path = base_path_os;
    2205              : 
    2206              :     __clove_stream_t* stream;
    2207            0 :     if (__clove_string_equal(opt_out, "stdout")) {
    2208            0 :         stream = (__clove_stream_t*)__clove_stream_console_new();
    2209              :     } else {
    2210              :         const char* report_path;
    2211            0 :         if (__clove_path_is_relative(opt_out)) {
    2212            0 :             report_path = __clove_path_rel_to_abs_exec_path(opt_out);
    2213              :         }
    2214              :         else {
    2215            0 :             report_path = opt_out;
    2216              :         } 
    2217            0 :         stream = (__clove_stream_t*)__clove_stream_file_new(report_path);
    2218              :     }
    2219              : 
    2220              :     //Select Report Format
    2221              :     __clove_report_list_tests_t* report;
    2222            0 :     if (__clove_string_equal("json", opt_report)) {
    2223            0 :         report = (__clove_report_list_tests_t*)__clove_report_list_tests_json_new(stream, &report_params);
    2224            0 :     } else if (__clove_string_equal("pretty", opt_report)) {
    2225            0 :         report = (__clove_report_list_tests_t*)__clove_report_list_tests_pretty_new(stream, &report_params);
    2226            0 :     } else if (__clove_string_equal("csv", opt_report)) {
    2227            0 :         report = (__clove_report_list_tests_t*)__clove_report_list_tests_csv_new(stream, &report_params);
    2228              :     } else {
    2229              :         //Just to avoid compile warnings. This can never happen because of validation did before.
    2230            0 :         return __CLOVE_CMD_ERRNO_UNMANAGED;
    2231              :     }
    2232              : 
    2233            0 :     int run_result = 0;
    2234              :      __clove_symbols_context_t context;
    2235            0 :     context.includes = &includes;
    2236            0 :     context.excludes = &excludes;
    2237              : 
    2238            0 :     __clove_vector_params_t vector_params = __clove_vector_params_defaulted(sizeof(__clove_suite_t));
    2239            0 :     vector_params.item_ctor = __clove_vector_suite_ctor;
    2240            0 :     vector_params.item_dtor = __clove_vector_suite_dtor;
    2241            0 :     __clove_vector_init(&context.suites, &vector_params);
    2242            0 :     context.prefix = "__clove_sym___";
    2243            0 :     context.prefix_length = __clove_string_length("__clove_sym___");
    2244            0 :     context.suites_count = 0;
    2245            0 :     context.tests_count = 0;
    2246              : 
    2247            0 :     int result = __clove_symbols_for_each_function_by_prefix(&context, __clove_symbols_function_collect);
    2248            0 :     if (result == 0) {
    2249            0 :         run_result = __clove_cmd_list_test_execute((__clove_suite_t*)(context.suites.items), context.suites_count, context.tests_count, report);
    2250              :     }
    2251              :     else {
    2252            0 :         run_result = 1;
    2253              :     }
    2254            0 :     report->free(report);
    2255            0 :     stream->free(stream);
    2256              : 
    2257            0 :     __clove_memory_free(base_path_os);
    2258            0 :     __clove_vector_free(&context.suites);
    2259            0 :     __clove_vector_free((__clove_vector_t*)context.includes);
    2260            0 :     __clove_vector_free((__clove_vector_t*)context.excludes);
    2261              : 
    2262            0 :     if (run_result != 0) return __CLOVE_CMD_ERRNO_GENERIC;
    2263            0 :     return __CLOVE_CMD_ERRNO_OK;
    2264              : }
    2265              : 
    2266            2 : void __clove_cmdline_create_test_expr(__clove_cmdline_t* cmd, const char* opt1, const char* opt2,  __clove_vector_t* expressions) {
    2267            2 :     *expressions = __clove_vector_null();
    2268              :     
    2269            2 :     bool has_opt1 = __clove_cmdline_has_opt(cmd, opt1);
    2270            2 :     bool has_opt2 = __clove_cmdline_has_opt(cmd, opt2);
    2271            2 :     if ( !has_opt1 && !has_opt2) return;
    2272              :     
    2273              :     __clove_vector_t values;
    2274            0 :     __CLOVE_VECTOR_INIT(&values, char*);
    2275              : 
    2276            0 :     if (has_opt1) {
    2277            0 :         const __clove_vector_t* values1 = __clove_cmdline_get_opt_values(cmd, opt1);
    2278            0 :         __clove_vector_add_all(&values, values1);
    2279              :     }
    2280            0 :     if (has_opt2) {
    2281            0 :         const __clove_vector_t* values2 = __clove_cmdline_get_opt_values(cmd, opt2);
    2282            0 :         __clove_vector_add_all(&values, values2);
    2283              :     }
    2284              : 
    2285            0 :     size_t values_count = __clove_vector_count(&values);
    2286            0 :     __CLOVE_VECTOR_INIT_CAPACITY(expressions, __clove_test_expr_t, values_count);
    2287              : 
    2288            0 :     __CLOVE_VECTOR_FOREACH(&values, char*, expr_str, {
    2289              :         __clove_test_expr_t expr;
    2290              :         __clove_test_expr_init(&expr, *expr_str);
    2291              : 
    2292              :         __CLOVE_VECTOR_ADD(expressions, __clove_test_expr_t, expr);
    2293              :     });
    2294              :     
    2295            0 :     __clove_vector_free(&values);
    2296              : }
    2297              : #pragma endregion // CommandLine Impl
    2298              : 
    2299              : #pragma region PRIVATE - Test Impl
    2300              : #include <string.h>
    2301           41 : void __clove_vector_test_ctor(void* test) {
    2302              :     //cast to __clove_test_t* not needed
    2303           41 :     __clove_memory_memset(test, sizeof(__clove_test_t), 0);
    2304           41 : }
    2305              : 
    2306           41 : void __clove_vector_test_dtor(void* test_ptr) {
    2307           41 :     __clove_test_t* test = (__clove_test_t*)test_ptr;
    2308           41 :     __clove_memory_free(test->name);
    2309              : 
    2310              :     //See CLOVE_STRING_EQ and CLOVE_STRING_NE where string allocation happens
    2311           41 :     if (test->result == __CLOVE_TEST_RESULT_FAILED && test->issue.data_type == __CLOVE_GENERIC_STRING) {
    2312           11 :         __clove_memory_free(test->issue.expected._string);
    2313           11 :         __clove_memory_free(test->issue.actual._string);
    2314              :     }
    2315           41 : }
    2316              : #pragma endregion
    2317              : 
    2318              : #pragma region PRIVATE - Suite Impl
    2319            1 : void __clove_vector_suite_ctor(void* suite_ptr) {
    2320            1 :     __clove_suite_t* suite = (__clove_suite_t*)suite_ptr;
    2321            1 :     suite->name = NULL;
    2322            1 :     suite->fixtures.setup_once = __clove_utils_empty_funct;
    2323            1 :     suite->fixtures.teardown_once = __clove_utils_empty_funct;
    2324            1 :     suite->fixtures.setup = __clove_utils_empty_funct;
    2325            1 :     suite->fixtures.teardown = __clove_utils_empty_funct;
    2326              : 
    2327            1 :     __clove_vector_params_t params = __clove_vector_params_defaulted(sizeof(__clove_test_t));
    2328            1 :     params.item_ctor = __clove_vector_test_ctor;
    2329            1 :     params.item_dtor = __clove_vector_test_dtor;
    2330            1 :     __clove_vector_init(&(suite->tests), &params);
    2331            1 :     suite->test_count = 0;
    2332              : 
    2333            1 :     suite->issue.duration.seconds = 0;
    2334            1 :     suite->issue.duration.nanos_after_seconds = 0;
    2335            1 :     suite->issue.passed_count = 0;
    2336            1 :     suite->issue.failed_count = 0;
    2337            1 :     suite->issue.skipped_count = 0;
    2338            1 : }
    2339              : 
    2340            1 : void __clove_vector_suite_dtor(void* suite_ptr) {
    2341            1 :     __clove_suite_t* suite = (__clove_suite_t*)suite_ptr;
    2342            1 :     __clove_memory_free(suite->name);
    2343            1 :     __clove_vector_free(&suite->tests);
    2344            1 : }
    2345              : #pragma endregion // Suite Impl
    2346              : 
    2347              : #pragma region PRIVATE - Assert Impl
    2348              : #include <math.h>
    2349            0 : void __clove_assert_fail(__clove_test_t* _this) {
    2350            0 :     _this->result = __CLOVE_TEST_RESULT_FAILED;
    2351            0 :     _this->issue.assert = __CLOVE_ASSERT_FAIL;
    2352            0 : }
    2353              : 
    2354            0 : void __clove_assert_pass(__clove_test_t* _this) {
    2355            0 :     _this->result = __CLOVE_TEST_RESULT_PASSED;
    2356            0 : }
    2357              : 
    2358            5 : void __clove_assert_int(__clove_assert_check_e check_mode, int expected, int result, __clove_test_t* _this) {
    2359            5 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_INT, _int, _this)
    2360            5 : }
    2361              : 
    2362           27 : void __clove_assert_uint(__clove_assert_check_e check_mode, unsigned int expected, unsigned int result, __clove_test_t* _this) {
    2363           27 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_UINT, _uint, _this)
    2364           27 : }
    2365              : 
    2366            0 : void __clove_assert_long(__clove_assert_check_e check_mode, long expected, long result, __clove_test_t* _this) {
    2367            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_LONG, _long, _this)
    2368            0 : }
    2369              : 
    2370            0 : void __clove_assert_ulong(__clove_assert_check_e check_mode, unsigned long expected, unsigned long result, __clove_test_t* _this) {
    2371            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_ULONG, _ulong, _this)
    2372            0 : }
    2373              : 
    2374            0 : void __clove_assert_llong(__clove_assert_check_e check_mode, long long expected, long long result, __clove_test_t* _this) {
    2375            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_LLONG, _llong, _this)
    2376            0 : }
    2377              : 
    2378            0 : void __clove_assert_ullong(__clove_assert_check_e check_mode, unsigned long long expected, unsigned long long result, __clove_test_t* _this) {
    2379            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_ULLONG, _ullong, _this)
    2380            0 : }
    2381              : 
    2382            0 : void __clove_assert_sizet(__clove_assert_check_e check_mode, size_t expected, size_t result, __clove_test_t* _this) {
    2383            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_SIZET, _sizet, _this)
    2384            0 : }
    2385              : 
    2386            0 : void __clove_assert_char(__clove_assert_check_e check_mode, char expected, char result, __clove_test_t* _this) {
    2387            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_CHAR, _char, _this)
    2388            0 : }
    2389              : 
    2390            0 : void __clove_assert_bool(__clove_assert_check_e check_mode, bool expected, bool result, __clove_test_t* _this) {
    2391            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_BOOL, _bool, _this)
    2392            0 : }
    2393              : 
    2394           11 : void __clove_assert_null(__clove_assert_check_e check_mode, void* expected, void* result, __clove_test_t* _this) {
    2395           11 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_PTR, _ptr, _this)
    2396           11 : }
    2397              : 
    2398            0 : void __clove_assert_ptr(__clove_assert_check_e check_mode, void* expected, void* result, __clove_test_t* _this) {
    2399            0 :     __CLOVE_ASSERT_INTEGER_CHECK(check_mode, expected, result, __CLOVE_GENERIC_PTR, _ptr, _this)
    2400            0 : }
    2401              : 
    2402            0 : void __clove_assert_float(__clove_assert_check_e check_mode, float expected, float result, unsigned char precision, __clove_test_t* _this) {
    2403            0 :     bool pass_scenario = false;
    2404            0 :     if (check_mode == __CLOVE_ASSERT_EQ) { pass_scenario = fabsf(expected - result) <= __clove_math_decimalf(precision); }
    2405            0 :     else if (check_mode == __CLOVE_ASSERT_NE) { pass_scenario = fabsf(expected - result) > __clove_math_decimalf(precision); }
    2406            0 :     else if (check_mode == __CLOVE_ASSERT_GT)  { pass_scenario = expected > result; }
    2407            0 :     else if (check_mode == __CLOVE_ASSERT_GTE) { pass_scenario = expected >= result; }
    2408            0 :     else if (check_mode == __CLOVE_ASSERT_LT)  { pass_scenario = expected < result; }
    2409            0 :     else if (check_mode == __CLOVE_ASSERT_LTE) { pass_scenario = expected <= result; }
    2410            0 :     if (pass_scenario) {
    2411            0 :         _this->result = __CLOVE_TEST_RESULT_PASSED;
    2412              :     }
    2413              :     else {
    2414            0 :         _this->result = __CLOVE_TEST_RESULT_FAILED;
    2415            0 :         _this->issue.assert = check_mode;
    2416            0 :         _this->issue.data_type = __CLOVE_GENERIC_FLOAT;
    2417            0 :         _this->issue.expected._float = expected;
    2418            0 :         _this->issue.actual._float = result;
    2419            0 :         _this->issue.floating_precision = precision;
    2420              :     }
    2421            0 : }
    2422              : 
    2423            0 : void __clove_assert_double(__clove_assert_check_e check_mode, double expected, double result, unsigned char precision, __clove_test_t* _this) {
    2424            0 :     bool pass_scenario = false;
    2425            0 :     if (check_mode == __CLOVE_ASSERT_EQ) { pass_scenario = fabs(expected - result) <= __clove_math_decimald(precision); }
    2426            0 :     else if (check_mode == __CLOVE_ASSERT_NE) { pass_scenario = fabs(expected - result) > __clove_math_decimald(precision); }
    2427            0 :     else if (check_mode == __CLOVE_ASSERT_GT)  { pass_scenario = expected > result; }
    2428            0 :     else if (check_mode == __CLOVE_ASSERT_GTE) { pass_scenario = expected >= result; }
    2429            0 :     else if (check_mode == __CLOVE_ASSERT_LT)  { pass_scenario = expected < result; }
    2430            0 :     else if (check_mode == __CLOVE_ASSERT_LTE) { pass_scenario = expected <= result; }
    2431            0 :     if (pass_scenario) {
    2432            0 :         _this->result = __CLOVE_TEST_RESULT_PASSED;
    2433              :     }
    2434              :     else {
    2435            0 :         _this->result = __CLOVE_TEST_RESULT_FAILED;
    2436            0 :         _this->issue.assert = check_mode;
    2437            0 :         _this->issue.data_type = __CLOVE_GENERIC_DOUBLE;
    2438            0 :         _this->issue.expected._double = expected;
    2439            0 :         _this->issue.actual._double = result;
    2440            0 :         _this->issue.floating_precision = precision;
    2441              :     }
    2442            0 : }
    2443              : 
    2444           11 : void __clove_assert_string(__clove_assert_check_e check_mode, const char* expected, const char* result, __clove_test_t* _this) {
    2445           11 :     bool pass_scenario = false;
    2446           11 :     if (check_mode == __CLOVE_ASSERT_EQ) { pass_scenario = strcmp(expected, result) == 0; }
    2447            0 :     else if (check_mode == __CLOVE_ASSERT_NE) { pass_scenario = strcmp(expected, result) != 0; }
    2448              : 
    2449           11 :     if (pass_scenario) {
    2450            0 :         _this->result = __CLOVE_TEST_RESULT_PASSED;
    2451              :     }
    2452              :     else {
    2453           11 :         _this->result = __CLOVE_TEST_RESULT_FAILED;
    2454           11 :         _this->issue.assert = check_mode;
    2455           11 :         _this->issue.data_type = __CLOVE_GENERIC_STRING;
    2456           11 :         _this->issue.expected._string = __clove_string_strdup(expected); //in case is allocated on the stack within the test function
    2457           11 :         _this->issue.actual._string = __clove_string_strdup(result); //in case is allocated on the stack within the test function
    2458              :     }
    2459           11 : }
    2460              : #pragma endregion // Assert Impl
    2461              : 
    2462              : #pragma region PRIVATE - Stream Impl
    2463            1 : __clove_stream_console_t* __clove_stream_console_new(void) {
    2464            1 :     __clove_stream_console_t* stream = __CLOVE_MEMORY_MALLOC_TYPE(__clove_stream_console_t);
    2465            1 :     stream->base.open = __clove_stream_console_open;
    2466            1 :     stream->base.close = __clove_stream_console_close;
    2467            1 :     stream->base.writef = __clove_stream_console_writef;
    2468            1 :     stream->base.seek = __clove_stream_console_seek;
    2469            1 :     stream->base.has_ansi_support = __clove_stream_console_has_ansi_support;
    2470            1 :     stream->base.free = __clove_stream_console_free;
    2471            1 :     return stream;
    2472              : }
    2473            1 : bool __clove_stream_console_open(__clove_stream_t* stream) {
    2474              :     __CLOVE_UNUSED_VAR(stream);
    2475            1 :     return true;
    2476              : }
    2477            1 : void __clove_stream_console_close(__clove_stream_t* stream) { 
    2478              :     __CLOVE_UNUSED_VAR(stream);
    2479              :     //nothing todo
    2480            1 : }
    2481           46 : void __clove_stream_console_writef(__clove_stream_t* stream, const char* format, ...) {
    2482              :     __CLOVE_UNUSED_VAR(stream);
    2483              :     
    2484              :     va_list args;
    2485           46 :     va_start(args, format);
    2486           46 :     __clove_console_vprintf(format, args);
    2487           46 :     va_end(args);
    2488           46 : }
    2489            0 : void __clove_stream_console_seek(__clove_stream_t* stream, long offset, int origin) {
    2490              :     __CLOVE_UNUSED_VAR(stream);
    2491              :     __CLOVE_UNUSED_VAR(offset);
    2492              :     __CLOVE_UNUSED_VAR(origin);
    2493              :     //nothing todo
    2494            0 : }
    2495              : 
    2496              : #ifdef _WIN32
    2497              : #include <windows.h>
    2498              : #include <stdbool.h>
    2499              : #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
    2500              : #define ENABLE_VIRTUAL_TERMINAL_PROCESSING  0x0004
    2501              : #endif
    2502              : bool __clove_stream_console_has_ansi_support(__clove_stream_t* stream) {
    2503              :     __CLOVE_UNUSED_VAR(stream);
    2504              : 
    2505              :     DWORD outMode = 0, inMode = 0;
    2506              :     HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    2507              :     HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
    2508              : 
    2509              :     if (stdoutHandle == INVALID_HANDLE_VALUE || stdinHandle == INVALID_HANDLE_VALUE) {
    2510              :         //exit(GetLastError());
    2511              :         return false;
    2512              :     }
    2513              : 
    2514              :     if (!GetConsoleMode(stdoutHandle, &outMode) || !GetConsoleMode(stdinHandle, &inMode)) {
    2515              :         //exit(GetLastError());
    2516              :         return false;
    2517              :     }
    2518              : 
    2519              :     // Enable ANSI escape codes
    2520              :     outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    2521              : 
    2522              :     // Set stdin as no echo and unbuffered
    2523              :     inMode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
    2524              : 
    2525              :     if (!SetConsoleMode(stdoutHandle, outMode) || !SetConsoleMode(stdinHandle, inMode)) {
    2526              :         //exit(GetLastError());
    2527              :         return false;
    2528              :     }
    2529              :     return true;
    2530              : }
    2531              : #else
    2532              : #include <stdbool.h>
    2533              : #include <unistd.h>
    2534            1 : bool __clove_stream_console_has_ansi_support(__clove_stream_t* stream) {
    2535              :     __CLOVE_UNUSED_VAR(stream);
    2536              : 
    2537            1 :     if (isatty(STDOUT_FILENO)) {
    2538              :         // standard output is a tty
    2539            0 :         return true;
    2540              :     }
    2541            1 :     return false;
    2542              : }
    2543              : #endif //_WIN32
    2544              : 
    2545              : 
    2546            1 : void __clove_stream_console_free(__clove_stream_t* stream) {
    2547            1 :     __clove_memory_free(stream);
    2548            1 : }
    2549              : 
    2550            0 : __clove_stream_file_t* __clove_stream_file_new(const char* file_path) {
    2551            0 :     __clove_stream_file_t* stream = __CLOVE_MEMORY_MALLOC_TYPE(__clove_stream_file_t);
    2552            0 :     stream->base.open = __clove_stream_file_open;
    2553            0 :     stream->base.close = __clove_stream_file_close;
    2554            0 :     stream->base.writef = __clove_stream_file_writef;
    2555            0 :     stream->base.seek = __clove_stream_file_seek;
    2556            0 :     stream->base.has_ansi_support = __clove_stream_file_has_ansi_support;
    2557            0 :     stream->base.free = __clove_stream_file_free;
    2558            0 :     stream->file_path = __clove_string_strdup(file_path);
    2559            0 :     stream->file = NULL;
    2560            0 :     return stream;
    2561              : }
    2562            0 : bool __clove_stream_file_open(__clove_stream_t* stream) {
    2563            0 :     __clove_stream_file_t* _this = (__clove_stream_file_t*)stream;
    2564            0 :     _this->file = __clove_file_open(_this->file_path, "wb"); //binary mode so \n will stay \n (and not converted to \r\n on windows)
    2565            0 :     return _this->file != NULL;
    2566              : }
    2567            0 : void __clove_stream_file_close(__clove_stream_t* stream) {
    2568            0 :     __clove_stream_file_t* _this = (__clove_stream_file_t*)stream;
    2569            0 :     __clove_file_close(_this->file);
    2570            0 : }
    2571            0 : void __clove_stream_file_writef(__clove_stream_t* stream, const char* format, ...) {
    2572            0 :     __clove_stream_file_t* _this = (__clove_stream_file_t*)stream;
    2573              :     va_list args;
    2574            0 :     va_start(args, format);
    2575            0 :     __clove_file_vprintf(_this->file, format, args);
    2576            0 :     va_end(args);
    2577            0 : }
    2578            0 : void __clove_stream_file_seek(__clove_stream_t* stream, long offset, int origin) {
    2579            0 :      __clove_stream_file_t* _this = (__clove_stream_file_t*)stream;
    2580            0 :     fseek(_this->file, offset, origin); //TODO: wrap into __clove_file_seek method
    2581            0 : }
    2582            0 : bool __clove_stream_file_has_ansi_support(struct __clove_stream_t* _this) {
    2583              :     __CLOVE_UNUSED_VAR(_this);
    2584            0 :     return false;
    2585              : }
    2586            0 : void __clove_stream_file_free(__clove_stream_t* stream) {
    2587            0 :     __clove_stream_file_t* _this = (__clove_stream_file_t*)stream;
    2588            0 :     _this->file = NULL;
    2589            0 :     __clove_memory_free((char*)_this->file_path);
    2590            0 :     __clove_memory_free(_this);
    2591            0 : }
    2592              : 
    2593              : //In Memory Stream
    2594            0 : __clove_stream_memory_t* __clove_stream_memory_new(void) {
    2595            0 :     __clove_stream_memory_t* stream = __CLOVE_MEMORY_MALLOC_TYPE(__clove_stream_memory_t);
    2596            0 :     stream->base.open = __clove_stream_memory_open;
    2597            0 :     stream->base.close = __clove_stream_memory_close;
    2598            0 :     stream->base.writef = __clove_stream_memory_writef;
    2599            0 :     stream->base.seek = __clove_stream_memory_seek;
    2600            0 :     stream->base.has_ansi_support = __clove_stream_memory_has_ansi_support;
    2601            0 :     stream->base.free = __clove_stream_memory_free;
    2602            0 :     __CLOVE_VECTOR_INIT(&stream->lines, char*);
    2603            0 :     return stream;
    2604              : }
    2605            0 : bool __clove_stream_memory_open(__clove_stream_t* stream) {
    2606              :     __CLOVE_UNUSED_VAR(stream);
    2607            0 :     return true;
    2608              : }
    2609            0 : void __clove_stream_memory_close(__clove_stream_t* stream) { 
    2610              :     __CLOVE_UNUSED_VAR(stream);
    2611              :     //nothing todo
    2612            0 : }
    2613            0 : void __clove_stream_memory_writef(__clove_stream_t* stream, const char* format, ...) {
    2614              :     va_list args;
    2615            0 :     va_start(args, format);
    2616              :     
    2617            0 :     char* line = __CLOVE_MEMORY_CALLOC_TYPE_N(char, 1000); //TODO: Better computing real line size.
    2618            0 :     __clove_string_vsprintf(line, 1000, format, args);
    2619            0 :     __CLOVE_VECTOR_ADD(&((__clove_stream_memory_t*)stream)->lines, char*, line);
    2620              : 
    2621            0 :     va_end(args);
    2622            0 : }
    2623            0 : void __clove_stream_memory_seek(__clove_stream_t* stream, long offset, int origin) {
    2624              :     __CLOVE_UNUSED_VAR(stream);
    2625              :     __CLOVE_UNUSED_VAR(offset);
    2626              :     __CLOVE_UNUSED_VAR(origin);
    2627              :     //nothing todo
    2628            0 : }
    2629              : 
    2630            0 : bool __clove_stream_memory_has_ansi_support(__clove_stream_t* stream) {
    2631              :     __CLOVE_UNUSED_VAR(stream);
    2632            0 :     return false;
    2633              : }
    2634              : 
    2635            0 : void __clove_stream_memory_free(__clove_stream_t* stream) {
    2636            0 :     __clove_vector_free(&((__clove_stream_memory_t*)stream)->lines);
    2637            0 :     __clove_memory_free(stream);
    2638            0 : }
    2639              : 
    2640            0 : char* __clove_stream_memory_get_line(__clove_stream_memory_t* mem_stream, size_t index) {
    2641            0 :     return (char*)__clove_vector_get(&mem_stream->lines, index);
    2642              : }
    2643              : 
    2644            0 : char* __clove_stream_memory_as_string(__clove_stream_memory_t* mem_stream) {
    2645            0 :     size_t buffer_size = 0;
    2646            0 :     __CLOVE_VECTOR_FOREACH(&mem_stream->lines, char*, line, {
    2647              :        buffer_size += __clove_string_length(*line);
    2648              :     });
    2649              : 
    2650            0 :     char* buffer = __CLOVE_MEMORY_CALLOC_TYPE_N(char, buffer_size + 1);
    2651            0 :     __CLOVE_VECTOR_FOREACH(&mem_stream->lines, char*, line, {
    2652              :        __clove_string_strcat(buffer, buffer_size + 1, *line);
    2653              :     });
    2654            0 :     return buffer;
    2655              : }
    2656              : #pragma endregion //Stream Impl
    2657              : 
    2658              : #pragma region PRIVATE - Report Impl
    2659            0 : void __clove_test_expr_init(__clove_test_expr_t* expr,  const char* expr_str) {
    2660            0 :     const char* dot_begin = __clove_string_strstr(expr_str, ".");
    2661            0 :     if (dot_begin) {
    2662            0 :         const size_t expr_len = __clove_string_length(expr_str);
    2663            0 :         const size_t suite_len = dot_begin - expr_str;
    2664            0 :         const size_t test_len = expr_str + expr_len-1 - dot_begin;
    2665            0 :         if (suite_len == 0) expr->suite_view = __clove_string_view_from_str("");
    2666            0 :         else expr->suite_view = __clove_string_view_from_be(expr_str, dot_begin - 1);
    2667              : 
    2668            0 :         if (test_len == 0) expr->test_view = __clove_string_view_from_str("");
    2669            0 :         else expr->test_view = __clove_string_view_from_str(dot_begin + 1);
    2670              :     } else {
    2671            0 :         expr->suite_view = __clove_string_view_from_str(expr_str);
    2672            0 :         expr->test_view = __clove_string_view_from_str("*");
    2673              :     }
    2674            0 : }
    2675              : 
    2676            0 : bool __clove_test_expr_validate_vw(const __clove_string_view_t* match, const __clove_string_view_t* view) {
    2677            0 :     if (__clove_string_view_strequals(match, "*")) return true;
    2678            0 :     const size_t match_len = __clove_string_view_length(match);
    2679            0 :     if (match_len == 0) return false;
    2680            0 :     const char* match_start = __clove_string_view_begin(match);
    2681            0 :     const char* match_end = __clove_string_view_end(match);
    2682              : 
    2683            0 :     bool start_asterisk = match_start[0] == '*';
    2684            0 :     bool end_asterisk = match_end[0] == '*';
    2685            0 :     if (start_asterisk && end_asterisk) {
    2686            0 :         if (match_len <= 2) return false;
    2687            0 :         __clove_string_view_t fixture = __clove_string_view_from_be(match_start+1, match_end-1);
    2688            0 :         return __clove_string_view_contains(view, &fixture);
    2689              :     }
    2690            0 :     if (start_asterisk) {
    2691            0 :         return __clove_string_view_nendswith(view, match, 1);
    2692              :     }
    2693            0 :     if (end_asterisk) {
    2694            0 :         return __clove_string_view_ncmp(match, view, __clove_string_view_length(match)-1);
    2695              :     }
    2696            0 :     return __clove_string_view_equals(match, view);
    2697              : }
    2698              : 
    2699            0 : bool __clove_test_expr_validate(__clove_test_expr_t* expr, const __clove_string_view_t* suite, const __clove_string_view_t* test) {
    2700            0 :     if (!__clove_test_expr_validate_vw(&(expr->suite_view), suite)) return false;
    2701            0 :     if (!__clove_test_expr_validate_vw(&(expr->test_view), test)) return false;
    2702            0 :     return true;
    2703              : }
    2704              : #pragma endregion // Report Impl
    2705              : 
    2706              : #pragma region PRIVATE - RunTests Report Pretty Impl
    2707              : #include <stdio.h>
    2708            1 : __clove_report_pretty_t* __clove_report_run_tests_pretty_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    2709            1 :     __clove_report_pretty_t* result = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_pretty_t);
    2710            1 :     result->base.start = __clove_report_pretty_start;
    2711            1 :     result->base.begin_suite = __clove_report_pretty_begin_suite;
    2712            1 :     result->base.end_suite = __clove_report_pretty_end_suite;
    2713            1 :     result->base.end = __clove_report_pretty_end;
    2714            1 :     result->base.end_test = __clove_report_pretty_end_test;
    2715            1 :     result->base.free = __clove_report_pretty_free;
    2716            1 :     result->stream = stream;
    2717            1 :     result->params = params;
    2718            1 :     return result;
    2719              : }
    2720              : 
    2721            1 : void __clove_report_pretty_free(__clove_report_t* report) {
    2722            1 :     __clove_memory_free(report);
    2723            1 : }
    2724              : 
    2725            1 : void __clove_report_pretty_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count) {
    2726            1 :     __clove_report_pretty_t* report = (__clove_report_pretty_t*)_this;
    2727            1 :     report->start_time = __clove_time_now();
    2728            1 :     report->max_test_digits = (unsigned int)snprintf(NULL, 0U, "%zu", test_count);
    2729            1 :     report->test_count = test_count;
    2730              : 
    2731            1 :     bool activated = report->stream->has_ansi_support(report->stream);
    2732            1 :     if (activated) {
    2733            0 :         report->labels.info = "[\x1b[1;34mINFO\x1b[0m]";
    2734            0 :         report->labels.warn = "[\x1b[33mWARN\x1b[0m]";
    2735            0 :         report->labels.erro = "[\x1b[1;31mERRO\x1b[0m]";
    2736            0 :         report->labels.pass = "[\x1b[1;32mPASS\x1b[0m]";
    2737            0 :         report->labels.skip = "[\x1b[33mSKIP\x1b[0m]";
    2738            0 :         report->labels.fail = "[\x1b[1;31mFAIL\x1b[0m]";
    2739              :     }
    2740              :     else {
    2741            1 :         report->labels.info = "[INFO]";
    2742            1 :         report->labels.warn = "[WARN]";
    2743            1 :         report->labels.erro = "[ERRO]";
    2744            1 :         report->labels.pass = "[PASS]";
    2745            1 :         report->labels.skip = "[SKIP]";
    2746            1 :         report->labels.fail = "[FAIL]";
    2747              :     }
    2748              : 
    2749            1 :     const char* level_str = "<unknown>";
    2750            1 :     if (report->params->report_detail == __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED) {
    2751            1 :         level_str = "Full";
    2752            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED) {
    2753            0 :         level_str = "Failed only";
    2754            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED_SKIPPED) {
    2755            0 :         level_str = "Failed + Skipped";
    2756              :     }
    2757              : 
    2758            1 :     size_t longest_suite_and_test_name = 0;    
    2759           43 :     __CLOVE_VECTOR_FOREACH(suites, __clove_suite_t, each_suite, {
    2760              :         size_t suite_length = __clove_string_length(each_suite->name);
    2761              :         __CLOVE_VECTOR_FOREACH(&each_suite->tests, __clove_test_t, each_test, { 
    2762              :             size_t test_length = __clove_string_length(each_test->name);
    2763              : 
    2764              :             if (longest_suite_and_test_name < suite_length + test_length) {
    2765              :                 longest_suite_and_test_name = suite_length + test_length;
    2766              :             }
    2767              :         });
    2768              :     });
    2769              : 
    2770              :     //Force minimum length in case of longest suite/name is less 
    2771            1 :     if (longest_suite_and_test_name < 46) longest_suite_and_test_name = 46; //rounded to 50 by next operation
    2772              : 
    2773              :     //+1 take into account dot separator (suite.name)
    2774              :     //+3 to have at least 3 more dot after suite.name
    2775            1 :     report->max_suite_and_test_name_size = longest_suite_and_test_name + 1 + 3;
    2776              :     //max len capping
    2777            1 :     if (report->max_suite_and_test_name_size > __CLOVE_STRING_LENGTH) report->max_suite_and_test_name_size = __CLOVE_STRING_LENGTH;
    2778              :     
    2779            1 :     size_t suite_count = __clove_vector_count(suites);
    2780              : 
    2781            1 :     report->stream->open(report->stream);
    2782            1 :     report->stream->writef(report->stream, "%s Executing Test Runner with detail level: '%s'\n", report->labels.info, level_str);
    2783            1 :     report->stream->writef(report->stream, "%s Suites / Tests found: %zu / %zu\n", report->labels.info, suite_count, test_count);
    2784            1 : }
    2785            1 : void __clove_report_pretty_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    2786              :     __CLOVE_UNUSED_VAR(_this);
    2787              :     __CLOVE_UNUSED_VAR(suite);
    2788              :     __CLOVE_UNUSED_VAR(index);
    2789              :     //nothing todo
    2790            1 : }
    2791            1 : void __clove_report_pretty_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    2792              :     __CLOVE_UNUSED_VAR(_this);
    2793              :     __CLOVE_UNUSED_VAR(suite);
    2794              :     __CLOVE_UNUSED_VAR(index);
    2795              :     //nothing todo
    2796            1 : }
    2797            1 : void __clove_report_pretty_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed) {
    2798            1 :     __clove_report_pretty_t* report = (__clove_report_pretty_t*)_this;
    2799            1 :     __clove_time_t end_time = __clove_time_now();
    2800            1 :     __clove_time_t diff = __clove_time_sub(&end_time, &(report->start_time));
    2801            1 :     unsigned long long millis = __clove_time_to_millis(&diff);
    2802              : 
    2803            1 :     report->stream->writef(report->stream, "%s Total: %zu, Passed: %zu, Failed: %zu, Skipped: %zu\n", report->labels.info, report->test_count, passed, failed, skipped);
    2804            1 :     report->stream->writef(report->stream, "%s Run duration: %llu ms\n", report->labels.info, millis);
    2805            1 :     if (passed == report->test_count) { report->stream->writef(report->stream, "%s Run result: SUCCESS :-)\n", report->labels.info); }
    2806            1 :     else if (failed > 0) { report->stream->writef(report->stream, "%s Run result: FAILURE :_(\n", report->labels.erro); }
    2807            0 :     else if (skipped > 0) { report->stream->writef(report->stream, "%s Run result: OK, but some test has been skipped!\n", report->labels.warn); }
    2808              : 
    2809            1 :     report->stream->close(report->stream);
    2810            1 : }
    2811              : 
    2812           41 : void __clove_report_pretty_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number) {
    2813           41 :     __clove_report_pretty_t* report = (__clove_report_pretty_t*)_this;
    2814              :     
    2815           41 :     bool print_passed = false;
    2816           41 :     bool print_failed = false;
    2817           41 :     bool print_skipped = false;
    2818           41 :     if (report->params->report_detail == __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED) {
    2819           41 :         print_passed = true;
    2820           41 :         print_failed = true;
    2821           41 :         print_skipped = true;
    2822            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED) {
    2823            0 :         print_passed = false;
    2824            0 :         print_failed = true;
    2825            0 :         print_skipped = false;
    2826            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED_SKIPPED) {
    2827            0 :         print_passed = false;
    2828            0 :         print_failed = true;
    2829            0 :         print_skipped = true;
    2830              :     }
    2831              : 
    2832              :     //Build test identifier with padding: Suite.Test.....
    2833              :     char test_identifier[__CLOVE_STRING_LENGTH];
    2834           41 :     __clove_string_sprintf(test_identifier, __CLOVE_STRING_LENGTH, "%s.%s", suite->name, test->name);
    2835           41 :     __clove_string_pad_right(test_identifier, __CLOVE_STRING_LENGTH, report->max_suite_and_test_name_size);
    2836              : 
    2837           51 :     if (print_passed && test->result == __CLOVE_TEST_RESULT_PASSED) {
    2838           10 :         float millis = (float)(__clove_time_to_nanos(&(test->duration))) / (float)__CLOVE_TIME_TRANSL_NANOS_PER_MILLIS;
    2839           10 :         int decimal = millis > 1.f ? 0 : 3;
    2840              : 
    2841           10 :         report->stream->writef(report->stream, "%s %0*zu) %s%s (%.*f ms)\n", 
    2842              :             report->labels.info, 
    2843              :             report->max_test_digits, test_number,
    2844              :             test_identifier,
    2845              :             report->labels.pass, 
    2846              :             decimal, millis);
    2847              :     }
    2848           55 :     else if (print_failed && test->result == __CLOVE_TEST_RESULT_FAILED) {
    2849           24 :         char msg[__CLOVE_STRING_LENGTH] = "FAILURE but NO MESSAGE!!!";
    2850              : 
    2851           24 :         if (test->issue.assert == __CLOVE_ASSERT_FAIL) {
    2852            0 :             __clove_string_sprintf(msg, sizeof(msg), "%s", "A FAIL assertion was met!");
    2853              :         }
    2854              :         else {
    2855           24 :             __CLOVE_SWITCH_BEG(test->issue.data_type)
    2856           24 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_BOOL) {
    2857            0 :                     const char* exp = test->issue.expected._bool ? "true" : "false";
    2858            0 :                     const char* act = test->issue.actual._bool ? "true" : "false";
    2859              :                     //__clove_string_sprintf(msg, sizeof(msg), "expected [%s] but was [%s]", exp, act);
    2860            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%s");
    2861              :                 }
    2862           24 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_CHAR) {
    2863              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2864            0 :                     const char exp = test->issue.expected._char;
    2865            0 :                     const char act = test->issue.actual._char;
    2866              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%c] but was [%c]", non, exp, act);
    2867            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%c");
    2868              :                 }
    2869           24 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_INT) {
    2870              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2871            1 :                     const int exp = test->issue.expected._int;
    2872            1 :                     const int act = test->issue.actual._int;
    2873              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%d] but was [%d]", non, exp, act);
    2874            1 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%d");
    2875              :                 }
    2876           23 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_UINT) {
    2877              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2878           12 :                     const unsigned int exp = test->issue.expected._uint;
    2879           12 :                     const unsigned int act = test->issue.actual._uint;
    2880              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%u] but was [%u]", non, exp, act);
    2881           12 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%u");
    2882              :                 }
    2883           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LONG) {
    2884              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2885            0 :                     const long exp = test->issue.expected._long;
    2886            0 :                     const long act = test->issue.actual._long;
    2887              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%ld] but was [%ld]", non, exp, act);
    2888            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%ld");
    2889              :                 }
    2890           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULONG) {
    2891              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2892            0 :                     const unsigned long exp = test->issue.expected._ulong;
    2893            0 :                     const unsigned long act = test->issue.actual._ulong;
    2894              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%lu] but was [%lu]", non, exp, act);
    2895            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%lu");
    2896              :                 }
    2897           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LLONG) {
    2898              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2899            0 :                     const long long exp = test->issue.expected._llong;
    2900            0 :                     const long long act = test->issue.actual._llong;
    2901              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%lld] but was [%lld]", non, exp, act);
    2902            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%lld");
    2903              :                 }
    2904           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULLONG) {
    2905              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2906            0 :                     const unsigned long long exp = test->issue.expected._ullong;
    2907            0 :                     const unsigned long long act = test->issue.actual._ullong;
    2908              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%llu] but was [%llu]", non, exp, act);
    2909            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%llu");
    2910              :                 }
    2911           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_SIZET) {
    2912              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2913            0 :                     const size_t exp = test->issue.expected._sizet;
    2914            0 :                     const size_t act = test->issue.actual._sizet;
    2915              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%zu] but was [%zu]", non, exp, act);
    2916            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%zu");
    2917              :                 }
    2918           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_FLOAT) {
    2919            0 :                     const float exp = test->issue.expected._float;
    2920            0 :                     const float act = test->issue.actual._float;
    2921            0 :                     char format[6] = {0}; //Example: %.NNf
    2922            0 :                     __clove_string_sprintf(format, sizeof(format), "%%.%df", test->issue.floating_precision);
    2923            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, format);
    2924              :                 }
    2925           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_DOUBLE) {
    2926            0 :                     const double exp = test->issue.expected._double;
    2927            0 :                     const double act = test->issue.actual._double;
    2928            0 :                     char format[6] = {0}; //Example: %.NNf
    2929            0 :                     __clove_string_sprintf(format, sizeof(format), "%%.%df", test->issue.floating_precision);
    2930            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, format);
    2931              :                 }
    2932           11 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_STRING) {
    2933           11 :                     const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2934           11 :                     const char* exp = test->issue.expected._string;
    2935           11 :                     const char* act = test->issue.actual._string;
    2936              : 
    2937           11 :                     const size_t max_len = 16;
    2938           11 :                     const size_t exp_len = __clove_string_length(exp);
    2939           11 :                     const size_t act_len = __clove_string_length(act);
    2940              : 
    2941           22 :                     if (exp_len <= max_len && act_len <= max_len) {
    2942           11 :                         char* exp_escaped = __clove_string_escape(exp);
    2943           11 :                         char* act_escaped = __clove_string_escape(act);
    2944           11 :                         __clove_string_sprintf(msg, sizeof(msg), "%sexpected \"%s\" but was \"%s\"", non, exp_escaped, act_escaped);
    2945           11 :                         __clove_memory_free(exp_escaped);
    2946           11 :                         __clove_memory_free(act_escaped);
    2947              :                     }
    2948              :                     else {
    2949              :                         char exp_short[16];
    2950              :                         char act_short[16];
    2951            0 :                         __clove_report_pretty_string_ellipse(exp, exp_len, act, act_len, exp_short, act_short, 16);
    2952              : 
    2953            0 :                         char* exp_escaped = __clove_string_escape(exp_short);
    2954            0 :                         char* act_escaped = __clove_string_escape(act_short);
    2955            0 :                         __clove_string_sprintf(msg, sizeof(msg), "%sexpected [%zu]\"%s\" but was [%zu]\"%s\"", non, exp_len, exp_escaped, act_len, act_escaped);
    2956            0 :                         __clove_memory_free(exp_escaped);
    2957            0 :                         __clove_memory_free(act_escaped);
    2958              :                     }
    2959              :                 }
    2960            0 :                 __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_PTR) {
    2961              :                     //const char* non = test->issue.assert == __CLOVE_ASSERT_EQ ? "" : "not ";
    2962            0 :                     const void* exp = test->issue.expected._ptr;
    2963            0 :                     const void* act = test->issue.actual._ptr;
    2964              :                     //__clove_string_sprintf(msg, sizeof(msg), "%sexpected [%p] but was [%p]", non, exp, act);
    2965            0 :                     __PRETTY_PRINT_FAIL_ASSERT_MSG(msg, sizeof(msg), test->issue.assert, exp, act, "%p");
    2966              :                 }
    2967              :             __CLOVE_SWITCH_END()
    2968              :         }
    2969              : 
    2970           24 :         const char* file_path = test->file_name;
    2971           24 :         if (report->params->tests_base_path) {
    2972           24 :             file_path = __clove_path_relative(test->file_name, report->params->tests_base_path);
    2973              :         }
    2974              :         
    2975           24 :         report->stream->writef(report->stream, "%s %0*zu) %s%s %s:%zu: %s\n", 
    2976              :             report->labels.erro, 
    2977              :             report->max_test_digits, test_number,
    2978              :             test_identifier,
    2979              :             report->labels.fail, 
    2980              :             file_path, test->issue.line, msg);
    2981              :     }
    2982            7 :     else if (print_skipped && test->result == __CLOVE_TEST_RESULT_SKIPPED) {
    2983              : 
    2984            7 :         const char* file_path = test->file_name;
    2985            7 :         if (report->params->tests_base_path) {
    2986            7 :             file_path = __clove_path_relative(test->file_name, report->params->tests_base_path);
    2987              :         }
    2988              : 
    2989            7 :         report->stream->writef(report->stream, "%s %0*zu) %s%s %s:%zu: %s\n", 
    2990              :             report->labels.warn, 
    2991              :             report->max_test_digits, test_number,
    2992              :             test_identifier,
    2993              :             report->labels.skip, 
    2994              :             file_path, test->funct_line, "Missing assertion!");
    2995              :     }
    2996           41 : }
    2997              : 
    2998            0 : void __clove_report_pretty_string_ellipse(
    2999              :     const char* exp, size_t exp_len,
    3000              :     const char* act, size_t act_len,
    3001              :     char* exp_short, char* act_short, size_t short_size)
    3002              : {
    3003            0 :     size_t iter_len = exp_len < act_len ? exp_len : act_len;
    3004            0 :     if (iter_len == 0) {
    3005            0 :         __clove_string_ellipse(exp, exp_len, 0, exp_short, short_size);
    3006            0 :         __clove_string_ellipse(act, act_len, 0, act_short, short_size);
    3007            0 :         return;
    3008              :     }
    3009              : 
    3010            0 :     for (size_t i = 0; i < iter_len; ++i) {
    3011            0 :         if (exp[i] != act[i]) {
    3012            0 :             __clove_string_ellipse(exp, exp_len, i, exp_short, short_size);
    3013            0 :             __clove_string_ellipse(act, act_len, i, act_short, short_size);
    3014            0 :             return;
    3015              :         }
    3016              :     }
    3017              : 
    3018              :     //Scenario where the shortest one is the like the "prefix" of the longest one 
    3019            0 :     __clove_string_ellipse(exp, exp_len, iter_len-1, exp_short, short_size);
    3020            0 :     __clove_string_ellipse(act, act_len, iter_len-1, act_short, short_size);
    3021              : }
    3022              : #pragma endregion // RunTests Report Pretty Impl
    3023              : 
    3024              : #pragma region PRIVATE - RunTests Report Csv Impl
    3025              : #include <stdio.h>
    3026            0 : __clove_report_run_tests_csv_t* __clove_report_run_tests_csv_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    3027            0 :     __clove_report_run_tests_csv_t* result = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_run_tests_csv_t);
    3028            0 :     result->base.start = __clove_report_run_tests_csv_start;
    3029            0 :     result->base.begin_suite = __clove_report_run_tests_csv_begin_suite;
    3030            0 :     result->base.end_suite = __clove_report_run_tests_csv_end_suite;
    3031            0 :     result->base.end = __clove_report_run_tests_csv_end;
    3032            0 :     result->base.end_test = __clove_report_run_tests_csv_end_test;
    3033            0 :     result->base.free = __clove_report_run_tests_csv_free;
    3034            0 :     result->stream = stream;
    3035            0 :     result->params = params;
    3036            0 :     return result;
    3037              : }
    3038              : 
    3039            0 : void __clove_report_run_tests_csv_free(__clove_report_t* report) {
    3040            0 :     __clove_memory_free(report);
    3041            0 : }
    3042              : 
    3043            0 : void __clove_report_run_tests_csv_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count) {
    3044              :     __CLOVE_UNUSED_VAR(_this);
    3045              :     __CLOVE_UNUSED_VAR(suites);
    3046              :     __CLOVE_UNUSED_VAR(test_count);
    3047              : 
    3048            0 :     __clove_report_run_tests_csv_t* report = (__clove_report_run_tests_csv_t*)_this;
    3049            0 :     report->stream->open(report->stream);
    3050            0 :     report->stream->writef(report->stream, "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", "Suite","Test","Status","Duration","File","Line","Assert","Type","Expected","Actual");
    3051            0 : }
    3052            0 : void __clove_report_run_tests_csv_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    3053              :     __CLOVE_UNUSED_VAR(_this);
    3054              :     __CLOVE_UNUSED_VAR(suite);
    3055              :     __CLOVE_UNUSED_VAR(index);
    3056              : 
    3057              :     //nothing todo
    3058            0 : }
    3059            0 : void __clove_report_run_tests_csv_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    3060              :     __CLOVE_UNUSED_VAR(_this);
    3061              :     __CLOVE_UNUSED_VAR(suite);
    3062              :     __CLOVE_UNUSED_VAR(index);
    3063              :     //nothing todo
    3064            0 : }
    3065            0 : void __clove_report_run_tests_csv_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed) {
    3066              :     __CLOVE_UNUSED_VAR(passed);
    3067              :     __CLOVE_UNUSED_VAR(skipped);
    3068              :     __CLOVE_UNUSED_VAR(failed);
    3069              : 
    3070            0 :     __clove_report_run_tests_csv_t* report = (__clove_report_run_tests_csv_t*)_this;
    3071            0 :     report->stream->close(report->stream);
    3072            0 : }
    3073              : 
    3074            0 : void __clove_report_run_tests_csv_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number) {
    3075              :     __CLOVE_UNUSED_VAR(test_number);
    3076              :     
    3077            0 :     __clove_report_run_tests_csv_t* report = (__clove_report_run_tests_csv_t*)_this;
    3078              : 
    3079            0 :     bool print_passed = false;
    3080            0 :     bool print_failed = false;
    3081            0 :     bool print_skipped = false;
    3082            0 :     if (report->params->report_detail == __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED) {
    3083            0 :         print_passed = true;
    3084            0 :         print_failed = true;
    3085            0 :         print_skipped = true;
    3086            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED) {
    3087            0 :         print_passed = false;
    3088            0 :         print_failed = true;
    3089            0 :         print_skipped = false;
    3090            0 :     } else if (report->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED_SKIPPED) {
    3091            0 :         print_passed = false;
    3092            0 :         print_failed = true;
    3093            0 :         print_skipped = true;
    3094              :     }
    3095              : 
    3096              :     ////Suite,Test,Status,Duration,File,Line,Assert,Type,Expected,Actual
    3097            0 :     if (print_passed && test->result == __CLOVE_TEST_RESULT_PASSED) {
    3098            0 :         report->stream->writef(report->stream, "%s,%s,%s,%llu,%s,%s,%s,%s,%s,%s\n", 
    3099              :             suite->name, test->name, test->result, __clove_time_to_nanos(&(test->duration)),"","","","","","");
    3100              :     } 
    3101            0 :     else if (print_failed && test->result == __CLOVE_TEST_RESULT_FAILED) {
    3102            0 :         const char* data_type = (test->issue.assert == __CLOVE_ASSERT_FAIL) ? "" : test->issue.data_type;
    3103            0 :         const char* file_name = __clove_path_relative(test->file_name, report->params->tests_base_path);
    3104              :       
    3105            0 :         report->stream->writef(report->stream, "%s,%s,%s,%s,%s,%zu,%s,%s,", 
    3106              :             suite->name, test->name, test->result, "",file_name,test->issue.line, test->issue.assert, data_type);
    3107              : 
    3108            0 :         __clove_report_run_tests_csv_print_data(report, test, &test->issue.expected);
    3109            0 :         report->stream->writef(report->stream, ",");
    3110            0 :         __clove_report_run_tests_csv_print_data(report, test, &test->issue.actual);
    3111            0 :         report->stream->writef(report->stream, "\n");
    3112              :     }
    3113            0 :     else if (print_skipped && test->result == __CLOVE_TEST_RESULT_SKIPPED) {
    3114            0 :         const char* file_name = __clove_path_relative(test->file_name, report->params->tests_base_path);
    3115              : 
    3116            0 :         report->stream->writef(report->stream, "%s,%s,%s,%s,%s,%zu,%s,%s,%s,%s\n", 
    3117              :             suite->name, test->name, test->result,"",file_name,test->funct_line,"","","","");
    3118              :     }
    3119            0 : }
    3120              : 
    3121            0 : void __clove_report_run_tests_csv_print_data(__clove_report_run_tests_csv_t* instance, __clove_test_t* test, __clove_generic_u* data) {
    3122            0 :     if (test->issue.assert == __CLOVE_ASSERT_FAIL) {
    3123            0 :         instance->stream->writef(instance->stream, "%s", "");
    3124              :     } else {
    3125            0 :         __CLOVE_SWITCH_BEG(test->issue.data_type)
    3126            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_BOOL)
    3127            0 :                 instance->stream->writef(instance->stream, "%s", data->_bool ? "true" : "false");
    3128            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_CHAR)
    3129            0 :                 instance->stream->writef(instance->stream, "%c", data->_char);
    3130            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_INT)
    3131            0 :                 instance->stream->writef(instance->stream, "%d", data->_int);
    3132            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_UINT)
    3133            0 :                 instance->stream->writef(instance->stream, "%u", data->_uint);
    3134            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LONG)
    3135            0 :                 instance->stream->writef(instance->stream, "%ld", data->_long);
    3136            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULONG)
    3137            0 :                 instance->stream->writef(instance->stream, "%lu", data->_ulong);
    3138            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LLONG)
    3139            0 :                 instance->stream->writef(instance->stream, "%lld", data->_llong);
    3140            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULLONG)
    3141            0 :                 instance->stream->writef(instance->stream, "%llu", data->_ullong);
    3142            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_SIZET)
    3143            0 :                 instance->stream->writef(instance->stream, "%zu", data->_sizet);
    3144            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_FLOAT)
    3145            0 :                 instance->stream->writef(instance->stream, "%.*f", test->issue.floating_precision, data->_float);
    3146            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_DOUBLE)
    3147            0 :                 instance->stream->writef(instance->stream, "%.*f", test->issue.floating_precision, data->_double);
    3148            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_STRING) {
    3149            0 :                 char* escaped = __clove_string_csv_escape(data->_string);
    3150            0 :                 instance->stream->writef(instance->stream, "%s", escaped);
    3151            0 :                 __clove_memory_free(escaped);
    3152              :             }
    3153            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_PTR)
    3154            0 :                 instance->stream->writef(instance->stream, "%p", data->_ptr);
    3155              :         __CLOVE_SWITCH_END()
    3156              :     }
    3157            0 : }
    3158              : #pragma endregion //Report RunTests Csv Impl
    3159              : 
    3160              : 
    3161              : 
    3162              : #pragma region PRIVATE - Report Json Impl
    3163              : #include <stdio.h>
    3164              : #include <stdlib.h>
    3165            0 : __clove_report_json_t* __clove_report_run_tests_json_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    3166            0 :     __clove_report_json_t* result = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_json_t);
    3167            0 :     result->base.start = __clove_report_json_start;
    3168            0 :     result->base.begin_suite = __clove_report_json_begin_suite;
    3169            0 :     result->base.end_suite = __clove_report_json_end_suite;
    3170            0 :     result->base.end = __clove_report_json_end;
    3171            0 :     result->base.end_test = __clove_report_json_end_test;
    3172            0 :     result->base.free = __clove_report_json_free;
    3173            0 :     result->stream = stream;
    3174            0 :     result->params = params;
    3175            0 :     result->clove_version = __CLOVE_VERSION;
    3176            0 :     result->json_schema = "1.0";
    3177            0 :     result->current_suite = NULL;
    3178            0 :     result->suite_tests_counter = 0;
    3179            0 :     result->suite_tests_number = 0;
    3180              : 
    3181            0 :     result->suite_count = 0;
    3182            0 :     result->test_count = 0;
    3183            0 :     result->is_first_suite_test = false;
    3184              :     //Full report is the main usage scenario, so a report will be computed during test execution,
    3185              :     //instead, for detail Failed (or Failed+Skipped) need it to cache suites (and related test) and only compute
    3186              :     //the report at end of tests executions
    3187            0 :     result->is_realtime_scenario = params->report_detail == __CLOVE_REPORT_DETAIL__PASSED_FAILED_SKIPPED;
    3188            0 :     result->is_reporting_enabled = result->is_realtime_scenario;
    3189            0 :     result->cached_suites = __clove_vector_null();
    3190            0 :     return result;
    3191              : }
    3192              : 
    3193            0 : void __clove_report_json_free(__clove_report_t* report) {
    3194            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)report;
    3195            0 :     __clove_vector_free(&instance->cached_suites);
    3196            0 :     __clove_memory_free(report);
    3197            0 : }
    3198              : 
    3199            0 : void __clove_report_json_start(__clove_report_t* _this, __clove_vector_t* suites, size_t test_count) {
    3200              :     __CLOVE_UNUSED_VAR(suites);
    3201              : 
    3202            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)_this;
    3203            0 :     instance->suite_count = __clove_vector_count(suites);
    3204            0 :     instance->test_count = test_count;
    3205              : 
    3206            0 :     if (!instance->is_realtime_scenario) {
    3207            0 :         __CLOVE_VECTOR_INIT_CAPACITY(&instance->cached_suites, __clove_suite_t*, instance->suite_count);
    3208              :     }
    3209              : 
    3210            0 :     bool opened = instance->stream->open(instance->stream);
    3211            0 :     if (!opened) { __clove_console_printf("ERROR OPENING STREAM\n"); } //TODO: ToString stream
    3212              : 
    3213            0 :     instance->stream->writef(instance->stream, "{\n");
    3214            0 :     instance->stream->writef(instance->stream, "\t\"clove_version\" : \"%s\",\n", instance->clove_version);
    3215            0 :     instance->stream->writef(instance->stream, "\t\"json_schema\" : \"%s\",\n", instance->json_schema);
    3216            0 :     instance->stream->writef(instance->stream, "\t\"result\" : {\n");
    3217            0 :     instance->stream->writef(instance->stream, "\t\t\"suite_count\" : %zu,\n", instance->suite_count);
    3218            0 :     instance->stream->writef(instance->stream, "\t\t\"test_count\" : %zu,\n", test_count);
    3219            0 :     instance->stream->writef(instance->stream, "\t\t\"suites\" : {\n");
    3220            0 : }
    3221              : 
    3222              : 
    3223            0 : void __clove_report_json_end(__clove_report_t* _this, size_t passed, size_t skipped, size_t failed) {
    3224            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)_this;
    3225              :     
    3226            0 :     if (!instance->is_reporting_enabled) {
    3227            0 :         instance->is_reporting_enabled = true;
    3228              :     
    3229            0 :         size_t suite_count = __clove_vector_count(&instance->cached_suites);
    3230            0 :         size_t test_number = 0;
    3231              :         
    3232            0 :         bool report_failed = false;
    3233            0 :         bool report_skipped = false;
    3234            0 :         if (instance->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED) {
    3235            0 :             report_failed = true;
    3236            0 :             report_skipped = false;
    3237            0 :         } else if (instance->params->report_detail == __CLOVE_REPORT_DETAIL__FAILED_SKIPPED) {
    3238            0 :             report_failed = true;
    3239            0 :             report_skipped = true;
    3240              :         }
    3241              : 
    3242            0 :         for(size_t suite_index=0; suite_index < suite_count; ++suite_index) {
    3243            0 :             __clove_suite_t* suite = *(__clove_suite_t**)__clove_vector_get(&instance->cached_suites, suite_index);
    3244            0 :             bool has_failed = report_failed && suite->issue.failed_count > 0;
    3245            0 :             bool has_skipped = report_skipped && suite->issue.skipped_count > 0;
    3246            0 :             if (!has_failed && !has_skipped) continue; 
    3247              : 
    3248            0 :             instance->suite_tests_number = 0;
    3249            0 :             if (has_failed) instance->suite_tests_number += suite->issue.failed_count;
    3250            0 :             if (has_skipped) instance->suite_tests_number += suite->issue.skipped_count;
    3251              : 
    3252            0 :             __clove_report_json_begin_suite(_this, suite, suite_index);
    3253              : 
    3254            0 :             for(size_t test_index=0; test_index < __clove_vector_count(&suite->tests); ++test_index) { 
    3255            0 :                 __clove_test_t* test = (__clove_test_t*)__clove_vector_get(&suite->tests, test_index);
    3256            0 :                 bool failed_case = report_failed && test->result == __CLOVE_TEST_RESULT_FAILED;
    3257            0 :                 bool skipped_case = report_skipped && test->result == __CLOVE_TEST_RESULT_SKIPPED;
    3258            0 :                 if (!failed_case && !skipped_case) continue;
    3259              : 
    3260            0 :                 __clove_report_json_end_test(_this, suite, test, ++test_number);
    3261              :             }
    3262              : 
    3263            0 :             __clove_report_json_end_suite(_this, suite, suite_index);
    3264              :         }
    3265              :     }
    3266              : 
    3267              :     //Write overall results
    3268            0 :     const char* status = "UNKNOWN";
    3269            0 :     if (passed == instance->test_count) status = __CLOVE_TEST_RESULT_PASSED;
    3270            0 :     else if (failed > 0) status = __CLOVE_TEST_RESULT_FAILED;
    3271            0 :     else if (skipped > 0) status = __CLOVE_TEST_RESULT_SKIPPED;
    3272              : 
    3273            0 :     instance->stream->writef(instance->stream, "\t\t},\n"); //suites
    3274            0 :     instance->stream->writef(instance->stream, "\t\t\"test_passed\" : %zu,\n", passed);
    3275            0 :     instance->stream->writef(instance->stream, "\t\t\"test_skipped\" : %zu,\n", skipped);
    3276            0 :     instance->stream->writef(instance->stream, "\t\t\"test_failed\" : %zu,\n", failed);
    3277            0 :     instance->stream->writef(instance->stream, "\t\t\"status\" : \"%s\"\n", status);
    3278            0 :     instance->stream->writef(instance->stream, "\t}\n"); //result
    3279            0 :     instance->stream->writef(instance->stream, "}"); //object
    3280              : 
    3281            0 :     instance->stream->close(instance->stream);
    3282            0 : }
    3283              : 
    3284            0 : void __clove_report_json_print_data(__clove_report_json_t* instance, __clove_test_t* test, __clove_generic_u* data) {
    3285            0 :     if (test->issue.assert == __CLOVE_ASSERT_FAIL) {
    3286            0 :         instance->stream->writef(instance->stream, "%s", "");
    3287              :     } else {
    3288            0 :         __CLOVE_SWITCH_BEG(test->issue.data_type)
    3289            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_BOOL)
    3290            0 :                 instance->stream->writef(instance->stream, "%s", data->_bool ? "true" : "false");
    3291            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_CHAR)
    3292            0 :                 instance->stream->writef(instance->stream, "%c", data->_char);
    3293            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_INT)
    3294            0 :                 instance->stream->writef(instance->stream, "%d", data->_int);
    3295            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_UINT)
    3296            0 :                 instance->stream->writef(instance->stream, "%u", data->_uint);
    3297            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LONG)
    3298            0 :                 instance->stream->writef(instance->stream, "%ld", data->_long);
    3299            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULONG)
    3300            0 :                 instance->stream->writef(instance->stream, "%lu", data->_ulong);
    3301            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_LLONG)
    3302            0 :                 instance->stream->writef(instance->stream, "%lld", data->_llong);
    3303            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_ULLONG)
    3304            0 :                 instance->stream->writef(instance->stream, "%llu", data->_ullong);
    3305            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_SIZET)
    3306            0 :                 instance->stream->writef(instance->stream, "%zu", data->_sizet);
    3307            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_FLOAT)
    3308            0 :                 instance->stream->writef(instance->stream, "%.*f", test->issue.floating_precision, data->_float);
    3309            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_DOUBLE)
    3310            0 :                 instance->stream->writef(instance->stream, "%.*f", test->issue.floating_precision, data->_double);
    3311            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_STRING) {
    3312            0 :                 char* escaped = __clove_string_escape(data->_string);
    3313            0 :                 instance->stream->writef(instance->stream, "%s", escaped);
    3314            0 :                 __clove_memory_free(escaped);
    3315              :             }
    3316            0 :             __CLOVE_SWITCH_CASE(__CLOVE_GENERIC_PTR)
    3317            0 :                 instance->stream->writef(instance->stream, "%p", data->_ptr);
    3318              :         __CLOVE_SWITCH_END()
    3319              :     }
    3320            0 : }
    3321              : 
    3322            0 : void __clove_report_json_begin_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    3323              :     __CLOVE_UNUSED_VAR(index);
    3324              : 
    3325            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)_this;
    3326            0 :     if (instance->is_reporting_enabled) {
    3327            0 :         instance->is_first_suite_test = true;
    3328            0 :         instance->current_suite = suite;
    3329              :     }
    3330            0 : }
    3331              : 
    3332            0 : void __clove_report_json_end_suite(__clove_report_t* _this, __clove_suite_t* suite, size_t index) {
    3333              :     __CLOVE_UNUSED_VAR(index);
    3334              : 
    3335            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)_this;
    3336            0 :     if (!instance->is_reporting_enabled) {
    3337            0 :         __CLOVE_VECTOR_ADD(&instance->cached_suites, __clove_suite_t*, suite);
    3338            0 :         return;
    3339              :     } 
    3340              : 
    3341            0 :     const char* comma = "";
    3342            0 :     if (index < instance->suite_count-1) {
    3343            0 :         comma = ",";
    3344              :     }
    3345            0 :     instance->stream->writef(instance->stream, "\t\t\t}%s\n", comma); //close suite    
    3346              : 
    3347            0 :     instance->current_suite = NULL;
    3348              : }
    3349              : 
    3350            0 : void __clove_report_json_end_test(__clove_report_t* _this, __clove_suite_t* suite, __clove_test_t* test, size_t test_number) {
    3351              :     __CLOVE_UNUSED_VAR(test_number);
    3352              : 
    3353            0 :     __clove_report_json_t* instance = (__clove_report_json_t*)_this;
    3354            0 :     if (!instance->is_reporting_enabled) return;
    3355              :     
    3356            0 :     if (instance->is_first_suite_test) {
    3357            0 :         const char* file_path = __clove_path_relative(test->file_name, instance->params->tests_base_path);
    3358            0 :         char* escaped_file = __clove_string_strdup(file_path);
    3359            0 :         __clove_string_replace_char(escaped_file, '\\', '/');
    3360              :         
    3361            0 :         instance->stream->writef(instance->stream, "\t\t\t\"%s\" : {\n", instance->current_suite->name);
    3362            0 :         instance->stream->writef(instance->stream, "\t\t\t\t\"file\" : \"%s\",\n", escaped_file);
    3363            0 :         instance->stream->writef(instance->stream, "\t\t\t\t\"tests\" : {\n");
    3364            0 :         instance->suite_tests_counter = 0;
    3365              :    
    3366            0 :         __clove_memory_free(escaped_file);
    3367            0 :         instance->is_first_suite_test = false;
    3368              :     }
    3369              : 
    3370            0 :     instance->suite_tests_counter++;
    3371            0 :     instance->stream->writef(instance->stream, "\t\t\t\t\t\"%s\" : {\n", test->name);
    3372            0 :     instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"status\" : \"%s\",\n", test->result);
    3373            0 :     instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"duration\" : %llu", __clove_time_to_nanos(&(test->duration)));
    3374            0 :     if (test->result == __CLOVE_TEST_RESULT_FAILED) {
    3375            0 :         instance->stream->writef(instance->stream, ",\n");
    3376            0 :         instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"line\" : %zu,\n", test->issue.line);
    3377            0 :         instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"assert\" : \"%s\"", test->issue.assert);        
    3378            0 :         if (test->issue.assert != __CLOVE_ASSERT_FAIL) {
    3379            0 :             instance->stream->writef(instance->stream, ",\n");
    3380            0 :             instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"type\" : \"%s\",\n", test->issue.data_type);
    3381            0 :             instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"expected\" : \"");
    3382            0 :             __clove_report_json_print_data(instance, test, &(test->issue.expected));
    3383            0 :             instance->stream->writef(instance->stream, "\",\n");
    3384              :             
    3385            0 :             instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"actual\" : \"");
    3386            0 :             __clove_report_json_print_data(instance, test, &(test->issue.actual));
    3387            0 :             instance->stream->writef(instance->stream, "\"\n");
    3388              :         } else {
    3389            0 :             instance->stream->writef(instance->stream, "\n");
    3390              :         }
    3391            0 :     } else if (test->result == __CLOVE_TEST_RESULT_SKIPPED) {
    3392            0 :         instance->stream->writef(instance->stream, ",\n");
    3393            0 :         instance->stream->writef(instance->stream, "\t\t\t\t\t\t\"line\" : %zu\n", test->funct_line);
    3394              :     } else {
    3395            0 :         instance->stream->writef(instance->stream, "\n");
    3396              :     }
    3397            0 :     instance->stream->writef(instance->stream, "\t\t\t\t\t}");
    3398              : 
    3399            0 :     size_t suite_total_tests = suite->test_count; //realtime scenario
    3400            0 :     if (!instance->is_realtime_scenario) suite_total_tests = instance->suite_tests_number;
    3401              : 
    3402            0 :     if (instance->suite_tests_counter < suite_total_tests) {
    3403            0 :         instance->stream->writef(instance->stream, ",\n");
    3404              :     }
    3405              :     else {
    3406            0 :         instance->stream->writef(instance->stream, "\n");
    3407            0 :         instance->stream->writef(instance->stream, "\t\t\t\t}\n"); //close "tests"
    3408              :     }
    3409              : }
    3410              : #pragma endregion // Report Json Impl
    3411              : 
    3412              : #pragma region PRIVATE - Report List Test Impl
    3413            0 : __clove_report_list_tests_pretty_t* __clove_report_list_tests_pretty_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    3414            0 :     __clove_report_list_tests_pretty_t* _this = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_list_tests_pretty_t);
    3415            0 :     _this->base.begin = __clove_report_list_tests_pretty_begin;
    3416            0 :     _this->base.begin_suite = __clove_report_list_tests_pretty_begin_suite;
    3417            0 :     _this->base.begin_test = __clove_report_list_tests_pretty_begin_test;
    3418            0 :     _this->base.end_test = __clove_report_list_tests_pretty_end_test;
    3419            0 :     _this->base.end_suite = __clove_report_list_tests_pretty_end_suite;
    3420            0 :     _this->base.end = __clove_report_list_tests_pretty_end;
    3421            0 :     _this->base.free = __clove_report_list_tests_pretty_free;
    3422            0 :     _this->stream = stream;
    3423            0 :     _this->params = params;
    3424            0 :     _this->suite_format = NULL;
    3425            0 :     _this->test_format = NULL;
    3426            0 :     _this->is_suite_first_test = false;
    3427            0 :     _this->current_suite = NULL;
    3428            0 :     return _this;
    3429              : }
    3430            0 : void __clove_report_list_tests_pretty_free(__clove_report_list_tests_t* _this) {
    3431            0 :     __clove_memory_free((__clove_report_list_tests_pretty_t*)_this);
    3432            0 : }
    3433            0 : void __clove_report_list_tests_pretty_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count) {
    3434            0 :     __clove_report_list_tests_pretty_t* pretty = (__clove_report_list_tests_pretty_t*)_this;
    3435            0 :     pretty->stream->open(pretty->stream);
    3436              : 
    3437            0 :     bool activated = pretty->stream->has_ansi_support(pretty->stream);
    3438            0 :     if (activated) {
    3439            0 :         pretty->suite_format = "\x1b[1;34m%s\x1b[0m (file: %s)\n";
    3440            0 :         pretty->test_format = "- \x1b[1;32m%s\x1b[0m [line: %zu]\n";
    3441            0 :         pretty->stream->writef(pretty->stream, "\nListing \x1b[1;32m%zu\x1b[0m Test(s) in \x1b[1;34m%zu\x1b[0m Suite(s):\n\n", test_count, suite_count);
    3442              :     } else {
    3443            0 :         pretty->suite_format = "%s (file: %s)\n";
    3444            0 :         pretty->test_format = "- %s [line: %zu]\n";
    3445            0 :         pretty->stream->writef(pretty->stream, "\nListing %zu Test(s) in %zu Suite(s):\n\n", test_count, suite_count);
    3446              :     }
    3447            0 : }
    3448            0 : void __clove_report_list_tests_pretty_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3449              :      __CLOVE_UNUSED_VAR(index);
    3450              : 
    3451            0 :     __clove_report_list_tests_pretty_t* pretty = (__clove_report_list_tests_pretty_t*)_this;
    3452            0 :     pretty->is_suite_first_test = true;
    3453            0 :     pretty->current_suite = suite;
    3454            0 : }
    3455            0 : void __clove_report_list_tests_pretty_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3456              :     __CLOVE_UNUSED_VAR(_this);
    3457              :     __CLOVE_UNUSED_VAR(suite);
    3458              :     __CLOVE_UNUSED_VAR(index);
    3459              :     //nothing todo
    3460            0 : }
    3461            0 : void __clove_report_list_tests_pretty_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3462              :     __CLOVE_UNUSED_VAR(_this);
    3463              :     __CLOVE_UNUSED_VAR(test);
    3464              :     __CLOVE_UNUSED_VAR(index);
    3465              :     //nothing todo
    3466            0 : }
    3467            0 : void __clove_report_list_tests_pretty_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3468              :     __CLOVE_UNUSED_VAR(index);
    3469              : 
    3470            0 :     __clove_report_list_tests_pretty_t* pretty = (__clove_report_list_tests_pretty_t*)_this;
    3471            0 :     if (pretty->is_suite_first_test) {
    3472            0 :         const char* file_path = __clove_path_relative(test->file_name, pretty->params->tests_base_path);
    3473            0 :         pretty->stream->writef(pretty->stream, pretty->suite_format, pretty->current_suite->name, file_path); 
    3474            0 :         pretty->is_suite_first_test = false;  
    3475              :     }
    3476            0 :     pretty->stream->writef(pretty->stream, pretty->test_format, test->name, test->funct_line);
    3477            0 : }
    3478            0 : void __clove_report_list_tests_pretty_end(__clove_report_list_tests_t* _this) {
    3479            0 :     __clove_report_list_tests_pretty_t* pretty = (__clove_report_list_tests_pretty_t*)_this;
    3480            0 :     pretty->stream->close(pretty->stream);
    3481            0 : }
    3482              : 
    3483            0 : __clove_report_list_tests_csv_t* __clove_report_list_tests_csv_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    3484            0 :     __clove_report_list_tests_csv_t* _this = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_list_tests_csv_t);
    3485            0 :     _this->base.begin = __clove_report_list_tests_csv_begin;
    3486            0 :     _this->base.begin_suite = __clove_report_list_tests_csv_begin_suite;
    3487            0 :     _this->base.begin_test = __clove_report_list_tests_csv_begin_test;
    3488            0 :     _this->base.end_test = __clove_report_list_tests_csv_end_test;
    3489            0 :     _this->base.end_suite = __clove_report_list_tests_csv_end_suite;
    3490            0 :     _this->base.end = __clove_report_list_tests_csv_end;
    3491            0 :     _this->base.free = __clove_report_list_tests_csv_free;
    3492            0 :     _this->stream = stream;
    3493            0 :     _this->params = params;
    3494            0 :     _this->current_suite = NULL;
    3495            0 :     return _this;
    3496              : }
    3497            0 : void __clove_report_list_tests_csv_free(__clove_report_list_tests_t* _this) {
    3498            0 :     __clove_memory_free((__clove_report_list_tests_csv_t*)_this);
    3499            0 : }
    3500            0 : void __clove_report_list_tests_csv_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count) {
    3501              :     __CLOVE_UNUSED_VAR(test_count);
    3502              : 
    3503            0 :     __clove_report_list_tests_csv_t* csv = (__clove_report_list_tests_csv_t*)_this;
    3504            0 :     csv->stream->open(csv->stream);
    3505            0 :     if (suite_count > 0) {
    3506            0 :          csv->stream->writef(csv->stream, "%s,%s,%s,%s\n", "Suite", "Test", "File", "Line");
    3507              :     }
    3508            0 : }
    3509            0 : void __clove_report_list_tests_csv_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3510              :     __CLOVE_UNUSED_VAR(index);
    3511              : 
    3512            0 :     __clove_report_list_tests_csv_t* csv = (__clove_report_list_tests_csv_t*)_this;
    3513            0 :     csv->current_suite = suite;
    3514            0 : }
    3515            0 : void __clove_report_list_tests_csv_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3516              :     __CLOVE_UNUSED_VAR(suite);
    3517              :     __CLOVE_UNUSED_VAR(index);
    3518              : 
    3519            0 :     __clove_report_list_tests_csv_t* csv = (__clove_report_list_tests_csv_t*)_this;
    3520            0 :     csv->current_suite = NULL;
    3521            0 : }
    3522            0 : void __clove_report_list_tests_csv_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3523              :     __CLOVE_UNUSED_VAR(_this);
    3524              :     __CLOVE_UNUSED_VAR(test);
    3525              :     __CLOVE_UNUSED_VAR(index);
    3526              :     //nothing todo
    3527            0 : }
    3528            0 : void __clove_report_list_tests_csv_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3529              :     __CLOVE_UNUSED_VAR(index);
    3530              : 
    3531            0 :     __clove_report_list_tests_csv_t* csv = (__clove_report_list_tests_csv_t*)_this;
    3532            0 :     const char* file_path = __clove_path_relative(test->file_name, csv->params->tests_base_path);
    3533            0 :     csv->stream->writef(csv->stream, "%s,%s,%s,%zu\n", csv->current_suite->name, test->name, file_path, test->funct_line);
    3534            0 : }
    3535            0 : void __clove_report_list_tests_csv_end(__clove_report_list_tests_t* _this) {
    3536            0 :     __clove_report_list_tests_csv_t* csv = (__clove_report_list_tests_csv_t*)_this;
    3537            0 :     csv->stream->close(csv->stream);
    3538            0 : }
    3539              : 
    3540            0 : __clove_report_list_tests_json_t* __clove_report_list_tests_json_new(__clove_stream_t* stream, __clove_report_params_t* params) {
    3541            0 :     __clove_report_list_tests_json_t* _this = __CLOVE_MEMORY_MALLOC_TYPE(__clove_report_list_tests_json_t);
    3542            0 :     _this->base.begin = __clove_report_list_tests_json_begin;
    3543            0 :     _this->base.begin_suite = __clove_report_list_tests_json_begin_suite;
    3544            0 :     _this->base.begin_test = __clove_report_list_tests_json_begin_test;
    3545            0 :     _this->base.end_test = __clove_report_list_tests_json_end_test;
    3546            0 :     _this->base.end_suite = __clove_report_list_tests_json_end_suite;
    3547            0 :     _this->base.end = __clove_report_list_tests_json_end;
    3548            0 :     _this->base.free = __clove_report_list_tests_json_free;
    3549            0 :     _this->stream = stream;
    3550            0 :     _this->params = params;
    3551            0 :     _this->clove_version = __CLOVE_VERSION;
    3552            0 :     _this->json_schema = "1.0";
    3553            0 :     _this->suite_count = 0;
    3554            0 :     _this->is_suite_first_test = false;
    3555            0 :     _this->current_suite = NULL;
    3556            0 :     return _this;
    3557              : }
    3558            0 : void __clove_report_list_tests_json_free(__clove_report_list_tests_t* _this) {
    3559            0 :     __clove_memory_free((__clove_report_list_tests_json_t*)_this);
    3560            0 : }
    3561              : 
    3562            0 : void __clove_report_list_tests_json_begin(__clove_report_list_tests_t* _this, size_t suite_count, size_t test_count) {
    3563            0 :     __clove_report_list_tests_json_t* json = (__clove_report_list_tests_json_t*)_this;
    3564            0 :     json->suite_count = suite_count;
    3565              :     
    3566            0 :     json->stream->open(json->stream);
    3567              : 
    3568            0 :     json->stream->writef(json->stream, "{\n");
    3569            0 :     json->stream->writef(json->stream, "\t\"clove_version\" : \"%s\",\n", json->clove_version);
    3570            0 :     json->stream->writef(json->stream, "\t\"json_schema\" : \"%s\",\n", json->json_schema);
    3571            0 :     json->stream->writef(json->stream, "\t\"result\" : {\n");
    3572            0 :     json->stream->writef(json->stream, "\t\t\"suite_count\" : %zu,\n", suite_count);
    3573            0 :     json->stream->writef(json->stream, "\t\t\"test_count\" : %zu,\n", test_count);
    3574            0 :     json->stream->writef(json->stream, "\t\t\"suites\" : [\n");
    3575              :     
    3576            0 : }
    3577            0 : void __clove_report_list_tests_json_begin_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3578              :     __CLOVE_UNUSED_VAR(index);
    3579              :     
    3580            0 :     __clove_report_list_tests_json_t* json = (__clove_report_list_tests_json_t*)_this;
    3581            0 :     json->current_suite = suite;
    3582            0 :     json->is_suite_first_test = true;
    3583            0 : }
    3584            0 : void __clove_report_list_tests_json_end_suite(__clove_report_list_tests_t* _this,  __clove_suite_t* suite, size_t index) {
    3585              :     __CLOVE_UNUSED_VAR(suite);
    3586              : 
    3587            0 :     __clove_report_list_tests_json_t* json = (__clove_report_list_tests_json_t*)_this;
    3588            0 :     json->current_suite = NULL;
    3589              : 
    3590            0 :     const char* comma = "";
    3591            0 :     if (index < json->suite_count-1) {
    3592            0 :         comma = ",";
    3593              :     }
    3594            0 :     json->stream->writef(json->stream, "\t\t\t\t]\n");
    3595            0 :     json->stream->writef(json->stream, "\t\t\t}%s\n", comma);
    3596            0 : }
    3597            0 : void __clove_report_list_tests_json_begin_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3598              :     __CLOVE_UNUSED_VAR(_this);
    3599              :     __CLOVE_UNUSED_VAR(test);
    3600              :     __CLOVE_UNUSED_VAR(index);
    3601              :     //nothing todo
    3602            0 : }
    3603            0 : void __clove_report_list_tests_json_end_test(__clove_report_list_tests_t* _this,  __clove_test_t* test, size_t index) {
    3604            0 :     __clove_report_list_tests_json_t* json = (__clove_report_list_tests_json_t*)_this;
    3605            0 :     if (json->is_suite_first_test) {
    3606            0 :         const char* file_path = __clove_path_relative(test->file_name, json->params->tests_base_path);
    3607            0 :         char* escaped_file = __clove_string_strdup(file_path);
    3608            0 :         __clove_string_replace_char(escaped_file, '\\', '/');
    3609              : 
    3610            0 :         json->stream->writef(json->stream, "\t\t\t{\n");
    3611            0 :         json->stream->writef(json->stream, "\t\t\t\t\"name\" : \"%s\",\n", json->current_suite->name);
    3612            0 :         json->stream->writef(json->stream, "\t\t\t\t\"file\" : \"%s\",\n", escaped_file);
    3613            0 :         json->stream->writef(json->stream, "\t\t\t\t\"tests\" : [\n");
    3614              : 
    3615            0 :         __clove_memory_free(escaped_file);
    3616            0 :         json->is_suite_first_test = false;  
    3617              :     }
    3618            0 :     json->stream->writef(json->stream, "\t\t\t\t\t{\n");
    3619            0 :     json->stream->writef(json->stream, "\t\t\t\t\t\t\"name\" : \"%s\",\n", test->name);
    3620            0 :     json->stream->writef(json->stream, "\t\t\t\t\t\t\"line\" : %zu\n", test->funct_line);
    3621            0 :     const char* comma = "";
    3622            0 :     if (index < json->current_suite->test_count-1) {
    3623            0 :         comma = ",";
    3624              :     }
    3625            0 :     json->stream->writef(json->stream, "\t\t\t\t\t}%s\n", comma);
    3626            0 : }
    3627            0 : void __clove_report_list_tests_json_end(__clove_report_list_tests_t* _this) {
    3628            0 :     __clove_report_list_tests_json_t* json = (__clove_report_list_tests_json_t*)_this;
    3629              : 
    3630            0 :     json->stream->writef(json->stream, "\t\t]\n"); //end suites
    3631            0 :     json->stream->writef(json->stream, "\t}\n"); //end result
    3632            0 :     json->stream->writef(json->stream, "}\n");
    3633            0 :     json->stream->close(json->stream);
    3634            0 : }
    3635              : 
    3636              : //TODO: Add unit tests
    3637            0 : int __clove_cmd_list_test_execute(__clove_suite_t* suites, size_t suite_count, size_t test_count, __clove_report_list_tests_t* report) {
    3638            0 :     report->begin(report, suite_count, test_count);
    3639            0 :     for (size_t i = 0; i < suite_count; ++i) {
    3640            0 :         __clove_suite_t* each_suite = &suites[i];
    3641            0 :         report->begin_suite(report, each_suite, i);
    3642            0 :         for (size_t j = 0; j < each_suite->test_count; j++) {
    3643            0 :             __clove_test_t* each_test = (__clove_test_t*)__clove_vector_get(&each_suite->tests, j);
    3644            0 :             report->begin_test(report, each_test, j);
    3645            0 :             each_test->dry_run = true;
    3646            0 :             each_test->funct(each_test);
    3647            0 :             report->end_test(report, each_test, j);
    3648              :         }
    3649            0 :         report->end_suite(report, each_suite, i);
    3650              :     }
    3651            0 :     report->end(report);
    3652            0 :     return 0;
    3653              : }
    3654              : #pragma endregion
    3655              : 
    3656              : 
    3657              : #pragma region PRIVATE - Autodiscovery Impl
    3658           45 : bool __clove_symbols_function_validate(__clove_string_view_t* suite, __clove_string_view_t* type, __clove_string_view_t* name, __clove_symbols_context_t* context) {
    3659           45 :     if (__clove_vector_is_empty(context->includes) && __clove_vector_is_empty(context->excludes)) return true;
    3660            0 :     if (!__clove_string_view_strequals(type, "20")) return true;
    3661              : 
    3662              :     //Includes win over Excludes
    3663            0 :     if (!__clove_vector_is_empty(context->includes)) {
    3664            0 :         for(size_t i=0; i < __clove_vector_count(context->includes); ++i) {
    3665            0 :             __clove_test_expr_t* expr = (__clove_test_expr_t*)__clove_vector_get(context->includes, i);
    3666            0 :             if (__clove_test_expr_validate(expr, suite, name)) return true;
    3667              :         }
    3668            0 :         return false;
    3669              :     }
    3670              : 
    3671            0 :     if (!__clove_vector_is_empty(context->excludes)) {
    3672            0 :         for(size_t i=0; i < __clove_vector_count(context->excludes); ++i) {
    3673            0 :             __clove_test_expr_t* expr = (__clove_test_expr_t*)__clove_vector_get(context->excludes, i);
    3674            0 :             if (__clove_test_expr_validate(expr, suite, name)) return false;
    3675              :         }
    3676            0 :         return true;
    3677              :     }
    3678            0 :     return true;
    3679              : }
    3680              : 
    3681           45 : void __clove_symbols_function_collect(__clove_symbols_function_t exported_funct, __clove_symbols_context_t* context) {
    3682              :     /* Examples
    3683              :         __clove_sym___MySuite___11_setuponce
    3684              :         __clove_sym___MySuite___12_teardownonce
    3685              :         __clove_sym___MySuite___13_setup
    3686              :         __clove_sym___MySuite___14_teardown
    3687              :         __clove_sym___MySuite___20_MyTest01
    3688              :         __clove_sym___MySuite___20_MyTest02
    3689              :     */
    3690              :     static const char* end_suite_separator = "___";
    3691              :     static int end_suite_separator_length = 3;
    3692              :     //static const char* test_separator = "20_";
    3693              :     //static int test_separator_length = 3;
    3694              : 
    3695              :     static __clove_suite_t last_suite_temp; //just used as temporary data storage
    3696              :     static __clove_suite_t* last_suite_ptr = NULL;
    3697              :     static __clove_string_view_t suite_name_view = { NULL, 0 };
    3698              : 
    3699           45 :     const char* test_full_name = exported_funct.name;
    3700           45 :     const char* begin_suite_name = test_full_name + context->prefix_length;
    3701           45 :     const char* end_suite_name = __clove_string_strstr(begin_suite_name, end_suite_separator) - 1;
    3702              : 
    3703           45 :     __clove_string_view_t suite_vw = __clove_string_view_from_be(begin_suite_name, end_suite_name);
    3704           45 :     __clove_string_view_t type_vw = __clove_string_view_from_len(end_suite_name + 1 + end_suite_separator_length, 2);
    3705           45 :     __clove_string_view_t name_vw = __clove_string_view_from_str(__clove_string_view_end(&type_vw) + 2);
    3706              :     
    3707           45 :     bool pass = __clove_symbols_function_validate(&suite_vw, &type_vw, &name_vw, context);
    3708           45 :     if (!pass) return;
    3709              : 
    3710              :     //if suite changes, then start collecting temporary suite data, waiting for a first test to be found
    3711           45 :     if (suite_name_view.begin == NULL || !__clove_string_view_equals(&suite_vw, &suite_name_view)) {
    3712            1 :         suite_name_view = suite_vw;
    3713            1 :         last_suite_temp.fixtures.setup_once = NULL;
    3714            1 :         last_suite_temp.fixtures.teardown_once = NULL;
    3715            1 :         last_suite_temp.fixtures.setup = NULL;
    3716            1 :         last_suite_temp.fixtures.teardown = NULL;
    3717            1 :         last_suite_temp.test_count = 0;
    3718              :     }
    3719              : 
    3720           45 :     if (__clove_string_view_strequals(&type_vw, "11")) {
    3721            1 :         last_suite_temp.fixtures.setup_once = exported_funct.fun_ptr;
    3722              :     }
    3723           44 :     else if (__clove_string_view_strequals(&type_vw, "12")) {
    3724            1 :         last_suite_temp.fixtures.teardown_once = exported_funct.fun_ptr;
    3725              :     }
    3726           43 :     else if (__clove_string_view_strequals(&type_vw, "13")) {
    3727            1 :         last_suite_temp.fixtures.setup = exported_funct.fun_ptr;
    3728              :     }
    3729           42 :     else if (__clove_string_view_strequals(&type_vw, "14")) {
    3730            1 :         last_suite_temp.fixtures.teardown = exported_funct.fun_ptr;
    3731              :     }
    3732           41 :     else if (__clove_string_view_strequals(&type_vw, "20")) {
    3733           41 :         if (last_suite_temp.test_count == 0) {
    3734            1 :             last_suite_temp.test_count = 1; //just to record that at least one test case has been found
    3735              : 
    3736            1 :             last_suite_ptr = (__clove_suite_t*)__clove_vector_add_slot(&context->suites);
    3737            1 :             last_suite_ptr->name = __clove_string_view_as_string(&suite_name_view);
    3738            1 :             if (last_suite_temp.fixtures.setup_once)     last_suite_ptr->fixtures.setup_once    = last_suite_temp.fixtures.setup_once;
    3739            1 :             if (last_suite_temp.fixtures.teardown_once)  last_suite_ptr->fixtures.teardown_once = last_suite_temp.fixtures.teardown_once;
    3740            1 :             if (last_suite_temp.fixtures.setup)          last_suite_ptr->fixtures.setup         = last_suite_temp.fixtures.setup;
    3741            1 :             if (last_suite_temp.fixtures.teardown)       last_suite_ptr->fixtures.teardown      = last_suite_temp.fixtures.teardown;
    3742            1 :             context->suites_count++;
    3743              :         }
    3744              : 
    3745           41 :         __clove_test_t* test = (__clove_test_t*)__clove_vector_add_slot(&last_suite_ptr->tests);
    3746              :         //Switched to string allocation to make test structs independent of the source memory
    3747              :         //test->name = test_name + test_separator_length;
    3748           41 :         test->name = __clove_string_view_as_string(&name_vw);
    3749           41 :         test->funct = (void (*)(__clove_test_t*))exported_funct.fun_ptr;
    3750           41 :         last_suite_ptr->test_count++;
    3751           41 :         context->tests_count++;
    3752              :     }
    3753              : }
    3754              : 
    3755              : #ifdef _WIN32
    3756              : #include <windows.h>
    3757              : PIMAGE_EXPORT_DIRECTORY __clove_symbols_win_get_export_table_from(HMODULE module) {
    3758              :     // Start at the base of the module. The MS-DOS stub begins there.
    3759              :     PBYTE base = (PBYTE)module;
    3760              :     PIMAGE_DOS_HEADER mds = (PIMAGE_DOS_HEADER)module;
    3761              : 
    3762              :     PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)(base + mds->e_lfanew);
    3763              :     if (IMAGE_NT_SIGNATURE != nt_header->Signature) {
    3764              :         // Bad signature -- invalid image or module handle
    3765              :         return NULL;
    3766              :     }
    3767              : 
    3768              :     // Get the COFF file header.
    3769              :     //PIMAGE_FILE_HEADER cfh = &nt_header->FileHeader;
    3770              : 
    3771              :     // Get the "optional" header (it's not actually optional for executables).
    3772              :     PIMAGE_OPTIONAL_HEADER oh = &nt_header->OptionalHeader;
    3773              : 
    3774              :     // Finally, get the export directory table.
    3775              :     if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh->NumberOfRvaAndSizes) {
    3776              :         // This image doesn't have an export directory table.
    3777              :         return NULL;
    3778              :     }
    3779              :     DWORD rva = oh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    3780              :     PIMAGE_EXPORT_DIRECTORY edt = (PIMAGE_EXPORT_DIRECTORY)(base + rva);
    3781              :     return edt;
    3782              : }
    3783              : 
    3784              : int __clove_symbols_for_each_function_by_prefix(__clove_symbols_context_t* context, __clove_symbols_function_action action) {
    3785              :     HMODULE module = GetModuleHandle(0);
    3786              :     PIMAGE_EXPORT_DIRECTORY export_dir = __clove_symbols_win_get_export_table_from(module);
    3787              :     if (!export_dir) {
    3788              :         return 1;
    3789              :     }
    3790              : 
    3791              :     //Note: Don't know why if there is no exported function results NumberOfNames = 64. NumberOfFunctions = 0 instead.
    3792              :     //      So checking both counters to be sure if there is any exported function
    3793              :     if (export_dir->NumberOfNames == 0 || export_dir->NumberOfFunctions == 0) {
    3794              :         return 1;
    3795              :     }
    3796              : 
    3797              :     PBYTE base_addr = (PBYTE)module;
    3798              :     //DWORD names_count = export_dir->NumberOfNames;
    3799              :     PDWORD names_ptr = (PDWORD)(base_addr + export_dir->AddressOfNames);
    3800              :     DWORD ordinal_base_number = export_dir->Base;
    3801              :     PWORD ordinals_ptr = (PWORD)(base_addr + export_dir->AddressOfNameOrdinals); //ordinal offset from base ordinal
    3802              :     PDWORD functs_address_ptr = (PDWORD)(base_addr + export_dir->AddressOfFunctions);
    3803              : 
    3804              :     const char* prefix = context->prefix;
    3805              :     size_t prefix_length = context->prefix_length;
    3806              : 
    3807              :     //Takes advantage of symbols are lexically sorted. 
    3808              :     //And also that prefix starting with "__" will come first. So no need to start a binary search
    3809              :     unsigned char match_ongoing = 0;
    3810              :     for (size_t i = 0; i < export_dir->NumberOfNames; ++i)
    3811              :     {
    3812              :         char* each_name = (char*)(base_addr + names_ptr[i]);
    3813              :         unsigned long each_ordinal = ordinal_base_number + ordinals_ptr[i];
    3814              :         unsigned long* each_funct_addr = (PDWORD)(base_addr + functs_address_ptr[each_ordinal - ordinal_base_number]);
    3815              :         //printf("%lu) %s [0x%p]\n", each_ordinal, each_name, each_funct_addr);
    3816              : 
    3817              :         if (strncmp(prefix, each_name, prefix_length) == 0) {
    3818              :             if (!match_ongoing) match_ongoing = 1;
    3819              :             __clove_symbols_function_t funct;
    3820              :             funct.name = each_name;
    3821              :             funct.obj_ptr = each_funct_addr;
    3822              :             action(funct, context);
    3823              :         }
    3824              :         else {
    3825              :             //At the first failure, if match was ongoing then there are no more symbol with that prefix
    3826              :             if (match_ongoing) break;
    3827              :         }
    3828              :     }
    3829              :     return 0;
    3830              : }
    3831              : #elif __APPLE__
    3832              : #include <unistd.h>
    3833              : #include <fcntl.h>
    3834              : #include <sys/stat.h>
    3835              : #include <sys/mman.h>
    3836              : #include <string.h>
    3837              : #include <mach-o/getsect.h>
    3838              : #include <mach-o/loader.h>
    3839              : #include <mach-o/swap.h>
    3840              : #include <mach-o/dyld.h>
    3841              : typedef struct __clove_symbols_macos_module_t {
    3842              :     void* handle;
    3843              :     size_t size; //mmap handle size;
    3844              :     intptr_t address; //module base address 
    3845              : } __clove_symbols_macos_module_t;
    3846              : 
    3847              : 
    3848              : bool __clove_symbols_macos_image_slide(const char* abs_path, intptr_t* out_address)
    3849              : {   
    3850              :     //NOTE: dyld image names are in absolute path. So tu properly compare, need to pass an abs_path to this function.
    3851              :     for (uint32_t i = 0; i < _dyld_image_count(); i++)
    3852              :     {
    3853              :         if (strcmp(_dyld_get_image_name(i), abs_path) == 0) {
    3854              :             *out_address = _dyld_get_image_vmaddr_slide(i);
    3855              :             return true;
    3856              :         }
    3857              :     }
    3858              :     return false;
    3859              : }
    3860              : 
    3861              : int __clove_symbols_macos_open_module_handle(const char* module_abs_path, __clove_symbols_macos_module_t* out_module) {
    3862              :     int fd;
    3863              :     if ((fd = open(module_abs_path, O_RDONLY)) < 0) {
    3864              :         return 1;
    3865              :     }
    3866              : 
    3867              :     lseek(fd, 0, SEEK_SET);
    3868              :     struct stat st;
    3869              :     if (fstat(fd, &st) < 0) {
    3870              :         return 2;
    3871              :     }
    3872              : 
    3873              :     void* map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    3874              :     if (map == MAP_FAILED) {
    3875              :         return 3;
    3876              :     }
    3877              :     //mprotect(map, st.st_size, PROT_WRITE);
    3878              :     close(fd);
    3879              : 
    3880              :     out_module->handle = map;
    3881              :     out_module->size = st.st_size;
    3882              :     bool found = __clove_symbols_macos_image_slide(module_abs_path, &out_module->address);
    3883              :     if (!found) {
    3884              :         //TODO: add logging api like __clove_log_erro(frmt, args)
    3885              :         printf("[ERRO] cannot find image slide for: %s", module_abs_path);
    3886              :         return 4;
    3887              :     }
    3888              :     return 0;
    3889              : }
    3890              : 
    3891              : void __clove_symbols_macos_close_module_handle(__clove_symbols_macos_module_t* module) {
    3892              :     munmap(module->handle, module->size);
    3893              :     module->handle = NULL;
    3894              :     module->size = 0;
    3895              : }
    3896              : struct load_command* __clove_symbols_macos_find_command(struct mach_header_64* header, uint32_t cmd) {
    3897              :     struct load_command* lc = (struct load_command*)((uint64_t)header + sizeof(struct mach_header_64));
    3898              :     for (uint32_t i = 0; i < header->ncmds; i++) {
    3899              :         if (lc->cmd == cmd) {
    3900              :             return lc;
    3901              :         }
    3902              :         lc = (struct load_command*)((uint64_t)lc + lc->cmdsize);
    3903              :     }
    3904              :     return NULL;
    3905              : }
    3906              : 
    3907              : int __clove_symbols_for_each_function_by_prefix(__clove_symbols_context_t* context, __clove_symbols_function_action action) {
    3908              :     const char* module_path = __clove_utils_get_exec_abs_path();
    3909              : 
    3910              :     __clove_symbols_macos_module_t module;
    3911              :     if (__clove_symbols_macos_open_module_handle(module_path, &module) != 0) { return 1; };
    3912              : 
    3913              :     //Handling Mach-o file format x86_64 (little endian). This should works both for Intel and M1 cpus with 64 bits architecture
    3914              :     uint32_t magic_number = *(uint32_t*)module.handle;
    3915              :     if (magic_number != MH_MAGIC_64) {
    3916              :         puts("Current executable format is not supported (it's not Mach-o 64bit little-endian!");
    3917              :         return 2;
    3918              :     }
    3919              : 
    3920              :     struct mach_header_64* header = (struct mach_header_64*)module.handle;
    3921              :     struct load_command* symbol_lc = __clove_symbols_macos_find_command(header, LC_SYMTAB);
    3922              :     struct symtab_command* symbol_cmd = (struct symtab_command*)symbol_lc;
    3923              : 
    3924              :     struct nlist_64* symbol_table_64 = (struct nlist_64*)((uint64_t)header + symbol_cmd->symoff);
    3925              :     char* str_table = (char*)header + symbol_cmd->stroff;
    3926              :     //symbol_cmd->nsyms #number of symbols in the symbol table 
    3927              : 
    3928              :     //Loading Dynamic Symbol table to scan only for external symbols symbols in the Symbol Table 
    3929              :     struct load_command* dynsymbol_lc = __clove_symbols_macos_find_command(header, LC_DYSYMTAB);
    3930              :     struct dysymtab_command* dysymbol_cmd = (struct dysymtab_command*)dynsymbol_lc;
    3931              :     uint32_t external_symbol_start_index = dysymbol_cmd->iextdefsym;
    3932              :     uint32_t external_symbol_end_index = external_symbol_start_index + dysymbol_cmd->nextdefsym - 1U;
    3933              : 
    3934              :     const char* prefix = context->prefix;
    3935              :     const size_t prefix_length = context->prefix_length;
    3936              :     uint8_t match_ongoing = 0;
    3937              :     for (uint32_t i = external_symbol_start_index; i <= external_symbol_end_index; i++) {
    3938              :         struct nlist_64* sym = &symbol_table_64[i];
    3939              :         uint32_t table_index = sym->n_un.n_strx;
    3940              :         char* each_name = &str_table[table_index + 1]; //macho add one '_' before each symbol, so with +1 we want to skip it.
    3941              :         void* each_funct_addr = (void*)(sym->n_value + module.address); //n_value = offset address within TEXT segment (includes base addr of the TEXT segment)
    3942              : 
    3943              :         //Symbols seems to be "locally" sorted, so all clove external functions seems to be next to each other and sorted
    3944              :         if (strncmp(prefix, each_name, prefix_length) == 0) {
    3945              :             if (!match_ongoing) {
    3946              :                 match_ongoing = 1;
    3947              :             }
    3948              :             //__clove_symbols_function_t funct = { each_name, each_funct_addr };
    3949              :             __clove_symbols_function_t funct;
    3950              :             funct.name = each_name;
    3951              :             funct.obj_ptr = each_funct_addr;
    3952              :             action(funct, context);
    3953              :         }
    3954              :         else {
    3955              :             //At the first failure, if match was ongoing then there are no more symbol with that prefix
    3956              :             if (match_ongoing) {
    3957              :                 break;
    3958              :             }
    3959              :         }
    3960              : 
    3961              :     }
    3962              :     __clove_symbols_macos_close_module_handle(&module);
    3963              :     return 0;
    3964              : }
    3965              : #elif __linux__
    3966              : #include <unistd.h>
    3967              : #include <fcntl.h>
    3968              : #include <sys/stat.h>
    3969              : #include <sys/mman.h>
    3970              : #include <string.h>
    3971              : #include <elf.h>
    3972              : #include <link.h>
    3973              : 
    3974              : typedef struct __clove_symbols_lixux_module_t {
    3975              :     void* handle;
    3976              :     size_t size; //mmap handle size;
    3977              :     uintptr_t address; //module base address 
    3978              : } __clove_symbols_lixux_module_t;
    3979              : 
    3980            1 : int __clove_symbols_lixux_dl_callback(struct dl_phdr_info* info, size_t size, void* data)
    3981              : {
    3982              :     __CLOVE_UNUSED_VAR(size);
    3983              : 
    3984              :     #ifdef __GNUC__
    3985              :     #pragma GCC diagnostic push   
    3986              :     #pragma GCC diagnostic ignored "-Wpedantic"    //Disable pedantic
    3987              :     #endif
    3988              :     //Preventing GCC pedantic from emitting warning: "ISO C forbids conversion of function pointer to object pointer type"
    3989            1 :     const char* cb = (const char*)&__clove_symbols_lixux_dl_callback;
    3990              :     #ifdef __GNUC__
    3991              :     #pragma GCC diagnostic pop 
    3992              :     #endif 
    3993              : 
    3994            1 :     const char* base = (const char*)info->dlpi_addr;
    3995            1 :     const ElfW(Phdr)* first_load = NULL;
    3996              : 
    3997            4 :     for (int j = 0; j < info->dlpi_phnum; j++) {
    3998            4 :         const ElfW(Phdr)* phdr = &info->dlpi_phdr[j];
    3999              : 
    4000            4 :         if (phdr->p_type == PT_LOAD) {
    4001            2 :             const char* beg = base + phdr->p_vaddr;
    4002            2 :             const char* end = beg + phdr->p_memsz;
    4003              : 
    4004            2 :             if (first_load == NULL) first_load = phdr;
    4005            2 :             if (beg <= cb && cb < end) {
    4006              :                 // Found PT_LOAD that "covers" callback().
    4007              :                 //printf("ELF header is at %p, image linked at 0x%zx, relocation: 0x%zx\n", base + first_load->p_vaddr, first_load->p_vaddr, info->dlpi_addr);
    4008            1 :                 uintptr_t* addr_ptr = (uintptr_t*)data;
    4009            1 :                 *addr_ptr = info->dlpi_addr;
    4010            1 :                 return 1;
    4011              :             }
    4012              :         }
    4013              :     }
    4014            0 :     return 0;
    4015              : }
    4016              : 
    4017              : 
    4018              : //uintptr_t __clove_symbols_lixux_base_addr(const char* path)
    4019            1 : uintptr_t __clove_symbols_lixux_base_addr(void)
    4020              : {
    4021              :     uintptr_t base_addr;
    4022            1 :     dl_iterate_phdr(__clove_symbols_lixux_dl_callback, &base_addr);
    4023            1 :     return base_addr;
    4024              : }
    4025              : 
    4026            1 : int __clove_symbols_lixux_open_module_handle(const char* module_path, __clove_symbols_lixux_module_t* out_module) {
    4027              :     int fd;
    4028            1 :     if ((fd = open(module_path, O_RDONLY)) < 0) {
    4029            0 :         return 1;
    4030              :     }
    4031              : 
    4032            1 :     lseek(fd, 0, SEEK_SET);
    4033              :     struct stat st;
    4034            1 :     if (fstat(fd, &st) < 0) {
    4035            0 :         return 2;
    4036              :     }
    4037              : 
    4038            1 :     void* map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    4039            1 :     if (map == MAP_FAILED) {
    4040            0 :         return 3;
    4041              :     }
    4042              :     //mprotect(map, st.st_size, PROT_WRITE);
    4043            1 :     close(fd);
    4044              : 
    4045            1 :     out_module->handle = map;
    4046            1 :     out_module->size = st.st_size;
    4047              :     //out_module->address = __clove_symbols_lixux_base_addr(module_path);
    4048            1 :     out_module->address = __clove_symbols_lixux_base_addr();
    4049            1 :     return 0;
    4050              : }
    4051              : 
    4052            1 : void __clove_symbols_lixux_close_module_handle(__clove_symbols_lixux_module_t* module) {
    4053            1 :     munmap(module->handle, module->size);
    4054            1 :     module->handle = NULL;
    4055            1 :     module->size = 0;
    4056            1 : }
    4057              : 
    4058              : /*
    4059              :  * Compare two functions by their name
    4060              :  * Return negative if name1 is lesser than name2
    4061              :  * Return positive if name1 is greater than name1
    4062              :  * Return zero if name1 and name2 are equals
    4063              :  */
    4064          297 : int __clove_symbols_funct_name_comparator(void* f1, void* f2) {
    4065          297 :     __clove_symbols_function_t* funct1 = (__clove_symbols_function_t*)f1;
    4066          297 :     __clove_symbols_function_t* funct2 = (__clove_symbols_function_t*)f2;
    4067          297 :     return strcmp(funct1->name, funct2->name);
    4068              : }
    4069              : 
    4070            1 : int __clove_symbols_for_each_function_by_prefix(__clove_symbols_context_t* context, __clove_symbols_function_action action) {
    4071            1 :     const char* module_path = __clove_utils_get_exec_abs_path();
    4072              : 
    4073              :     __clove_symbols_lixux_module_t module;
    4074            1 :     if (__clove_symbols_lixux_open_module_handle(module_path, &module) != 0) { return 1; }
    4075              : 
    4076              :     //Check Elf header to be 64 bit little endian
    4077            1 :     unsigned char* magic = (unsigned char*)module.handle;
    4078            1 :     bool is_elf = (magic[0] == 0x7f && magic[1] == 0x45 && magic[2] == 0x4c && magic[3] == 0x46);
    4079            1 :     bool is_64 = (magic[4] == 0x02); //0x01 is 32 bit
    4080            1 :     bool is_little = (magic[5] == 0x01); //0x02 is big endian
    4081              : 
    4082            1 :     if (!(is_elf && is_64 && is_little)) {
    4083            0 :         puts("Current executable format is not supported (it's not ELF 64bit little-endian!)");
    4084            0 :         return 2;
    4085              :     }
    4086              : 
    4087            1 :     Elf64_Ehdr* header = (Elf64_Ehdr*)module.handle;
    4088              : 
    4089            1 :     Elf64_Shdr* sections = (Elf64_Shdr*)((uint64_t)header + header->e_shoff);
    4090            1 :     size_t section_count = header->e_shnum;
    4091              : 
    4092            1 :     Elf64_Sym* symbol_table = NULL;
    4093            1 :     Elf64_Shdr* symbol_table_section = NULL;
    4094           29 :     for (size_t i = 0; i < section_count; ++i) {
    4095           29 :         if (sections[i].sh_type == SHT_SYMTAB) {
    4096            1 :             symbol_table = (Elf64_Sym*)((uint64_t)header + sections[i].sh_offset);
    4097            1 :             symbol_table_section = &sections[i];
    4098            1 :             break;
    4099              :         }
    4100              :     }
    4101              : 
    4102            1 :     Elf64_Shdr* name_table_section = &sections[symbol_table_section->sh_link];
    4103            1 :     char* symbol_name_table = (char*)((uint64_t)header + name_table_section->sh_offset);
    4104              : 
    4105            1 :     size_t symbol_count = symbol_table_section->sh_size / symbol_table_section->sh_entsize;
    4106              : 
    4107              :     //Vector could be replaced with a sorted tree to sort while scanning for clove functions
    4108              :     __clove_vector_t clove_functions;
    4109            1 :     __clove_vector_params_t params = __clove_vector_params_defaulted(sizeof(__clove_symbols_function_t));
    4110            1 :     __clove_vector_init(&clove_functions, &params);
    4111              : 
    4112            1 :     const char* prefix = context->prefix;
    4113            1 :     size_t prefix_length = context->prefix_length;
    4114              : 
    4115         1177 :     for (size_t i = 0; i < symbol_count; ++i) {
    4116         1176 :         Elf64_Sym* sym = &symbol_table[i];
    4117         1176 :         if (ELF64_ST_TYPE(sym->st_info) == STT_FUNC) {
    4118          429 :             size_t name_index = sym->st_name;
    4119          429 :             char* sym_name = symbol_name_table + name_index;
    4120          429 :             if (!strncmp(sym_name, prefix, prefix_length)) {
    4121           45 :                 __clove_symbols_function_t* each_funct = (__clove_symbols_function_t*)__clove_vector_add_slot(&clove_functions);
    4122           45 :                 each_funct->name = sym_name;
    4123           45 :                 each_funct->obj_ptr = (void*)(module.address + sym->st_value);
    4124              :             }
    4125              :         }
    4126              :     }
    4127              : 
    4128              :     //Sort Symbols Alphanumeric ascendant
    4129            1 :     __clove_vector_sort(&clove_functions, __clove_symbols_funct_name_comparator);
    4130              : 
    4131           46 :     for (size_t i = 0; i < __clove_vector_count(&clove_functions); ++i)
    4132              :     {
    4133           45 :         __clove_symbols_function_t* each_funct = (__clove_symbols_function_t*)__clove_vector_get(&clove_functions, i);
    4134           45 :         action(*each_funct, context);
    4135              :     }
    4136            1 :     __clove_vector_free(&clove_functions);
    4137            1 :     __clove_symbols_lixux_close_module_handle(&module);
    4138            1 :     return 0;
    4139              : }
    4140              : #else 
    4141              : //Not Possible. Shoud be one of the OS cases before
    4142              : int __clove_symbols_for_each_function_by_prefix(__clove_symbols_context_t* context, __clove_symbols_function_action action) {
    4143              :     puts("Autodiscovery not yet implemented for this OS!!!");
    4144              :     return 1;
    4145              : }
    4146              : #endif //_WIN32 symbol table
    4147              : #pragma endregion // Autodiscovery Impl
    4148              : 
    4149              : #pragma region PRIVATE - Run Impl
    4150              : #define __CLOVE_RUNNER_AUTO() \
    4151              : char* __clove_exec_abs_path;\
    4152              : char* __clove_exec_abs_basepath;\
    4153              : __CLOVE_ASSERT_CHECK_E_DECL() \
    4154              : __CLOVE_TEST_RESULT_E_DECL() \
    4155              : __CLOVE_GENERIC_TYPE_E_DECL() \
    4156              : int main(int argc, char* argv[]) {\
    4157              :     return __clove_runner_auto(argc, argv);\
    4158              : }
    4159              : 
    4160            1 : int __clove_runner_auto(int argc, char* argv[]) {
    4161            1 :     __clove_exec_abs_path = __clove_path_to_absolute(argv[0]);
    4162            1 :     __clove_exec_abs_basepath = __clove_path_basepath(__clove_exec_abs_path);
    4163              : 
    4164              :     //argc = 5;
    4165              :     //const char* argv2[] = {"exec", "-i", "*.ActShortThanExpForthCharDiff", "-r", "pretty"};
    4166              :     //const char* argv2[] = {"exec", "-l", "-r", "csv"};
    4167              : 
    4168              :     __clove_vector_t cmd_handlers;
    4169            1 :     __CLOVE_VECTOR_INIT(&cmd_handlers, __clove_cmdline_handler_f);
    4170            1 :     __CLOVE_VECTOR_ADD(&cmd_handlers, __clove_cmdline_handler_f, __clove_cmdline_handle_help);
    4171            1 :     __CLOVE_VECTOR_ADD(&cmd_handlers, __clove_cmdline_handler_f, __clove_cmdline_handle_version);
    4172            1 :     __CLOVE_VECTOR_ADD(&cmd_handlers, __clove_cmdline_handler_f, __clove_cmdline_handle_run_tests);
    4173            1 :     __CLOVE_VECTOR_ADD(&cmd_handlers, __clove_cmdline_handler_f, __clove_cmdline_handle_list_tests);
    4174            1 :     __CLOVE_VECTOR_ADD(&cmd_handlers, __clove_cmdline_handler_f, __clove_cmdline_handle_default);
    4175              : 
    4176            1 :     __clove_cmdline_errno_t cmd_result = __CLOVE_CMD_ERRNO_INVALID_PARAM;
    4177              :     __clove_cmdline_t cmdline;
    4178            1 :     __clove_cmdline_init(&cmdline, (const char**)argv, argc);
    4179              : 
    4180            5 :     __CLOVE_VECTOR_FOREACH(&cmd_handlers, __clove_cmdline_handler_f, handler, {
    4181              :         __clove_cmdline_errno_t result = (*handler)(&cmdline);
    4182              :         if (result != __CLOVE_CMD_ERRNO_UNMANAGED) {
    4183              :             cmd_result =  result;
    4184              :             break;
    4185              :         }
    4186              :     });
    4187              : 
    4188            1 :     __clove_vector_free(&cmd_handlers);
    4189            1 :     __clove_cmdline_free(&cmdline);
    4190            1 :     __clove_memory_free(__clove_exec_abs_path);
    4191            1 :     __clove_memory_free(__clove_exec_abs_basepath);
    4192            1 :     return cmd_result;
    4193              : }
    4194              : 
    4195            1 : int __clove_run_tests_with_report(__clove_report_t* report, __clove_vector_t* includes,  __clove_vector_t* excludes) {
    4196              :     //0 => OK
    4197              :     //1 => ERROR
    4198              :     //2 => TESTS WITH FAILURES
    4199              :     
    4200            1 :     int run_result = 0;
    4201              : 
    4202              :     __clove_symbols_context_t context;
    4203            1 :     context.includes = includes;
    4204            1 :     context.excludes = excludes;
    4205              : 
    4206            1 :     __clove_vector_params_t vector_params = __clove_vector_params_defaulted(sizeof(__clove_suite_t));
    4207            1 :     vector_params.item_ctor = __clove_vector_suite_ctor;
    4208            1 :     vector_params.item_dtor = __clove_vector_suite_dtor;
    4209            1 :     __clove_vector_init(&context.suites, &vector_params);
    4210            1 :     context.prefix = "__clove_sym___";
    4211            1 :     context.prefix_length = __clove_string_length("__clove_sym___");
    4212            1 :     context.suites_count = 0;
    4213            1 :     context.tests_count = 0;
    4214              : 
    4215            1 :     int result = __clove_symbols_for_each_function_by_prefix(&context, __clove_symbols_function_collect);
    4216            1 :     if (result == 0) {
    4217              :         //0 in case of test success/warning
    4218              :         //1 in case of test failure
    4219            1 :         run_result = __clove_exec_suites(&context.suites, context.tests_count, report);
    4220            1 :         if (run_result != 0) run_result = 2;
    4221              :     }
    4222              :     else {
    4223            0 :         run_result = 1;
    4224              :     }
    4225            1 :     __clove_vector_free(&context.suites);
    4226            1 :     return run_result;
    4227              : }
    4228              : 
    4229            1 : int __clove_exec_suites(__clove_vector_t* suites, size_t test_count, __clove_report_t* report) {
    4230            1 :     report->start(report, suites, test_count);
    4231            1 :     size_t passed = 0;
    4232            1 :     size_t failed = 0;
    4233            1 :     size_t skipped = 0;
    4234              :     
    4235            1 :     size_t test_start_counter = 1;
    4236            2 :     __CLOVE_VECTOR_FOR(suites, __clove_suite_t, each_suite, i, {
    4237              :         report->begin_suite(report, each_suite, i);
    4238              :         __clove_exec_suite(each_suite, test_start_counter, &passed, &failed, &skipped, report);
    4239              :         report->end_suite(report, each_suite, i);
    4240              :         test_start_counter += each_suite->test_count;
    4241              :     });
    4242            1 :     report->end(report, passed, skipped, failed);
    4243            1 :     return failed == 0 ? 0 : 1;
    4244              : }
    4245              : 
    4246            1 : void __clove_exec_suite(__clove_suite_t* suite, size_t test_counter, size_t* passed, size_t* failed, size_t* skipped, __clove_report_t* report) {
    4247            1 :     __clove_time_t suite_start = __clove_time_now();
    4248            1 :     suite->fixtures.setup_once();
    4249              : 
    4250           42 :     for (size_t i = 0; i < suite->test_count; i++) {
    4251           41 :         __clove_test_t* each_test = (__clove_test_t*)__clove_vector_get(&suite->tests, i);
    4252           41 :         each_test->result = __CLOVE_TEST_RESULT_SKIPPED;
    4253              : 
    4254           41 :         __clove_time_t test_start = __clove_time_now();
    4255           41 :         suite->fixtures.setup();
    4256           41 :         each_test->funct(each_test);
    4257           41 :         suite->fixtures.teardown();
    4258           41 :         __clove_time_t test_end = __clove_time_now();
    4259           41 :         each_test->duration = __clove_time_sub(&test_end, &test_start);
    4260              : 
    4261           41 :         __CLOVE_SWITCH_BEG(each_test->result) 
    4262           41 :             __CLOVE_SWITCH_CASE(__CLOVE_TEST_RESULT_PASSED)  { (*passed)++;  suite->issue.passed_count++; }
    4263           31 :             __CLOVE_SWITCH_CASE(__CLOVE_TEST_RESULT_FAILED)  { (*failed)++;  suite->issue.failed_count++; }
    4264            7 :             __CLOVE_SWITCH_CASE(__CLOVE_TEST_RESULT_SKIPPED) { (*skipped)++; suite->issue.skipped_count++;}
    4265              :         __CLOVE_SWITCH_END()
    4266              : 
    4267           41 :         report->end_test(report, suite, each_test, test_counter + i);
    4268              :     }
    4269            1 :     suite->fixtures.teardown_once();
    4270            1 :     __clove_time_t suite_end = __clove_time_now();
    4271            1 :     suite->issue.duration = __clove_time_sub(&suite_end, &suite_start);
    4272            1 : }
    4273              : #pragma endregion // Run Impl
    4274              : 
    4275              : #endif //CLOVE_IMPLEMENTATION
    4276              : #pragma endregion // IMPLEMENTATION
    4277              : 
    4278              : #pragma endregion // PRIVATE
    4279              : 
    4280              : #pragma region PUBLIC
    4281              : #pragma region PUBLIC - UTILS
    4282              : /*
    4283              :  * Provide the executable absolute path
    4284              :  */
    4285              : #define CLOVE_EXEC_PATH() __clove_utils_get_exec_abs_path()
    4286              :  /*
    4287              :   * Provide the executable absolute base path
    4288              :   */
    4289              : #define CLOVE_EXEC_BASE_PATH() __clove_utils_get_exec_abs_basepath()
    4290              : #pragma endregion //UTILS
    4291              : 
    4292              : #pragma region PUBLIC - ASSERTS
    4293              : #define CLOVE_FAIL()                       do { __CLOVE_ASSERT_GUARD __clove_assert_fail(_this); } while(0)
    4294              : #define CLOVE_PASS()                       do { __CLOVE_ASSERT_GUARD __clove_assert_pass(_this); } while(0)
    4295              :           
    4296              : #define CLOVE_IS_TRUE(res)                 do { __CLOVE_ASSERT_GUARD __clove_assert_bool(__CLOVE_ASSERT_EQ, true, res, _this); } while(0)
    4297              : #define CLOVE_IS_FALSE(res)                do { __CLOVE_ASSERT_GUARD __clove_assert_bool(__CLOVE_ASSERT_EQ, false, res, _this);  } while(0)
    4298              :           
    4299              : #define CLOVE_CHAR_EQ(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4300              : #define CLOVE_CHAR_NE(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4301              : #define CLOVE_CHAR_GT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4302              : #define CLOVE_CHAR_GTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4303              : #define CLOVE_CHAR_LT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4304              : #define CLOVE_CHAR_LTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_char(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4305              :           
    4306              : #define CLOVE_INT_EQ(exp, res)             do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4307              : #define CLOVE_INT_NE(exp, res)             do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4308              : #define CLOVE_INT_GT(exp, res)             do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4309              : #define CLOVE_INT_GTE(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4310              : #define CLOVE_INT_LT(exp, res)             do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4311              : #define CLOVE_INT_LTE(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_int(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4312              :           
    4313              : #define CLOVE_UINT_EQ(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4314              : #define CLOVE_UINT_NE(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4315              : #define CLOVE_UINT_GT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4316              : #define CLOVE_UINT_GTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4317              : #define CLOVE_UINT_LT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4318              : #define CLOVE_UINT_LTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_uint(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4319              :           
    4320              : #define CLOVE_LONG_EQ(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4321              : #define CLOVE_LONG_NE(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4322              : #define CLOVE_LONG_GT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4323              : #define CLOVE_LONG_GTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4324              : #define CLOVE_LONG_LT(exp, res)            do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4325              : #define CLOVE_LONG_LTE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_long(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4326              :        
    4327              : #define CLOVE_ULONG_EQ(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4328              : #define CLOVE_ULONG_NE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4329              : #define CLOVE_ULONG_GT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4330              : #define CLOVE_ULONG_GTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4331              : #define CLOVE_ULONG_LT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4332              : #define CLOVE_ULONG_LTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ulong(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4333              :        
    4334              : #define CLOVE_LLONG_EQ(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4335              : #define CLOVE_LLONG_NE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4336              : #define CLOVE_LLONG_GT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4337              : #define CLOVE_LLONG_GTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4338              : #define CLOVE_LLONG_LT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4339              : #define CLOVE_LLONG_LTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_llong(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4340              :        
    4341              : #define CLOVE_ULLONG_EQ(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4342              : #define CLOVE_ULLONG_NE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4343              : #define CLOVE_ULLONG_GT(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4344              : #define CLOVE_ULLONG_GTE(exp, res)         do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4345              : #define CLOVE_ULLONG_LT(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4346              : #define CLOVE_ULLONG_LTE(exp, res)         do { __CLOVE_ASSERT_GUARD __clove_assert_ullong(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4347              :        
    4348              : #define CLOVE_SIZET_EQ(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4349              : #define CLOVE_SIZET_NE(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4350              : #define CLOVE_SIZET_GT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_GT, exp, res, _this); } while(0)
    4351              : #define CLOVE_SIZET_GTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_GTE, exp, res, _this); } while(0)
    4352              : #define CLOVE_SIZET_LT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_LT, exp, res, _this); } while(0)
    4353              : #define CLOVE_SIZET_LTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_sizet(__CLOVE_ASSERT_LTE, exp, res, _this); } while(0)
    4354              :        
    4355              : #define CLOVE_FLOAT_EQ(exp, res)           CLOVE_FLOAT_EQ_P(exp, res, (unsigned char)6)
    4356              : #define CLOVE_FLOAT_NE(exp, res)           CLOVE_FLOAT_NE_P(exp, res, (unsigned char)6)
    4357              : #define CLOVE_FLOAT_EQ_P(exp, res, prec)   do { __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_EQ, exp, res, (unsigned char)prec, _this); } while(0)
    4358              : #define CLOVE_FLOAT_NE_P(exp, res, prec)   do { __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_NE, exp, res, (unsigned char)prec, _this); } while(0)
    4359              : #define CLOVE_FLOAT_GT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_GT, exp, res, (unsigned char)6, _this); } while(0)
    4360              : #define CLOVE_FLOAT_GTE(exp, res)          do {  __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_GTE, exp, res, (unsigned char)6, _this); } while(0)
    4361              : #define CLOVE_FLOAT_LT(exp, res)           do { __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_LT, exp, res, (unsigned char)6, _this); } while(0)
    4362              : #define CLOVE_FLOAT_LTE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_float(__CLOVE_ASSERT_LTE, exp, res, (unsigned char)6, _this); } while(0)
    4363              :   
    4364              : #define CLOVE_DOUBLE_EQ(exp, res)          CLOVE_DOUBLE_EQ_P(exp, res, (unsigned char)15)
    4365              : #define CLOVE_DOUBLE_NE(exp, res)          CLOVE_DOUBLE_NE_P(exp, res, (unsigned char)15)
    4366              : #define CLOVE_DOUBLE_EQ_P(exp, res, prec)  do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_EQ, exp, res, prec, _this); } while(0)
    4367              : #define CLOVE_DOUBLE_NE_P(exp, res, prec)  do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_NE, exp, res, prec, _this); } while(0)
    4368              : #define CLOVE_DOUBLE_GT(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_GT, exp, res, (unsigned char)15, _this); } while(0)
    4369              : #define CLOVE_DOUBLE_GTE(exp, res)         do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_GTE, exp, res, (unsigned char)15, _this); } while(0)
    4370              : #define CLOVE_DOUBLE_LT(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_LT, exp, res, (unsigned char)15, _this); } while(0)
    4371              : #define CLOVE_DOUBLE_LTE(exp, res)         do { __CLOVE_ASSERT_GUARD __clove_assert_double(__CLOVE_ASSERT_LTE, exp, res, (unsigned char)15, _this); } while(0)
    4372              :        
    4373              : #define CLOVE_NULL(res)                    do { __CLOVE_ASSERT_GUARD __clove_assert_null(__CLOVE_ASSERT_EQ, NULL, (void*)res, _this); } while(0)
    4374              : #define CLOVE_NOT_NULL(res)                do { __CLOVE_ASSERT_GUARD __clove_assert_null(__CLOVE_ASSERT_NE, NULL, (void*)res, _this); } while(0)
    4375              :        
    4376              : #define CLOVE_PTR_EQ(p1, p2)               do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_EQ, (void*)p1, (void*)p2, _this); } while(0)
    4377              : #define CLOVE_PTR_NE(p1, p2)               do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_NE, (void*)p1, (void*)p2, _this); } while(0)
    4378              : #define CLOVE_PTR_GT(p1, p2)               do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_GT, (void*)p1, (void*)p2, _this); } while(0)
    4379              : #define CLOVE_PTR_GTE(p1, p2)              do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_GTE, (void*)p1, (void*)p2, _this); } while(0)
    4380              : #define CLOVE_PTR_LT(p1, p2)               do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_LT, (void*)p1, (void*)p2, _this); } while(0)
    4381              : #define CLOVE_PTR_LTE(p1, p2)              do { __CLOVE_ASSERT_GUARD __clove_assert_ptr(__CLOVE_ASSERT_LTE, (void*)p1, (void*)p2, _this); } while(0)
    4382              :        
    4383              : #define CLOVE_STRING_EQ(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_string(__CLOVE_ASSERT_EQ, exp, res, _this); } while(0)
    4384              : #define CLOVE_STRING_NE(exp, res)          do { __CLOVE_ASSERT_GUARD __clove_assert_string(__CLOVE_ASSERT_NE, exp, res, _this); } while(0)
    4385              : #pragma endregion //ASSERTS
    4386              : 
    4387              : #pragma region PUBLIC - SUITE
    4388              :   //CLOVE_SUITE_NAME must be defined by the user
    4389              : #define CLOVE_SUITE_SETUP_ONCE() __CLOVE_SUITE_SETUP_ONCE_AUTO()
    4390              : #define CLOVE_SUITE_TEARDOWN_ONCE() __CLOVE_SUITE_TEARDOWN_ONCE_AUTO()
    4391              : #define CLOVE_SUITE_SETUP() __CLOVE_SUITE_SETUP_AUTO()
    4392              : #define CLOVE_SUITE_TEARDOWN() __CLOVE_SUITE_TEARDOWN_AUTO()
    4393              : #define CLOVE_TEST(title) __CLOVE_TEST_AUTO(title)
    4394              : #pragma endregion // SUITE
    4395              : 
    4396              : #pragma region PUBLIC - RUNNER
    4397              : #define CLOVE_RUNNER() __CLOVE_RUNNER_AUTO()
    4398              : #pragma endregion // RUNNER
    4399              : 
    4400              : #pragma endregion //PUBLIC
    4401              : 
    4402              : #if defined(__GNUC__) && __GNUC__ <= 12 // GNU Unknown Pragma Fix: END
    4403              : #pragma GCC diagnostic pop
    4404              : #endif 
    4405              : 
    4406              : #endif //__CLOVE_H
        

Generated by: LCOV version 2.0-1