src/umockcall.c (337 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include <stddef.h> #include <string.h> #include "macro_utils/macro_utils.h" #include "umock_c/umockcall.h" #include "umock_c/umockalloc.h" #include "umock_c/umock_log.h" typedef struct UMOCKCALL_TAG { char* function_name; void* umockcall_data; UMOCKCALL_DATA_COPY_FUNC umockcall_data_copy; UMOCKCALL_DATA_FREE_FUNC umockcall_data_free; UMOCKCALL_DATA_STRINGIFY_FUNC umockcall_data_stringify; UMOCKCALL_DATA_ARE_EQUAL_FUNC umockcall_data_are_equal; unsigned int fail_call : 1; unsigned int ignore_all_calls : 1; unsigned int call_can_fail : 1; } UMOCKCALL; UMOCKCALL_HANDLE umockcall_create(const char* function_name, void* umockcall_data, UMOCKCALL_DATA_COPY_FUNC umockcall_data_copy, UMOCKCALL_DATA_FREE_FUNC umockcall_data_free, UMOCKCALL_DATA_STRINGIFY_FUNC umockcall_data_stringify, UMOCKCALL_DATA_ARE_EQUAL_FUNC umockcall_data_are_equal) { UMOCKCALL* result; if ((function_name == NULL) || (umockcall_data == NULL) || (umockcall_data_copy == NULL) || (umockcall_data_free == NULL) || (umockcall_data_stringify == NULL) || (umockcall_data_are_equal == NULL)) { /* Codes_SRS_UMOCKCALL_01_003: [ If any of the arguments are NULL, umockcall_create shall fail and return NULL. ] */ UMOCK_LOG("umockcall: Cannot create call, invalid arguments: function_name = %p, umockcall_data = %p, umockcall_data_free = %p, umockcall_data_stringify = %p, umockcall_data_are_equal = %p.", function_name, umockcall_data, umockcall_data_free, umockcall_data_stringify, umockcall_data_are_equal); result = NULL; } else { /* Codes_SRS_UMOCKCALL_01_001: [ umockcall_create shall create a new instance of a umock call and on success it shall return a non-NULL handle to it. ] */ result = (UMOCKCALL*)umockalloc_malloc(sizeof(UMOCKCALL)); /* Codes_SRS_UMOCKCALL_01_002: [ If allocating memory for the umock call instance fails, umockcall_create shall return NULL. ] */ if (result != NULL) { size_t function_name_length = strlen(function_name); result->function_name = (char*)umockalloc_malloc(function_name_length + 1); if (result->function_name == NULL) { /* Codes_SRS_UMOCKCALL_01_002: [ If allocating memory for the umock call instance fails, umockcall_create shall return NULL. ] */ UMOCK_LOG("umockcall: Cannot allocate memory for the call function name."); umockalloc_free(result); result = NULL; } else { (void)memcpy(result->function_name, function_name, function_name_length + 1); result->umockcall_data = umockcall_data; result->umockcall_data_copy = umockcall_data_copy; result->umockcall_data_free = umockcall_data_free; result->umockcall_data_stringify = umockcall_data_stringify; result->umockcall_data_are_equal = umockcall_data_are_equal; result->fail_call = 0; result->ignore_all_calls = 0; } } } return result; } void umockcall_destroy(UMOCKCALL_HANDLE umockcall) { /* Codes_SRS_UMOCKCALL_01_005: [ If the umockcall argument is NULL then umockcall_destroy shall do nothing. ]*/ if (umockcall != NULL) { /* Codes_SRS_UMOCKCALL_01_004: [ umockcall_destroy shall free a previously allocated umock call instance. ] */ umockcall->umockcall_data_free(umockcall->umockcall_data); umockalloc_free(umockcall->function_name); umockalloc_free(umockcall); } } /* Codes_SRS_UMOCKCALL_01_006: [ umockcall_are_equal shall compare the two mock calls and return whether they are equal or not. ] */ int umockcall_are_equal(UMOCKCALL_HANDLE left, UMOCKCALL_HANDLE right) { int result; if (left == right) { /* Codes_SRS_UMOCKCALL_01_024: [ If both left and right pointers are equal, umockcall_are_equal shall return 1. ] */ result = 1; } else if ((left == NULL) || (right == NULL)) { /* Codes_SRS_UMOCKCALL_01_015: [ If only one of the left or right arguments are NULL, umockcall_are_equal shall return 0. ] */ result = 0; } else { if (left->umockcall_data_are_equal != right->umockcall_data_are_equal) { /* Codes_SRS_UMOCKCALL_01_014: [ If the two calls have different are_equal functions that have been passed to umockcall_create then the calls shall be considered different and 0 shall be returned. ] */ result = 0; } else if (strcmp(left->function_name, right->function_name) != 0) { /* Codes_SRS_UMOCKCALL_01_025: [ If the function name does not match for the 2 calls, umockcall_are_equal shall return 0. ]*/ result = 0; } else { /* Codes_SRS_UMOCKCALL_01_026: [ The call data shall be evaluated by calling the umockcall_data_are_equal function passed in umockcall_create while passing as arguments the umockcall_data associated with each call handle. ]*/ switch (left->umockcall_data_are_equal(left->umockcall_data, right->umockcall_data)) { default: /* Codes_SRS_UMOCKCALL_01_029: [ If the underlying umockcall_data_are_equal fails (returns anything else than 0 or 1), then umockcall_are_equal shall fail and return -1. ] */ UMOCK_LOG("umockcall: comparing call data failed."); result = -1; break; case 1: /* Codes_SRS_UMOCKCALL_01_027: [ If the underlying umockcall_data_are_equal returns 1, then umockcall_are_equal shall return 1. ]*/ result = 1; break; case 0: /* Codes_SRS_UMOCKCALL_01_028: [ If the underlying umockcall_data_are_equal returns 0, then umockcall_are_equal shall return 0. ]*/ result = 0; break; } } } return result; } char* umockcall_stringify(UMOCKCALL_HANDLE umockcall) { char* result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_017: [ If the umockcall argument is NULL, umockcall_stringify shall return NULL. ]*/ UMOCK_LOG("umockcall: NULL umockcall in stringify."); result = NULL; } else { /* Codes_SRS_UMOCKCALL_01_019: [ To obtain the arguments string, umockcall_stringify shall call the umockcall_data_stringify function passed to umockcall_create and pass to it the umockcall_data pointer (also given in umockcall_create). ]*/ char* stringified_args = umockcall->umockcall_data_stringify(umockcall->umockcall_data); if (stringified_args == NULL) { /* Codes_SRS_UMOCKCALL_01_020: [ If the underlying umockcall_data_stringify call fails, umockcall_stringify shall fail and return NULL. ]*/ UMOCK_LOG("umockcall: umockcall data stringify failed."); result = NULL; } else { /* Codes_SRS_UMOCKCALL_01_016: [ umockcall_stringify shall return a string representation of the mock call in the form "[function_name(arguments)]". ] */ size_t function_name_length = strlen(umockcall->function_name); size_t stringified_args_length = strlen(stringified_args); /* 4 because () and [] */ size_t call_length = function_name_length + stringified_args_length + 4; /* Codes_SRS_UMOCKCALL_01_018: [ The returned string shall be a newly allocated string and it is to be freed by the caller. ]*/ result = (char*)umockalloc_malloc(call_length + 1); /* Codes_SRS_UMOCKCALL_01_021: [ If not enough memory can be allocated for the string to be returned, umockcall_stringify shall fail and return NULL. ]*/ if (result != NULL) { result[0] = '['; (void)memcpy(&result[1], umockcall->function_name, function_name_length); result[function_name_length + 1] = '('; (void)memcpy(&result[function_name_length + 2], stringified_args, stringified_args_length); result[function_name_length + stringified_args_length + 2] = ')'; result[function_name_length + stringified_args_length + 3] = ']'; result[function_name_length + stringified_args_length + 4] = '\0'; } /* Codes_SRS_UMOCKCALL_01_030: [ umockcall_stringify shall free the string obtained from umockcall_data_stringify. ]*/ umockalloc_free(stringified_args); } } return result; } void* umockcall_get_call_data(UMOCKCALL_HANDLE umockcall) { void* umockcall_data; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_023: [ If umockcall is NULL, umockcall_get_call_data shall return NULL. ]*/ UMOCK_LOG("umockcall: NULL umockcall in getting call data."); umockcall_data = NULL; } else { /* Codes_SRS_UMOCKCALL_01_022: [ umockcall_get_call_data shall return the associated umock call data that was passed to umockcall_create. ]*/ umockcall_data = umockcall->umockcall_data; } return umockcall_data; } /* Codes_SRS_UMOCKCALL_01_031: [ umockcall_clone shall clone a umock call and on success it shall return a handle to the newly cloned call. ] */ UMOCKCALL_HANDLE umockcall_clone(UMOCKCALL_HANDLE umockcall) { UMOCKCALL_HANDLE result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_032: [ If umockcall is NULL, umockcall_clone shall return NULL. ]*/ UMOCK_LOG("umockcall_clone: NULL umockcall in getting call data."); result = NULL; } else { result = (UMOCKCALL*)umockalloc_malloc(sizeof(UMOCKCALL)); if (result == NULL) { /* Codes_SRS_UMOCKCALL_01_043: [ If allocating memory for the new umock call fails, umockcall_clone shall return NULL. ]*/ UMOCK_LOG("umockcall_clone: Failed allocating memory for new copied call."); } else { size_t function_name_length = strlen(umockcall->function_name); result->function_name = (char*)umockalloc_malloc(function_name_length + 1); if (result->function_name == NULL) { /* Codes_SRS_UMOCKCALL_01_036: [ If allocating memory for the function name fails, umockcall_clone shall return NULL. ]*/ UMOCK_LOG("umockcall_clone: Failed allocating memory for new copied call function name."); umockalloc_free(result); result = NULL; } else { /* Codes_SRS_UMOCKCALL_01_035: [ umockcall_clone shall copy also the function name. ]*/ (void)memcpy(result->function_name, umockcall->function_name, function_name_length + 1); /* Codes_SRS_UMOCKCALL_01_033: [ The call data shall be cloned by calling the umockcall_data_copy function passed in umockcall_create and passing as argument the umockcall_data value passed in umockcall_create. ]*/ result->umockcall_data = umockcall->umockcall_data_copy(umockcall->umockcall_data); if (result->umockcall_data == NULL) { /* Codes_SRS_UMOCKCALL_01_034: [ If umockcall_data_copy fails then umockcall_clone shall return NULL. ]*/ UMOCK_LOG("umockcall_clone: Failed copying call data."); umockalloc_free(result->function_name); umockalloc_free(result); result = NULL; } else { /* Codes_SRS_UMOCKCALL_01_037: [ umockcall_clone shall also copy all the functions passed to umockcall_create (umockcall_data_copy, umockcall_data_free, umockcall_data_are_equal, umockcall_data_stringify). ]*/ result->umockcall_data_are_equal = umockcall->umockcall_data_are_equal; result->umockcall_data_copy = umockcall->umockcall_data_copy; result->umockcall_data_free = umockcall->umockcall_data_free; result->umockcall_data_stringify = umockcall->umockcall_data_stringify; result->ignore_all_calls = umockcall->ignore_all_calls; result->call_can_fail = umockcall->call_can_fail; result->fail_call = umockcall->fail_call; } } } } return result; } int umockcall_set_fail_call(UMOCKCALL_HANDLE umockcall, int fail_call) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_039: [ If umockcall is NULL, umockcall_set_fail_call shall return a non-zero value. ]*/ UMOCK_LOG("umockcall_set_fail_call: NULL umockcall."); result = __LINE__; } else { switch (fail_call) { default: /* Codes_SRS_UMOCKCALL_01_040: [ If a value different than 0 and 1 is passed as fail_call, umockcall_set_fail_call shall return a non-zero value. ]*/ UMOCK_LOG("umockcall_set_fail_call: Invalid fail_call value: %d.", fail_call); result = __LINE__; break; case 0: /* Codes_SRS_UMOCKCALL_01_038: [ umockcall_set_fail_call shall store the fail_call value, associating it with the umockcall call instance. ]*/ umockcall->fail_call = 0; /* Codes_SRS_UMOCKCALL_01_044: [ On success umockcall_set_fail_call shall return 0. ]*/ result = 0; break; case 1: /* Codes_SRS_UMOCKCALL_01_038: [ umockcall_set_fail_call shall store the fail_call value, associating it with the umockcall call instance. ]*/ umockcall->fail_call = 1; /* Codes_SRS_UMOCKCALL_01_044: [ On success umockcall_set_fail_call shall return 0. ]*/ result = 0; break; } } return result; } int umockcall_get_fail_call(UMOCKCALL_HANDLE umockcall) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_042: [ If umockcall is NULL, umockcall_get_fail_call shall return -1. ]*/ UMOCK_LOG("NULL umokcall argument."); result = -1; } else { /* Codes_SRS_UMOCKCALL_01_041: [ umockcall_get_fail_call shall retrieve the fail_call value, associated with the umockcall call instance. ]*/ result = umockcall->fail_call ? 1 : 0; } return result; } int umockcall_set_ignore_all_calls(UMOCKCALL_HANDLE umockcall, int ignore_all_calls) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_047: [ If umockcall is NULL, umockcall_set_ignore_all_calls shall return a non-zero value. ]*/ UMOCK_LOG("umockcall_set_fail_call: NULL umockcall."); result = __LINE__; } else { switch (ignore_all_calls) { default: /* Codes_SRS_UMOCKCALL_01_048: [ If a value different than 0 and 1 is passed as ignore_all_calls, umockcall_set_ignore_all_calls shall return a non-zero value. ]*/ UMOCK_LOG("umockcall_set_fail_call: Invalid ignore_all_calls value: %d.", ignore_all_calls); result = __LINE__; break; case 0: /* Codes_SRS_UMOCKCALL_01_045: [ umockcall_set_ignore_all_calls shall store the ignore_all_calls value, associating it with the umockcall call instance. ]*/ umockcall->ignore_all_calls = 0; /* Codes_SRS_UMOCKCALL_01_046: [ On success umockcall_set_ignore_all_calls shall return 0. ]*/ result = 0; break; case 1: /* Codes_SRS_UMOCKCALL_01_045: [ umockcall_set_ignore_all_calls shall store the ignore_all_calls value, associating it with the umockcall call instance. ]*/ umockcall->ignore_all_calls = 1; /* Codes_SRS_UMOCKCALL_01_046: [ On success umockcall_set_ignore_all_calls shall return 0. ]*/ result = 0; break; } } return result; } int umockcall_get_ignore_all_calls(UMOCKCALL_HANDLE umockcall) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_01_050: [ If umockcall is NULL, umockcall_get_ignore_all_calls shall return -1. ]*/ UMOCK_LOG("NULL umokcall argument."); result = -1; } else { /* Codes_SRS_UMOCKCALL_01_049: [ umockcall_get_ignore_all_calls shall retrieve the ignore_all_calls value, associated with the umockcall call instance. ]*/ result = umockcall->ignore_all_calls ? 1 : 0; } return result; } int umockcall_set_call_can_fail(UMOCKCALL_HANDLE umockcall, int call_can_fail) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_31_051: [ If umockcall is NULL, umockcall_set_call_can_fail shall return -1. ]*/ UMOCK_LOG("umockcall_set_fail_call: NULL umockcall."); result = -1; } else { switch (call_can_fail) { default: /* Codes_SRS_UMOCKCALL_31_052: [ If a value different than 0 and 1 is passed as umockcall_set_call_can_fail, umockcall_set_call_can_fail shall return -1. ]*/ UMOCK_LOG("umockcall_c_set_can_fail: Invalid ignore_all_calls value: %d.", call_can_fail); result = -1; break; case 0: /* Codes_SRS_UMOCKCALL_31_053: [ umockcall_set_call_can_fail shall store the call_can_fail value, associating it with the umockcall call instance. ]*/ umockcall->call_can_fail = 0; result = 0; break; case 1: /* Codes_SRS_UMOCKCALL_31_053: [ umockcall_set_call_can_fail shall store the call_can_fail value, associating it with the umockcall call instance. ]*/ umockcall->call_can_fail = 1; result = 0; break; } } return result; } int umockcall_get_call_can_fail(UMOCKCALL_HANDLE umockcall) { int result; if (umockcall == NULL) { /* Codes_SRS_UMOCKCALL_31_054: [ If umockcall is NULL, umockcall_get_call_can_fail shall return -1. ]*/ UMOCK_LOG("NULL umockcall argument."); result = -1; } else { /* Codes_SRS_UMOCKCALL_31_055: [ umockcall_get_call_can_fail shall retrieve the call_can_fail value, associated with the umockcall call instance. ]*/ result = umockcall->call_can_fail ? 1 : 0; } return result; }