// // Created by Rick Barenthin on 09.02.22. // #ifndef WAITUI_BDD_FOR_C_EXT_H #define WAITUI_BDD_FOR_C_EXT_H #include "bdd-for-c.h" #define __BDD_EXT_1ST_PARAM_FMT__ "'%s'" #define __BDD_EXT_OTHER_PARAM_FMT__ ", '%s'" /** * Create the format based on the count passed. * @param num The number of format string parameters * @return */ static inline char *__bdd_ext_build_format__(int num) { size_t length = (sizeof(__BDD_EXT_1ST_PARAM_FMT__) - 1) + (num - 1) * (sizeof(__BDD_EXT_OTHER_PARAM_FMT__) - 1) + 1; char *fmt = calloc(length, sizeof(*fmt)); if (!fmt) { perror("calloc(__bdd_ext_build_format__)"); abort(); } for (int i = 0; i < num; i++) { if (i != 0) { strcat(fmt, __BDD_EXT_OTHER_PARAM_FMT__); } else { strcat(fmt, __BDD_EXT_1ST_PARAM_FMT__); } } return fmt; } /** * Create a format string from a test description and format parameters. * * @param description The description of the test case * @param num The number of format string parameters * @param ... The format string parameters a comma * separated arguments * @return The created format string */ static inline char *__bdd_ext_format_string_params__(const char *description, int num, ...) { va_list args; va_list copy; int length = 1; int written = 0; char *fmt_string = NULL; char *fmt = __bdd_ext_build_format__(num); va_start(args, num); va_copy(copy, args); length += snprintf(NULL, 0, "%s [", description); length += vsnprintf(NULL, 0, fmt, copy); length += snprintf(NULL, 0, "]"); fmt_string = calloc(length, sizeof(*fmt_string)); if (!fmt_string) { perror("calloc(__bdd_ext_format_string_params__)"); abort(); } va_end(copy); written += snprintf(fmt_string, length, "%s [", description); written += vsnprintf(fmt_string + written, length - written, fmt, args); written += snprintf(fmt_string + written, length - written, "]"); va_end(args); free(fmt); return fmt_string; } /** * Create an array of `#test_param` structs. * * @note This macro must be used for passing test parameters to `for_it()`. * @example: test_params({"input", "expected"}, {"input1", "expected1"}) */ #define test_params(...) \ { __VA_ARGS__ } /** * Define arguments for a format string as one macro argument. * * @note This macro must be used for passing test parameters to `for_it()`. * @example: format_args(STR_FMT(&string), STR_FMT(&string1)); */ #define format_args(...) __VA_ARGS__ /** * Define arguments for a format string as one macro argument. * * The first argument must be the number of format string parameters. * * @example: params_format(1, "%s", "%d"); */ #define params_format(...) __VA_ARGS__ /** * Create a parametrized test case. * * Each test parameter results in an isolated test case which is * executed independently and has its own output showing the test * description followed by the given test parameters. * * @note: The given test parameters can be accessed by `#test_param`. * @note: You must call `for_it_end()` after the test code to free * allocated memory. * * @example: for_it("returns 1 and sets claim on existing claim", * params_format(2, "%s", "%d"), * format_args(test_param.input, test_param.expected), * { char *input; int expected; }, * test_params( * {"test input 1", 0}, * {"test input 2", 1}, * {"test input 4", 2}, * {"test input 5", 3} * ) * ) * * @param description: The description of the test * @param params_format: A format string for printing the parameters * of a test. Use `params_format()` macro for * format creation. * @param format_args: The arguments for the parameter format. Use * `format_args()` macro for arguments creation. * @param param_struct_body: The struct to be created holding the test * parameters. * @param params: The test parameters to be used */ #define for_it(description, params_format, format_args, param_struct_body, \ params) \ do { \ struct __bdd_ext_test_param__ param_struct_body \ __bdd_ext_test_params__[] = params; \ int __bdd_ext_input_size__ = sizeof(__bdd_ext_test_params__) / \ sizeof(__bdd_ext_test_params__[0]); \ for (int __bdd_ext_i__ = 0; __bdd_ext_i__ < __bdd_ext_input_size__; \ __bdd_ext_i__++) { \ struct __bdd_ext_test_param__ test_param = \ __bdd_ext_test_params__[__bdd_ext_i__]; \ char *__bdd_ext_param_format_string__ = \ __bdd_ext_format_string_params__(description, \ params_format); \ it(__bdd_ext_param_format_string__, format_args) { /** * End a parametrized test and free all resources allocated in #for_it. */ #define for_it_end() \ } \ free(__bdd_ext_param_format_string__); \ } \ } \ while (0) #endif//WAITUI_BDD_FOR_C_EXT_H