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, ¶ms);
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), ¶ms);
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 = §ions[i];
4098 1 : break;
4099 : }
4100 : }
4101 :
4102 1 : Elf64_Shdr* name_table_section = §ions[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, ¶ms);
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
|