/* * Copyright (c) 2016-2020 Belledonne Communications SARL. * * This file is part of bctoolbox. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BCTOOLBOX_TESTER_H #define BCTOOLBOX_TESTER_H #include #include #include #include #include typedef void (*test_function_t)(void); /** Function used in all suites - it is invoked before all and each tests and also after each and all tests * @return 0 means success, otherwise it's an error **/ typedef int (*pre_post_function_t)(void); // typedef int (*test_suite_function_t)(const char *name); typedef struct { const char *name; test_function_t func; const char *tags[2]; } test_t; #define TEST_NO_TAG(name, func) \ { name, func, { NULL, NULL } } #define TEST_ONE_TAG(name, func, tag) \ { name, func, { tag, NULL } } #define TEST_TWO_TAGS(name, func, tag1, tag2) \ { name, func, { tag1, tag2 } } typedef struct { const char *name; /*suite name*/ pre_post_function_t before_all; /*function invoked before running the suite. If not returning 0, suite is not launched. */ pre_post_function_t after_all; /*function invoked at the end of the suite, even if some tests failed. */ test_function_t before_each; /*function invoked before each test within this suite. */ test_function_t after_each; /*function invoked after each test within this suite, even if it failed. */ int nb_tests; /* number of tests */ test_t *tests; /* tests within this suite */ } test_suite_t; #ifdef __cplusplus extern "C" { #endif #define CHECK_ARG(argument, index, argc) \ if(index >= argc) { \ fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ return -1; \ } \ BCTBX_PUBLIC void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args) , int verbosity_info, int verbosity_error, const char* expected_res); BCTBX_PUBLIC void bc_tester_helper(const char *name, const char* additionnal_helper); BCTBX_PUBLIC int bc_tester_parse_args(int argc, char** argv, int argid); BCTBX_PUBLIC int bc_tester_start(const char* prog_name); BCTBX_PUBLIC int bc_tester_register_suites(void); BCTBX_PUBLIC int bc_tester_register_suite_by_name(const char *suite_name); BCTBX_PUBLIC void bc_tester_add_suite(test_suite_t *suite); BCTBX_PUBLIC void bc_tester_set_max_parallel_suites(int max_parallel_suites); BCTBX_PUBLIC void bc_tester_uninit(void); BCTBX_PUBLIC void bc_tester_printf(int level, const char *fmt, ...); BCTBX_PUBLIC const char * bc_tester_get_resource_dir_prefix(void); BCTBX_PUBLIC void bc_tester_set_resource_dir_prefix(const char *name); BCTBX_PUBLIC const char * bc_tester_get_writable_dir_prefix(void); BCTBX_PUBLIC void bc_tester_set_writable_dir_prefix(const char *name); BCTBX_PUBLIC void bc_tester_set_silent_func(int (*func)(const char*)); BCTBX_PUBLIC void bc_tester_set_verbose_func(int (*func)(const char*)); BCTBX_PUBLIC void bc_tester_set_logfile_func(int (*func)(const char*)); BCTBX_PUBLIC int bc_tester_nb_suites(void); BCTBX_PUBLIC int bc_tester_nb_tests(const char* name); BCTBX_PUBLIC void bc_tester_list_suites(void); BCTBX_PUBLIC void bc_tester_list_tests(const char *suite_name); BCTBX_PUBLIC const char * bc_tester_suite_name(int suite_index); BCTBX_PUBLIC const char * bc_tester_test_name(const char *suite_name, int test_index); BCTBX_PUBLIC int bc_tester_run_suite(test_suite_t *suite, const char *tag_name); BCTBX_PUBLIC int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name); BCTBX_PUBLIC int bc_tester_suite_index(const char *suite_name); BCTBX_PUBLIC const char * bc_tester_current_suite_name(void); BCTBX_PUBLIC const char * bc_tester_current_test_name(void); BCTBX_PUBLIC const char ** bc_tester_current_test_tags(void); BCTBX_PUBLIC char* bc_sprintfva(const char* format, va_list args); BCTBX_PUBLIC char* bc_sprintf(const char* format, ...); BCTBX_PUBLIC void bc_free(void *ptr); BCTBX_PUBLIC char * bc_tester_get_failed_asserts(void); BCTBX_PUBLIC unsigned int bc_get_number_of_failures(void); BCTBX_PUBLIC void bc_set_trace_handler(void(*handler)(int, const char*, va_list)); /** * Get full path to the given resource * * @param name relative resource path * @return path to the resource. Must be freed by caller. */ BCTBX_PUBLIC char * bc_tester_res(const char *name); /** * Get full path to the given writable_file * * @param name relative writable file path * @return path to the writable file. Must be freed by caller. */ BCTBX_PUBLIC char * bc_tester_file(const char *name); /*Redefine the CU_... macros WITHOUT final ';' semicolon, to allow IF conditions and smarter error message */ extern int CU_assertImplementation(int bValue, unsigned int uiLine, const char *strCondition, const char *strFile, const char *strFunction, int bFatal); /** * Test unit assertion * * @return 1 if assert was true, 0 otherwise */ BCTBX_PUBLIC int bc_assert(const char* file, int line, int predicate, const char* format); #define _BC_ASSERT_PRED(name, pred, actual, expected, type, ...) \ do { \ char format[4096] = {0}; \ type cactual = (actual); \ type cexpected = (expected); \ snprintf(format, 4096, name "(" #actual ", " #expected ") - " __VA_ARGS__); \ bc_assert(__FILE__, __LINE__, pred, format); \ } while (0) #define BC_PASS(msg) bc_assert(__FILE__, __LINE__, TRUE, "BC_PASS(" #msg ").") #define BC_FAIL(msg) bc_assert(__FILE__, __LINE__, FALSE, "BC_FAIL(" #msg ").") #define BC_ASSERT(value) bc_assert(__FILE__, __LINE__, (value), #value) #define BC_TEST(value) bc_assert(__FILE__, __LINE__, (value), #value) #define BC_ASSERT_TRUE(value) bc_assert(__FILE__, __LINE__, (value), "BC_ASSERT_TRUE(" #value ")") #define BC_ASSERT_FALSE(value) bc_assert(__FILE__, __LINE__, !(value), "BC_ASSERT_FALSE(" #value ")") #define BC_ASSERT_PTR_EQUAL(actual, expected) bc_assert(__FILE__, __LINE__, ((actual) == (expected)), "BC_ASSERT_PTR_EQUAL(" #actual "!=" #expected ")") #define BC_ASSERT_PTR_NOT_EQUAL(actual, expected) bc_assert(__FILE__, __LINE__, ((actual) != (expected)), "BC_ASSERT_PTR_NOT_EQUAL(" #actual "==" #expected ")") #define BC_ASSERT_PTR_NULL(value) bc_assert(__FILE__, __LINE__, ((value) == NULL), "BC_ASSERT_PTR_NULL(" #value ")") #define BC_ASSERT_PTR_NOT_NULL(value) bc_assert(__FILE__, __LINE__, ((value) != NULL), "BC_ASSERT_PTR_NOT_NULL(" #value ")") #define BC_ASSERT_STRING_NOT_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_NOT_EQUAL", (strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, "Expected NOT %s but it was.", cexpected) #define BC_ASSERT_NSTRING_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_EQUAL", !(strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, "Expected %*s but was %*s.", (int)(count), cexpected, (int)(count), cactual) #define BC_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_NOT_EQUAL", (strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, "Expected %*s but it was.", (int)count, cexpected) #define BC_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_EQUAL", ((fabs((double)(cactual) - (cexpected)) <= fabs((double)(granularity)))), actual, expected, double, "Expected %f but was %f.", cexpected, cactual) #define BC_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_NOT_EQUAL", ((fabs((double)(cactual) - (cexpected)) > fabs((double)(granularity)))), actual, expected, double, "Expected %f but was %f.", cexpected, cactual) #define BC_ASSERT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_EQUAL", ((cactual) == (cexpected)), actual, expected, type, "Expected " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_NOT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_NOT_EQUAL", ((cactual) != (cexpected)), actual, expected, type, "Expected NOT " type_format " but it was.", cexpected) #define BC_ASSERT_STRING_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_EQUAL", cactual && cexpected && !(strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, "Expected %s but was %s.", cexpected, cactual) #define BC_ASSERT_GREATER(actual, min, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_GREATER", ((cactual) >= (cexpected)), actual, min, type, "Expected at least " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_LOWER(actual, max, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_LOWER", ((cactual) <= (cexpected)), actual, max, type, "Expected at most " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_GREATER_STRICT(actual, min, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_GREATER", ((cactual) > (cexpected)), actual, min, type, "Expected more than " type_format " but was " type_format ".", cexpected, cactual) #define BC_ASSERT_LOWER_STRICT(actual, max, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_LOWER", ((cactual) < (cexpected)), actual, max, type, "Expected less than " type_format " but was " type_format ".", cexpected, cactual) #ifdef __cplusplus } #endif #endif