From 1853fd4f9750d5b1997471baf1ef74fa88931da3 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 4 Sep 2018 17:50:15 +0200 Subject: third_party: Update cmocka to version 1.1.3 * Added function to filter tests (cmocka_set_test_filter) * Fixed fixture error reporting * Some improvement for API documentation -> https://api.cmocka.org/ * Fixed subunit output on failures * Do not abort if a test is skipped Signed-off-by: Andreas Schneider Reviewed-by: Jeremy Allison --- third_party/cmocka/cmocka.c | 261 ++++++++++++++++++++++++++++++++------------ third_party/cmocka/cmocka.h | 28 +++-- 2 files changed, 214 insertions(+), 75 deletions(-) (limited to 'third_party/cmocka') diff --git a/third_party/cmocka/cmocka.c b/third_party/cmocka/cmocka.c index 0861c2cbcd6..b21fe15536c 100644 --- a/third_party/cmocka/cmocka.c +++ b/third_party/cmocka/cmocka.c @@ -1,6 +1,6 @@ /* * Copyright 2008 Google Inc. - * Copyright 2014-2015 Andreas Schneider + * Copyright 2014-2018 Andreas Schneider * Copyright 2015 Jakub Hrozek * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,7 +45,7 @@ #include /* - * This allows one to add a platform specific header file. Some embedded platforms + * This allows to add a platform specific header file. Some embedded platforms * sometimes miss certain types and definitions. * * Example: @@ -148,12 +148,17 @@ typedef struct ListNode { } ListNode; /* Debug information for malloc(). */ -typedef struct MallocBlockInfo { +struct MallocBlockInfoData { void* block; /* Address of the block returned by malloc(). */ size_t allocated_size; /* Total size of the allocated block. */ size_t size; /* Request block size. */ SourceLocation location; /* Where the block was allocated. */ ListNode node; /* Node within list of all allocated blocks. */ +}; + +typedef union { + struct MallocBlockInfoData *data; + char *ptr; } MallocBlockInfo; /* State of each test. */ @@ -247,7 +252,7 @@ static void remove_always_return_values(ListNode * const map_head, static size_t check_for_leftover_values_list(const ListNode * head, const char * const error_message); -static int check_for_leftover_values( +static size_t check_for_leftover_values( const ListNode * const map_head, const char * const error_message, const size_t number_of_symbol_names); @@ -305,6 +310,8 @@ static CMOCKA_THREAD ListNode global_allocated_blocks; static enum cm_message_output global_msg_output = CM_OUTPUT_STDOUT; +static const char *global_test_filter_pattern; + #ifndef _WIN32 /* Signals caught by exception_handler(). */ static const int exception_signals[] = { @@ -381,9 +388,15 @@ struct CMUnitTestState { /* Exit the currently executing test. */ static void exit_test(const int quit_application) { - const char *abort_test = getenv("CMOCKA_TEST_ABORT"); + const char *env = getenv("CMOCKA_TEST_ABORT"); + int abort_test = 0; + + if (env != NULL && strlen(env) == 1) { + abort_test = (env[0] == '1'); + } - if (abort_test != NULL && abort_test[0] == '1') { + if (global_skip_test == 0 && + abort_test == 1) { print_error("%s", cm_error_message); abort(); } else if (global_running_test) { @@ -453,7 +466,7 @@ static int c_strreplace(char *src, memmove(src + of + rl, src + of + pl, l - of - pl + 1); } - strncpy(src + of, repl, rl); + memcpy(src + of, repl, rl); if (str_replaced != NULL) { *str_replaced = 1; @@ -464,6 +477,64 @@ static int c_strreplace(char *src, return 0; } +static int c_strmatch(const char *str, const char *pattern) +{ + int ok; + + if (str == NULL || pattern == NULL) { + return 0; + } + + for (;;) { + /* Check if pattern is done */ + if (*pattern == '\0') { + /* If string is at the end, we're good */ + if (*str == '\0') { + return 1; + } + + return 0; + } + + if (*pattern == '*') { + /* Move on */ + pattern++; + + /* If we are at the end, everything is fine */ + if (*pattern == '\0') { + return 1; + } + + /* Try to match each position */ + for (; *str != '\0'; str++) { + ok = c_strmatch(str, pattern); + if (ok) { + return 1; + } + } + + /* No match */ + return 0; + } + + /* If we are at the end, leave */ + if (*str == '\0') { + return 0; + } + + /* Check if we have a single wildcard or matching char */ + if (*pattern != '?' && *str != *pattern) { + return 0; + } + + /* Move string and pattern */ + str++; + pattern++; + } + + return 0; +} + /* Create function results and expected parameter lists. */ void initialize_testing(const char *test_name) { (void)test_name; @@ -489,7 +560,8 @@ static void fail_if_leftover_values(const char *test_name) { remove_always_return_values(&global_function_parameter_map_head, 2); if (check_for_leftover_values( &global_function_parameter_map_head, - "%s parameter still has values that haven't been checked.\n", 2)) { + "'%s' parameter still has values that haven't been checked.\n", + 2)) { error_occurred = 1; } @@ -620,7 +692,7 @@ static int list_find(ListNode * const head, const void *value, /* Returns the first node of a list */ static int list_first(ListNode * const head, ListNode **output) { - ListNode *target_node; + ListNode *target_node = NULL; assert_non_null(head); if (list_empty(head)) { return 0; @@ -708,8 +780,8 @@ static void add_symbol_value(ListNode * const symbol_map_head, static int get_symbol_value( ListNode * const head, const char * const symbol_names[], const size_t number_of_symbol_names, void **output) { - const char* symbol_name; - ListNode *target_node; + const char* symbol_name = NULL; + ListNode *target_node = NULL; assert_non_null(head); assert_non_null(symbol_names); assert_true(number_of_symbol_names); @@ -717,8 +789,8 @@ static int get_symbol_value( symbol_name = symbol_names[0]; if (list_find(head, symbol_name, symbol_names_match, &target_node)) { - SymbolMapValue *map_value; - ListNode *child_list; + SymbolMapValue *map_value = NULL; + ListNode *child_list = NULL; int return_value = 0; assert_non_null(target_node); assert_non_null(target_node->value); @@ -730,6 +802,10 @@ static int get_symbol_value( ListNode *value_node = NULL; return_value = list_first(child_list, &value_node); assert_true(return_value); + /* Add a check to silence clang analyzer */ + if (return_value == 0) { + goto out; + } *output = (void*) value_node->value; return_value = value_node->refcount; if (value_node->refcount - 1 == 0) { @@ -746,9 +822,9 @@ static int get_symbol_value( list_remove_free(target_node, free_symbol_map_value, (void*)0); } return return_value; - } else { - cm_print_error("No entries for symbol %s.\n", symbol_name); } +out: + cm_print_error("No entries for symbol %s.\n", symbol_name); return 0; } @@ -835,11 +911,11 @@ static size_t check_for_leftover_values_list(const ListNode * head, * Checks if there are any leftover values set up by the test that were never * retrieved through execution, and fail the test if that is the case. */ -static int check_for_leftover_values( +static size_t check_for_leftover_values( const ListNode * const map_head, const char * const error_message, const size_t number_of_symbol_names) { const ListNode *current; - int symbols_with_leftover_values = 0; + size_t symbols_with_leftover_values = 0; assert_non_null(map_head); assert_true(number_of_symbol_names); @@ -865,7 +941,7 @@ static int check_for_leftover_values( location->file, location->line); } } else { - cm_print_error("%s.", value->symbol_name); + cm_print_error("%s: ", value->symbol_name); check_for_leftover_values(child_list, error_message, number_of_symbol_names - 1); } @@ -1187,19 +1263,24 @@ static int string_not_equal_display_error( */ static int memory_equal_display_error(const char* const a, const char* const b, const size_t size) { - int differences = 0; + size_t differences = 0; size_t i; for (i = 0; i < size; i++) { const char l = a[i]; const char r = b[i]; if (l != r) { - cm_print_error("difference at offset %" PRIdS " 0x%02x 0x%02x\n", - i, l, r); + if (differences < 16) { + cm_print_error("difference at offset %" PRIdS " 0x%02x 0x%02x\n", + i, l, r); + } differences ++; } } - if (differences) { - cm_print_error("%d bytes of %p and %p differ\n", + if (differences > 0) { + if (differences >= 16) { + cm_print_error("...\n"); + } + cm_print_error("%"PRIdS " bytes of %p and %p differ\n", differences, (void *)a, (void *)b); return 0; } @@ -1526,7 +1607,7 @@ void _expect_any( void _check_expected( const char * const function_name, const char * const parameter_name, const char* file, const int line, const LargestIntegralType value) { - void *result; + void *result = NULL; const char* symbols[] = {function_name, parameter_name}; const int rc = get_symbol_value(&global_function_parameter_map_head, symbols, 2, &result); @@ -1819,16 +1900,22 @@ static void vcm_free_error(char *err_msg) /* Use the real malloc in this function. */ #undef malloc void* _test_malloc(const size_t size, const char* file, const int line) { - char* ptr; - MallocBlockInfo *block_info; + char *ptr = NULL; + MallocBlockInfo block_info; ListNode * const block_list = get_allocated_blocks_list(); - const size_t allocate_size = size + (MALLOC_GUARD_SIZE * 2) + - sizeof(*block_info) + MALLOC_ALIGNMENT; - char* const block = (char*)malloc(allocate_size); + size_t allocate_size; + char *block = NULL; + + allocate_size = size + (MALLOC_GUARD_SIZE * 2) + + sizeof(struct MallocBlockInfoData) + MALLOC_ALIGNMENT; + assert_true(allocate_size > size); + + block = (char *)malloc(allocate_size); assert_non_null(block); /* Calculate the returned address. */ - ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + sizeof(*block_info) + + ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData) + MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1)); /* Initialize the guard blocks. */ @@ -1836,14 +1923,14 @@ void* _test_malloc(const size_t size, const char* file, const int line) { memset(ptr + size, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE); memset(ptr, MALLOC_ALLOC_PATTERN, size); - block_info = (MallocBlockInfo*)(ptr - (MALLOC_GUARD_SIZE + - sizeof(*block_info))); - set_source_location(&block_info->location, file, line); - block_info->allocated_size = allocate_size; - block_info->size = size; - block_info->block = block; - block_info->node.value = block_info; - list_add(block_list, &block_info->node); + block_info.ptr = ptr - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); + set_source_location(&block_info.data->location, file, line); + block_info.data->allocated_size = allocate_size; + block_info.data->size = size; + block_info.data->block = block; + block_info.data->node.value = block_info.ptr; + list_add(block_list, &block_info.data->node); return ptr; } #define malloc test_malloc @@ -1864,19 +1951,19 @@ void* _test_calloc(const size_t number_of_elements, const size_t size, void _test_free(void* const ptr, const char* file, const int line) { unsigned int i; char *block = discard_const_p(char, ptr); - MallocBlockInfo *block_info; + MallocBlockInfo block_info; if (ptr == NULL) { return; } _assert_true(cast_ptr_to_largest_integral_type(ptr), "ptr", file, line); - block_info = (MallocBlockInfo*)(block - (MALLOC_GUARD_SIZE + - sizeof(*block_info))); + block_info.ptr = block - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); /* Check the guard blocks. */ { char *guards[2] = {block - MALLOC_GUARD_SIZE, - block + block_info->size}; + block + block_info.data->size}; for (i = 0; i < ARRAY_SIZE(guards); i++) { unsigned int j; char * const guard = guards[i]; @@ -1886,19 +1973,22 @@ void _test_free(void* const ptr, const char* file, const int line) { cm_print_error(SOURCE_LOCATION_FORMAT ": error: Guard block of %p size=%lu is corrupt\n" SOURCE_LOCATION_FORMAT ": note: allocated here at %p\n", - file, line, - ptr, (unsigned long)block_info->size, - block_info->location.file, block_info->location.line, + file, + line, + ptr, + (unsigned long)block_info.data->size, + block_info.data->location.file, + block_info.data->location.line, (void *)&guard[j]); _fail(file, line); } } } } - list_remove(&block_info->node, NULL, NULL); + list_remove(&block_info.data->node, NULL, NULL); - block = discard_const_p(char, block_info->block); - memset(block, MALLOC_FREE_PATTERN, block_info->allocated_size); + block = discard_const_p(char, block_info.data->block); + memset(block, MALLOC_FREE_PATTERN, block_info.data->allocated_size); free(block); } #define free test_free @@ -1909,7 +1999,7 @@ void *_test_realloc(void *ptr, const char *file, const int line) { - MallocBlockInfo *block_info; + MallocBlockInfo block_info; char *block = ptr; size_t block_size = size; void *new_block; @@ -1923,16 +2013,16 @@ void *_test_realloc(void *ptr, return NULL; } - block_info = (MallocBlockInfo*)(block - (MALLOC_GUARD_SIZE + - sizeof(*block_info))); + block_info.ptr = block - (MALLOC_GUARD_SIZE + + sizeof(struct MallocBlockInfoData)); new_block = _test_malloc(size, file, line); if (new_block == NULL) { return NULL; } - if (block_info->size < size) { - block_size = block_info->size; + if (block_info.data->size < size) { + block_size = block_info.data->size; } memcpy(new_block, ptr, block_size); @@ -1960,17 +2050,18 @@ static size_t display_allocated_blocks(const ListNode * const check_point) { assert_non_null(check_point->next); for (node = check_point->next; node != head; node = node->next) { - const MallocBlockInfo * const block_info = - (const MallocBlockInfo*)node->value; - assert_non_null(block_info); + const MallocBlockInfo block_info = { + .ptr = discard_const(node->value), + }; + assert_non_null(block_info.ptr); if (allocated_blocks == 0) { cm_print_error("Blocks allocated...\n"); } cm_print_error(SOURCE_LOCATION_FORMAT ": note: block %p allocated here\n", - block_info->location.file, - block_info->location.line, - block_info->block); + block_info.data->location.file, + block_info.data->location.line, + block_info.data->block); allocated_blocks++; } return allocated_blocks; @@ -1987,9 +2078,13 @@ static void free_allocated_blocks(const ListNode * const check_point) { assert_non_null(node); while (node != head) { - MallocBlockInfo * const block_info = (MallocBlockInfo*)node->value; + const MallocBlockInfo block_info = { + .ptr = discard_const(node->value), + }; node = node->next; - free(discard_const_p(char, block_info) + sizeof(*block_info) + MALLOC_GUARD_SIZE); + free(discard_const_p(char, block_info.data) + + sizeof(struct MallocBlockInfoData) + + MALLOC_GUARD_SIZE); } } @@ -2415,7 +2510,7 @@ static void cmprintf_subunit(enum cm_printf_type type, case PRINTF_TEST_FAILURE: print_message("failure: %s", test_name); if (error_message != NULL) { - print_message(" [\n%s]\n", error_message); + print_message(" [\n%s\n]\n", error_message); } break; case PRINTF_TEST_SKIPPED: @@ -2515,6 +2610,11 @@ void cmocka_set_message_output(enum cm_message_output output) global_msg_output = output; } +void cmocka_set_test_filter(const char *pattern) +{ + global_test_filter_pattern = pattern; +} + /**************************************************************************** * TIME CALCULATIONS ****************************************************************************/ @@ -2800,7 +2900,15 @@ int _cmocka_run_group_tests(const char *group_name, (tests[i].test_func != NULL || tests[i].setup_func != NULL || tests[i].teardown_func != NULL)) { - cm_tests[i] = (struct CMUnitTestState) { + if (global_test_filter_pattern != NULL) { + int ok; + + ok = c_strmatch(tests[i].name, global_test_filter_pattern); + if (!ok) { + continue; + } + } + cm_tests[total_tests] = (struct CMUnitTestState) { .test = &tests[i], .status = CM_TEST_NOT_STARTED, .state = NULL, @@ -2871,10 +2979,16 @@ int _cmocka_run_group_tests(const char *group_name, break; } } else { + char err_msg[2048] = {0}; + + snprintf(err_msg, sizeof(err_msg), + "Could not run test: %s", + cmtest->error_message); + cmprintf(PRINTF_TEST_ERROR, test_number, cmtest->test->name, - "Could not run the test - check test fixtures"); + err_msg); total_errors++; } } @@ -3167,7 +3281,7 @@ int _run_group_tests(const UnitTest * const tests, const size_t number_of_tests) const char *setup_name; size_t num_setups = 0; UnitTestFunction teardown = NULL; - const char *teardown_name; + const char *teardown_name = NULL; size_t num_teardowns = 0; size_t current_test = 0; size_t i; @@ -3178,10 +3292,21 @@ int _run_group_tests(const UnitTest * const tests, const size_t number_of_tests) size_t total_failed = 0; /* Check point of the heap state. */ const ListNode * const check_point = check_point_allocated_blocks(); - const char** failed_names = (const char**)malloc(number_of_tests * - sizeof(*failed_names)); + const char **failed_names = NULL; void **current_state = NULL; - TestState group_state; + TestState group_state = { + .check_point = NULL, + }; + + if (number_of_tests == 0) { + return -1; + } + + failed_names = (const char **)malloc(number_of_tests * + sizeof(*failed_names)); + if (failed_names == NULL) { + return -2; + } /* Find setup and teardown function */ for (i = 0; i < number_of_tests; i++) { diff --git a/third_party/cmocka/cmocka.h b/third_party/cmocka/cmocka.h index 4fd82a98b30..e6861c83d27 100644 --- a/third_party/cmocka/cmocka.h +++ b/third_party/cmocka/cmocka.h @@ -1,5 +1,6 @@ /* * Copyright 2008 Google Inc. + * Copyright 2014-2018 Andreas Schneider * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +57,7 @@ int __stdcall IsDebuggerPresent(); /* If __WORDSIZE is not set, try to figure it out and default to 32 bit. */ #ifndef __WORDSIZE -# if defined(__x86_64__) && !defined(__ILP32__) +# if (defined(__x86_64__) && !defined(__ILP32__)) || defined(__sparc_v9__) || defined(__sparcv9) # define __WORDSIZE 64 # else # define __WORDSIZE 32 @@ -1107,7 +1108,7 @@ void assert_return_code(int rc, int error); * @brief Assert that the given pointer is non-NULL. * * The function prints an error message to standard error and terminates the - * test by calling fail() if the pointer is non-NULL. + * test by calling fail() if the pointer is NULL. * * @param[in] pointer The pointer to evaluate. * @@ -1698,8 +1699,8 @@ static inline void _unit_test_dummy(void **state) { */ #define cmocka_unit_test_prestate_setup_teardown(f, setup, teardown, state) { #f, f, setup, teardown, state } -#define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof(tests)[0]) -#define run_group_tests(tests) _run_group_tests(tests, sizeof(tests) / sizeof(tests)[0]) +#define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof((tests)[0])) +#define run_group_tests(tests) _run_group_tests(tests, sizeof(tests) / sizeof((tests)[0])) #ifdef DOXYGEN /** @@ -1763,7 +1764,7 @@ int cmocka_run_group_tests(const struct CMUnitTest group_tests[], CMFixtureFunction group_teardown); #else # define cmocka_run_group_tests(group_tests, group_setup, group_teardown) \ - _cmocka_run_group_tests(#group_tests, group_tests, sizeof(group_tests) / sizeof(group_tests)[0], group_setup, group_teardown) + _cmocka_run_group_tests(#group_tests, group_tests, sizeof(group_tests) / sizeof((group_tests)[0]), group_setup, group_teardown) #endif #ifdef DOXYGEN @@ -1832,7 +1833,7 @@ int cmocka_run_group_tests_name(const char *group_name, CMFixtureFunction group_teardown); #else # define cmocka_run_group_tests_name(group_name, group_tests, group_setup, group_teardown) \ - _cmocka_run_group_tests(group_name, group_tests, sizeof(group_tests) / sizeof(group_tests)[0], group_setup, group_teardown) + _cmocka_run_group_tests(group_name, group_tests, sizeof(group_tests) / sizeof((group_tests)[0]), group_setup, group_teardown) #endif /** @} */ @@ -2269,7 +2270,7 @@ enum cm_message_output { /** * @brief Function to set the output format for a test. * - * The output format for the test can either be set globally using this + * The ouput format for the test can either be set globally using this * function or overriden with environment variable CMOCKA_MESSAGE_OUTPUT. * * The environment variable can be set to either STDOUT, SUBUNIT, TAP or XML. @@ -2279,6 +2280,19 @@ enum cm_message_output { */ void cmocka_set_message_output(enum cm_message_output output); + +/** + * @brief Set a pattern to only run the test matching the pattern. + * + * This allows to filter tests and only run the ones matching the pattern. Thep + * pattern can include two wildards. The first is '*', a wildcard that matches + * zero or more characters, or ‘?’, a wildcard that matches exactly one + * character. + * + * @param[in] pattern The pattern to match, e.g. "test_wurst*" + */ +void cmocka_set_test_filter(const char *pattern); + /** @} */ #endif /* CMOCKA_H_ */ -- cgit v1.2.1