/** \copyright MIT License Copyright (c) 2020, Adewale Azeez \author Adewale Azeez <iamthecarisma@gmail.com> \date 10 April 2020 \file cester.h Cester is a header only unit testing framework for C. The header file can be downloaded and placed in a project folder or can be used as part of libopen library by including it in the projects like `<libopen/cester.h>`. A single test file is considered a test suite in cester, a single test file should contain related tests functions only. */ #ifndef LIBOPEN_CESTER_H #define LIBOPEN_CESTER_H /* BEFORE YOU SUGGEST ANY EDIT PLEASE TRY TO UNDERSTAND THIS CODE VERY WELL. */ #ifdef __cplusplus extern "C" { #endif /** The inline keyword to optimize the function. In C89 and C90 the inline keyword semantic is different from current C standard semantic hence for compilation targeting C89 or C99 the inline keyword is ommited. */ #ifdef __STDC_VERSION__ #define __CESTER_STDC_VERSION__ __STDC_VERSION__ #else #ifdef __cplusplus #if __cplusplus > 199711L #define __CESTER_STDC_VERSION__ __cplusplus #endif #endif #endif #ifndef __CESTER_STDC_VERSION__ #define __CESTER_INLINE__ #define __CESTER_LONG_LONG__ long #define __CESTER_LONG_LONG_FORMAT__ "%ld" #ifdef __FUNCTION__ #define __CESTER_FUNCTION__ __FUNCTION__ #else #define __CESTER_FUNCTION__ "<unknown>" #endif #define CESTER_NULL 0L #define inline #else #define __CESTER_INLINE__ inline #define __CESTER_LONG_LONG__ long long #define __CESTER_LONG_LONG_FORMAT__ "%lld" #define __CESTER_FUNCTION__ __func__ #define CESTER_NULL NULL #endif #ifdef __cplusplus #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) #define __CESTER_CAST_CHAR_ARRAY__ (unsigned) #else #define __CESTER_CAST_CHAR_ARRAY__ (char*) #endif #else #define __CESTER_CAST_CHAR_ARRAY__ #endif #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #define _POSIX_SOURCE #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #endif #include <stdlib.h> #include <time.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #ifndef CESTER_NO_SIGNAL #include <signal.h> #include <setjmp.h> jmp_buf buf; #endif #ifndef __BASE_FILE__ #ifdef _MSC_VER #pragma message("__BASE_FILE__ not defined. Define the __BASE_FILE__ directive in Properties -> C/C++ -> Preprocessor -> Preprocessor Definition as __BASE_FILE__=\"%(Filename)%(Extension)\" or register your test cases manually.") #else #pragma message("__BASE_FILE__ not defined. Define __BASE_FILE__ during compilation. -D__BASE_FILE__=\"/the/path/to/yout/testfile.c\" or register your test cases manually.") #endif #endif /** set pointer to null after free */ #define cester_meta_free(x) free(x); x = CESTER_NULL #if defined __has_include #if !__has_include (__BASE_FILE__) #pragma message("__BASE_FILE__ is not in include directory. Add the option '-I.' for your compiler so it can find the file.") #endif #endif #ifdef _WIN32 #ifndef CESTER_EXCLUDE_WINDOWS_H #ifndef NOMINMAX #define NOMINMAX #endif #include <windows.h> #endif #include <direct.h> #define mkdir(x,y) _mkdir(x) #ifndef stat #define stat __stat64 #endif /* ** Windows ** Support Windows XP ** To avoid error message : procedure entry point ** InitializeConditionVariable could not be located ** in Kernel32.dll */ #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x502 #define EXOTICTYPES_WINDLLEXPORT 1 /* Linux */ #else #define EXOTICTYPES_WINDLLEXPORT 0 #endif #ifndef __cplusplus #if EXOTICTYPES_WINDLLEXPORT #define EXOTIC_API __declspec(dllexport) /**< the platform is windows use windows export keyword __declspec(dllexport) */ #else #define EXOTIC_API extern /**< Keyword to export the functions to allow ussage dynamically. NOT USED. IGNORED */ #endif #else #define EXOTIC_API #endif #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) #define CESTER_RESET_TERMINAL 15 /**< reset the terminal color //Nothing */ #define CESTER_BOLD 15 /**< bold text //Nothing */ #define CESTER_FOREGROUND_BLACK 8 /**< gray terminal foreground color */ #define CESTER_FOREGROUND_RED 4 /**< red terminal foreground color */ #define CESTER_FOREGROUND_GREEN 2 /**< green foreground color */ #define CESTER_FOREGROUND_YELLOW 6 /**< yellow terminal foreground color */ #define CESTER_FOREGROUND_BLUE 3 /**< blue terminal foreground color */ #define CESTER_FOREGROUND_MAGENTA 5 /**< magenta terminal foreground color */ #define CESTER_FOREGROUND_CYAN 11 /**< cyan terminal foreground color */ #define CESTER_FOREGROUND_WHITE 15 /**< white terminal foreground color */ #define CESTER_FOREGROUND_GRAY 8 /**< gray terminal foreground color */ #define CESTER_BACKGROUND_BLACK 0 /**< black terminal background color */ #define CESTER_BACKGROUND_RED 64 /**< red terminal background color */ #define CESTER_BACKGROUND_GREEN 39 /**< green terminal background color */ #define CESTER_BACKGROUND_YELLOW 96 /**< yellow terminal background color */ #define CESTER_BACKGROUND_BLUE 48 /**< blue terminal background color */ #define CESTER_BACKGROUND_MAGENTA 87 /**< magenta terminal background color */ #define CESTER_BACKGROUND_CYAN 176 /**< cyan terminal background color */ #define CESTER_BACKGROUND_GRAY 0 /**< gray terminal background color */ #define CESTER_BACKGROUND_WHITE 10 /**< gray terminal background color */ #define CESTER_RESET_TERMINAL_ATTR() SetConsoleTextAttribute(cester_hConsole, cester_default_color); /**< reset the terminal color */ #else #define CESTER_RESET_TERMINAL "\x1B[0m" /**< reset the terminal color */ #define CESTER_BOLD "\x1B[1m" /**< bold text */ #define CESTER_FOREGROUND_BLACK "\x1B[30m" /**< gray terminal foreground color */ #define CESTER_FOREGROUND_RED "\x1B[31m" /**< red terminal foreground color */ #define CESTER_FOREGROUND_GREEN "\x1B[32m" /**< green foreground color */ #define CESTER_FOREGROUND_YELLOW "\x1B[33m" /**< yellow terminal foreground color */ #define CESTER_FOREGROUND_BLUE "\x1B[34m" /**< blue terminal foreground color */ #define CESTER_FOREGROUND_MAGENTA "\x1B[35m" /**< magenta terminal foreground color */ #define CESTER_FOREGROUND_CYAN "\x1B[36m" /**< cyan terminal foreground color */ #define CESTER_FOREGROUND_WHITE "\x1B[37m" /**< white terminal foreground color */ #define CESTER_FOREGROUND_GRAY "\x1B[90m" /**< gray terminal foreground color */ #define CESTER_BACKGROUND_BLACK "\x1B[40m" /**< black terminal background color */ #define CESTER_BACKGROUND_RED "\x1B[41m" /**< red terminal background color */ #define CESTER_BACKGROUND_GREEN "\x1B[42m" /**< green terminal background color */ #define CESTER_BACKGROUND_YELLOW "\x1B[43m" /**< yellow terminal background color */ #define CESTER_BACKGROUND_BLUE "\x1B[44m" /**< blue terminal background color */ #define CESTER_BACKGROUND_MAGENTA "\x1B[45m" /**< magenta terminal background color */ #define CESTER_BACKGROUND_CYAN "\x1B[46m" /**< cyan terminal background color */ #define CESTER_BACKGROUND_GRAY "\x1B[100m" /**< gray terminal background color */ #define CESTER_BACKGROUND_WHITE "\x1B[47m" /**< gray terminal background color */ #define CESTER_RESET_TERMINAL_ATTR() ; /**< reset the terminal color */ #endif /** Cester current version */ #define CESTER_VERSION "0.4" /** Cester current version */ #define CESTER_VERSION_NUM 0.4 /** Cester License */ #define CESTER_LICENSE "MIT License" /** Cester Authors */ #define CESTER_AUTHOR "Adewale Azeez and other contributors" /** The hash # symbol for macro directive */ #define CESTER_HASH_SIGN # /** Concat two items including C macro directives. */ #define CESTER_CONCAT(x, y) x y /** The type of caparison to perform on two values. This is introduce to resolve the bug https://github.com/exoticlibraries/libcester/issues/30 */ enum cester_assertion_caparator { CESTER_COMPARATOR_EQUAL, /**< the comparisson operator is '==' */ CESTER_COMPARATOR_NOT_EQUAL, /**< the comparisson operator is '!=' */ CESTER_COMPARATOR_GREATER_THAN, /**< the comparisson operator is '>' */ CESTER_COMPARATOR_GREATER_THAN_OR_EQUAL, /**< the comparisson operator is '>=' */ CESTER_COMPARATOR_LESSER_THAN, /**< the comparisson operator is '<' */ CESTER_COMPARATOR_LESSER_THAN_OR_EQUAL /**< the comparisson operator is '<=' */ }; /** The execution status of a test case that indicates whether a test passes of fails. And also enable the detection of the reason if a test fail. */ enum cester_test_status { CESTER_RESULT_SUCCESS, /**< the test case passed */ CESTER_RESULT_FAILURE, /**< the test case failes dues to various reason mostly AssertionError */ CESTER_RESULT_TERMINATED, /**< in isolated test, the test case was termiated by a user or another program */ CESTER_RESULT_SEGFAULT, /**< the test case crahses or causes segmentation fault */ CESTER_RESULT_UNRELEASED_STREAM, /**< the test case has unreleased streams */ #ifndef CESTER_NO_MEM_TEST CESTER_RESULT_MEMORY_LEAK, /**< the test case passes or fails but failed to free allocated memory */ #endif CESTER_RESULT_TIMED_OUT, /**< cester terminated the test case because it running for too long */ CESTER_RESULT_UNKNOWN /**< the test case was never ran */ }; typedef enum cester_test_type { CESTER_NORMAL_TEST, /**< normal test in global or test suite. For internal use only. */ CESTER_NORMAL_TODO_TEST, /**< test to be implemented in future. For internal use only. */ CESTER_NORMAL_SKIP_TEST, /**< test to be skipped. For internal use only. */ CESTER_BEFORE_ALL_TEST, /**< test to run before all normal tests in global or test suite. For internal use only. */ CESTER_BEFORE_EACH_TEST, /**< test to run before each normal tests in global or test suite. For internal use only. */ CESTER_AFTER_ALL_TEST, /**< test to run after all normal tests in global or test suite. For internal use only. */ CESTER_AFTER_EACH_TEST, /**< test to run after each normal tests in global or test suite. For internal use only. */ CESTER_OPTIONS_FUNCTION, /**< the cester function for test, this wil be excuted before running the tests. For internal use only. */ CESTER_TEST_FILE_COMMENT, /**< The function that holds the text defined in the CESTER_COMMENT macro. For internal use only. */ CESTER_TESTS_TERMINATOR /**< the last value in the test cases to terminates the tests. For internal use only. */ } TestType; #ifndef CESTER_NO_STREAM_CAPTURE /** The structure that manages the stream that has been captured by cester. It keeps record of the original stream and also of the stream that replaces the original, this way when a stream is to be released by cester it can simly set the original stream to it original state with no consequences and the extrac stream can be properlly freed. */ typedef struct captured_stream { unsigned line_num; /**< the line number where the stream was captured. For internal use only. */ char *function_name; /**< The function name (test case) where the stream was catured. For internal use only.*/ char *original_stream_ptr_str; /**< The captured stream pointer address as string. For internal use only.*/ char *replaced_stream_ptr_str; /**< The stream to replace the captured stream pointer address as string. For internal use only.*/ char *stream_buffer; /**< The stream content. This is needed so we can peoperly free allocated memory. For internal use only.*/ char *replaced_stream_file_path; /**< The file path to the temporary file that replaces the stream. For internal use only.*/ FILE original_stream; /**< The actual address of the captured stream. For internal use only.*/ FILE *original_stream_handle; /**< The actual variable of the captured stream. For internal use only.*/ FILE *replaced_stream_handle; /**< The opened file handle that replaces the captured stream. For internal use only.*/ } CapturedStream; #endif /** The test instance that contains the command line argument length and values, with void* pointer that can be used to share data between unit tests. */ typedef struct test_instance { unsigned argc; /**< the length of the command line arg */ char **argv; /**< the command line arguments */ void *arg; /**< pointer to an object that can be passed between unit tests */ } TestInstance; /** The function signature for each test case and the before after functions. It accepts the ::test_instance as it only argument. */ typedef void (*cester_test)(TestInstance*); /** The function signature for function to execute before and after each test cases. It accepts the ::test_instance, char* and unsigned as parameters. */ typedef void (*cester_before_after_each)(TestInstance*, char * const, unsigned); /** A void function signature with no return type and no parameters. */ typedef void (*cester_void)(void); typedef struct test_case { unsigned execution_status; /**< the test execution result status. For internal use only. */ unsigned line_num; /**< the line number where the test case is created. For internal use only. */ enum cester_test_status expected_result; /**< The expected result for the test case. For internal use only. */ #ifndef CESTER_NO_TIME double start_tic; /**< the time taken for the test case to complete. For internal use only. */ double execution_time; /**< the time taken for the test case to complete. For internal use only. */ #endif char* execution_output; /**< the test execution output in string. For internal use only. */ char *name; /**< the test function name. For internal use only. */ cester_test test_function; /**< the function that enclosed the tests. For internal use only. */ cester_before_after_each test_ba_function; /**< the function that enclosed the tests. For internal use only. */ cester_void test_void_function; /**< the function that enclosed the tests. For internal use only. */ TestType test_type; /**< the type of the test function. For internal use only. */ } TestCase; #ifndef CESTER_NO_MEM_TEST typedef struct allocated_memory { unsigned line_num; /**< the line number where the memory was allocated. For internal use only. */ size_t allocated_bytes; /**< the number of allocated bytes. For internal use only. */ unsigned function_name_allocated; /**< check whether the vallue was set using malloc. For internal use only. */ char* address; /**< the allocated pointer address. For internal use only. */ char* function_name; /**< the function where the memory is allocated in. For internal use only. */ const char* file_name; /**< the file name where the memory is allocated. For internal use only. */ } AllocatedMemory; #endif /** The initial amount of item the ::CesterArray can accept the first time it initialized. */ #define CESTER_ARRAY_INITIAL_CAPACITY 30 /** The maximum number of item the ::CesterArray can contain, in case of the Memory manager array reaching this max capacity continous mem test will be disabled. */ #define CESTER_ARRAY_MAX_CAPACITY ((size_t) - 5) typedef struct cester_array_struct { size_t size; /**< the size of the item in the array */ size_t capacity; /**< the number of item the array can contain before expanding */ void** buffer; /**< pointer to the pointers of items added to the array */ } CesterArray; #define CESTER_ARRAY_FOREACH(w,x,y,z) for (x = 0; x < w->size; ++x) {\ void* y = w->buffer[x];\ z\ } /** This structure manages the _BEFORE_ and _AFTER_ functions for the test main ::test_instance. And also accounts for all the registered test cases. This is for Cester internal use only. */ typedef struct super_test_instance { unsigned no_color; /**< Do not print to the console with color if one. For internal use only. */ unsigned total_tests_count; /**< the total number of tests to run, assert, eval e.t.c. To use in your code call CESTER_TOTAL_TESTS_COUNT */ unsigned total_tests_ran; /**< the total number of tests that was run e.t.c. To use in your code call CESTER_TOTAL_TESTS_RAN */ unsigned total_failed_tests_count; /**< the total number of tests that failed. To use in your code call CESTER_TOTAL_FAILED_TESTS_COUNT */ unsigned total_passed_tests_count; /**< the total number of tests that passed. To use in your code call CESTER_TOTAL_FAILED_TESTS_COUNT */ unsigned total_test_errors_count; /**< the total number of errors that occurs. To use in your code call CESTER_TOTAL_TEST_ERRORS_COUNT */ unsigned verbose_level; /**< the level of cester verbosity for how much information is printed in the terminal */ unsigned print_error_only; /**< if false or 0 prints all t assertion evaluation result, default is 1/true */ unsigned print_version; /**< prints cester version before running tests */ unsigned selected_test_cases_size; /**< the number of selected test casses from command line. For internal use only. */ unsigned selected_test_cases_found; /**< the number of selected test casses from command line that is found in the test file. For internal use only. */ unsigned single_output_only; /**< display the output for a single test only no summary and syntesis. For internal use only. */ unsigned mem_test_active; /**< Enable or disable memory test at runtime. Enabled by default. For internal use only. */ unsigned stream_capture_active; /**< Enable or disable memory test at runtime. Enabled by default. For internal use only. */ unsigned current_execution_status; /**< the current test case status. This is used when the test cases run on a single process. For internal use only. */ unsigned isolate_tests; /**< Isolate each test case to run in different process to prevent a crashing test case from crahsing others. For internal use only. */ unsigned skipped_test_count; /**< The number of test cases to be skipped. For internal use only. */ unsigned todo_tests_count; /**< The number of test cases that would be implemented in future. For internal use only. */ unsigned format_test_name; /**< Format the test name for fine output e.g. 'test_file_exit' becomes 'test file exist'. For internal use only. */ unsigned report_success_regardless; /**< If the value is set to 1 the test will be mark as success even if it fails. For internal use only. */ unsigned report_failure_regardless; /**< If the value is set to 1 the test will be mark as failure even if it passes. For internal use only. */ TestType current_cester_function_type; /**< The current cester funtion type, this enable cester to properly track memory allocation in non test case functions. For internal use only. */ #ifndef CESTER_NO_TIME double start_tic; /**< The unix time when the tests starts. For internal use only. */ #endif char *main_execution_output; /**< The main test execution output in string. For internal use only. . */ char *flattened_cmd_argv; /**< Flattened command line argument for sub process. For internal use only. */ char *test_file_path; /**< The main test file full path. For internal use only. */ char *output_format; /**< The output format to print the test result in. For internal use only. */ #ifndef CESTER_NO_STREAM_CAPTURE char *output_stream_str; /**< The string value of the output stream pointer. For internal use only. */ char *captured_streams_tmp_folder; /**< The folder to store temporary file for captured streams. For internal use only. */ #endif TestInstance *test_instance ; /**< The test instance for sharing datas. For internal use only. */ #ifndef CESTER_NO_STREAM_CAPTURE FILE output_stream_address; /**< Output stream address. incase the output stream was captured in test it state can be reset. For internal use only. */ #endif FILE *output_stream; /**< Output stream to write message to, stdout by default. For internal use only. */ char **selected_test_cases_names; /**< selected test cases from command line. For internal use only. e.g. --cester-test=Test2,Test1 */ TestCase *current_test_case; /**< The currently running test case. For internal use only. */ CesterArray *registered_test_cases; /**< all the manually registered test cases in the instance. For internal use only. */ CesterArray *captured_streams; /**< all the file stream captured for testing by cester. For internal use only. */ #ifndef CESTER_NO_MEM_TEST CesterArray* mem_alloc_manager; /**< the array of allocated memory. For testing and detecting memory leaks. For internal use only. */ #endif } SuperTestInstance; /* CesterArray */ static __CESTER_INLINE__ unsigned cester_array_init(CesterArray**); static __CESTER_INLINE__ unsigned cester_array_add(CesterArray*, void*); static __CESTER_INLINE__ void* cester_array_remove_at(CesterArray*, size_t); static __CESTER_INLINE__ void cester_array_destroy(CesterArray*); static __CESTER_INLINE__ unsigned cester_run_all_test(unsigned, char **); static __CESTER_INLINE__ void cester_str_value_after_first(char *, char, char**); SuperTestInstance superTestInstance = { 0, /* no_color */ 0, /* total_tests_count */ 0, /* total_tests_ran */ 0, /* total_failed_tests_count */ 0, /* total_passed_tests_count */ 0, /* total_test_errors_count */ 0, /* verbose_level */ 1, /* print_error_only */ 0, /* print_version */ 0, /* selected_test_cases_size */ 0, /* selected_test_cases_found */ 0, /* single_output_only */ 1, /* mem_test_active */ 1, /* stream_capture_active */ CESTER_RESULT_SUCCESS, /* current_execution_status */ 1, /* isolate_tests */ 0, /* skipped_test_count */ 0, /* todo_tests_count */ 1, /* format_test_name */ 0, /* report_success_regardless */ 0, /* report_failure_regardless */ CESTER_TESTS_TERMINATOR, /* current_cester_function_type */ #ifndef CESTER_NO_TIME 0.0, /* start_tic */ #endif (char*)"", /* main_execution_output */ (char*)"", /* flattened_cmd_argv */ #ifdef __BASE_FILE__ (char*)__BASE_FILE__, /* test_file_path */ #else (char*)__FILE__, /* test_file_path */ #endif CESTER_NULL, /* output_format */ #ifndef CESTER_NO_STREAM_CAPTURE (char*)"", /* output_stream_str */ (char*)"./build/libcester/captured_streams/", /* captured_streams_tmp_folder */ #endif CESTER_NULL, /* test_instance */ #ifndef CESTER_NO_STREAM_CAPTURE CESTER_NULL, /* output_stream_address */ #endif 0, /* output_stream */ CESTER_NULL, /* selected_test_cases_names */ 0, /* current_test_case */ 0, /* registered_test_cases */ 0, /* captured_streams */ #ifndef CESTER_NO_MEM_TEST 0 /* mem_alloc_manager */ #endif }; #ifdef _MSC_VER #define cester_sprintf(x,y,z,a,b,c) sprintf_s(x, y, z, a, b, c); #define cester_sprintf1(x,y,z,a) cester_sprintf(x,y,z,a,"","") #define cester_sprintf2(x,y,z,a,b) cester_sprintf(x,y,z,a,b,"") #define cester_sprintf3(x,y,z,a,b,c) cester_sprintf(x,y,z,a,b,c) #else #define cester_sprintf(x,y,z,a,b) sprintf(x, z, a, b); #define cester_sprintf1(x,y,z,a) sprintf(x, z, a) #define cester_sprintf2(x,y,z,a,b) sprintf(x, z, a, b) #define cester_sprintf3(x,y,z,a,b,c) sprintf(x, z, a, b, c) #endif /* cester options */ /** Change the output stream used by cester to write data. The default is `stdout`. E.g to change the output stream to a file. \code{.c} CESTER_CHANGE_STREAM(fopen("./test.txt", "w+")); \endcode The code above changes the stream to a file test.txt, all the output from the test will be written in the file. **/ #define CESTER_CHANGE_STREAM(x) { cester_ptr_to_str(&(superTestInstance.output_stream_str), x); superTestInstance.output_stream_address = *x; } (superTestInstance.output_stream = x) /** Do not print to the output stream with color. This should be used to prevent writing the color bytes into a file stream (in case). This option can also be set from the command line with `--cester-nocolor` */ #define CESTER_NOCOLOR() (superTestInstance.no_color = 1) /** Change the option to print error only for the assertion. The default value is true. Change the value to false to print all the results. The macro CESTER_VERBOSE also modify the value to false. */ #define CESTER_PRINT_ERROR_ONLY(x) (superTestInstance.print_error_only = x) /** Print minimal info into the output stream. With this option set the expression evaluated will not be printed in the result output. This option can also be set from the command line with `--cester-minimal` or `--cester-verbose-level=0` */ #define CESTER_MINIMAL() (superTestInstance.verbose_level = 0) /** Print as much info as possible into the output stream. With this option set both passed and failed expression evaluated will be printed in the result. This macro also set the value of print_error_only only to false to display output of all the assertions. This option can also be set from the command line with `--cester-verbose` or `--cester-verbose-level=10` */ #define CESTER_VERBOSE() (superTestInstance.verbose_level = 10); (superTestInstance.print_error_only = 0) /** Change the verbose level of the output, the higher the velue the more the information printed into the terminal. 0 value means no output apart from the testcase's and value 4 and above prints the full path to the test file. */ #define CESTER_DEBUG_LEVEL(x) (superTestInstance.verbose_level = x) /** Deprecated. Use CESTER_DEBUG_LEVEL */ #define CESTER_VERBOSE_LEVEL(x) (superTestInstance.verbose_level = x) /** Print cester version before running any test. This option can also be set from the command line with `--cester-printversion` **/ #define CESTER_PRINT_VERSION() (superTestInstance.print_version = 1) /** Display test for a single test case only, skip syntesis and summary. This option can also be set from the command line with `--cester-singleoutput` **/ #define CESTER_SINGLE_OUPUT_ONLY() (superTestInstance.single_output_only = 1) /** Do not isolate the tests, run each of the test cases in a single process. The drawback is if a test case causes segfault or crash the entire test crashes and no summary is displayed. No isolation causes a crash one crash all scenerio. This option can also be set from the command line with `--cester-noisolation` **/ #define CESTER_NO_ISOLATION() (superTestInstance.isolate_tests = 0) /** Disable memory leak detection test. This option can also be set from the command line with `--cester-nomemtest` **/ #define CESTER_NO_MEMTEST() (superTestInstance.mem_test_active = 0) /** Enable memory allocation. The combination of CESTER_NO_MEMTEST() and CESTER_DO_MEMTEST() is valid only in non isolated tests. This togle combined with `CESTER_NO_MEMTEST()` can be used to selectively test memory allocation in a test e.g. Calling CESTER_NO_MEMTEST() before a test case will prevent memory test from the beginning of that function and calling CESTER_DO_MEMTEST() at the end of the test case will ensure memory allocation will be validated in all the other test case that follows. **/ #define CESTER_DO_MEMTEST() (superTestInstance.mem_test_active = 1) /** Disable stream capture features. This option can also be set from the command line with `--cester-nostreamcapture` **/ #define CESTER_NO_STREAMCAPTURE() (superTestInstance.stream_capture_active = 0) /** Enable stream capture features. The combination of CESTER_NO_STREAMCAPTURE() and CESTER_DO_STREAMCAPTURE() is valid only in non isolated tests. This togle combined with `CESTER_NO_STREAMCAPTURE()` can be used to selectively test stream capture and content in a test e.g. Calling CESTER_NO_STREAMCAPTURE() before a test case will prevent stream capturing from the beginning of that function and calling CESTER_DO_STREAMCAPTURE() at the end of the test case will ensure stream capturing will be enabled in all the other test case that follows. **/ #define CESTER_DO_STREAMCAPTURE() (superTestInstance.stream_capture_active = 1) /** Change the output format to text */ #define CESTER_OUTPUT_TEXT() superTestInstance.output_format = (char*) "text" /** Change the output format to junitxml */ #define CESTER_OUTPUT_JUNITXML() superTestInstance.output_format = (char*) "junitxml" /** Change the output format to TAP (Test Anything Protocol) */ #define CESTER_OUTPUT_TAP() superTestInstance.output_format = (char*) "tap" /** Change the output format to TAP (Test Anything Protocol) Version 13 */ #define CESTER_OUTPUT_TAPV13() superTestInstance.output_format = (char*) "tapV13" /** Format the test case name for output. E.g the test name `modify_test_instance` becomes `modify test instance`. This does not apply to junitxml as the test name remain the way it declared in the test source. */ #define CESTER_FORMAT_TESTNAME() superTestInstance.format_test_name = 1; /** Do not format the test case name, it remain the way it declared in the test source. */ #define CESTER_DONT_FORMAT_TESTNAME() superTestInstance.format_test_name = 0; /* test counts */ /** The total number of tests that is present in the test file. */ #define CESTER_TOTAL_TESTS_COUNT (superTestInstance.total_tests_count) /** The total number of tests that was ran. */ #define CESTER_TOTAL_TESTS_RAN (superTestInstance.total_tests_ran) /** The total number of tests that failed. */ #define CESTER_TOTAL_FAILED_TESTS_COUNT (superTestInstance.total_failed_tests_count) /** The total number of errors that occur during the test. The errors is not tied to the test cases, the error is tied to cester fixtures, environment error and error that occur outside a test case. Error that occur within a test case is reported for that test case */ #define CESTER_TOTAL_TEST_ERRORS_COUNT (superTestInstance.total_test_errors_count) /** The number of test that was skipped. If the selected test_cases_size is 0 then no test was skipped else the number of executed selected test cases minus the total number of test cases is the number of test that was skipped. */ #define CESTER_TOTAL_TESTS_SKIPPED (superTestInstance.skipped_test_count) /** The total number of tests that passed. CESTER_TOTAL_TESTS_COUNT - CESTER_TOTAL_FAILED_TESTS_COUNT */ #define CESTER_TOTAL_PASSED_TESTS_COUNT (superTestInstance.total_passed_tests_count) /** The number of test that was marked as todo and skipped. If the selected test_cases_size is 0 then no test was skipped else the number of executed selected test cases minus the total number of test cases is the number of test that was skipped. */ #define CESTER_TOTAL_TODO_TESTS (superTestInstance.todo_tests_count) /** Run all the test registered in cester, the TestInstance* pointer will be initalized with the pointer to the string arguments from cli and the length of the arguments. The `void* arg` pointer in the TestInstance* can be initalized in the *_BEFORE_* function to share data between the unit tests. */ #define CESTER_RUN_ALL_TESTS(x,y) cester_run_all_test(x,y) /** Always mark the test as success even if the test cases failed or an error occur while running the test. */ #define CESTER_REPORT_SUCCESS_REGARDLESS() (superTestInstance.report_failure_regardless = 0); (superTestInstance.report_success_regardless = 1) /** Always mark the test as failure even if the test cases passes and no error occur. */ #define CESTER_REPORT_FAILURE_REGARDLESS() (superTestInstance.report_success_regardless = 0); (superTestInstance.report_failure_regardless = 1) #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) int cester_default_color = CESTER_RESET_TERMINAL; HANDLE cester_hConsole; #else const char* cester_default_color = CESTER_RESET_TERMINAL; #endif static void cester_copy_str(char **src_out, char **dest_out, int size) { int index = 0; while (index < size) { (*dest_out)[index] = (*src_out)[index]; index++; } (*dest_out)[index] = '\0'; } static __CESTER_INLINE__ char *cester_extract_name(char const* const file_path) { unsigned i = 0, j = 0; char *file_name_only_actual; char *file_name_only = (char*) malloc (sizeof (char) * 200); while (file_path[i] != '\0') { if (file_path[i] == '\\' || file_path[i] == '/') { j = 0; } else { file_name_only[j] = file_path[i]; j++; } ++i; } file_name_only_actual = (char*) malloc(j+1); cester_copy_str(&file_name_only, &file_name_only_actual, j); cester_meta_free(file_name_only); return file_name_only_actual; } static __CESTER_INLINE__ char *cester_extract_name_only(char const* const file_path) { unsigned i = 0; char *file_name = cester_extract_name(file_path); while (file_name[i] != '\0') { if (file_name[i] == '.') { file_name[i] = '\0'; break; } ++i; } return file_name; } static __CESTER_INLINE__ void cester_concat_str(char **out, const char * extra); /* For some wierd reasons sprintf clears old array first before concatenatng in old compiler e.g Turbo C. So we first convert int to str then concat it to str*/ static __CESTER_INLINE__ void cester_concat_char(char **out, char extra) { char tmp[5] ; cester_sprintf1(tmp, 5, "%c", extra); cester_concat_str(out, tmp); } static __CESTER_INLINE__ void cester_concat_int(char **out, int extra) { char tmp[30]; cester_sprintf1(tmp, 30, "%d", extra); cester_concat_str(out, tmp); } static __CESTER_INLINE__ void cester_concat_sizet(char ** out, size_t extra) { char tmp[30]; cester_sprintf1(tmp, 30, __CESTER_LONG_LONG_FORMAT__, (__CESTER_LONG_LONG__)extra); cester_concat_str(out, tmp); } static __CESTER_INLINE__ void cester_ptr_to_str(char **out, void* extra) { (*out) = (char*) malloc(sizeof(char) * 30 ); cester_sprintf1((*out), (30), "%p", extra); } static __CESTER_INLINE__ unsigned cester_str_after_prefix(const char* arg, char* prefix, unsigned prefix_size, char** out) { unsigned i = 0, index = 0; char *value = (char*) malloc(sizeof (char) * 1000); while (1) { if (arg[i] == '\0') { if (i < prefix_size) { cester_meta_free(value); return 0; } else { break; } } if (i < prefix_size && arg[i] != prefix[i]) { cester_meta_free(value); return 0; } if (i >= prefix_size) { value[i-prefix_size] = arg[i]; } ++i; } i = i-prefix_size; *out = (char*) malloc(i+1); cester_copy_str(&value, out, i); cester_meta_free(value); return 1; } static __CESTER_INLINE__ char* cester_str_replace(char* str, char old_char, char new_char) { char* tmp = (char*) malloc(strlen(str) + 1); unsigned index = 0; do { if (*str == old_char) { tmp[index] = new_char; } else { tmp[index] = *str; } ++str; index++; } while (*str != '\0'); tmp[index] = '\0'; return tmp; } static __CESTER_INLINE__ unsigned cester_string_equals(char* arg, char* arg1) { unsigned i = 0; if (arg == CESTER_NULL || arg1 == CESTER_NULL) { return 0; } while (1) { if (arg[i] == '\0' && arg1[i] == '\0') { break; } if (arg[i] != arg1[i]) { return 0; } ++i; } return 1; } static __CESTER_INLINE__ unsigned cester_string_contains(char* arg, char* arg1) { unsigned i = 0, index = 0; if (arg == CESTER_NULL || arg1 == CESTER_NULL) { return 0; } while (1) { if (arg[i] == '\0' || arg1[index] == '\0') { return 0; } if (arg[i] == arg1[index]) { i++; index++; while (arg[i] == arg1[index]) { if (arg[i] == '\0') { break; } i++; index++; } if (arg1[index] == '\0') { return 1; } index = 0; continue; } ++i; } return 1; } #ifndef CESTER_NO_PRINT_INFO static __CESTER_INLINE__ unsigned cester_str_size(char* arg) { unsigned size = 0; while (1) { if (arg[size] == '\0') { break; } ++size; } return size; } #endif static __CESTER_INLINE__ unsigned cester_string_starts_with(char* arg, char* arg1) { unsigned i = 0; while (1) { if (arg[i] == '\0' && arg1[i] == '\0') { break; } if (arg[i] != arg1[i]) { if (arg1[i] == '\0') { break; } else { return 0; } } ++i; } return 1; } static __CESTER_INLINE__ void unpack_selected_extra_args(char *arg, char ***out, unsigned *out_size) { unsigned i = 0; unsigned size = 0, current_index = 0; char* prefix = (char*) "test="; char **arr = (char**) malloc(30 * sizeof(char*)); arr[size] = (char*) malloc(sizeof(char) * 1000); while (1) { if (arg[i] == '\0') { ++size; break; } if (i < 5 && arg[i] != prefix[i]) { break; } if (arg[i] == ',') { arr[size][current_index] = '\0'; current_index = 0; ++size; arr[size] = (char*) malloc(sizeof(char) * 1000); goto continue_loop; } if (i >= 5) { arr[size][current_index] = arg[i]; ++current_index; } continue_loop: ++i; } if (current_index > 0) { arr[size-1][current_index] = '\0'; } if (current_index == 0) { cester_meta_free(arr[0]); cester_meta_free(arr); return; } current_index = 0; (*out) = (char**) malloc(size * sizeof(char*)); while (current_index < size) { (*out)[current_index] = arr[current_index]; current_index++; } cester_meta_free(arr); *out_size = size; } static __CESTER_INLINE__ void cester_str_value_after_first(char *arg, char from, char** out) { unsigned i = 0, index = 0; unsigned found_char = 0; char *value = (char*) malloc(sizeof(char) * 200); while (1) { if (arg[i] == '\0') { break; } if (arg[i] == from) { found_char = 1; goto continue_loop; } if (found_char == 1) { value[index] = arg[i]; ++index; } continue_loop: ++i; } (*out) = (char*) malloc(index+1); cester_copy_str(&value, out, index); cester_meta_free(value); } static __CESTER_INLINE__ void cester_concat_str(char **out, const char * extra) { size_t extra_length; size_t original_length; size_t new_length; char * concatted; if (!extra) { extra_length = 0; } else { extra_length = strlen(extra); } if (*out) { original_length = strlen(*out); } else { original_length = 0; } new_length = original_length + extra_length; concatted = (char *)malloc(sizeof(char) * new_length + 1); if (original_length > 0) { strncpy(concatted, *out, original_length); concatted[original_length] = 0; } else { concatted[0] = 0; } if (extra_length > 0) { strncpy(concatted + original_length, extra, extra_length); concatted[original_length + extra_length] = 0; } if (*out && *out[0] != 0) { cester_meta_free(*out); } *out = concatted; } static __CESTER_INLINE__ void cester_concat_ptr(char **out, void *ptr) { char *extra; cester_ptr_to_str(&extra, ptr); cester_concat_str(out, extra); cester_meta_free(extra); } static __CESTER_INLINE__ unsigned cester_is_validate_output_option(char *format_option) { return (cester_string_equals(format_option, (char*) "junitxml") || cester_string_equals(format_option, (char*) "tap") || cester_string_equals(format_option, (char*) "tapV13") || cester_string_equals(format_option, (char*) "text")); } #ifdef _WIN32 #define CESTER_SELECTCOLOR(x) (superTestInstance.no_color == 1 ? cester_default_color : x) #else #define CESTER_SELECTCOLOR(x) (superTestInstance.no_color == 1 ? "" : x) #endif #define CESTER_GET_RESULT_AGGR (superTestInstance.total_failed_tests_count == 0 ? "SUCCESS" : "FAILURE") #define CESTER_GET_RESULT_AGGR_COLOR (superTestInstance.total_failed_tests_count == 0 ? (CESTER_FOREGROUND_GREEN) : (CESTER_FOREGROUND_RED)) #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) #define CESTER_DELEGATE_FPRINT(y) fprintf(superTestInstance.output_stream, "%s", y) #define CESTER_DELEGATE_FPRINT_STR(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%s", y) #define CESTER_DELEGATE_FPRINT_PTR(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%p", y) #define CESTER_DELEGATE_FPRINT_INT(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%d", y) #define CESTER_DELEGATE_FPRINT_UINT(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%u", y) #ifndef CESTER_NO_TIME #define CESTER_DELEGATE_FPRINT_DOUBLE(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%f", y) #define CESTER_DELEGATE_FPRINT_DOUBLE_2(x,y) SetConsoleTextAttribute(cester_hConsole, CESTER_SELECTCOLOR(x)); fprintf(superTestInstance.output_stream, "%.2f", y) #endif #else #define CESTER_DELEGATE_FPRINT(y) fprintf(superTestInstance.output_stream, "%s", y) #define CESTER_DELEGATE_FPRINT_STR(x,y) fprintf(superTestInstance.output_stream, "%s%s%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #define CESTER_DELEGATE_FPRINT_PTR(x,y) fprintf(superTestInstance.output_stream, "%s%p%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #define CESTER_DELEGATE_FPRINT_INT(x,y) fprintf(superTestInstance.output_stream, "%s%d%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #define CESTER_DELEGATE_FPRINT_UINT(x,y) fprintf(superTestInstance.output_stream, "%s%u%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #ifndef CESTER_NO_TIME #define CESTER_DELEGATE_FPRINT_DOUBLE(x,y) fprintf(superTestInstance.output_stream, "%s%f%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #define CESTER_DELEGATE_FPRINT_DOUBLE_2(x,y) fprintf(superTestInstance.output_stream, "%s%.2f%s", CESTER_SELECTCOLOR(x), y, CESTER_SELECTCOLOR(CESTER_RESET_TERMINAL)) #endif #endif static __CESTER_INLINE__ void cester_print_version(void) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "cester v"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), CESTER_VERSION); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " by "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), CESTER_AUTHOR); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ".\n"); } static __CESTER_INLINE__ void cester_print_help(void) { char *file_name = cester_extract_name_only(superTestInstance.test_file_path); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), CESTER_LICENSE); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nUsage: ./"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), file_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " [--FLAGS] [ARGS...]\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nwhere --FLAGS include:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-verbose-level=[LEVEL] change how much information is printed in the terminal\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-minimal print minimal info into the output stream\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-verbose print as much info as possible into the output stream\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-nocolor do not print info with coloring\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-singleoutput display cester version and exit. Does not report flag error\n"); #ifndef CESTER_NO_MEM_TEST CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-nomemtest disable memory leak detection in the tests\n"); #endif #ifndef CESTER_NO_STREAM_CAPTURE CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-nostreamcapture disable stream capture and assertions in the tests\n"); #endif #ifdef __CESTER_STDC_VERSION__ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-noisolation run all the test on a single process. Prevents recovery from crash.\n"); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-printversion display cester version before running the tests\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-dontformatname leave the test case name as declared in the source file in the output\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-test=Test1,... run only selected tests. Seperate the test cases by comma\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-output=[FORMAT] change the format in which the test results are printed\n"); #ifndef CESTER_NO_PRINT_INFO CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-info=[IOPTIONS],[IOPTIONS...] print out all or specific information about the test executablle\n"); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-version display cester version and exit\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " --cester-help display this help info version and exit\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "See https://exoticlibraries.github.io/libcester/docs/options.html for more details\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nSupported output formats. [FORMAT]:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " text\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " junitxml\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " tap\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " tapV13\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nSupported info options. [IOPTIONS]:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " all\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " options\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " comments\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " before_all\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " before_each\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " before*\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " after_all\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " after_each\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " after*\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test_skip\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test_todo\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test*\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nVerbose levels. [LEVEL]:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " 0 - No information alias of --cester-minimal\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " 1,2\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " 3 - Meaningful information\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " 4,5,6,7,8,9\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " 10 - Meaningful informations + garbage alias of --cester-verbose\n"); cester_meta_free(file_name); } static void cester_print_test_case_message(char const* const type, char const* const message, char const* const file_path, unsigned const line_num) { char *cleaned_name = (char *) (superTestInstance.verbose_level >= 4 ? file_path : cester_extract_name(file_path) ); if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, type); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " "); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, cleaned_name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_int(&(superTestInstance.current_test_case)->execution_output, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " in '"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, (superTestInstance.current_test_case)->name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "': "); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, message); } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void cester_print_assertion(char const* const expression, char const* const file_path, unsigned const line_num) { char *cleaned_name = (char *) (superTestInstance.verbose_level >= 4 ? file_path : cester_extract_name(file_path) ); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, cleaned_name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_int(&(superTestInstance.current_test_case)->execution_output, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " in '"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, (superTestInstance.current_test_case)->name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " expr => '"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, expression); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void cester_print_expect_actual(unsigned expecting, char const* const expect, char const* const received, char const* const file_path, unsigned const line_num) { char *cleaned_name = (char *) (superTestInstance.verbose_level >= 4 ? file_path : cester_extract_name(file_path) ); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, cleaned_name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_int(&(superTestInstance.current_test_case)->execution_output, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " in '"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, (superTestInstance.current_test_case)->name); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "' =>"); if (expecting == 0) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " not expecting "); } else { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " expected "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, expect); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ", received "); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, received); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "'"); } /*CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), (superTestInstance.verbose_level >= 4 ? file_path : cester_extract_name(file_path) )); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ":"); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_YELLOW), line_num); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ":"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " in '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), (superTestInstance.current_test_case)->name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "' =>"); if (expecting == 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " not expecting "); } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " expected "); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), received); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ", received "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), expect);*/ if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } } #ifndef CESTER_NO_TIME static __CESTER_INLINE__ void print_test_result(double time_spent) { #else static __CESTER_INLINE__ void print_test_result(void) { #endif unsigned cached_total_failed_tests_count = superTestInstance.total_failed_tests_count; CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\nRan "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_WHITE), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test(s) in "); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_WHITE), (time_spent > 60 ? (time_spent / 60) : time_spent) ); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), (time_spent > 60 ? " Minutes\n" : " Seconds\n" )); #else CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " test(s)\n"); #endif superTestInstance.total_failed_tests_count = superTestInstance.current_execution_status == CESTER_RESULT_SUCCESS && superTestInstance.total_failed_tests_count == 0 ? 0 : 1; CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "Synthesis: "); if (superTestInstance.report_success_regardless == 1) { CESTER_DELEGATE_FPRINT_STR(CESTER_FOREGROUND_GREEN, "SUCCESS"); } else if (superTestInstance.report_failure_regardless == 1) { CESTER_DELEGATE_FPRINT_STR(CESTER_FOREGROUND_RED, "FAILURE"); } else { CESTER_DELEGATE_FPRINT_STR(CESTER_GET_RESULT_AGGR_COLOR, CESTER_GET_RESULT_AGGR); } superTestInstance.total_failed_tests_count = cached_total_failed_tests_count; CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " Tests: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_YELLOW), CESTER_TOTAL_TESTS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " | Passing: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GREEN), CESTER_TOTAL_PASSED_TESTS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " | Failing: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_RED), CESTER_TOTAL_FAILED_TESTS_COUNT); if (CESTER_TOTAL_TEST_ERRORS_COUNT > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " | Errors: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_RED), CESTER_TOTAL_TEST_ERRORS_COUNT); } if (CESTER_TOTAL_TESTS_SKIPPED > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " | Skipped: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_YELLOW), CESTER_TOTAL_TESTS_SKIPPED); } if (CESTER_TOTAL_TODO_TESTS > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), " | Todo: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_YELLOW), CESTER_TOTAL_TODO_TESTS); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); if (superTestInstance.report_failure_regardless == 1 || superTestInstance.report_success_regardless == 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Avoid using the CESTER_REPORT_*_REGARDLESS macros, they hides the actual result of the test\n"); } } static __CESTER_INLINE__ void print_test_case_result(TestCase* test_case) { char *cleaned_name = (superTestInstance.format_test_name == 1 ? cester_str_replace(test_case->name, '_', ' ') : test_case->name ); #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) unsigned print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_GRAY; #else char* print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_GRAY; #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " "); if (test_case->test_type == CESTER_NORMAL_TODO_TEST || test_case->test_type == CESTER_NORMAL_SKIP_TEST) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "o "); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "("); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_GRAY), (test_case->execution_time > 60 ? (test_case->execution_time / 60) : test_case->execution_time)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), (test_case->execution_time > 60 ? "m" : "s")); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), ") "); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), cleaned_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), (test_case->test_type == CESTER_NORMAL_TODO_TEST ? " TODO " : " SKIP ")); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); } else { if (test_case->execution_status == CESTER_RESULT_SUCCESS) { #ifdef _WIN32 CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GREEN), "+ "); #else #ifdef __CESTER_STDC_VERSION__ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GREEN), "\u2713 "); #else CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GREEN), "+ "); #endif #endif } else { #ifdef _WIN32 CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "- "); #else #ifdef __CESTER_STDC_VERSION__ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "X "); #else CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "- "); #endif #endif print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_RED; } #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((print_color), "("); CESTER_DELEGATE_FPRINT_DOUBLE_2((print_color), (test_case->execution_time > 60 ? (test_case->execution_time / 60) : test_case->execution_time)); CESTER_DELEGATE_FPRINT_STR((print_color), (test_case->execution_time > 60 ? "m" : "s")); CESTER_DELEGATE_FPRINT_STR((print_color), ") "); #endif CESTER_DELEGATE_FPRINT_STR((print_color), cleaned_name); CESTER_DELEGATE_FPRINT_STR((print_color), "\n"); } if (superTestInstance.format_test_name == 1) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void print_test_case_outputs(TestCase* test_case) { char *cleaned_name = (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path) ); if (test_case->execution_status == CESTER_RESULT_SEGFAULT || test_case->execution_status == CESTER_RESULT_TERMINATED) { if (test_case->execution_status == CESTER_RESULT_SEGFAULT) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "SegfaultError "); } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "PrematureTermination "); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), cleaned_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ":"); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_WHITE), test_case->line_num); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ": "); if (test_case->execution_status == CESTER_RESULT_SEGFAULT) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "Segmentation fault "); } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "Premature Termination "); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "in '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), test_case->name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "' \n"); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), test_case->execution_output); if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void write_testcase_tap(TestCase *a_test_case, char* file_name, int index) { char *cleaned_name = (superTestInstance.format_test_name == 1 ? cester_str_replace(a_test_case->name, '_', ' ') : a_test_case->name ); #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) unsigned print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_YELLOW; #else char* print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_YELLOW; #endif if (a_test_case->execution_status == CESTER_RESULT_SUCCESS || a_test_case->test_type == CESTER_NORMAL_SKIP_TEST || a_test_case->test_type == CESTER_NORMAL_TODO_TEST) { if (a_test_case->execution_status == CESTER_RESULT_SUCCESS) { print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_GREEN; } CESTER_DELEGATE_FPRINT_STR((print_color), "ok "); } else { print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_RED; CESTER_DELEGATE_FPRINT_STR((print_color), "not ok "); } CESTER_DELEGATE_FPRINT_INT((print_color), index); CESTER_DELEGATE_FPRINT_STR((print_color), " - "); if (a_test_case->test_type == CESTER_NORMAL_SKIP_TEST) { CESTER_DELEGATE_FPRINT_STR((print_color), "# SKIP "); } else if (a_test_case->test_type == CESTER_NORMAL_TODO_TEST) { CESTER_DELEGATE_FPRINT_STR((print_color), "# TODO "); } CESTER_DELEGATE_FPRINT_STR((print_color), cleaned_name); CESTER_DELEGATE_FPRINT_STR((print_color), ", "); switch (a_test_case->execution_status) { case CESTER_RESULT_SUCCESS: CESTER_DELEGATE_FPRINT_STR((print_color), "Passed"); break; case CESTER_RESULT_SEGFAULT: CESTER_DELEGATE_FPRINT_STR((print_color), "Failed: Segmentation fault "); break; case CESTER_RESULT_TERMINATED: CESTER_DELEGATE_FPRINT_STR((print_color), "Failed: Premature Termination "); break; case CESTER_RESULT_UNRELEASED_STREAM: CESTER_DELEGATE_FPRINT_STR((print_color), "Failed: Unreleased Stream "); break; #ifndef CESTER_NO_MEM_TEST case CESTER_RESULT_MEMORY_LEAK: CESTER_DELEGATE_FPRINT_STR((print_color), "Failed: Memory leak"); break; #endif default: if (a_test_case->test_type != CESTER_NORMAL_SKIP_TEST && a_test_case->test_type != CESTER_NORMAL_TODO_TEST) { CESTER_DELEGATE_FPRINT_STR((print_color), "Failed"); } break; } CESTER_DELEGATE_FPRINT_STR((print_color), "\n"); if (superTestInstance.verbose_level >= 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); } if (superTestInstance.format_test_name == 1) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void write_testcase_tap_v13(TestCase *a_test_case, char* file_name, int index) { char *cleaned_name = (superTestInstance.format_test_name == 1 ? cester_str_replace(a_test_case->name, '_', ' ') : a_test_case->name ); char *clean_file_path = (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path)); #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) unsigned print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_YELLOW; #else char* print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_YELLOW; #endif if (a_test_case->execution_status == CESTER_RESULT_SUCCESS || a_test_case->test_type == CESTER_NORMAL_SKIP_TEST || a_test_case->test_type == CESTER_NORMAL_TODO_TEST) { if (a_test_case->execution_status == CESTER_RESULT_SUCCESS) { print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_GREEN; } CESTER_DELEGATE_FPRINT_STR((print_color), "ok "); } else { print_color = __CESTER_CAST_CHAR_ARRAY__ CESTER_FOREGROUND_RED; CESTER_DELEGATE_FPRINT_STR((print_color), "not ok "); } CESTER_DELEGATE_FPRINT_INT((print_color), index); CESTER_DELEGATE_FPRINT_STR((print_color), " - "); if (a_test_case->test_type == CESTER_NORMAL_SKIP_TEST) { CESTER_DELEGATE_FPRINT_STR((print_color), "# SKIP "); } else if (a_test_case->test_type == CESTER_NORMAL_TODO_TEST) { CESTER_DELEGATE_FPRINT_STR((print_color), "# TODO "); } CESTER_DELEGATE_FPRINT_STR((print_color), cleaned_name); CESTER_DELEGATE_FPRINT_STR((print_color), "\n"); if (superTestInstance.verbose_level >= 1 && a_test_case->test_type != CESTER_NORMAL_SKIP_TEST && a_test_case->test_type != CESTER_NORMAL_TODO_TEST) { if (a_test_case->execution_status == CESTER_RESULT_SUCCESS && superTestInstance.verbose_level == 0) { if (superTestInstance.format_test_name == 1) { cester_meta_free(cleaned_name); } return; } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " ---\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " at:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " file: "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), clean_file_path); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n test_case: "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n line: "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), a_test_case->line_num); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n column: 1"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " outputs:\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " message: "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->name); switch (a_test_case->execution_status) { case CESTER_RESULT_SUCCESS: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " passed"); break; case CESTER_RESULT_SEGFAULT: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " failed: Segmentation fault "); break; case CESTER_RESULT_TERMINATED: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " failed: Premature termination "); break; case CESTER_RESULT_UNRELEASED_STREAM: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " failed: Unreleased stream "); break; #ifndef CESTER_NO_MEM_TEST case CESTER_RESULT_MEMORY_LEAK: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " failed: Memory leak"); break; #endif default: if (a_test_case->test_type != CESTER_NORMAL_SKIP_TEST && a_test_case->test_type != CESTER_NORMAL_TODO_TEST) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " failed"); } break; } #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n time: "); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_GRAY), a_test_case->execution_time); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "\n ...\n"); } if (superTestInstance.format_test_name == 1) { cester_meta_free(cleaned_name); } if (superTestInstance.verbose_level < 4) { cester_meta_free(clean_file_path); } } static __CESTER_INLINE__ void write_testcase_junitxml(TestCase *a_test_case, char* file_name) { char *clean_file_path = (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <testcase"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " classname="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), file_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " name="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), a_test_case->name); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " time="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_MAGENTA), a_test_case->execution_time); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); switch (a_test_case->execution_status) { case CESTER_RESULT_SUCCESS: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "/>\n"); break; case CESTER_RESULT_SEGFAULT: case CESTER_RESULT_TERMINATED: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n <failure"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " message="); if (a_test_case->execution_status == CESTER_RESULT_SEGFAULT) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"the test case crashed\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"SegmentationFault\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "SegfaultError "); } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"the test case was terminated\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"PrematureTermination\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "PrematureTermination "); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), clean_file_path); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), ":"); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), a_test_case->line_num); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), ": "); if (a_test_case->execution_status == CESTER_RESULT_SEGFAULT) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "Segmentation fault "); } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "Premature Termination "); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "in '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "' \n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </failure>\n </testcase>\n"); break; case CESTER_RESULT_UNRELEASED_STREAM: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n <failure"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " message="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"the test case failed to release captured streams\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"StreamCaptureError\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "\n </failure>\n </testcase>\n"); break; #ifndef CESTER_NO_MEM_TEST case CESTER_RESULT_MEMORY_LEAK: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n <failure"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " message="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"the test case leaks memory\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"MemoryLeakError\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "\n </failure>\n </testcase>\n"); break; #endif default: CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n <failure"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " message="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"the test case failed\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"TestFailed\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), a_test_case->execution_output); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </failure>\n </testcase>\n"); break; } if (superTestInstance.verbose_level < 4) { cester_meta_free(clean_file_path); } } #ifndef CESTER_NO_MEM_TEST static __CESTER_INLINE__ unsigned check_memory_allocated_for_functions(char *funcname1, char *funcname2, char *prefix, char **write_string) { unsigned mem_index; unsigned leaked_memory_count = 0; char *cleaned_name = (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path) ); if (superTestInstance.mem_test_active == 1) { CESTER_ARRAY_FOREACH(superTestInstance.mem_alloc_manager, mem_index, alloc_mem, { if ((funcname1 != CESTER_NULL && cester_string_equals((char*)((AllocatedMemory*)alloc_mem)->function_name, funcname1)) || (funcname2 != CESTER_NULL && cester_string_equals((char*)((AllocatedMemory*)alloc_mem)->function_name, funcname2))) { leaked_memory_count += 1; if (superTestInstance.current_test_case != CESTER_NULL) { cester_concat_str(write_string, prefix); cester_concat_str(write_string, "MemoryLeakError "); cester_concat_str(write_string, cleaned_name); cester_concat_str(write_string, ":"); cester_concat_int(write_string, ((AllocatedMemory*)alloc_mem)->line_num); cester_concat_str(write_string, ": "); cester_concat_str(write_string, "in '"); cester_concat_str(write_string, (char*)((AllocatedMemory*)alloc_mem)->function_name); if (superTestInstance.verbose_level >= 2) { cester_concat_str(write_string, "' => Memory allocated in line '"); cester_concat_int(write_string, ((AllocatedMemory*)alloc_mem)->line_num); cester_concat_str(write_string, "' not freed. Leaking '"); cester_concat_sizet(write_string, ((AllocatedMemory *)alloc_mem)->allocated_bytes); cester_concat_str(write_string, "' Bytes "); } cester_concat_str(write_string, "\n"); } } }) } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } return leaked_memory_count; } #endif /** Clean up all the super instance date and free all the allocated memories used by libcester super instance */ static void cester_cleanup_super_instance(void); static __CESTER_INLINE__ int cester_print_result(TestCase cester_test_cases[], TestInstance* test_instance) { unsigned index_sub, ret_val; unsigned i, index4, index5, index6, index7; char *prefix = (char *) ""; char *file_name = cester_extract_name_only(superTestInstance.test_file_path); #ifndef CESTER_NO_TIME clock_t tok; double time_spent; tok = clock(); time_spent = (double)(tok - superTestInstance.start_tic) / CLOCKS_PER_SEC; #endif if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_AFTER_ALL_TEST && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_AFTER_ALL_TEST; ((cester_test)cester_test_cases[i].test_function)(test_instance); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index4, test_case, { if (((TestCase*)test_case)->test_type == CESTER_AFTER_ALL_TEST && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_AFTER_ALL_TEST; ((cester_test)((TestCase*)test_case)->test_function)(test_instance); } }) if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1 || cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { prefix = (char *) "# "; } #ifndef CESTER_NO_MEM_TEST ret_val = check_memory_allocated_for_functions((char *)"CESTER_BEFORE_ALL", (char *)"CESTER_OPTIONS", prefix, &superTestInstance.main_execution_output); if (ret_val > 0) { superTestInstance.current_execution_status = CESTER_RESULT_MEMORY_LEAK; superTestInstance.total_test_errors_count += ret_val; } #endif if (superTestInstance.single_output_only == 0) { if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml") == 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "<?xml"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " version="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"1.0\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " encoding="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"UTF-8\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " ?>\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "<testsuite"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " tests="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_MAGENTA), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " failures="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_MAGENTA), superTestInstance.total_failed_tests_count); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " name="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), file_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " errors="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_MAGENTA), CESTER_TOTAL_TEST_ERRORS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " skipped="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_MAGENTA), CESTER_TOTAL_TESTS_SKIPPED + CESTER_TOTAL_TODO_TESTS); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " time="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_MAGENTA), time_spent); #endif CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_NORMAL_TEST && cester_test_cases[i].execution_status != CESTER_RESULT_UNKNOWN) { write_testcase_junitxml(&cester_test_cases[i], file_name); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index5, test_case, { if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST && ((TestCase*)test_case)->execution_status != CESTER_RESULT_UNKNOWN) { write_testcase_junitxml(((TestCase*)test_case), file_name); } }) CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "</testsuite>\n"); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_WHITE), 1); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), ".."); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_WHITE), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); index_sub = 1; if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if ((cester_test_cases[i].test_type == CESTER_NORMAL_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST)) { if (superTestInstance.selected_test_cases_size > 0 && cester_test_cases[i].execution_status == CESTER_RESULT_UNKNOWN) { continue; } write_testcase_tap(&cester_test_cases[i], file_name, index_sub); ++index_sub; } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index5, test_case, { if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) { if (superTestInstance.selected_test_cases_size > 0 && ((TestCase*)test_case)->execution_status == CESTER_RESULT_UNKNOWN) { continue; } write_testcase_tap(((TestCase*)test_case), file_name, index_sub); ++index_sub; } }) CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), superTestInstance.main_execution_output); if (superTestInstance.verbose_level >= 1) { if (CESTER_TOTAL_TEST_ERRORS_COUNT > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TEST_ERRORS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " total error(s) occured\n"); } if (CESTER_TOTAL_TODO_TESTS > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TODO_TESTS); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " todo test case(s) skipped\n"); } if (CESTER_TOTAL_TESTS_SKIPPED > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TESTS_SKIPPED); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " test case(s) skipped\n"); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# Failed "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_FAILED_TESTS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " of "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " tests\n# Time "); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_GRAY), (time_spent > 60 ? (time_spent / 60) : time_spent)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), (time_spent > 60 ? " Minutes\n" : " Seconds\n" )); #else CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " tests\n"); #endif } } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_CYAN), "TAP version 13"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_CYAN), "\n"); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_CYAN), 1); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_CYAN), ".."); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_CYAN), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_CYAN), "\n"); index_sub = 1; if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if ((cester_test_cases[i].test_type == CESTER_NORMAL_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST)) { if (superTestInstance.selected_test_cases_size > 0 && cester_test_cases[i].execution_status == CESTER_RESULT_UNKNOWN) { continue; } write_testcase_tap_v13(&cester_test_cases[i], file_name, index_sub); ++index_sub; } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index5, test_case, { if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) { if (superTestInstance.selected_test_cases_size > 0 && ((TestCase*)test_case)->execution_status == CESTER_RESULT_UNKNOWN) { continue; } write_testcase_tap_v13(((TestCase*)test_case), file_name, index_sub); ++index_sub; } }) CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), superTestInstance.main_execution_output); if (superTestInstance.verbose_level >= 1) { if (CESTER_TOTAL_TEST_ERRORS_COUNT > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TEST_ERRORS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " total error(s) occured\n"); } if (CESTER_TOTAL_TODO_TESTS > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TODO_TESTS); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " todo test case(s) skipped\n"); } if (CESTER_TOTAL_TESTS_SKIPPED > 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_TESTS_SKIPPED); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " test case(s) skipped\n"); } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), "# Failed "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), CESTER_TOTAL_FAILED_TESTS_COUNT); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " of "); CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_GRAY), (superTestInstance.selected_test_cases_size == 0 ? CESTER_TOTAL_TESTS_COUNT : CESTER_TOTAL_TESTS_RAN)); #ifndef CESTER_NO_TIME CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " tests\n# Time "); CESTER_DELEGATE_FPRINT_DOUBLE_2((CESTER_FOREGROUND_GRAY), (time_spent > 60 ? (time_spent / 60) : time_spent)); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), (time_spent > 60 ? " Minutes\n" : " Seconds\n" )); #else CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_GRAY), " tests\n"); #endif } } else { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (superTestInstance.selected_test_cases_size > 0 && cester_test_cases[i].execution_status != CESTER_RESULT_UNKNOWN) { print_test_case_result(&cester_test_cases[i]); } else if (((cester_test_cases[i].test_type == CESTER_NORMAL_TEST && cester_test_cases[i].execution_status != CESTER_RESULT_UNKNOWN) || (cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST)) && superTestInstance.selected_test_cases_size == 0) { print_test_case_result(&cester_test_cases[i]); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index6, test_case_delegate, { TestCase* test_case = (TestCase*) test_case_delegate; if (superTestInstance.selected_test_cases_size > 0 && test_case->execution_status != CESTER_RESULT_UNKNOWN) { print_test_case_result(test_case); } else if (((test_case->test_type == CESTER_NORMAL_TEST && test_case->execution_status != CESTER_RESULT_UNKNOWN) || (test_case->test_type == CESTER_NORMAL_TODO_TEST || test_case->test_type == CESTER_NORMAL_SKIP_TEST)) && superTestInstance.selected_test_cases_size == 0) { print_test_case_result(test_case); } }) CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_NORMAL_TEST && cester_test_cases[i].execution_status != CESTER_RESULT_UNKNOWN) { print_test_case_outputs(&cester_test_cases[i]); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index7, test_case_delegate1, { TestCase* test_case1 = (TestCase*) test_case_delegate1; if (test_case1->test_type == CESTER_NORMAL_TEST && test_case1->execution_status != CESTER_RESULT_UNKNOWN) { print_test_case_outputs(test_case1); } }) CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), superTestInstance.main_execution_output); #ifndef CESTER_NO_TIME print_test_result(time_spent); #else print_test_result(); #endif } } CESTER_RESET_TERMINAL_ATTR(); cester_cleanup_super_instance(); if (CESTER_TOTAL_FAILED_TESTS_COUNT != 0 && superTestInstance.current_execution_status == CESTER_RESULT_SUCCESS) { cester_meta_free(file_name); return CESTER_RESULT_FAILURE; } if (superTestInstance.report_success_regardless == 1) { cester_meta_free(file_name); return CESTER_RESULT_SUCCESS; } else if (superTestInstance.report_failure_regardless == 1) { cester_meta_free(file_name); return CESTER_RESULT_FAILURE; } cester_meta_free(file_name); return superTestInstance.current_execution_status; } /* Assertions, Tests */ /** Does nothing just an empty placeholder. Can be used in the CESTER_SKIP_TEST and CESTER_TODO_TEST when compiling with -ansi and -pedantic-errors flag */ #define cester_assert_nothing() /** Send the parameter into a black hole. */ #define cester_swallow(param) /** Compare two argument using the provided operator Prints the expression as in the source code \param w a value to compare to y \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y a value to compare to w \param z the expression to print in output */ #define cester_assert_cmp_msg(w,x,y,z) cester_evaluate_expression(w x y, z, __FILE__, __LINE__) /** Compare two argument using the provided operator Prints the expression as in the source code \param x a value to compare to z \param y the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param z a value to compare to x */ #define cester_assert_cmp(x,y,z) cester_assert_cmp_msg(x, y, z, "(" #x " " #y " " #z ")") /** Check if the expression evaluates to true. Prints the expression as in the source code. \param x the expression to check if true */ #define cester_assert_true(x) cester_assert_cmp_msg(x, ==, 1, "(" #x ")") /** Check if the expression evaluates to true. Prints the second argument to the macro as the expression in output. \param x the expression to check if true \param y the text to print out in output */ #define cester_assert_true_msg(x,y) cester_assert_cmp_msg(x, ==, 1, y) /** Check if the expression evaluates to false. Prints the expression as in the source code. \param x the expression to check if false */ #define cester_assert_false(x) cester_assert_cmp_msg(x, ==, 0, "(" #x ")") /** Check if the expression evaluates to false. Prints the second argument to the macro as the expression in output. \param x the expression to check if false \param y the text to print out in output */ #define cester_assert_false_msg(x,y) cester_assert_cmp_msg(x, ==, 0, y) /** Assertion macro that passes if an expression is CESTER_NULL. Prints the expression as in the source code. \param x the expression to check if it CESTER_NULL. */ #define cester_assert_null(x) cester_assert_cmp_msg(x, ==, CESTER_NULL, "(" #x ")") /** Assertion macro that passes if an expression is not CESTER_NULL. Prints the expression as in the source code. \param x the expression to check if it not CESTER_NULL. */ #define cester_assert_not_null(x) cester_assert_cmp_msg(x, !=, CESTER_NULL, "!(" #x ")") /** Assertion macro that passes if the two expression is equal. Prints the expression as in the source code \param x the first expression to compare \param y the second expression to compare to the first expression */ #define cester_assert_equal(x,y) cester_evaluate_expect_actual(x==y, 1, #x, #y, __FILE__, __LINE__) /** Assertion macro that passes if the two expression is not equal. Prints the expression as in the source code \param x the first expression to compare \param y the second expression to compare to the first expression */ #define cester_assert_not_equal(x,y) cester_evaluate_expect_actual(x!=y, 0, #x, #y, __FILE__, __LINE__) /** Compare two strings. If the comparison fails the test case is marked as failed. The advantage of this macro is that it display the actual values of the two strings. \param x a string to compare \param y another string to compare with the first string */ #define cester_assert_str_equal(x,y) cester_evaluate_expect_actual_str(x, y, #x, #y, 1, __FILE__, __LINE__) /** alias for cester_assert_str_equal */ #define cester_assert_str_eq cester_assert_str_equal /** Compare two strings. If the comparison passes the test case is marked as failed. The advantage of this macro is that it display the actual values of the two strings. \param x a string to compare \param y another string to compare with the first string */ #define cester_assert_str_not_equal(x,y) cester_evaluate_expect_actual_str(x, y, #x, #y, 0, __FILE__, __LINE__) /** alias for cester_assert_ptr_not_equal */ #define cester_assert_str_ne cester_assert_str_not_equal /** Compare two pointers. If the comparison fails the test case is marked as failed. The advantage of this macro is that it display the actual values of the two pointers. \param x a pointer to compare \param y another pointer to compare with the first pointer */ #define cester_assert_ptr_equal(x,y) cester_evaluate_expect_actual_ptr(x, y, #x, #y, 1, __FILE__, __LINE__) /** alias for cester_assert_ptr_equal */ #define cester_assert_ptr_eq cester_assert_ptr_equal /** Compare two pointers. If the comparison passes the test case is marked as failed. The advantage of this macro is that it display the actual values of the two pointers. \param x a pointer to compare \param y another pointer to compare with the first pointer */ #define cester_assert_ptr_not_equal(x,y) cester_evaluate_expect_actual_ptr(x, y, #x, #y, 0, __FILE__, __LINE__) /** alias for cester_assert_ptr_not_equal */ #define cester_assert_ptr_ne cester_assert_ptr_not_equal /* document the following, add 'compile time only' */ #define __internal_cester_assert_cmp(w,x,y,z) (w x y, z, w, y, #x, __FILE__, __LINE__) #define __internal_cester_assert_eq(x,y,z) (CESTER_COMPARATOR_EQUAL, "expected " #z ",%s received " #z, y, x, "", __FILE__, __LINE__) #define __internal_cester_assert_ne(x,y,z) (CESTER_COMPARATOR_NOT_EQUAL, "not expecting " #z ",%s found " #z, x, y, "", __FILE__, __LINE__) #define __internal_cester_assert_gt(x,y,z) (CESTER_COMPARATOR_GREATER_THAN, "expected value to be greater than " #z ",%s received " #z, x, y, "", __FILE__, __LINE__) #define __internal_cester_assert_ge(x,y,z) (CESTER_COMPARATOR_GREATER_THAN_OR_EQUAL, "expected value to be greater than or equal to " #z ",%s received " #z, x, y, "", __FILE__, __LINE__) #define __internal_cester_assert_lt(x,y,z) (CESTER_COMPARATOR_LESSER_THAN, "expected value to be lesser than " #z ",%s received " #z, x, y, "", __FILE__, __LINE__) #define __internal_cester_assert_le(x,y,z) (CESTER_COMPARATOR_LESSER_THAN_OR_EQUAL, "expected value to be lesser than or equal to " #z ",%s received " #z, x, y, "", __FILE__, __LINE__) /** Compare two char using the provided operator This macro prints out the actual values of the two chars. \param w a char \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another char \param z the string formated for output */ #define cester_assert_cmp_char(w,x,y,z) CESTER_CONCAT(cester_compare_char_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two characters are the same. This macro prints out the actual values of the two characters. \param x a char \param y another char */ #define cester_assert_char_eq(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_eq(x,y,%c)) /** Check if the two char are not the same. This macro prints out the actual values of the two chars. \param x a char \param y another char */ #define cester_assert_char_ne(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_ne(x,y,%c)) /** Check if the a char is greater than the other. This macro prints out the actual values of the two chars. \param x a char \param y another char */ #define cester_assert_char_gt(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_gt(x,y,%c)) /** Check if the a char is greater than or equal to the other. This macro prints out the actual values of the two chars. \param x a char \param y another char */ #define cester_assert_char_ge(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_ge(x,y,%c)) /** Check if the a char is lesser than the other. This macro prints out the actual values of the two chars. \param x a char \param y another char */ #define cester_assert_char_lt(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_lt(x,y,%c)) /** Check if the a char is lesser than or equal to the other. This macro prints out the actual values of the two chars. \param x a char \param y another char */ #define cester_assert_char_le(x,y) CESTER_CONCAT(cester_compare_char, __internal_cester_assert_le(x,y,%c)) /** Compare two unsigned char using the provided operator This macro prints out the actual values of the two unsigned char. \param w an unsigned char \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another unsigned char \param z the string formated for output */ #define cester_assert_cmp_uchar(w,x,y,z) CESTER_CONCAT(cester_compare_uchar_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two unsigned char are the same. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_eq(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_eq(x,y,%c)) /** Check if the two unsigned char are not the same. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_ne(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_ne(x,y,%c)) /** Check if the a unsigned char is greater than the other. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_gt(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_gt(x,y,%c)) /** Check if the a unsigned char is greater than or equal to the other. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_ge(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_ge(x,y,%c)) /** Check if the a unsigned char is lesser than the other. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_lt(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_lt(x,y,%c)) /** Check if the a unsigned char is lesser than or equal to the other. This macro prints out the actual values of the two unsigned char. \param x an unsigned char \param y another unsigned char */ #define cester_assert_uchar_le(x,y) CESTER_CONCAT(cester_compare_uchar, __internal_cester_assert_le(x,y,%c)) /** Compare two short using the provided operator This macro prints out the actual values of the two short. \param w a short \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another short \param z the string formated for output */ #define cester_assert_cmp_short(w,x,y,z) CESTER_CONCAT(cester_compare_short_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two short are the same. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_eq(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_eq(x,y,%hi)) /** Check if the two short are not the same. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_ne(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_ne(x,y,%hi)) /** Check if the a short is greater than the other. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_gt(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_gt(x,y,%hi)) /** Check if the a short is greater than or equal to the other. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_ge(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_ge(x,y,%hi)) /** Check if the a short is lesser than the other. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_lt(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_lt(x,y,%hi)) /** Check if the a short is lesser than or equal to the other. This macro prints out the actual values of the two short. \param x a short \param y another short */ #define cester_assert_short_le(x,y) CESTER_CONCAT(cester_compare_short, __internal_cester_assert_le(x,y,%hi)) /** Compare two unsigned short using the provided operator This macro prints out the actual values of the two unsigned short. \param w an unsigned short \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another unsigned short \param z the string formated for output */ #define cester_assert_cmp_ushort(w,x,y,z) CESTER_CONCAT(cester_compare_ushort_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two unsigned short are the same. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_eq(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_eq(x,y,%hu)) /** Check if the two unsigned short are not the same. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_ne(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_ne(x,y,%hu)) /** Check if the a unsigned short is greater than the other. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_gt(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_gt(x,y,%hu)) /** Check if the a unsigned short is greater than or equal to the other. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_ge(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_ge(x,y,%hu)) /** Check if the a unsigned short is lesser than the other. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_lt(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_lt(x,y,%hu)) /** Check if the a unsigned short is lesser than or equal to the other. This macro prints out the actual values of the two unsigned short. \param x an unsigned short \param y another unsigned short */ #define cester_assert_ushort_le(x,y) CESTER_CONCAT(cester_compare_ushort, __internal_cester_assert_le(x,y,%hu)) /** Compare two int using the provided operator This macro prints out the actual values of the two int. \param w an int \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another int \param z the string formated for output */ #define cester_assert_cmp_int(w,x,y,z) CESTER_CONCAT(cester_compare_int_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two int are the same. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_eq(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_eq(x,y,%d)) /** Check if the two int are not the same. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_ne(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_ne(x,y,%d)) /** Check if the a int is greater than the other. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_gt(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_gt(x,y,%d)) /** Check if the a int is greater than or equal to the other. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_ge(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_ge(x,y,%d)) /** Check if the a int is lesser than the other. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_lt(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_lt(x,y,%d)) /** Check if the a int is lesser than or equal to the other. This macro prints out the actual values of the two int. \param x an int \param y another int */ #define cester_assert_int_le(x,y) CESTER_CONCAT(cester_compare_int, __internal_cester_assert_le(x,y,%d)) /** Compare two unsigned int using the provided operator This macro prints out the actual values of the two unsigned int. \param w an unsigned int \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another unsigned int \param z the string formated for output */ #define cester_assert_cmp_uint(w,x,y,z) CESTER_CONCAT(cester_compare_uint_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two unsigned int are the same. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_eq(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_eq(x,y,%u)) /** Check if the two unsigned int are not the same. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_ne(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_ne(x,y,%u)) /** Check if the a unsigned int is greater than the other. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_gt(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_gt(x,y,%u)) /** Check if the a unsigned int is greater than or equal to the other. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_ge(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_ge(x,y,%u)) /** Check if the a unsigned int is lesser than the other. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_lt(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_lt(x,y,%u)) /** Check if the a unsigned int is lesser than or equal to the other. This macro prints out the actual values of the two unsigned int. \param x an unsigned int \param y another unsigned int */ #define cester_assert_uint_le(x,y) CESTER_CONCAT(cester_compare_uint, __internal_cester_assert_le(x,y,%u)) /** Compare two long using the provided operator This macro prints out the actual values of the two long. \param w a long \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another long \param z the string formated for output */ #define cester_assert_cmp_long(w,x,y,z) CESTER_CONCAT(cester_compare_long_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two long are the same. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_eq(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_eq(x,y,%li)) /** Check if the two long are not the same. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_ne(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_ne(x,y,%li)) /** Check if the a long is greater than the other. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_gt(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_gt(x,y,%li)) /** Check if the a long is greater than or equal to the other. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_ge(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_ge(x,y,%li)) /** Check if the a long is lesser than the other. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_lt(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_lt(x,y,%li)) /** Check if the a long is lesser than or equal to the other. This macro prints out the actual values of the two long. \param x a long \param y another long */ #define cester_assert_long_le(x,y) CESTER_CONCAT(cester_compare_long, __internal_cester_assert_le(x,y,%li)) /** Compare two unsigned long using the provided operator This macro prints out the actual values of the two unsigned long. \param w a unsigned long \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another unsigned long \param z the string formated for output */ #define cester_assert_cmp_ulong(w,x,y,z) CESTER_CONCAT(cester_compare_ulong_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two unsigned long are the same. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_eq(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_eq(x,y,%lu)) /** Check if the two unsigned long are not the same. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_ne(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_ne(x,y,%lu)) /** Check if the a unsigned long is greater than the other. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_gt(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_gt(x,y,%lu)) /** Check if the a unsigned long is greater than or equal to the other. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_ge(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_ge(x,y,%lu)) /** Check if the a unsigned long is lesser than the other. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_lt(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_lt(x,y,%lu)) /** Check if the a unsigned long is lesser than or equal to the other. This macro prints out the actual values of the two unsigned long. \param x a unsigned long \param y another unsigned long */ #define cester_assert_ulong_le(x,y) CESTER_CONCAT(cester_compare_ulong, __internal_cester_assert_le(x,y,%lu)) /** Compare two long long using the provided operator This macro prints out the actual values of the two long long. \param w a long long \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another long long \param z the string formated for output */ #define cester_assert_cmp_llong(w,x,y,z) CESTER_CONCAT(cester_compare_llong_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two long long are the same. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_eq(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_eq(x,y,%li)) #else #define cester_assert_llong_eq(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_eq(x,y,%lli)) #endif /** Check if the two long long are not the same. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_ne(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ne(x,y,%li)) #else #define cester_assert_llong_ne(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ne(x,y,%lli)) #endif /** Check if the a long long is greater than the other. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_gt(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_gt(x,y,%li)) #else #define cester_assert_llong_gt(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_gt(x,y,%lli)) #endif /** Check if the a long long is greater than or equal to the other. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_ge(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ge(x,y,%li)) #else #define cester_assert_llong_ge(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ge(x,y,%lli)) #endif /** Check if the a long long is lesser than the other. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_lt(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_lt(x,y,%li)) #else #define cester_assert_llong_lt(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_lt(x,y,%lli)) #endif /** Check if the a long long is lesser than or equal to the other. This macro prints out the actual values of the two long long. \param x a long long \param y another long long */ #ifndef __CESTER_STDC_VERSION__ #define cester_assert_llong_le(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ge(x,y,%li)) #else #define cester_assert_llong_le(x,y) CESTER_CONCAT(cester_compare_llong, __internal_cester_assert_ge(x,y,%lli)) #endif /** Compare two unsigned long long using the provided operator This macro prints out the actual values of the two unsigned long long. \param w a unsigned long long \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another unsigned long long \param z the string formated for output */ #define cester_assert_cmp_ullong(w,x,y,z) CESTER_CONCAT(cester_compare_ullong_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two unsigned long long are the same. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_eq(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_eq(x,y,%llu)) /** Check if the two unsigned long long are not the same. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_ne(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_ne(x,y,%llu)) /** Check if the a unsigned long long is greater than the other. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_gt(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_gt(x,y,%llu)) /** Check if the a unsigned long long is greater than or equal to the other. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_ge(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_ge(x,y,%llu)) /** Check if the a unsigned long long is lesser than the other. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_lt(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_lt(x,y,%llu)) /** Check if the a unsigned long long is lesser than or equal to the other. This macro prints out the actual values of the two unsigned long long. \param x a unsigned long long \param y another unsigned long long */ #define cester_assert_ullong_le(x,y) CESTER_CONCAT(cester_compare_ullong, __internal_cester_assert_le(x,y,%llu)) /** Compare two float using the provided operator This macro prints out the actual values of the two float. \param w a float \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another float \param z the string formated for output */ #define cester_assert_cmp_float(w,x,y,z) CESTER_CONCAT(cester_compare_float_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two float are the same. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_eq(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_eq(x,y,%f)) /** Check if the two float are not the same. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_ne(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_ne(x,y,%f)) /** Check if the a float is greater than the other. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_gt(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_gt(x,y,%f)) /** Check if the a float is greater than or equal to the other. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_ge(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_ge(x,y,%f)) /** Check if the a float is lesser than the other. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_lt(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_lt(x,y,%f)) /** Check if the a float is lesser than or equal to the other. This macro prints out the actual values of the two float. \param x a float \param y another float */ #define cester_assert_float_le(x,y) CESTER_CONCAT(cester_compare_float, __internal_cester_assert_le(x,y,%f)) /** Compare two double using the provided operator This macro prints out the actual values of the two double. \param w a double \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another double \param z the string formated for output */ #define cester_assert_cmp_double(w,x,y,z) CESTER_CONCAT(cester_compare_double_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two double are the same. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_eq(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_eq(x,y,%lf)) /** Check if the two double are not the same. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_ne(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_ne(x,y,%lf)) /** Check if the a double is greater than the other. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_gt(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_gt(x,y,%lf)) /** Check if the a double is greater than or equal to the other. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_ge(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_ge(x,y,%lf)) /** Check if the a double is lesser than the other. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_lt(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_lt(x,y,%lf)) /** Check if the a double is lesser than or equal to the other. This macro prints out the actual values of the two double. \param x a double \param y another double */ #define cester_assert_double_le(x,y) CESTER_CONCAT(cester_compare_double, __internal_cester_assert_le(x,y,%lf)) /** Compare two long double using the provided operator This macro prints out the actual values of the two long double. \param w a long double \param x the operator to use for the comparison. One of ==, !=, <, >, <=, >= \param y another long double \param z the string formated for output */ #define cester_assert_cmp_ldouble(w,x,y,z) CESTER_CONCAT(cester_compare_ldouble_pre_evaluated, __internal_cester_assert_cmp(w,x,y,z)) /** Check if the two long double are the same. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_eq(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_eq(x,y,%e)) /** Check if the two long double are not the same. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_ne(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_ne(x,y,%e)) /** Check if the a long double is greater than the other. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_gt(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_gt(x,y,%e)) /** Check if the a long double is greater than or equal to the other. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_ge(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_ge(x,y,%e)) /** Check if the a long double is lesser than the other. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_lt(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_lt(x,y,%e)) /** Check if the a long double is lesser than or equal to the other. This macro prints out the actual values of the two long double. \param x a long double \param y another long double */ #define cester_assert_ldouble_le(x,y) CESTER_CONCAT(cester_compare_ldouble, __internal_cester_assert_le(x,y,%e)) static __CESTER_INLINE__ void cester_evaluate_expression(unsigned eval_result, char const* const expression, char const* const file_path, unsigned const line_num) { if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } if (eval_result == 0) { superTestInstance.current_execution_status = CESTER_RESULT_FAILURE; cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "EvaluationError "); } else if (superTestInstance.verbose_level >= 1 && superTestInstance.print_error_only == 0) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "Passed "); } /*my brain failed to work in this if condition. I beleive the if condition can be simplified*/ if ((superTestInstance.verbose_level >= 1 || eval_result == 0) && ((superTestInstance.print_error_only == 1 && eval_result == 0) || superTestInstance.print_error_only == 0)) { cester_print_assertion(expression, file_path, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "\n"); } } static __CESTER_INLINE__ void cester_evaluate_expect_actual(unsigned eval_result, unsigned expecting, char const* const expected, char const* const actual, char const* const file_path, unsigned const line_num) { if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } if (eval_result == 0) { superTestInstance.current_execution_status = CESTER_RESULT_FAILURE; cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "AssertionError "); } else if (superTestInstance.verbose_level >= 1 && superTestInstance.print_error_only == 0) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "Passed "); } if ((superTestInstance.verbose_level >= 1 || eval_result == 0) && ((superTestInstance.print_error_only == 1 && eval_result == 0) || superTestInstance.print_error_only == 0)) { cester_print_expect_actual(expecting, expected, actual, file_path, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "\n"); } } static __CESTER_INLINE__ void cester_evaluate_expect_actual_str(char const* const expected_in, char const* const actual_in, char const* const expected_expr, char const* const actual_expr, unsigned expecting, char const* const file_path, unsigned const line_num) { unsigned eval_result; char *expected; char *actual; expected = (char*) ""; actual = (char*) ""; eval_result = cester_string_equals((char*)expected_in, (char*)actual_in); if (superTestInstance.verbose_level >= 3) { cester_concat_str(&expected, expected_expr); cester_concat_str(&actual, actual_expr); cester_concat_char(&expected, '='); cester_concat_char(&actual, '='); } cester_concat_str(&expected, expected_in); cester_concat_str(&actual, actual_in); if (eval_result != expecting) { superTestInstance.current_execution_status = CESTER_RESULT_FAILURE; if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "AssertionError "); } else if (superTestInstance.verbose_level >= 1 && superTestInstance.print_error_only == 0) { if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "Passed "); } if ((superTestInstance.verbose_level >= 1 || eval_result != expecting) && ((superTestInstance.print_error_only == 1 && eval_result != expecting) || superTestInstance.print_error_only == 0)) { cester_print_expect_actual(expecting, expected, actual, file_path, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "\n"); } cester_meta_free(expected); cester_meta_free(actual); } static __CESTER_INLINE__ void cester_evaluate_expect_actual_ptr(void* ptr1, void* ptr2, char const* const expected_expr, char const* const actual_expr, unsigned expecting, char const* const file_path, unsigned const line_num) { unsigned eval_result; char *expected; char *actual; eval_result = ptr1 == ptr2; if (superTestInstance.verbose_level >= 3) { expected = (char*) ""; actual = (char*) ""; cester_concat_str(&expected, expected_expr); cester_concat_str(&actual, actual_expr); cester_concat_char(&expected, '='); cester_concat_char(&actual, '='); cester_concat_ptr(&expected, ptr1); cester_concat_ptr(&actual, ptr2); } else { cester_ptr_to_str(&expected, ptr1); cester_ptr_to_str(&actual, ptr2); } if (eval_result != expecting) { superTestInstance.current_execution_status = CESTER_RESULT_FAILURE; if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "AssertionError "); } else if (superTestInstance.verbose_level >= 1 && superTestInstance.print_error_only == 0) { if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "# "); } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, " - "); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "Passed "); } if ((superTestInstance.verbose_level >= 1 || eval_result != expecting) && ((superTestInstance.print_error_only == 1 && eval_result != expecting) || superTestInstance.print_error_only == 0)) { cester_print_expect_actual(expecting, expected, actual, file_path, line_num); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "\n"); } cester_meta_free(expected); cester_meta_free(actual); } /* Use the cester_assertion_caparator type to determine what comparission operation to perform on the two values */ #define CESTER_INTERNAL_EVALUATE(comparator_type, x, y, result) {\ if (comparator_type == CESTER_COMPARATOR_EQUAL) {\ result = (x == y);\ } else if (comparator_type == CESTER_COMPARATOR_NOT_EQUAL) {\ result = (x != y);\ } else if (comparator_type == CESTER_COMPARATOR_GREATER_THAN) {\ result = (x > y);\ } else if (comparator_type == CESTER_COMPARATOR_GREATER_THAN_OR_EQUAL) {\ result = (x >= y);\ } else if (comparator_type == CESTER_COMPARATOR_LESSER_THAN) {\ result = (x < y);\ } else if (comparator_type == CESTER_COMPARATOR_LESSER_THAN_OR_EQUAL) {\ result = (x <= y);\ } else {\ result = (x == y);\ }\ } static __CESTER_INLINE__ void cester_compare_char_pre_evaluated(int eval_result, char const* const expr, char first, char second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_char(enum cester_assertion_caparator comparator_type, char const* const expr, char first, char second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_char_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_uchar_pre_evaluated(int eval_result, char const* const expr, unsigned char first, unsigned char second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_uchar(enum cester_assertion_caparator comparator_type, char const* const expr, unsigned char first, unsigned char second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_uchar_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_int_pre_evaluated(int eval_result, char const* const expr, int first, int second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_int(enum cester_assertion_caparator comparator_type, char const* const expr, int first, int second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_int_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_uint_pre_evaluated(int eval_result, char const* const expr, unsigned int first, unsigned int second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_uint(enum cester_assertion_caparator comparator_type, char const* const expr, unsigned int first, unsigned int second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_uint_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_short_pre_evaluated(int eval_result, char const* const expr, short first, short second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_short(enum cester_assertion_caparator comparator_type, char const* const expr, short first, short second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_short_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ushort_pre_evaluated(int eval_result, char const* const expr, unsigned short first, unsigned short second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ushort(enum cester_assertion_caparator comparator_type, char const* const expr, unsigned short first, unsigned short second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_ushort_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_long_pre_evaluated(int eval_result, char const* const expr, long first, long second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_long(enum cester_assertion_caparator comparator_type, char const* const expr, long first, long second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_long_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ulong_pre_evaluated(int eval_result, char const* const expr, unsigned long first, unsigned long second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ulong(enum cester_assertion_caparator comparator_type, char const* const expr, unsigned long first, unsigned long second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_ulong_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_llong_pre_evaluated(int eval_result, char const* const expr, __CESTER_LONG_LONG__ first, __CESTER_LONG_LONG__ second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_llong(enum cester_assertion_caparator comparator_type, char const* const expr, __CESTER_LONG_LONG__ first, __CESTER_LONG_LONG__ second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_llong_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ullong_pre_evaluated(int eval_result, char const* const expr, unsigned __CESTER_LONG_LONG__ first, unsigned __CESTER_LONG_LONG__ second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ullong(enum cester_assertion_caparator comparator_type, char const* const expr, unsigned __CESTER_LONG_LONG__ first, unsigned __CESTER_LONG_LONG__ second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_ullong_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_float_pre_evaluated(int eval_result, char const* const expr, float first, float second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_float(enum cester_assertion_caparator comparator_type, char const* const expr, float first, float second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_float_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_double_pre_evaluated(int eval_result, char const* const expr, double first, double second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_double(enum cester_assertion_caparator comparator_type, char const* const expr, double first, double second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_double_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ldouble_pre_evaluated(int eval_result, char const* const expr, long double first, long double second, char const* const op, char const* const file_path, unsigned const line_num) { char expression[2048] = ""; cester_sprintf3(expression, 2048, expr, second, op, first); cester_evaluate_expression(eval_result, (char*)expression, file_path, line_num); } static __CESTER_INLINE__ void cester_compare_ldouble(enum cester_assertion_caparator comparator_type, char const* const expr, long double first, long double second, char const* const op, char const* const file_path, unsigned const line_num) { int eval_result = 0; CESTER_INTERNAL_EVALUATE(comparator_type, first, second, eval_result); cester_compare_ldouble_pre_evaluated(eval_result, expr, first, second, op, file_path, line_num); } #ifndef __CESTER_STDC_VERSION__ /** Create a test case, this uses the first arguments as the test case name and identifier and the body of the test. */ #define CESTER_TEST(x,y,z) static void cester_test_##x(TestInstance* y); /** Create a test case that has not been implemented, It is skipped and generates warning. This macro will print message in output to remind the developer of it implementation. Good for TDD. This uses the first arguments as the test case name and identifier and the body of the test. */ #define CESTER_TODO_TEST(x,y,z) static void cester_test_##x(TestInstance* y); /** Create a test case that is not run. This uses the first arguments as the test case name and identifier and the body of the test. */ #define CESTER_SKIP_TEST(x,y,z) static void cester_test_##x(TestInstance* y); /** The function that would be invoked once before running any test in the test file. You can only have one of this function in a test file. */ #define CESTER_BEFORE_ALL(x,y) void cester_before_all_test(TestInstance* x); /** The function that would be invoked before each test. You can only have one of this function in a test file. */ #define CESTER_BEFORE_EACH(w,x,y,z) void cester_before_each_test(TestInstance* w, char * const x, unsigned y); /** The function that would be invoked once after running all the tests in the test file. You can only have one of this function in a test file. */ #define CESTER_AFTER_ALL(x,y) void cester_after_all_test(TestInstance* x); /** The functions that would be invoked after each test is ran. You can only have one of this function in a test file. */ #define CESTER_AFTER_EACH(w,x,y,z) void cester_after_each_test(TestInstance* w, char * const x, unsigned y); /** Set the options for cester, anything in this macro will be executed before the tests starts running. */ #define CESTER_OPTIONS(x) void cester_options_before_main(void); /** Absorb the statements and logic in a test file before re including the __BASE_FILE__. This way code can be written in the global space of the test file. \note do not put other CESTER_ macros inside this one, this should contain only your C or C++ code. */ #define CESTER_BODY(x) /** A multiline comment macro everything in the macro is printed out at the beginning of the test. Comma in the content will cause issue in the macro expansion when the code is compiled with C version less than C99. It should not begin or end in quote, escape characters is expanded when printed out */ #define CESTER_COMMENT(x) void cester_test_file_comment_function(void); #ifndef CESTER_NO_MOCK /** Mock a function to just return a value. the first argument is the name of the function to mock, the second argument is the return type of the function, the third parameter is the value that is returned when the function is called. This still requires using the -Wl,--wrap option to wrap the parameter to override the initial function. E.g. if the function `multiply_by` is mocked the option `-Wl,--wrap=multiply_by` should be added during compilation. Th mocking features only works on GCC for now. */ #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,z) __attribute__((weak)) y x; y __real_##x; /** */ #define CESTER_MOCK_FUNCTION(x,y,z) __attribute__((weak)) y x; extern y __real_##x; #else #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,z) #define CESTER_MOCK_FUNCTION(x,y,z) #endif #else #define CESTER_TEST(x,y,...) static void cester_test_##x(TestInstance* y); #define CESTER_TODO_TEST(x,y,...) static void cester_test_##x(TestInstance* y); #define CESTER_SKIP_TEST(x,y,...) static void cester_test_##x(TestInstance* y); #define CESTER_BEFORE_ALL(x,...) void cester_before_all_test(TestInstance* x); #define CESTER_BEFORE_EACH(w,x,y,...) void cester_before_each_test(TestInstance* w, char * const x, unsigned y); #define CESTER_AFTER_ALL(x,...) void cester_after_all_test(TestInstance* x); #define CESTER_AFTER_EACH(w,x,y,...) void cester_after_each_test(TestInstance* w, char * const x, unsigned y); #define CESTER_OPTIONS(...) void cester_options_before_main(void); #define CESTER_BODY(...) #define CESTER_COMMENT(...) void cester_test_file_comment_function(void); #ifndef CESTER_NO_MOCK #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,...) __attribute__((weak)) y x; y __real_##x; #define CESTER_MOCK_FUNCTION(x,y,...) __attribute__((weak)) y x; extern y __real_##x; #else #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,...) #define CESTER_MOCK_FUNCTION(x,y,...) #endif #endif #ifdef __BASE_FILE__ #ifdef __cplusplus } #endif #include __BASE_FILE__ #ifdef __cplusplus extern "C" { #endif #else #endif #undef CESTER_TEST #undef CESTER_TODO_TEST #undef CESTER_SKIP_TEST #undef CESTER_BEFORE_ALL #undef CESTER_BEFORE_EACH #undef CESTER_AFTER_ALL #undef CESTER_AFTER_EACH #undef CESTER_OPTIONS #undef CESTER_BODY #undef CESTER_COMMENT #undef CESTER_MOCK_SIMPLE_FUNCTION #undef CESTER_MOCK_FUNCTION #ifdef __CESTER_STDC_VERSION__ #ifndef CESTER_NO_TIME #define CESTER_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TEST }, #define CESTER_TODO_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TODO_TEST }, #define CESTER_SKIP_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_SKIP_TEST }, #define CESTER_BEFORE_ALL(x,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_before_all_test", (cester_before_all_test), CESTER_NULL, CESTER_NULL, CESTER_BEFORE_ALL_TEST }, #define CESTER_BEFORE_EACH(w,x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) (char*) "", (char*) "cester_before_each_test", CESTER_NULL, (cester_before_each_test), CESTER_NULL, CESTER_BEFORE_EACH_TEST }, #define CESTER_AFTER_ALL(x,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_after_all_test", (cester_after_all_test), CESTER_NULL, CESTER_NULL, CESTER_AFTER_ALL_TEST }, #define CESTER_AFTER_EACH(w,x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_after_each_test", CESTER_NULL, (cester_after_each_test), CESTER_NULL, CESTER_AFTER_EACH_TEST }, #define CESTER_OPTIONS(...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_options_before_main", CESTER_NULL, CESTER_NULL, (cester_options_before_main), CESTER_OPTIONS_FUNCTION }, #define CESTER_COMMENT(...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_test_file_comment_function", CESTER_NULL, CESTER_NULL, (cester_test_file_comment_function), CESTER_TEST_FILE_COMMENT }, #else #define CESTER_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TEST }, #define CESTER_TODO_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TODO_TEST }, #define CESTER_SKIP_TEST(x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_SKIP_TEST }, #define CESTER_BEFORE_ALL(x,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_before_all_test", (cester_before_all_test), CESTER_NULL, CESTER_NULL, CESTER_BEFORE_ALL_TEST }, #define CESTER_BEFORE_EACH(w,x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) (char*) "", (char*) "cester_before_each_test", CESTER_NULL, (cester_before_each_test), CESTER_NULL, CESTER_BEFORE_EACH_TEST }, #define CESTER_AFTER_ALL(x,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_after_all_test", (cester_after_all_test), CESTER_NULL, CESTER_NULL, CESTER_AFTER_ALL_TEST }, #define CESTER_AFTER_EACH(w,x,y,...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_after_each_test", CESTER_NULL, (cester_after_each_test), CESTER_NULL, CESTER_AFTER_EACH_TEST }, #define CESTER_OPTIONS(...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_options_before_main", CESTER_NULL, CESTER_NULL, (cester_options_before_main), CESTER_OPTIONS_FUNCTION }, #define CESTER_COMMENT(...) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_test_file_comment_function", CESTER_NULL, CESTER_NULL, (cester_test_file_comment_function), CESTER_TEST_FILE_COMMENT }, #endif #define CESTER_BODY(...) #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,...) #define CESTER_MOCK_FUNCTION(x,y,...) #else #ifndef CESTER_NO_TIME #define CESTER_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TEST }, #define CESTER_TODO_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TODO_TEST }, #define CESTER_SKIP_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_SKIP_TEST }, #define CESTER_BEFORE_ALL(x,y) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_before_all_test", (cester_before_all_test), CESTER_NULL, CESTER_NULL, CESTER_BEFORE_ALL_TEST }, #define CESTER_BEFORE_EACH(w,x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) (char*) "", (char*) "cester_before_each_test", CESTER_NULL, (cester_before_each_test), CESTER_NULL, CESTER_BEFORE_EACH_TEST }, #define CESTER_AFTER_ALL(x,y) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_after_all_test", (cester_after_all_test), CESTER_NULL, CESTER_NULL, CESTER_AFTER_ALL_TEST }, #define CESTER_AFTER_EACH(w,x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_after_each_test", CESTER_NULL, (cester_after_each_test), CESTER_NULL, CESTER_AFTER_EACH_TEST }, #define CESTER_OPTIONS(x) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_options_before_main", CESTER_NULL, CESTER_NULL, (cester_options_before_main), CESTER_OPTIONS_FUNCTION }, #define CESTER_COMMENT(x) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, 0.000, 0.000, (char*) "", (char*) "cester_test_file_comment_function", CESTER_NULL, CESTER_NULL, (cester_test_file_comment_function), CESTER_TEST_FILE_COMMENT }, #else #define CESTER_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TEST }, #define CESTER_TODO_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_TODO_TEST }, #define CESTER_SKIP_TEST(x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) #x, (cester_test_##x), CESTER_NULL, CESTER_NULL, CESTER_NORMAL_SKIP_TEST }, #define CESTER_BEFORE_ALL(x,y) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_before_all_test", (cester_before_all_test), CESTER_NULL, CESTER_NULL, CESTER_BEFORE_ALL_TEST }, #define CESTER_BEFORE_EACH(w,x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) (char*) "", (char*) "cester_before_each_test", CESTER_NULL, (cester_before_each_test), CESTER_NULL, CESTER_BEFORE_EACH_TEST }, #define CESTER_AFTER_ALL(x,y) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_after_all_test", (cester_after_all_test), CESTER_NULL, CESTER_NULL, CESTER_AFTER_ALL_TEST }, #define CESTER_AFTER_EACH(w,x,y,z) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_after_each_test", CESTER_NULL, (cester_after_each_test), CESTER_NULL, CESTER_AFTER_EACH_TEST }, #define CESTER_OPTIONS(x) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_options_before_main", CESTER_NULL, CESTER_NULL, (cester_options_before_main), CESTER_OPTIONS_FUNCTION }, #define CESTER_COMMENT(x) { CESTER_RESULT_UNKNOWN, __LINE__, CESTER_RESULT_SUCCESS, (char*) "", (char*) "cester_test_file_comment_function", CESTER_NULL, CESTER_NULL, (cester_test_file_comment_function), CESTER_TEST_FILE_COMMENT }, #endif #define CESTER_BODY(x) #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,z) #define CESTER_MOCK_FUNCTION(x,y,z) #endif #ifdef __cplusplus } #endif static TestCase cester_test_cases[] = { #ifdef __BASE_FILE__ #include __BASE_FILE__ #endif #ifndef CESTER_NO_TIME { CESTER_RESULT_UNKNOWN, 0, CESTER_RESULT_SUCCESS, 0.000, 0.000, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_TESTS_TERMINATOR } #else { CESTER_RESULT_UNKNOWN, 0, CESTER_RESULT_SUCCESS, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_NULL, CESTER_TESTS_TERMINATOR } #endif }; #ifdef __cplusplus extern "C" { #endif #undef CESTER_TEST #undef CESTER_TODO_TEST #undef CESTER_SKIP_TEST #undef CESTER_BEFORE_ALL #undef CESTER_BEFORE_EACH #undef CESTER_AFTER_ALL #undef CESTER_AFTER_EACH #undef CESTER_OPTIONS #undef CESTER_BODY #undef CESTER_COMMENT #undef CESTER_MOCK_SIMPLE_FUNCTION #undef CESTER_MOCK_FUNCTION #ifdef __CESTER_STDC_VERSION__ #define CESTER_TEST(x,y,...) static void cester_test_##x(TestInstance* y) { __VA_ARGS__ } #define CESTER_TODO_TEST(x,y,...) static void cester_test_##x(TestInstance* y) { } #define CESTER_SKIP_TEST(x,y,...) static void cester_test_##x(TestInstance* y) { __VA_ARGS__ } #define CESTER_BEFORE_ALL(x,...) void cester_before_all_test(TestInstance* x) { __VA_ARGS__ CESTER_NO_ISOLATION(); } #define CESTER_BEFORE_EACH(w,x,y,...) void cester_before_each_test(TestInstance* w, char * const x, unsigned y) { __VA_ARGS__ CESTER_NO_ISOLATION(); } #define CESTER_AFTER_ALL(x,...) void cester_after_all_test(TestInstance* x) { __VA_ARGS__ CESTER_NO_ISOLATION(); } #define CESTER_AFTER_EACH(w,x,y,...) void cester_after_each_test(TestInstance* w, char * const x, unsigned y) { __VA_ARGS__ CESTER_NO_ISOLATION(); } #define CESTER_OPTIONS(...) void cester_options_before_main(void) { __VA_ARGS__ } #define CESTER_BODY(...) __VA_ARGS__ #define CESTER_COMMENT(...) void cester_test_file_comment_function(void) { if (cester_string_equals(superTestInstance.output_format, (char*) "text") == 1) { CESTER_DELEGATE_FPRINT_STR((cester_default_color), "\n"); CESTER_DELEGATE_FPRINT_STR((cester_default_color), #__VA_ARGS__); CESTER_DELEGATE_FPRINT_STR((cester_default_color), "\n"); } } #ifndef CESTER_NO_MOCK #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,...) y __wrap_##x { return __VA_ARGS__; } #define CESTER_MOCK_FUNCTION(x,y,...) y __wrap_##x { __VA_ARGS__ } #else #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,...) #define CESTER_MOCK_FUNCTION(x,y,...) #endif #else #define CESTER_TEST(x,y,z) static void cester_test_##x(TestInstance* y) { z } #define CESTER_TODO_TEST(x,y,z) static void cester_test_##x(TestInstance* y) { } #define CESTER_SKIP_TEST(x,y,z) static void cester_test_##x(TestInstance* y) { z } #define CESTER_BEFORE_ALL(x,y) void cester_before_all_test(TestInstance* x) { y CESTER_NO_ISOLATION(); } #define CESTER_BEFORE_EACH(w,x,y,z) void cester_before_each_test(TestInstance* w, char * const x, unsigned y) { z CESTER_NO_ISOLATION(); } #define CESTER_AFTER_ALL(x,y) void cester_after_all_test(TestInstance* x) { y CESTER_NO_ISOLATION(); } #define CESTER_AFTER_EACH(w,x,y,z) void cester_after_each_test(TestInstance* w, char * const x, unsigned y) { z CESTER_NO_ISOLATION(); } #define CESTER_OPTIONS(x) void cester_options_before_main(void) { x } #define CESTER_BODY(x) x #define CESTER_COMMENT(x) void cester_test_file_comment_function(void) { if (cester_string_equals(superTestInstance.output_format, (char*) "text") == 1) { CESTER_DELEGATE_FPRINT_STR((cester_default_color), "\n"); CESTER_DELEGATE_FPRINT_STR((cester_default_color), #x); CESTER_DELEGATE_FPRINT_STR((cester_default_color), "\n"); } } #ifndef CESTER_NO_MOCK #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,z) y __wrap_##x { return z; } #define CESTER_MOCK_FUNCTION(x,y,z) y __wrap_##x { z } #else #define CESTER_MOCK_SIMPLE_FUNCTION(x,y,z) #define CESTER_MOCK_FUNCTION(x,y,z) #endif #endif /** Manually register a test case in situation where the the test are not auto detected or selected test cases want to be run. If a test is registered manually all auto detected test will not be executed. */ #define CESTER_REGISTER_TEST(x) cester_register_test((char*)#x, (cester_test_##x), CESTER_NULL, CESTER_NULL, __LINE__, CESTER_NORMAL_TEST) /** Manually register a test case as a skip test which cases the test case not to run but it will be reported in result and logged under skipped tests. Reason for skipping a test can be unavailability of resources or any other reason. */ #define CESTER_REGISTER_SKIP_TEST(x) cester_register_test((char*)#x, (cester_test_##x), CESTER_NULL, CESTER_NULL, __LINE__, CESTER_NORMAL_SKIP_TEST) /** Manually register a test case that is yet to be implemented so it will be skipped but it will be reported in result and logged under todo tests. */ #define CESTER_REGISTER_TODO_TEST(x) cester_register_test((char*)#x, (cester_test_##x), CESTER_NULL, CESTER_NULL, __LINE__, CESTER_NORMAL_TODO_TEST) /** Manually notify cester to execute the BEFORE_ALL function to execute before all the test case are run. */ #define CESTER_REGISTER_BEFORE_ALL() cester_register_test("cester_before_all_test", (cester_before_all_test), CESTER_NULL, CESTER_NULL, __LINE__, CESTER_BEFORE_ALL_TEST) /** Manually notify cester to execute the BEFORE_EACH function to execute every time before a test case is run. */ #define CESTER_REGISTER_BEFORE_EACH() cester_register_test("cester_before_each_test", CESTER_NULL, (cester_before_each_test), CESTER_NULL, __LINE__, CESTER_BEFORE_EACH_TEST) /** Manually notify cester to execute the AFTER_ALL function to execute after all the test case are run. */ #define CESTER_REGISTER_AFTER_ALL() cester_register_test("cester_after_all_test", (cester_after_all_test), CESTER_NULL, CESTER_NULL, __LINE__, CESTER_AFTER_ALL_TEST) /** Manually notify cester to execute the AFTER_EACH function to execute every time after a test case is run. */ #define CESTER_REGISTER_AFTER_EACH() cester_register_test("cester_after_each_test", CESTER_NULL, (cester_after_each_test), CESTER_NULL, __LINE__, CESTER_AFTER_EACH_TEST) /** Manually notify cester to execute the CESTER_OPTIONS block before running the tests. */ #define CESTER_REGISTER_OPTIONS() cester_register_test("cester_options_before_main", CESTER_NULL, CESTER_NULL, (cester_options_before_main), __LINE__, CESTER_OPTIONS_FUNCTION) /** Manually notify cester to print the CESTER_COMMENT content before running the tests. */ #define CESTER_REGISTER_COMMENT() cester_register_test("cester_test_file_comment_function", CESTER_NULL, CESTER_NULL, (cester_test_file_comment_function), __LINE__, CESTER_OPTIONS_FUNCTION) /** Set the expected result of a test case. \param x the test case name \param y the expected result. Can be one of the ::cester_test_status enum */ #define CESTER_TEST_SHOULD(x,y) cester_expected_test_result(#x, y); /** Change the expected result of a test case to Segfault. If the test segfault then it passes. If it does not segfault it is marked as failed. \param x the test case name */ #define CESTER_TEST_SHOULD_SEGFAULT(x) CESTER_TEST_SHOULD(x, CESTER_RESULT_SEGFAULT); /** Change the expected result of a test case to failure. If the test case passed then it marked as failure. If it failed then it consider as passed. \param x the test case name */ #define CESTER_TEST_SHOULD_FAIL(x) CESTER_TEST_SHOULD(x, CESTER_RESULT_FAILURE); /** Change the expected test case result. If the test case is terminated by user or another program then it passes ortherwise it fails. \param x the test case name */ #define CESTER_TEST_SHOULD_BE_TERMINATED(x) CESTER_TEST_SHOULD(x, CESTER_RESULT_TERMINATED); /** Change the expected test case result. If the test case has any un released captured stream it passes. Dont ignore CESTER_RESULT_UNRELEASED_STREAM failure it can result in more erros in other test cases and will leave dangling pointers in memory with no way to tract and free them. \param x the test case name */ #define CESTER_TEST_SHOULD_NOT_RELEASE_STREAM(x) CESTER_TEST_SHOULD(x, CESTER_RESULT_UNRELEASED_STREAM); #ifndef CESTER_NO_MEM_TEST /** Change the expected test case result to leak memory. If the test case does not leak any memory then the test case is marked as failure. \param x the test case name */ #define CESTER_TEST_SHOULD_LEAK_MEMORY(x) CESTER_TEST_SHOULD(x, CESTER_RESULT_MEMORY_LEAK); #else #define CESTER_TEST_SHOULD_LEAK_MEMORY(x) #endif #if !defined(__unix__) && !defined(__unix) && !(defined(__APPLE__) && defined(__MACH__)) && !defined(_WIN32) #pragma message("Stream capture not supported on this platform, open an issue on the github repo with the platform details") #endif #ifndef CESTER_NO_STREAM_CAPTURE /** Change the folder to use to store the FILE handle for the captured streams. \param path1 the folder to used for captured stream \param fallback_path the secpnd folder to used for captured stream if path1 is CESTER_NULL */ static void cester_set_captured_streams_tmp_folder(char *path1, char *fallback_path) { struct stat st = {0}; if (path1) { superTestInstance.captured_streams_tmp_folder = path1; } else { superTestInstance.captured_streams_tmp_folder = fallback_path; } #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) || defined(_WIN32) if (mkdir(superTestInstance.captured_streams_tmp_folder, 0777) != 0 && stat(superTestInstance.captured_streams_tmp_folder, &st) == -1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to create the temp folder '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), superTestInstance.captured_streams_tmp_folder); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "' stream capture tests might fail\n"); } #endif } /** Change the folder to use to store the FILE handle for the captured streams. \param x the new folder to used for captured stream */ #define CESTER_CHANGE_STREAM_CAPTURE_TM_FOLDER(x) cester_set_captured_streams_tmp_folder(x, CESTER_NULL) /** Capture a FILE stream to test it behaviour in realtime. This simply opens a temporary file on the system then replaces the stream to capture with the temporary file. n the assertion functions the temporary file content is observed. To return the stream back to th original state call the cester_release_stream function. It important to release a stream immediately after assertions else any output to that stream will be capturd also. \param stream the stream to capture \param file_path the name of the file where the test case is written \param line_num the line number where the stream is being captured */ static void cester_capture_stream(FILE *stream, char const* const file_path, unsigned const line_num) { CapturedStream *captured_stream = (CapturedStream *) calloc(1, sizeof(CapturedStream)); char *replaced_stream_file_path = (char *) ""; FILE *replaced_stream = CESTER_NULL; struct stat st = {0}; if (superTestInstance.stream_capture_active == 0) return; if (superTestInstance.captured_streams == CESTER_NULL) { if (cester_array_init(&superTestInstance.captured_streams) == 0) { if (superTestInstance.output_stream==CESTER_NULL) { superTestInstance.output_stream = stdout; cester_ptr_to_str(&(superTestInstance.output_stream_str), stdout); superTestInstance.output_stream_address = *stdout; } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to initialize the captured stream array. Input and Output Stream test disabled.\n"); return; } } #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) || defined(_WIN32) if (stat(superTestInstance.captured_streams_tmp_folder, &st) == -1) { cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Unable to capture the stream because temp folder '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, superTestInstance.captured_streams_tmp_folder); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' cannot be created.\n"); return; } #else cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Unable to capture the stream because this platform "); cester_concat_str(&superTestInstance.current_test_case->execution_output, "is currently not supported, open an issue on the github "); cester_concat_str(&superTestInstance.current_test_case->execution_output, "repo with this platform detail.\n"); return; #endif cester_concat_str(&replaced_stream_file_path, superTestInstance.captured_streams_tmp_folder); cester_concat_str(&replaced_stream_file_path, "/"); cester_concat_ptr(&replaced_stream_file_path, stream); cester_concat_str(&replaced_stream_file_path, ".txt"); replaced_stream = fopen(replaced_stream_file_path, "w+"); if (!captured_stream || replaced_stream == CESTER_NULL) { cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Unable to capture the stream '"); cester_concat_ptr(&superTestInstance.current_test_case->execution_output, stream); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' due to memory allocation error, all assertion will fail for the stream.\n"); goto cester_capture_stream_cleanup; return; } captured_stream->line_num = line_num; captured_stream->original_stream = *stream; captured_stream->original_stream_handle = stream; captured_stream->replaced_stream_handle = replaced_stream; captured_stream->replaced_stream_file_path = replaced_stream_file_path; captured_stream->function_name = superTestInstance.current_test_case->name; captured_stream->stream_buffer = CESTER_NULL; cester_ptr_to_str(&(captured_stream->original_stream_ptr_str), stream); cester_ptr_to_str(&(captured_stream->replaced_stream_ptr_str), replaced_stream); if (cester_array_add(superTestInstance.captured_streams, captured_stream) == 0) { cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Unable to capture the stream '"); cester_concat_ptr(&superTestInstance.current_test_case->execution_output, stream); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' all assertion will fail for the stream.\n"); goto cester_capture_stream_cleanup; return; } *stream = *(captured_stream->replaced_stream_handle); return; cester_capture_stream_cleanup: if (replaced_stream != CESTER_NULL) { fclose(replaced_stream); if (remove(replaced_stream_file_path)) { cester_print_test_case_message("StreamCaptureCleanupWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Failed to delete residual stream file '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, replaced_stream_file_path); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' manually delete it from your file system.\n"); } } if (captured_stream) { cester_meta_free(captured_stream); } } /** Release a single captured stream and specify the stream to set back to it original state. Care needs to be taken when using this function because if a captured_stream is specified for a stream the captured_stream will be freed and the stream set to the captured_stream cached stream, so if the stream is not actually for the captured_stream the stream is forecver lost in the memory as the address is compltely dropped. \param stream the stream to release \param captured_stream the CapturedStream stream object \param file_path the name of the file where the test case is written \param line_num the line number where the stream is being released */ static void cester_release_captured_stream(FILE *stream, CapturedStream *captured_stream, char const* const file_path, unsigned const line_num) { if (superTestInstance.stream_capture_active == 0) return; if (stream != CESTER_NULL) { fflush(stream); fclose(captured_stream->replaced_stream_handle); if (remove(captured_stream->replaced_stream_file_path)) { cester_print_test_case_message("StreamCaptureCleanupWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Failed to delete residual stream file '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, captured_stream->replaced_stream_file_path); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' manually delete it from your file system.\n"); } *stream = captured_stream->original_stream; } if (captured_stream->stream_buffer != CESTER_NULL) { cester_meta_free(captured_stream->stream_buffer); } cester_meta_free(captured_stream->original_stream_ptr_str); cester_meta_free(captured_stream->replaced_stream_ptr_str); cester_meta_free(captured_stream->replaced_stream_file_path); cester_meta_free(captured_stream); } /** Reset a stream state and content. This does not return the stream to the original owner, it simply clear the content of the stream. \param stream the stream to clear it content \param file_path the name of the file where the test case is written \param line_num the line number where the stream content is being cleared */ static void cester_reset_stream(FILE *stream, char const* const file_path, unsigned const line_num) { size_t index; char *stream_ptr_str; if (superTestInstance.stream_capture_active == 0) return; if (superTestInstance.captured_streams == CESTER_NULL) { goto cester_reset_stream_cleanup; } cester_ptr_to_str(&stream_ptr_str, stream); if (superTestInstance.captured_streams != CESTER_NULL) { CESTER_ARRAY_FOREACH(superTestInstance.captured_streams, index, captured_stream_, { CapturedStream *captured_stream; if (captured_stream_ != CESTER_NULL) { captured_stream = (CapturedStream *) captured_stream_; if (cester_string_equals(captured_stream->original_stream_ptr_str, stream_ptr_str) == 1) { if (stream != CESTER_NULL) { fclose(captured_stream->replaced_stream_handle); captured_stream->replaced_stream_handle = fopen(captured_stream->replaced_stream_file_path, "w+"); *stream = *(captured_stream->replaced_stream_handle); captured_stream->line_num = line_num; } cester_meta_free(stream_ptr_str); return; } } }) } cester_reset_stream_cleanup: cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "No stream with the pointer address '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, stream_ptr_str); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' captured so nothing is reset \n"); cester_meta_free(stream_ptr_str); } /** Get the content of the stream as string (char *), if the content of the stream is greater than 4GB this will fail. Empty string is returned if the stream is not captured. \param stream the stream to get it content \param file_path the name of the file where the test case is written \param line_num the line number where the stream content is being requested */ static char *cester_stream_content(FILE *stream, char const* const file_path, unsigned const line_num) { size_t index; size_t length; char *stream_ptr_str; if (superTestInstance.captured_streams == CESTER_NULL || superTestInstance.stream_capture_active == 0) { return (char *) ""; } cester_ptr_to_str(&stream_ptr_str, stream); if (superTestInstance.captured_streams != CESTER_NULL) { CESTER_ARRAY_FOREACH(superTestInstance.captured_streams, index, captured_stream_, { CapturedStream *captured_stream; if (captured_stream_ != CESTER_NULL) { captured_stream = (CapturedStream *) captured_stream_; if (cester_string_equals(captured_stream->original_stream_ptr_str, stream_ptr_str) == 1) { if (stream != CESTER_NULL) { fflush(stream); fseek(captured_stream->replaced_stream_handle, 0, SEEK_END); length = ftell(captured_stream->replaced_stream_handle); fseek(captured_stream->replaced_stream_handle, 0, SEEK_SET); if (captured_stream->stream_buffer != CESTER_NULL) { cester_meta_free(captured_stream->stream_buffer); } captured_stream->stream_buffer = (char *) malloc(length+1); if (captured_stream->stream_buffer) { length = fread(captured_stream->stream_buffer, 1, length, captured_stream->replaced_stream_handle); captured_stream->stream_buffer[length] = '\0'; } cester_meta_free(stream_ptr_str); return captured_stream->stream_buffer; } cester_meta_free(stream_ptr_str); return (char *) ""; } } }) } cester_meta_free(stream_ptr_str); return (char *) ""; } /** Release already captured FILE handle, if the stream was not captured before a warnning is printed. when the CapturedStream object is released, the temporary file receiving the input is closed and deleted. \param stream the stream to release \param file_path the name of the file where the test case is written \param line_num the line number where the stream is being released */ static void cester_release_stream(FILE *stream, char const* const file_path, unsigned const line_num) { size_t index; char *stream_ptr_str; if (superTestInstance.stream_capture_active == 0) return; if (superTestInstance.captured_streams == CESTER_NULL) { goto cester_release_stream_cleanup; } cester_ptr_to_str(&stream_ptr_str, stream); if (superTestInstance.captured_streams != CESTER_NULL) { CESTER_ARRAY_FOREACH(superTestInstance.captured_streams, index, captured_stream_, { CapturedStream *captured_stream; if (captured_stream_ != CESTER_NULL) { captured_stream = (CapturedStream *) captured_stream_; if (cester_string_equals(captured_stream->original_stream_ptr_str, stream_ptr_str) == 1) { if (cester_array_remove_at(superTestInstance.captured_streams, index) == CESTER_NULL) { cester_print_test_case_message("StreamCaptureCleanupWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Failed to remove captured stream with pointer address '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, stream_ptr_str); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' from captured stream array, expect non breaking issues.\n"); } cester_meta_free(stream_ptr_str); cester_release_captured_stream(stream, captured_stream, file_path, line_num); captured_stream = CESTER_NULL; return; } } }) } cester_release_stream_cleanup: cester_print_test_case_message("StreamCaptureWarning", "", file_path, line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "No stream with the pointer address '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, stream_ptr_str); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' captured so nothing is realeased \n"); cester_meta_free(stream_ptr_str); } /** Check the captured streams after a test case exeution completes and report error if the test case has any un release stream. The single most important reason for this check is to release the output stream used to write the test result. stdout in most case. \param test_case the test case which execution just end */ static unsigned release_forgotten_captured_streams(TestCase *test_case) { size_t index; unsigned unreleased_stream_count = 0; if (superTestInstance.captured_streams == CESTER_NULL || superTestInstance.stream_capture_active == 0) { goto release_forgotten_captured_streams_cleanup; } CESTER_ARRAY_FOREACH(superTestInstance.captured_streams, index, captured_stream_, { CapturedStream *captured_stream = (CapturedStream *) captured_stream_; if (captured_stream == CESTER_NULL) { continue; } if (cester_string_equals(captured_stream->original_stream_ptr_str, superTestInstance.output_stream_str) == 1) { fflush(superTestInstance.output_stream); *(superTestInstance.output_stream) = superTestInstance.output_stream_address; } if (captured_stream != CESTER_NULL && cester_string_equals(captured_stream->function_name, test_case->name) == 1) { unreleased_stream_count++; cester_print_test_case_message("StreamCaptureError", "", superTestInstance.test_file_path, captured_stream->line_num); cester_concat_str(&test_case->execution_output, "You forgot to realease the stream '"); cester_concat_str(&test_case->execution_output, captured_stream->original_stream_ptr_str); cester_concat_str(&test_case->execution_output, "' captured in line "); cester_concat_int(&test_case->execution_output, captured_stream->line_num); cester_concat_str(&test_case->execution_output, "\n"); }; if (cester_array_remove_at(superTestInstance.captured_streams, index) == CESTER_NULL) { cester_print_test_case_message("StreamCaptureCleanupWarning", "", superTestInstance.test_file_path, captured_stream->line_num); cester_concat_str(&superTestInstance.current_test_case->execution_output, "Failed to remove captured stream with pointer address '"); cester_concat_str(&superTestInstance.current_test_case->execution_output, captured_stream->original_stream_ptr_str); cester_concat_str(&superTestInstance.current_test_case->execution_output, "' from captured stream array, expect non breaking issues.\n"); } else { index--; } cester_release_captured_stream(captured_stream->original_stream_handle, captured_stream, superTestInstance.test_file_path, captured_stream->line_num); captured_stream = CESTER_NULL; }) release_forgotten_captured_streams_cleanup: return unreleased_stream_count; } /** Alias for cester_capture_stream function */ #define CESTER_CAPTURE_STREAM(x) cester_capture_stream(x, __FILE__, __LINE__) /** Alias for cester_stream_content function */ #define CESTER_STREAM_CONTENT(x) cester_stream_content(x, __FILE__, __LINE__) /** Alias for cester_reset_stream function */ #define CESTER_RESET_STREAM(x) cester_reset_stream(x, __FILE__, __LINE__) /** Alias for cester_release_stream function */ #define CESTER_RELEASE_STREAM(x) cester_release_stream(x, __FILE__, __LINE__) /** Capture the stdin stream that receive the input for the active program */ #define CESTER_CAPTURE_STDIN() CESTER_CAPTURE_STREAM(stdin) /** Get the stdin content. */ #define CESTER_STDIN_CONTENT() CESTER_STREAM_CONTENT(stdin) /** Clear the stdin content. */ #define CESTER_RESET_STDIN() CESTER_RESET_STREAM(stdin) /** Release the stdin stream that receive the input for the active program */ #define CESTER_RELEASE_STDIN() CESTER_RELEASE_STREAM(stdin) /** Capture the stdout stream where everything sent to printf is written into */ #define CESTER_CAPTURE_STDOUT() CESTER_CAPTURE_STREAM(stdout) /** Get the stdout content. */ #define CESTER_STDOUT_CONTENT() CESTER_STREAM_CONTENT(stdout) /** Clear the stdout content. */ #define CESTER_RESET_STDOUT() CESTER_RESET_STREAM(stdout) /** Release the stdout stream where everything sent to printf is written into */ #define CESTER_RELEASE_STDOUT() CESTER_RELEASE_STREAM(stdout) /** Capture the stderr stream */ #define CESTER_CAPTURE_STDERR() CESTER_CAPTURE_STREAM(stderr) /** Get the stderr content. */ #define CESTER_STDERR_CONTENT() CESTER_STREAM_CONTENT(stderr) /** Clear the stderr content. */ #define CESTER_RESET_STDERR() CESTER_RESET_STREAM(stderr) /** Release the stderr stream */ #define CESTER_RELEASE_STDERR() CESTER_RELEASE_STREAM(stderr) /** Check whether the content of a stream equals a value \param x the stream \param y the string to check if it same as the stream content */ #define cester_assert_stream_content_equal(x,y) cester_assert_str_equal(CESTER_STREAM_CONTENT(x), y) /** Check whether the content of a stream contains a value \param x the stream \param y the string to check if it present as the stream content */ #define cester_assert_stream_content_contain(x, y) cester_assert_true(cester_string_contains(CESTER_STREAM_CONTENT(x), y)) /** Check whether the content of a stream does not equal a value \param x the stream \param y the string to check if it not same as the stream content */ #define cester_assert_stream_content_not_equal(x,y) cester_assert_str_not_equal(CESTER_STREAM_CONTENT(x), y) /** Check whether the content of a stream does not contains a value \param x the stream \param y the string to check if it not present as the stream content */ #define cester_assert_stream_content_not_contain(x, y) cester_assert_false(cester_string_contains(CESTER_STREAM_CONTENT(x), y)) /** Check whether the content of stdin stream equals a value */ #define cester_assert_stdin_stream_content_equal(y) cester_assert_str_equal(CESTER_STDIN_CONTENT(), y) /** Check whether the content of stdin stream contains a value */ #define cester_assert_stdin_stream_content_contain(y) cester_assert_true(cester_string_contains(CESTER_STDIN_CONTENT(), y)) /** Check whether the content of stdin stream does not equals a value */ #define cester_assert_stdin_stream_content_not_equal(y) cester_assert_str_not_equal(CESTER_STDIN_CONTENT(), y) /** Check whether the content of stdin stream does not contains a value */ #define cester_assert_stdin_stream_content_not_contain(y) cester_assert_false(cester_string_contains(CESTER_STDIN_CONTENT(), y)) /** Check whether the content of stdout stream equals a value */ #define cester_assert_stdout_stream_content_equal(y) cester_assert_str_equal(CESTER_STDOUT_CONTENT(), y) /** Alias for cester_assert_stdout_stream_content_equal */ #define cester_assert_printf_equal cester_assert_stdout_stream_content_equal /** Check whether the content of stdout stream contains a value */ #define cester_assert_stdout_stream_content_contain(y) cester_assert_true(cester_string_contains(CESTER_STDOUT_CONTENT(), y)) /** Alias for cester_assert_stdout_stream_content_contain */ #define cester_assert_printf_contain cester_assert_stdout_stream_content_contain /** Check whether the content of stdout stream does not equals a value */ #define cester_assert_stdout_stream_content_not_equal(y) cester_assert_str_not_equal(CESTER_STDOUT_CONTENT(), y) /** Alias for cester_assert_stdout_stream_content_not_equal */ #define cester_assert_printf_not_equal cester_assert_stdout_stream_content_not_equal /** Check whether the content of stdout stream does not contains a value */ #define cester_assert_stdout_stream_content_not_contain(y) cester_assert_false(cester_string_contains(CESTER_STDOUT_CONTENT(), y)) /** Alias for cester_assert_stdout_stream_content_not_contain */ #define cester_assert_printf_not_contain cester_assert_stdout_stream_content_not_contain /** Check whether the content of stderr stream equals a value */ #define cester_assert_stderr_stream_content_equal(y) cester_assert_str_equal(CESTER_STDERR_CONTENT(), y) /** Check whether the content of stderr stream contains a value */ #define cester_assert_stderr_stream_content_contain(y) cester_assert_true(cester_string_contains(CESTER_STDERR_CONTENT(), y)) /** Check whether the content of stderr stream does not equals a value */ #define cester_assert_stderr_stream_content_not_equal(y) cester_assert_str_not_equal(CESTER_STDERR_CONTENT(), y) /** Check whether the content of stderr stream does not contains a value */ #define cester_assert_stderr_stream_content_not_contain(y) cester_assert_false(cester_string_contains(CESTER_STDERR_CONTENT(), y)) #else /* Empty Shells for the stream capturing feature to keep the test file valid still */ #define CESTER_CAPTURE_STREAM(x) #define CESTER_STREAM_CONTENT(x) #define CESTER_RESET_STREAM(x) #define CESTER_RELEASE_STREAM(x) #define CESTER_CAPTURE_STDIN() CESTER_CAPTURE_STREAM(stdin) #define CESTER_STDIN_CONTENT() CESTER_STREAM_CONTENT(stdin) #define CESTER_RESET_STDIN() CESTER_RESET_STREAM(stdin) #define CESTER_RELEASE_STDIN() CESTER_RELEASE_STREAM(stdin) #define CESTER_CAPTURE_STDOUT() CESTER_CAPTURE_STREAM(stdout) #define CESTER_STDOUT_CONTENT() CESTER_STREAM_CONTENT(stdout) #define CESTER_RESET_STDOUT() CESTER_RESET_STREAM(stdout) #define CESTER_RELEASE_STDOUT() CESTER_RELEASE_STREAM(stdout) #define CESTER_CAPTURE_STDERR() CESTER_CAPTURE_STREAM(stderr) #define CESTER_STDERR_CONTENT() CESTER_STREAM_CONTENT(stderr) #define CESTER_RESET_STDERR() CESTER_RESET_STREAM(stderr) #define CESTER_RELEASE_STDERR() CESTER_RELEASE_STREAM(stderr) #define cester_assert_stream_content_equal(x,y) #define cester_assert_stream_content_contain(x, y) #define cester_assert_stream_content_not_equal(x,y) #define cester_assert_stream_content_not_contain(x, y) #define cester_assert_stdin_stream_content_equal(y) #define cester_assert_stdin_stream_content_contain(y) #define cester_assert_stdin_stream_content_not_equal(y) #define cester_assert_stdin_stream_content_not_contain(y) #define cester_assert_stdout_stream_content_equal(y) #define cester_assert_printf_equal cester_assert_stdout_stream_content_equal #define cester_assert_stdout_stream_content_contain(y) #define cester_assert_printf_contain cester_assert_stdout_stream_content_contain #define cester_assert_stdout_stream_content_not_equal(y) #define cester_assert_printf_not_equal cester_assert_stdout_stream_content_not_equal #define cester_assert_stdout_stream_content_not_contain(y) #define cester_assert_printf_not_contain cester_assert_stdout_stream_content_not_contain #define cester_assert_stderr_stream_content_equal(y) #define cester_assert_stderr_stream_content_contain(y) #define cester_assert_stderr_stream_content_not_equal(y) #define cester_assert_stderr_stream_content_not_contain(y) #endif /** Manually register a test case */ static __CESTER_INLINE__ void cester_register_test(char *test_name, cester_test f1, cester_before_after_each f2, cester_void f3, unsigned line_num, TestType test_type) { TestCase* test_case ; if (superTestInstance.registered_test_cases == CESTER_NULL) { if (cester_array_init(&superTestInstance.registered_test_cases) == 0) { if (superTestInstance.output_stream==CESTER_NULL) { superTestInstance.output_stream = stdout; #ifndef CESTER_NO_STREAM_CAPTURE cester_ptr_to_str(&(superTestInstance.output_stream_str), stdout); superTestInstance.output_stream_address = *stdout; #endif } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to initialize the test cases array. Cannot run manually registered tests.\n"); CESTER_RESET_TERMINAL_ATTR(); return; } } test_case = (TestCase*) malloc(sizeof(TestCase)); if (!test_case) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "memory allocation error: Unable to register the test case '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), test_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "'\n"); CESTER_RESET_TERMINAL_ATTR(); return; } test_case->execution_status = CESTER_RESULT_UNKNOWN; test_case->line_num = line_num; test_case->expected_result = CESTER_RESULT_SUCCESS; #ifndef CESTER_NO_TIME test_case->start_tic = 0.000; test_case->execution_time = 0.000; #endif test_case->execution_output = (char*) ""; test_case->test_function = f1; test_case->test_ba_function = f2; test_case->test_void_function = f3; test_case->name = test_name; test_case->test_type = test_type; if (cester_array_add(superTestInstance.registered_test_cases, test_case) == 0) { if (superTestInstance.output_stream==CESTER_NULL) { superTestInstance.output_stream = stdout; #ifndef CESTER_NO_STREAM_CAPTURE cester_ptr_to_str(&(superTestInstance.output_stream_str), stdout); superTestInstance.output_stream_address = *stdout; #endif } cester_meta_free(test_case); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Failed to register '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), test_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "' \n"); CESTER_RESET_TERMINAL_ATTR(); superTestInstance.mem_test_active = 0; } } static __CESTER_INLINE__ void cester_expected_test_result(const char* const test_name, enum cester_test_status expected_result) { unsigned i,index; if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if ((cester_test_cases[i].test_type == CESTER_NORMAL_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST) && cester_string_equals(cester_test_cases[i].name, (char*)test_name) == 1) { cester_test_cases[i].expected_result = expected_result; } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index, test_case, { if ((((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) && cester_string_equals(((TestCase*)test_case)->name, (char*)test_name) == 1) { ((TestCase*)test_case)->expected_result = expected_result; } }) } static __CESTER_INLINE__ unsigned cester_run_test_no_isolation(TestInstance *, TestCase *, unsigned); static __CESTER_INLINE__ void cester_report_single_test_result(unsigned last_status, TestCase *a_test_case) { char *cleaned_name = (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path) ); #ifndef CESTER_NO_TIME clock_t tok ; tok = clock(); a_test_case->execution_time = (double)(((double)tok) - ((double)a_test_case->start_tic)) / CLOCKS_PER_SEC; #endif if ((a_test_case->expected_result == last_status || a_test_case->expected_result == CESTER_RESULT_FAILURE) && (last_status != CESTER_RESULT_SUCCESS)) { a_test_case->execution_status = CESTER_RESULT_SUCCESS; cester_concat_str(&a_test_case->execution_output, "Passed "); cester_concat_str(&a_test_case->execution_output, cleaned_name); cester_concat_str(&a_test_case->execution_output, ":"); cester_concat_int(&a_test_case->execution_output, a_test_case->line_num); cester_concat_str(&a_test_case->execution_output, ":"); cester_concat_str(&a_test_case->execution_output, " in '"); cester_concat_str(&a_test_case->execution_output, a_test_case->name); cester_concat_str(&a_test_case->execution_output, "'"); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&a_test_case->execution_output, " => "); switch (a_test_case->expected_result) { case CESTER_RESULT_FAILURE: cester_concat_str(&a_test_case->execution_output, "Failed as expected"); break; case CESTER_RESULT_SEGFAULT: cester_concat_str(&a_test_case->execution_output, "Segfault as expected"); break; case CESTER_RESULT_TERMINATED: cester_concat_str(&a_test_case->execution_output, "Prematurely terminated as expected"); break; case CESTER_RESULT_TIMED_OUT: cester_concat_str(&a_test_case->execution_output, "Timed out as expected"); break; case CESTER_RESULT_UNRELEASED_STREAM: cester_concat_str(&a_test_case->execution_output, "Have unreleased stream as expected (ARE YOU SERIOUS? BAD IDEA!!!!)"); break; #ifndef CESTER_NO_MEM_TEST case CESTER_RESULT_MEMORY_LEAK: cester_concat_str(&a_test_case->execution_output, "Leaked memory as expected"); break; #endif case CESTER_RESULT_SUCCESS: case CESTER_RESULT_UNKNOWN: break; } } cester_concat_str(&a_test_case->execution_output, "\n"); } else if (a_test_case->expected_result != last_status && a_test_case->expected_result != CESTER_RESULT_SUCCESS) { a_test_case->execution_status = last_status; cester_concat_str(&a_test_case->execution_output, "ResultError "); cester_concat_str(&a_test_case->execution_output, cleaned_name); cester_concat_str(&a_test_case->execution_output, ":"); cester_concat_int(&a_test_case->execution_output, a_test_case->line_num); cester_concat_str(&a_test_case->execution_output, ":"); cester_concat_str(&a_test_case->execution_output, " in '"); cester_concat_str(&a_test_case->execution_output, a_test_case->name); cester_concat_str(&a_test_case->execution_output, "'"); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&a_test_case->execution_output, " => "); switch (a_test_case->expected_result) { case CESTER_RESULT_FAILURE: cester_concat_str(&a_test_case->execution_output, "Expected to Fail but passed"); break; case CESTER_RESULT_SEGFAULT: cester_concat_str(&a_test_case->execution_output, "Expected to Segfault but passed"); break; case CESTER_RESULT_TERMINATED: cester_concat_str(&a_test_case->execution_output, "Expected to be Prematurely terminated but exit gracefully"); break; case CESTER_RESULT_TIMED_OUT: cester_concat_str(&a_test_case->execution_output, "Expected to Time out but ends in time"); break; case CESTER_RESULT_UNRELEASED_STREAM: cester_concat_str(&a_test_case->execution_output, "Expected to have unreleased stream but all streams were released"); break; #ifndef CESTER_NO_MEM_TEST case CESTER_RESULT_MEMORY_LEAK: cester_concat_str(&a_test_case->execution_output, "Expected to Leak memory but no memory was leaked"); break; #endif case CESTER_RESULT_SUCCESS: case CESTER_RESULT_UNKNOWN: break; } } cester_concat_str(&a_test_case->execution_output, "\n"); } else { a_test_case->execution_status = last_status; } if (a_test_case->execution_status == CESTER_RESULT_SUCCESS) { ++superTestInstance.total_passed_tests_count; } else { ++superTestInstance.total_failed_tests_count; } if (superTestInstance.single_output_only == 1) { superTestInstance.current_execution_status = last_status; } else { superTestInstance.current_execution_status = a_test_case->execution_status; } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } } static __CESTER_INLINE__ void cester_run_test(TestInstance *test_instance, TestCase *a_test_case, unsigned index) { unsigned last_status; last_status = CESTER_RESULT_UNKNOWN; #ifndef CESTER_NO_SIGNAL if (setjmp(buf) == 1) { goto check_isolation; } #endif #ifndef CESTER_NO_TIME a_test_case->start_tic = clock(); #endif #ifndef __CESTER_STDC_VERSION__ #pragma message("Isolated tests not supported in C version less than C99 and C++ version less than C++11. cester will rely on signal for crash reporting") superTestInstance.isolate_tests = 0; #endif if (superTestInstance.isolate_tests == 1 && last_status == CESTER_RESULT_UNKNOWN) { #ifdef __CESTER_STDC_VERSION__ #if defined(_WIN32) && !defined(CESTER_EXCLUDE_WINDOWS_H) HANDLE stdout_pipe_read; HANDLE stdout_pipe_write; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = CESTER_NULL; CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &sa, 0); #ifdef __cplusplus PROCESS_INFORMATION pi; STARTUPINFO si; si = { .cb = sizeof(STARTUPINFO), .dwFlags = STARTF_USESTDHANDLES, .hStdOutput = stdout_pipe_write }; pi = {0}; #else STARTUPINFO si = { .cb = sizeof(STARTUPINFO), .dwFlags = STARTF_USESTDHANDLES, .hStdOutput = stdout_pipe_write }; PROCESS_INFORMATION pi = {0}; #endif CHAR command[1500]; snprintf(command, 1500, "%s --cester-test=%s --cester-singleoutput --cester-noisolation --cester-verbose-level=%d %s %s %s %s %s %s", test_instance->argv[0], a_test_case->name, (superTestInstance.verbose_level), (superTestInstance.mem_test_active == 0 ? "--cester-nomemtest" : ""), (superTestInstance.format_test_name == 1 ? "--cester-dontformatname" : ""), (superTestInstance.stream_capture_active == 0 ? "--cester-nostreamcapture" : ""), (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1 ? "--cester-output=tap" : ""), (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1 ? "--cester-output=tapV13" : ""), superTestInstance.flattened_cmd_argv); CreateProcess( CESTER_NULL, command, CESTER_NULL, CESTER_NULL, TRUE, 0, CESTER_NULL, CESTER_NULL, &si, &pi); CloseHandle(stdout_pipe_write); DWORD len; DWORD maxlen; CHAR buffer[700]; maxlen = 700; do { ReadFile(stdout_pipe_read, buffer, maxlen, &len, CESTER_NULL); buffer[len] = '\0'; cester_concat_str(&a_test_case->execution_output, buffer); } while (len > 0); WaitForSingleObject(pi.hProcess, INFINITE); DWORD status; GetExitCodeProcess(pi.hProcess, &status); if ((status & 0x80000000)) { last_status = CESTER_RESULT_SEGFAULT; } else if (status == 1 && strlen(a_test_case->execution_output) == 0) { last_status = CESTER_RESULT_TERMINATED; } else { last_status = status; } end_sub_process: CloseHandle(pi.hProcess); CloseHandle(pi.hThread); #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) pid_t pid; int pipefd[2]; char *selected_test_unix; char *verbose_level_str; pipe(pipefd); pid = fork(); if (pid == -1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to create a seperate process for the '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), a_test_case->name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "'. Running the test on main process."); last_status = cester_run_test_no_isolation(test_instance, a_test_case, index); } else if (pid == 0) { selected_test_unix = (char*) ""; verbose_level_str = (char *) ""; cester_concat_str(&selected_test_unix, "--cester-test="); cester_concat_str(&selected_test_unix, a_test_case->name); cester_concat_str(&verbose_level_str, "--cester-verbose-level="); cester_concat_int(&verbose_level_str, superTestInstance.verbose_level); close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); execl(test_instance->argv[0], test_instance->argv[0], selected_test_unix, "--cester-singleoutput", "--cester-noisolation", verbose_level_str, (superTestInstance.mem_test_active == 0 ? "--cester-nomemtest" : ""), (superTestInstance.format_test_name == 1 ? "--cester-dontformatname" : ""), (superTestInstance.stream_capture_active == 0 ? "--cester-nostreamcapture" : ""), (superTestInstance.no_color == 1 ? "--cester-nocolor" : ""), (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1 ? "--cester-output=tap" : ""), (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1 ? "--cester-output=tapV13" : ""), superTestInstance.flattened_cmd_argv, (char*)CESTER_NULL); cester_meta_free(selected_test_unix); cester_meta_free(verbose_level_str); exit(CESTER_RESULT_FAILURE); } else { int status; char buffer[700]; size_t len; close(pipefd[1]); while ((len = read(pipefd[0], buffer, 700)) != 0) { buffer[len] = '\0'; cester_concat_str(&a_test_case->execution_output, buffer); } waitpid(pid, &status, 0); close(pipefd[0]); last_status = WEXITSTATUS(status); end_sub_process: kill(pid, SIGTERM); } #else #pragma message("Isolated tests not supported in this environment. The tests will be run on the main process") last_status = cester_run_test_no_isolation(test_instance, a_test_case, index); #define CESTER_NO_SUBPROCESS 1 #endif #endif } else if (last_status == CESTER_RESULT_UNKNOWN) { last_status = cester_run_test_no_isolation(test_instance, a_test_case, index); } resolve_test_result: cester_report_single_test_result(last_status, a_test_case); return; check_isolation: last_status = superTestInstance.current_execution_status; #ifdef __CESTER_STDC_VERSION__ #ifndef CESTER_NO_SUBPROCESS if (superTestInstance.isolate_tests == 1) { goto end_sub_process; } #endif #endif goto resolve_test_result; } static __CESTER_INLINE__ unsigned cester_run_test_no_isolation(TestInstance *test_instance, TestCase *a_test_case, unsigned index) { unsigned i, index1, index2, ret_val; char *prefix = (char *) ""; superTestInstance.current_execution_status = CESTER_RESULT_SUCCESS; if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_BEFORE_EACH_TEST) { superTestInstance.current_cester_function_type = CESTER_BEFORE_EACH_TEST; ((cester_before_after_each)cester_test_cases[i].test_ba_function)(test_instance, a_test_case->name, index); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index1, test_case, { if (((TestCase*)test_case)->test_type == CESTER_BEFORE_EACH_TEST) { superTestInstance.current_cester_function_type = CESTER_BEFORE_EACH_TEST; ((cester_before_after_each)((TestCase*)test_case)->test_ba_function)(test_instance, a_test_case->name, index); } }) superTestInstance.current_cester_function_type = CESTER_NORMAL_TEST; superTestInstance.current_test_case = a_test_case; ((cester_test)a_test_case->test_function)(test_instance); if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1) { prefix = (char *) "# "; } else if (cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { prefix = (char *) " - "; } #ifndef CESTER_NO_STREAM_CAPTURE if (release_forgotten_captured_streams(a_test_case) > 0) { superTestInstance.current_execution_status = CESTER_RESULT_UNRELEASED_STREAM; } #endif #ifndef CESTER_NO_MEM_TEST if (check_memory_allocated_for_functions(a_test_case->name, CESTER_NULL, prefix, &(superTestInstance.current_test_case)->execution_output) > 0) { superTestInstance.current_execution_status = CESTER_RESULT_MEMORY_LEAK; } #endif if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_AFTER_EACH_TEST) { superTestInstance.current_cester_function_type = CESTER_AFTER_EACH_TEST; ((cester_before_after_each)cester_test_cases[i].test_ba_function)(test_instance, a_test_case->name, index); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index2, test_case, { if (((TestCase*)test_case)->test_type == CESTER_AFTER_EACH_TEST) { superTestInstance.current_cester_function_type = CESTER_AFTER_EACH_TEST; ((cester_before_after_each)((TestCase*)test_case)->test_ba_function)(test_instance, a_test_case->name, index); } }) if (cester_string_equals(superTestInstance.output_format, (char*) "tap") == 1 || cester_string_equals(superTestInstance.output_format, (char*) "tapV13") == 1) { prefix = (char *) "# "; } #ifndef CESTER_NO_MEM_TEST ret_val = check_memory_allocated_for_functions((char *)"CESTER_BEFORE_EACH", CESTER_NULL, prefix, &superTestInstance.main_execution_output); if (ret_val > 0) { superTestInstance.total_test_errors_count += ret_val; } #endif ++superTestInstance.total_tests_ran; if (superTestInstance.single_output_only == 1) { CESTER_DELEGATE_FPRINT_STR((cester_default_color), a_test_case->execution_output); } return superTestInstance.current_execution_status; } #ifndef CESTER_NO_SIGNAL /*void (*signal(int , void (*)(int)))(int);*/ void cester_capture_signals(void); void cester_recover_on_signal(int sig_num); #endif /* use start param to save the state index instead of starting loop again or super var */ static __CESTER_INLINE__ void cester_run_all_test_iterator(int start) { unsigned i, j, index2, index3, test_index; unsigned found_test; char* selected_test_case_name; found_test = 0; test_index = 0; if (superTestInstance.selected_test_cases_size == 0) { if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_NORMAL_TEST && cester_test_cases[i].execution_status == CESTER_RESULT_UNKNOWN) { cester_run_test(superTestInstance.test_instance, &cester_test_cases[i], ++test_index); } else if (cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST) { ++superTestInstance.todo_tests_count; } else if (cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST) { ++superTestInstance.skipped_test_count; } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index2, test_case, { if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST && ((TestCase*)test_case)->execution_status == CESTER_RESULT_UNKNOWN) { cester_run_test(superTestInstance.test_instance, ((TestCase*)test_case), ++test_index); } else if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST) { ++superTestInstance.todo_tests_count; } else if (((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) { ++superTestInstance.skipped_test_count; } }) } else { for (j = superTestInstance.selected_test_cases_found; j < superTestInstance.selected_test_cases_size; ++j) { selected_test_case_name = superTestInstance.selected_test_cases_names[j]; found_test = 0; if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if ((cester_test_cases[i].test_type == CESTER_NORMAL_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST) && cester_string_equals(cester_test_cases[i].name, selected_test_case_name) == 1 && cester_test_cases[i].execution_status == CESTER_RESULT_UNKNOWN) { found_test = 1; if (cester_test_cases[i].test_type == CESTER_NORMAL_TEST) { ++superTestInstance.selected_test_cases_found; cester_run_test(superTestInstance.test_instance, &cester_test_cases[i], ++test_index); } else { cester_test_cases[i].execution_status = CESTER_RESULT_SUCCESS; if (cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST) { ++superTestInstance.skipped_test_count; } else { ++superTestInstance.todo_tests_count; } } } } } if (found_test == 0) { CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index3, test_case, { if ((((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) && cester_string_equals(((TestCase*)test_case)->name, selected_test_case_name) == 1 && ((TestCase*)test_case)->execution_status == CESTER_RESULT_UNKNOWN) { found_test = 1; if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST) { ++superTestInstance.selected_test_cases_found; cester_run_test(superTestInstance.test_instance, ((TestCase*)test_case), ++test_index); } else { ((TestCase*)test_case)->execution_status = CESTER_RESULT_SUCCESS; if (((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) { ++superTestInstance.skipped_test_count; } else { ++superTestInstance.todo_tests_count; } } } }) if (found_test == 0) { if (superTestInstance.verbose_level > 0 && cester_string_equals(superTestInstance.output_format, (char*) "text") == 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Warning: the test case '"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), superTestInstance.selected_test_cases_names[j]); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "' was not found! \n"); CESTER_RESET_TERMINAL_ATTR(); } } } } } } static void cester_cleanup_super_instance(void) { unsigned index; #ifndef CESTER_NO_MEM_TEST if (superTestInstance.mem_alloc_manager != CESTER_NULL) { CESTER_ARRAY_FOREACH(superTestInstance.mem_alloc_manager, index, alloc_mem, { if (alloc_mem != CESTER_NULL) { cester_meta_free(alloc_mem); } if (cester_array_remove_at(superTestInstance.mem_alloc_manager, index) != CESTER_NULL) { index--; } }); cester_array_destroy(superTestInstance.mem_alloc_manager); } #endif if (superTestInstance.registered_test_cases != CESTER_NULL) { index = 0; CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index, test_case, { if (strlen(((TestCase *)test_case)->execution_output) > 0) { cester_meta_free(((TestCase *)test_case)->execution_output); } cester_meta_free(test_case); if (cester_array_remove_at(superTestInstance.registered_test_cases, index) != CESTER_NULL) { index--; } }) cester_array_destroy(superTestInstance.registered_test_cases); } if (superTestInstance.selected_test_cases_size > 0) { index = 0; for (; index < superTestInstance.selected_test_cases_size; ++index) { cester_meta_free(superTestInstance.selected_test_cases_names[index]); } } if (superTestInstance.selected_test_cases_names != CESTER_NULL) { cester_meta_free(superTestInstance.selected_test_cases_names); } #ifndef CESTER_NO_STREAM_CAPTURE if (superTestInstance.output_stream_str != CESTER_NULL) { cester_meta_free(superTestInstance.output_stream_str); } #endif if (superTestInstance.test_instance != CESTER_NULL) { cester_meta_free(superTestInstance.test_instance); } } #ifndef CESTER_NO_PRINT_INFO /** Get the string value of the test type */ #define CESTER_TEST_FUNTION_TYPE_TO_STRING(test_type) (test_type == CESTER_NORMAL_TEST ? "CESTER_NORMAL_TEST" :\ (test_type == CESTER_NORMAL_TODO_TEST ? "CESTER_NORMAL_TODO_TEST" :\ (test_type == CESTER_NORMAL_SKIP_TEST ? "CESTER_NORMAL_SKIP_TEST" :\ (test_type == CESTER_BEFORE_ALL_TEST ? "CESTER_BEFORE_ALL_TEST" :\ (test_type == CESTER_BEFORE_EACH_TEST ? "CESTER_BEFORE_EACH_TEST" :\ (test_type == CESTER_AFTER_ALL_TEST ? "CESTER_AFTER_ALL_TEST" :\ (test_type == CESTER_AFTER_EACH_TEST ? "CESTER_AFTER_EACH_TEST" :\ (test_type == CESTER_OPTIONS_FUNCTION ? "CESTER_OPTIONS_FUNCTION" :\ (test_type == CESTER_TEST_FILE_COMMENT ? "CESTER_TEST_FILE_COMMENT" : "CESTER_TESTS_TERMINATOR"))))))))) /** Print out the test case attribute in the output format */ #define CESTER_PRINT_TEST_FUNCTION(tab, text_prefix, test_case) if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) {\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "" tab "<function");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " name=");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), test_case.name);\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " line_number=");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_INT((CESTER_FOREGROUND_MAGENTA), test_case.line_num);\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " type=");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), CESTER_TEST_FUNTION_TYPE_TO_STRING(test_case.test_type));\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"");\ CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "/>\n");\ } else {\ CESTER_DELEGATE_FPRINT(text_prefix); CESTER_DELEGATE_FPRINT(test_case.name);\ if (!cester_string_equals(info_section, "all")) CESTER_DELEGATE_FPRINT("\n");\ } /*! Prints out detail or specific information about the test esecutable. This is most useful for test managers and runner to manage test execution and also provide easy debugging. */ static __CESTER_INLINE__ unsigned int cester_print_tests_information(char *info_section) { unsigned index; char *file_name = cester_extract_name_only(superTestInstance.test_file_path); if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "<?xml"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " version="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"1.0\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " encoding="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\"UTF-8\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " ?>\n"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "<testinfo"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " file_name="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), file_name); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), " file_path="); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), superTestInstance.test_file_path); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_MAGENTA), "\""); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } if (cester_string_equals(info_section, "all")) { if (cester_string_equals(superTestInstance.output_format, (char*) "text")) { CESTER_DELEGATE_FPRINT("cester v"); CESTER_DELEGATE_FPRINT(CESTER_VERSION); CESTER_DELEGATE_FPRINT(" by "); CESTER_DELEGATE_FPRINT(CESTER_AUTHOR); CESTER_DELEGATE_FPRINT(".\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <options_and_comments"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\nOptions and Comments"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_OPTIONS_FUNCTION || cester_test_cases[index].test_type == CESTER_TEST_FILE_COMMENT) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </options_and_comments>\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <fixture_before"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\nFixture - Before"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_BEFORE_ALL_TEST || cester_test_cases[index].test_type == CESTER_BEFORE_EACH_TEST) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </fixture_before>\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <fixture_after"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\n\nFixture - After"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_AFTER_ALL_TEST || cester_test_cases[index].test_type == CESTER_AFTER_EACH_TEST) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </fixture_after>\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <tests"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\n\nTests"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_NORMAL_TEST) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </tests>\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <skip_tests"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\n\nSkip Tests"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_NORMAL_SKIP_TEST) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </skip_tests>\n"); } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " <todo_tests"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), ">\n"); } else { CESTER_DELEGATE_FPRINT("\n\nTodo Tests"); } for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_NORMAL_TODO_TEST) { CESTER_PRINT_TEST_FUNCTION(" ", "\n - ", cester_test_cases[index]) } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), " </todo_tests>\n"); } } else { for (index = 0; cester_test_cases[index].test_type != CESTER_TESTS_TERMINATOR; ++index) { if (cester_test_cases[index].test_type == CESTER_OPTIONS_FUNCTION && cester_string_contains(info_section, "options")) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_TEST_FILE_COMMENT && cester_string_contains(info_section, "comments")) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_BEFORE_ALL_TEST && (cester_string_contains(info_section, "before_all") || cester_string_contains(info_section, "before*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_BEFORE_EACH_TEST && (cester_string_contains(info_section, "before_each") || cester_string_contains(info_section, "before*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_AFTER_ALL_TEST && (cester_string_contains(info_section, "after_all") || cester_string_contains(info_section, "after*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_AFTER_EACH_TEST && (cester_string_contains(info_section, "after_each") || cester_string_contains(info_section, "after*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_NORMAL_TEST && (((cester_string_starts_with(info_section, "test") && cester_str_size(info_section) == 4) || cester_string_contains(info_section, "test,") || cester_string_contains(info_section, "test ")) || cester_string_contains(info_section, "test*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_NORMAL_SKIP_TEST && (cester_string_contains(info_section, "test_skip") || cester_string_contains(info_section, "test*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } else if (cester_test_cases[index].test_type == CESTER_NORMAL_TODO_TEST && (cester_string_contains(info_section, "test_todo") || cester_string_contains(info_section, "test*"))) { CESTER_PRINT_TEST_FUNCTION(" ", "", cester_test_cases[index]) } } } if (cester_string_equals(superTestInstance.output_format, (char*) "junitxml")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_BLUE), "</testinfo>"); } if (!cester_string_equals(superTestInstance.output_format, (char*) "text")) { CESTER_RESET_TERMINAL_ATTR(); } if (cester_string_equals(info_section, "all")) { CESTER_DELEGATE_FPRINT("\n"); } cester_meta_free(file_name); cester_meta_free(info_section); return CESTER_RESULT_SUCCESS; } #endif static __CESTER_INLINE__ unsigned cester_run_all_test(unsigned argc, char **argv) { char *arg; char *extra; #ifndef CESTER_NO_PRINT_INFO char *info_section; #endif unsigned i, j, index, index1; char *cester_option = CESTER_NULL; #ifdef _WIN32 #ifndef CESTER_EXCLUDE_WINDOWS_H CONSOLE_SCREEN_BUFFER_INFO info; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) { cester_default_color = info.wAttributes; } cester_hConsole = GetStdHandle(STD_OUTPUT_HANDLE); #endif #ifndef CESTER_NO_STREAM_CAPTURE cester_set_captured_streams_tmp_folder(getenv("TEMP"), (char *)"C:/libcester_tmp/"); #endif #else #ifndef CESTER_NO_STREAM_CAPTURE cester_set_captured_streams_tmp_folder(getenv("TMPDIR"), (char *)"/tmp/libcester_tmp/"); #endif #endif #ifndef CESTER_NO_SIGNAL cester_capture_signals(); #endif i = 0; j = 1; #ifndef CESTER_NO_PRINT_INFO info_section = CESTER_NULL; #endif if (superTestInstance.output_stream==CESTER_NULL) { superTestInstance.output_stream = stdout; #ifndef CESTER_NO_STREAM_CAPTURE cester_ptr_to_str(&(superTestInstance.output_stream_str), stdout); superTestInstance.output_stream_address = *stdout; #endif } #ifndef CESTER_NO_MEM_TEST if (superTestInstance.mem_alloc_manager == CESTER_NULL) { if (cester_array_init(&superTestInstance.mem_alloc_manager) == 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to initialize the memory management array. Memory test disabled.\n"); superTestInstance.mem_test_active = 0; } } #endif if (superTestInstance.registered_test_cases == CESTER_NULL) { if (cester_array_init(&superTestInstance.registered_test_cases) == 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "Unable to initialize the registered test cases array. Cannot continue tests.\n"); return CESTER_RESULT_FAILURE; } } /* resolve command line options */ for (;j < argc; ++j) { arg = argv[j]; if (cester_str_after_prefix(arg, (char*) "--cester-", 9, &cester_option) == 1) { if (cester_string_equals(cester_option, (char*) "minimal") == 1) { superTestInstance.verbose_level = 0; } else if (cester_string_equals(cester_option, (char*) "verbose") == 1) { superTestInstance.verbose_level = 10; superTestInstance.print_error_only = 0; } else if (cester_string_equals(cester_option, (char*) "nocolor") == 1) { superTestInstance.no_color = 1; } else if (cester_string_equals(cester_option, (char*) "printversion") == 1) { superTestInstance.print_version = 1; } else if (cester_string_equals(cester_option, (char*) "singleoutput") == 1) { superTestInstance.single_output_only = 1; } else if (cester_string_equals(cester_option, (char*) "noisolation") == 1) { superTestInstance.isolate_tests = 0; } else if (cester_string_equals(cester_option, (char*) "dontformatname") == 1) { superTestInstance.format_test_name = 0; #ifndef CESTER_NO_MEM_TEST } else if (cester_string_equals(cester_option, (char*) "nomemtest") == 1) { superTestInstance.mem_test_active = 0; #endif #ifndef CESTER_NO_STREAM_CAPTURE } else if (cester_string_equals(cester_option, (char*) "nostreamcapture") == 1) { superTestInstance.stream_capture_active = 0; #endif } else if (cester_string_equals(cester_option, (char*) "version") == 1) { CESTER_NOCOLOR(); cester_print_version(); cester_meta_free(cester_option); cester_cleanup_super_instance(); if (info_section != CESTER_NULL) { cester_meta_free(info_section); } return EXIT_SUCCESS; } else if (cester_string_equals(cester_option, (char*) "help") == 1) { CESTER_NOCOLOR(); cester_print_version(); cester_print_help(); cester_meta_free(cester_option); if (info_section != CESTER_NULL) { cester_meta_free(info_section); } cester_cleanup_super_instance(); return EXIT_SUCCESS; #ifndef CESTER_NO_PRINT_INFO } else if (cester_string_starts_with(cester_option, (char*) "info=") == 1) { cester_str_value_after_first(cester_option, '=', &info_section); #endif } else if (cester_string_starts_with(cester_option, (char*) "test=") == 1) { unpack_selected_extra_args(cester_option, &superTestInstance.selected_test_cases_names, &superTestInstance.selected_test_cases_size); } else if (cester_string_starts_with(cester_option, (char*) "verbose-level=") == 1) { cester_str_value_after_first(cester_option, '=', &extra); superTestInstance.verbose_level = atoi(extra); cester_meta_free(extra); if (superTestInstance.verbose_level >= 10) { superTestInstance.print_error_only = 0; } } else if (cester_string_starts_with(cester_option, (char*) "output=") == 1) { cester_str_value_after_first(cester_option, '=', &extra); if (cester_is_validate_output_option(extra) == 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "Invalid cester output format: "); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), extra); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "\n"); if (cester_string_starts_with(extra, (char*) "tap")) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Did you mean 'tap' or 'tapV13?'\n"); } CESTER_RESET_TERMINAL_ATTR() cester_meta_free(extra); cester_meta_free(cester_option); return EXIT_FAILURE; } else { if (cester_string_equals(extra, (char*) "junitxml")) { superTestInstance.output_format = (char*) "junitxml"; } else if (cester_string_equals(extra, (char*) "tap")) { superTestInstance.output_format = (char*) "tap"; } else if (cester_string_equals(extra, (char*) "tapV13")) { superTestInstance.output_format = (char*) "tapV13"; } else { superTestInstance.output_format = (char*) "text"; } } cester_meta_free(extra); } else if (superTestInstance.single_output_only != 1) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "Invalid cester option: --cester-"); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), cester_option); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_RED), "\n"); CESTER_RESET_TERMINAL_ATTR() cester_meta_free(cester_option); return EXIT_FAILURE; } if (cester_option != CESTER_NULL) { cester_meta_free(cester_option); cester_option = CESTER_NULL; } } else { if (strlen(argv[j]) != 0) { cester_concat_str(&superTestInstance.flattened_cmd_argv, argv[j]); cester_concat_str(&superTestInstance.flattened_cmd_argv, " "); } } } if (superTestInstance.output_format == CESTER_NULL) { superTestInstance.output_format = "text"; } #ifndef CESTER_NO_PRINT_INFO if (info_section != CESTER_NULL) { return cester_print_tests_information(info_section); } #endif if (superTestInstance.print_version == 1) { cester_print_version(); CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_WHITE), "\n"); CESTER_RESET_TERMINAL_ATTR(); } superTestInstance.test_instance = (TestInstance*) malloc(sizeof(TestInstance)); superTestInstance.test_instance->argc = argc; superTestInstance.test_instance->argv = argv; /* execute options */ for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if ((cester_test_cases[i].test_type == CESTER_OPTIONS_FUNCTION || cester_test_cases[i].test_type == CESTER_TEST_FILE_COMMENT) && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_OPTIONS_FUNCTION; ((cester_void)cester_test_cases[i].test_void_function)(); } else if ((cester_test_cases[i].test_type == CESTER_NORMAL_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_TODO_TEST || cester_test_cases[i].test_type == CESTER_NORMAL_SKIP_TEST) && superTestInstance.registered_test_cases->size == 0) { ++superTestInstance.total_tests_count; } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index, test_case, { if ((((TestCase*)test_case)->test_type == CESTER_OPTIONS_FUNCTION || ((TestCase*)test_case)->test_type == CESTER_TEST_FILE_COMMENT) && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_OPTIONS_FUNCTION; ((cester_void)((TestCase*)test_case)->test_void_function)(); } else if (((TestCase*)test_case)->test_type == CESTER_NORMAL_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_TODO_TEST || ((TestCase*)test_case)->test_type == CESTER_NORMAL_SKIP_TEST) { ++superTestInstance.total_tests_count; } }) /* before all */ if (superTestInstance.registered_test_cases->size == 0) { for (i=0;cester_test_cases[i].test_type != CESTER_TESTS_TERMINATOR;++i) { if (cester_test_cases[i].test_type == CESTER_BEFORE_ALL_TEST && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_BEFORE_ALL_TEST; ((cester_test)cester_test_cases[i].test_function)(superTestInstance.test_instance); } } } CESTER_ARRAY_FOREACH(superTestInstance.registered_test_cases, index1, test_case, { if (((TestCase*)test_case)->test_type == CESTER_BEFORE_ALL_TEST && superTestInstance.single_output_only == 0) { superTestInstance.current_cester_function_type = CESTER_BEFORE_ALL_TEST; ((cester_test)((TestCase*)test_case)->test_function)(superTestInstance.test_instance); } }) #ifndef CESTER_NO_TIME superTestInstance.start_tic = clock(); #endif cester_run_all_test_iterator(0); return cester_print_result(cester_test_cases, superTestInstance.test_instance); } #ifndef CESTER_NO_MAIN int main(int argc, char **argv) { return CESTER_RUN_ALL_TESTS(argc, argv); } #endif #ifndef CESTER_NO_SIGNAL void cester_capture_signals(void) { signal(SIGINT , cester_recover_on_signal); signal(SIGABRT , cester_recover_on_signal); signal(SIGILL , cester_recover_on_signal); signal(SIGFPE , cester_recover_on_signal); signal(SIGSEGV, cester_recover_on_signal); signal(SIGTERM , cester_recover_on_signal); } /* This is still faulty it works for SIGSEGV but SIGINT just crash to my face. So I will manually try to recover the test instead of using longjmp and setjmp which is behaving inconsistently. This still messes up for more than 2 crashes */ void cester_recover_on_signal(int sig_num) { cester_capture_signals(); switch (sig_num) { #ifndef CESTER_NO_MEM_TEST case SIGILL: superTestInstance.current_execution_status = CESTER_RESULT_MEMORY_LEAK; break; #endif case SIGSEGV: superTestInstance.current_execution_status = CESTER_RESULT_SEGFAULT; break; case SIGINT: /* this is one crazy kill signal */ if (superTestInstance.isolate_tests == 1) { return; } superTestInstance.current_execution_status = CESTER_RESULT_TERMINATED; cester_report_single_test_result(superTestInstance.current_execution_status, superTestInstance.current_test_case); cester_run_all_test_iterator(0); exit(cester_print_result(cester_test_cases, superTestInstance.test_instance)); break; case SIGFPE: case SIGTERM: case SIGABRT: superTestInstance.current_execution_status = CESTER_RESULT_FAILURE; break; } longjmp(buf, 1); } #endif /* CesterArray */ static __CESTER_INLINE__ unsigned cester_array_init(CesterArray** out) { void **buffer; CesterArray* array_local = (CesterArray*) malloc(sizeof(CesterArray)); if (!array_local) { return 0; } array_local->size = 0; array_local->capacity = CESTER_ARRAY_INITIAL_CAPACITY; buffer = (void**) malloc(sizeof(void*) * array_local->capacity); if (!buffer) { cester_meta_free(array_local); return 0; } array_local->buffer = buffer; *out = array_local; return 1; } static __CESTER_INLINE__ unsigned cester_array_add(CesterArray* array, void* item) { void** new_buffer; if (array->size >= array->capacity) { if (array->capacity >= CESTER_ARRAY_MAX_CAPACITY) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Max managable memory allocation reached, cannot expand array. Further Memory test disabled.\n"); superTestInstance.mem_test_active = 0; return 0; } array->capacity = array->capacity + CESTER_ARRAY_INITIAL_CAPACITY; new_buffer = (void**) malloc(sizeof(void*) * array->capacity); if (!new_buffer) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Failed to expand the memory allocation array. Further Memory test disabled.\n"); superTestInstance.mem_test_active = 0; return 0; } memcpy(new_buffer, array->buffer, array->size * sizeof(void*)); cester_meta_free(array->buffer); array->buffer = new_buffer; } array->buffer[array->size] = item; ++array->size; return 1; } static __CESTER_INLINE__ void* cester_array_remove_at(CesterArray* array, size_t index) { void* item; if (index >= array->size) { return CESTER_NULL; } item = array->buffer[index]; if (index != array->size - 1) { size_t block_size = (array->size - 1 - index) * sizeof(void*); memmove(&(array->buffer[index]), &(array->buffer[index + 1]), block_size); } array->size--; return item; } static __CESTER_INLINE__ void cester_array_destroy(CesterArray* array) { cester_meta_free(array->buffer); cester_meta_free(array); } /* Memory leak Detection procedures */ #ifndef CESTER_NO_MEM_TEST static __CESTER_INLINE__ void* cester_allocator(size_t nitems, size_t size, unsigned type, const char *file, unsigned line, const char *func) { void* p; const char* actual_function_name; #ifndef __CESTER_STDC_VERSION__ if (superTestInstance.current_test_case != CESTER_NULL) { actual_function_name = superTestInstance.current_test_case->name; } else { actual_function_name = func; } #else actual_function_name = func; #endif if (superTestInstance.current_cester_function_type == CESTER_BEFORE_ALL_TEST) { actual_function_name = "CESTER_BEFORE_ALL"; } else if (superTestInstance.current_cester_function_type == CESTER_OPTIONS_FUNCTION) { actual_function_name = "CESTER_OPTIONS"; } else if (superTestInstance.current_cester_function_type == CESTER_BEFORE_EACH_TEST) { actual_function_name = "CESTER_BEFORE_EACH"; } if (superTestInstance.mem_test_active == 1) { if (superTestInstance.mem_alloc_manager == CESTER_NULL) { if (cester_array_init(&superTestInstance.mem_alloc_manager) == 0) { if (superTestInstance.output_stream==CESTER_NULL) { superTestInstance.output_stream = stdout; #ifndef CESTER_NO_STREAM_CAPTURE cester_ptr_to_str(&(superTestInstance.output_stream_str), stdout); superTestInstance.output_stream_address = *stdout; #endif } CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Unable to initialize the memory management array. Memory test disabled.\n"); superTestInstance.mem_test_active = 0; } } } switch (type) { case 1: p = calloc(nitems, size); break; case 0: default: p = malloc(size); } if (superTestInstance.mem_test_active == 1) { AllocatedMemory* allocated_mem = (AllocatedMemory*) malloc(sizeof(AllocatedMemory)); allocated_mem->line_num = line; allocated_mem->allocated_bytes = size; allocated_mem->function_name_allocated = 1; if (cester_str_after_prefix(actual_function_name, (char*) "cester_test_", 12, (char **) &(allocated_mem->function_name)) == 0) { allocated_mem->function_name = (char *) actual_function_name; allocated_mem->function_name_allocated = 0; } allocated_mem->file_name = file; cester_ptr_to_str(&allocated_mem->address, p); if (cester_array_add(superTestInstance.mem_alloc_manager, allocated_mem) == 0) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Failed to register allocated memory. Memory test disabled.\n"); superTestInstance.mem_test_active = 0; } } return p; } static __CESTER_INLINE__ void cester_free(void *pointer, const char *file, unsigned line, const char *func) { unsigned index; char *cleaned_name = (char *) (superTestInstance.verbose_level >= 4 ? superTestInstance.test_file_path : cester_extract_name(superTestInstance.test_file_path) ); if (pointer == CESTER_NULL) { if (superTestInstance.mem_test_active == 1 && superTestInstance.current_test_case != CESTER_NULL) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "InvalidOperation "); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, cleaned_name); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ":"); cester_concat_int(&(superTestInstance.current_test_case)->execution_output, line); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, ": "); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "in '"); cester_concat_str(&(superTestInstance.current_test_case)->execution_output, (superTestInstance.current_test_case)->name); if (superTestInstance.verbose_level >= 2) { cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "' => Attempting to free a CESTER_NULL pointer"); } cester_concat_str(&(superTestInstance.current_test_case)->execution_output, "\n"); superTestInstance.current_execution_status = CESTER_RESULT_MEMORY_LEAK; } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } return; } if (superTestInstance.mem_test_active == 1) { char* address; cester_ptr_to_str(&address, pointer); CESTER_ARRAY_FOREACH(superTestInstance.mem_alloc_manager, index, alloc_mem, { if (cester_string_equals(((AllocatedMemory*)alloc_mem)->address, address) == 1) { if (!cester_array_remove_at(superTestInstance.mem_alloc_manager, index)) { CESTER_DELEGATE_FPRINT_STR((CESTER_FOREGROUND_YELLOW), "Memory allocation array corrupted. Further Memory test disabled.\n"); superTestInstance.mem_test_active = 0; } if (((AllocatedMemory*)alloc_mem)->function_name_allocated == 1) { cester_meta_free(((AllocatedMemory*)alloc_mem)->function_name); } cester_meta_free(((AllocatedMemory*)alloc_mem)->address); cester_meta_free(alloc_mem); break; } }) cester_meta_free(address); } if (superTestInstance.verbose_level < 4) { cester_meta_free(cleaned_name); } cester_meta_free(pointer); } #define malloc(x) cester_allocator( 0, x, 0, __FILE__, __LINE__, __CESTER_FUNCTION__) /**< Override the default malloc function for mem test */ #define calloc(x,y) cester_allocator( x, y, 1, __FILE__, __LINE__, __CESTER_FUNCTION__) /**< Override the default malloc function for mem test */ #define free(x) cester_free( x, __FILE__, __LINE__, __CESTER_FUNCTION__) /**< Override the default free function for mem test */ #endif #ifdef __cplusplus } #endif #endif