#ifndef __MOCK_C_H__ #define __MOCK_C_H__ #include "ftest/ftest.h" #include "tools_t/tools_t.h" #define ININITY_REPS -8 #define INITSTATE -1 #define DONOTHING 0 #define PRE_ID ___line_ /* * list of each variable called * use str_print_current_variables attibute function pointer to record variable * so if STR_PRINT_CUR_VAR is not defined, this list is empty! */ struct list_current_variable{ char *str_current_variables; struct list_current_variable *next; }; /* * list to store info abou mock function */ struct func_mock_info_struct{ long id; bool used; char *str_namefunc; char *str_conditions; char *str_caller; //char *str_current_variables; struct list_current_variable *l_current_var; int expect_call;/* 1 if EXPECT_MOCK_CALL and 0 if WILL_MOCK_CALL */ long call;/* increment when call (try to executed) and 0 if not : init value */ long failed_call;/* increment when condition not fill and 0 if not : init value */ long init_times_left;/* DONOTHING do nothing (pass to -> next), ININITY_REPS every time; INITSTATE init; > 0 execute and decrement */ long times_left;/* DONOTHING do nothing (pass to -> next), ININITY_REPS every time; INITSTATE init; > 0 execute and decrement */ struct func_mock_info_struct *next; }; /* * to list all mock responses of all mock functions in one list */ struct list_base_fmock{ struct func_mock_info_struct *info_mock; struct list_base_fmock *next; }; int parse_count_args_(char *input); void append_fmock_to_listmock(struct func_mock_info_struct **f_mock_list, struct func_mock_info_struct *f_mock); void append_list_base_fmock(struct list_base_fmock **l_fmock, struct func_mock_info_struct *f_mock); void append_variable_current(struct list_current_variable **lcurrent_var, char *current_var); void clear_fmock_info_list(struct func_mock_info_struct **f_mock_list); void clear_list_base_fmock(struct list_base_fmock **l_fmock); void clear_variable_current(struct list_current_variable **lcurrent_var); // if input == functioname___line_NBLINE return functioname, else it return the input //char* extract_name_func_mock(char *input); extern struct func_mock_info_struct *f_mock_glist; extern struct list_base_fmock *g_list_base_fmock; #if 0 int expect_call; /* 1 if EXPECT_MOCK_CALL and 0 if WILL_MOCK_CALL */\ long init_times_left; /* DONOTHING do nothing (pass to -> next), ININITY_REPS every time; INITSTATE init; > 0 execute and decrement */\ long times_left; /* DONOTHING do nothing (pass to -> next), ININITY_REPS every time; INITSTATE init; > 0 execute and decrement */\ #endif #define INIT_MOCK_INFO_IF_NO__(tmp__mock, namefunction, pre_id, id) \ (tmp__mock)->run = NULL;\ (tmp__mock)->call_mock_condition = NULL;\ /*(tmp__mock)->str_print_current_variables = list_mo_ ## namefunction .str_print_current_variables;*/\ ((tmp__mock)->info_mock)->expect_call = -1;\ ((tmp__mock)->info_mock)->used = true;\ ((tmp__mock)->info_mock)->call = 0;\ ((tmp__mock)->info_mock)->failed_call = 0;\ ((tmp__mock)->info_mock)->str_namefunc = malloc(strlen(#namefunction) + 43 + strlen(#pre_id));\ sprintf(((tmp__mock)->info_mock)->str_namefunc,"%s%s%d",#namefunction,#pre_id,id);\ ((tmp__mock)->info_mock)->str_conditions = NULL;\ ((tmp__mock)->info_mock)->str_caller = NULL;\ ((tmp__mock)->info_mock)->l_current_var= NULL;\ ((tmp__mock)->info_mock)->next = NULL;\ /*(tmp__mock)->next = NULL;*/\ append_fmock_to_listmock(&f_mock_glist, (tmp__mock)->info_mock);\ append_list_base_fmock( &g_list_base_fmock ,(tmp__mock)->info_mock); #define INIT_MOCK_INFO_IF_NO_(tmp_new_mock, namefunction, pre_id) \ INIT_MOCK_INFO_IF_NO__(tmp_new_mock, namefunction, pre_id, __LINE__) \ #define MOCK_FUNC(returntype, namefunction, args_prototype_with_parenthesis, args_call_with_parenthesis)\ /*typedef returntype FUNC_type_ ## namefunction args_prototype_with_parenthesis ;*/\ /*typedef args_prototype_with_parenthesis args_ ## namefunction;*/\ struct list_mock_return_ ## namefunction{\ returntype (*run) args_prototype_with_parenthesis;\ int (*call_mock_condition) args_prototype_with_parenthesis ;/* to store condition */\ char* (*str_print_current_variables) args_prototype_with_parenthesis ;/* to store current variables CREATE by macro STR_PRINT_CUR_VAR same arguments as MOCK_FUNC without returntype whoch is always char * */\ struct func_mock_info_struct *info_mock;\ struct list_mock_return_ ## namefunction *next;\ } list_mo_ ## namefunction;\ __attribute__((constructor)) void init_list_m_ ## namefunction(void){\ list_mo_ ## namefunction.info_mock = malloc(sizeof(struct func_mock_info_struct));\ (list_mo_ ## namefunction.info_mock)->used = false;\ (list_mo_ ## namefunction.info_mock)->times_left = INITSTATE;\ (list_mo_ ## namefunction.info_mock)->init_times_left = INITSTATE;\ list_mo_ ## namefunction.str_print_current_variables = NULL;\ list_mo_ ## namefunction.next = NULL;\ }\ \ __attribute__((destructor)) void destruct_list_m_ ## namefunction(void){ \ /*free(list_mo_ ## namefunction.info_mock);*/ \ struct list_mock_return_ ## namefunction *tmp_nn = list_mo_ ## namefunction.next, *ttmp_nn;\ if((list_mo_ ## namefunction.info_mock)->used == false ){\ free(list_mo_ ## namefunction.info_mock);\ }\ while(tmp_nn){\ ttmp_nn = tmp_nn;\ tmp_nn = tmp_nn->next;\ /*free(ttmp_nn->info_mock);*/\ free(ttmp_nn);\ }\ PRINT_DEBUG(" purge list mo_ %s done!\n",#namefunction);\ \ }\ \ returntype namefunction args_prototype_with_parenthesis {\ static size_t count_call_f=0;\ ++count_call_f;\ PRINT_DEBUG(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>count call of %s: %ld\n",#namefunction,count_call_f);\ struct list_mock_return_ ## namefunction *tmp_mock = &list_mo_ ## namefunction;\ if( (tmp_mock->info_mock)->times_left == INITSTATE ){\ PRINT_HK_C(colors_f[k_YELLOW],tab_hk_f[hk_TR]," WARNING, %s, no EXPECT_MOCK_CALL or WILL_MOCK_CALL, but called %ld times.\n",#namefunction, count_call_f);\ if(count_call_f==1){\ PRINT_HK_C(colors_f[k_YELLOW],tab_hk_f[hk_TR]," For instance:\n"\ "%s EXPECT_MOCK_CALL(%s,%s,%s,true,1){\n"\ "%s\t %s ret;\n%s \t ...do something with %s;\n"\ "%s\t return ret;\n"\ "%s }\n"\ "%s if call once and accept all args, the same args with WILL_MOCK_CALL \n\n",\ tab_hk_f[hk_TR], #returntype, #namefunction,#args_prototype_with_parenthesis, tab_hk_f[hk_TR],#returntype, \ tab_hk_f[hk_TR], #args_call_with_parenthesis, tab_hk_f[hk_TR], tab_hk_f[hk_TR], tab_hk_f[hk_TR] ); \ /*return (returntype)0;*/ \ INIT_MOCK_INFO_IF_NO_(tmp_mock,namefunction, PRE_ID);\ }/* to have log */\ /*if(list_mo_ ## namefunction.next ) PRINT_ERROR(" %s .next SHOULD BE NULL\n",STRFY(list_mo_ ## namefunction));*/\ }\ while(tmp_mock->next && (tmp_mock->info_mock)->times_left == 0) {tmp_mock = tmp_mock->next ;}\ ++((tmp_mock->info_mock)->call);\ if(tmp_mock->str_print_current_variables){\ append_variable_current(&((tmp_mock->info_mock)->l_current_var), tmp_mock->str_print_current_variables args_call_with_parenthesis);\ }\ else if(count_call_f == 1){\ PRINT_HK_C(colors_f[k_YELLOW],tab_hk_f[hk_TR]," no printer variable function defined, to define it:\n"\ "%s STR_PRINT_CUR_VAR(%s,%s,%s){\n"\ "%s\t char* ret=malloc(256);/*for instance*/;\n"\ "%s\t ... sprintf(ret,...., %s);/*for instance*/ \n"\ "%s\t return ret;\n"\ "%s }\n"\ "%s same prototype as MOCK_FUNC whithout returntype which always char* i\n\n",\ tab_hk_f[hk_TR], #namefunction,#args_prototype_with_parenthesis, #args_call_with_parenthesis, \ tab_hk_f[hk_TR], tab_hk_f[hk_TR], #args_call_with_parenthesis, tab_hk_f[hk_TR], tab_hk_f[hk_TR], tab_hk_f[hk_TR] ); \ }\ /*LOG("condition_func:%d\n", tmp_mock->call_mock_condition args_call_with_parenthesis);*/ /*LOG("%s\n","failure condition");*/\ /*EXPECT_EQ_TYPE_INT(1, tmp_mock->call_mock_condition args_call_with_parenthesis);*/ /*LOG("%s\n","failure condition");*/\ /*if ((tmp_mock->info_mock)->times_left == 0)*/ /*no longer response, default return */ \ /*return (returntype)0;*//* default return */\ if( (tmp_mock->info_mock)->str_caller == NULL){ \ if(count_call_f == 1){\ PRINT_HK_C(colors_f[k_YELLOW],tab_hk_f[hk_TR]," WARNING, no INIT_CALLER_MOCK; you can put it like this: \n"\ "%s TEST(nametest){\n"\ "%s\t INIT_CALLER_MOCK(%s); \n"\ "%s\t %s%s; \n"\ "%s }\n"\ "%s i.e before calling %s in this TEST, to have explicit logs\n",\ tab_hk_f[hk_TR], tab_hk_f[hk_TR], #namefunction, tab_hk_f[hk_TR],#namefunction,#args_call_with_parenthesis, tab_hk_f[hk_TR], tab_hk_f[hk_TR], #namefunction);} \ /*return (returntype)0;*/ \ }\ else if (((tmp_mock->info_mock)->times_left != 0) && ((tmp_mock->info_mock)->times_left != INITSTATE )) {\ size_t len0 = strlen((tmp_mock->info_mock)->str_conditions);\ size_t len1 = strlen("when checking condition call: aa");\ char *msg_call=malloc(len0 + len1 + strlen(__func__)+1);\ sprintf(msg_call,"when checking %s condition call: %s",__func__,(tmp_mock->info_mock)->str_conditions);\ HANDLE_OP_EXPECT_NAME(EQ,TYPE_INT,1, tmp_mock->call_mock_condition args_call_with_parenthesis, (tmp_mock->info_mock)->str_caller, msg_call); /*LOG("%s\n","failure condition");*/\ free(msg_call);\ }\ /*if(0 == tmp_mock->call_mock_condition args_call_with_parenthesis){\ PRINT_LOC("Failure, arguments not expected\ncondition ( %s ) not verified\n\n", (tmp_mock->info_mock)->str_conditions);\ PRINT_HK_C(RED_K,tab_hk_f[hk_TR]," 1 argument check failed from %s \n",__func__); \ }*/\ PRINT_DEBUG(" %*c VALUES: mock function:%s, conditions:%s t_left:%ld, init_left:%ld| args:%s\n",8,'^',(tmp_mock->info_mock)->str_namefunc, (tmp_mock->info_mock)->str_conditions, (tmp_mock->info_mock)->times_left,(tmp_mock->info_mock)->init_times_left, #args_call_with_parenthesis);\ if (((tmp_mock->info_mock)->times_left <= ININITY_REPS) || ((tmp_mock->info_mock)->times_left > 0)){\ --((tmp_mock->info_mock)->times_left);\ PRINT_DEBUG(" %*c VALUES: mock function:%s, conditions:%s t_left:%ld, init_left:%ld| args:%s\n",8,'v',(tmp_mock->info_mock)->str_namefunc, (tmp_mock->info_mock)->str_conditions, (tmp_mock->info_mock)->times_left,(tmp_mock->info_mock)->init_times_left, #args_call_with_parenthesis);\ if(1 == tmp_mock->call_mock_condition args_call_with_parenthesis){\ return tmp_mock->run args_call_with_parenthesis;\ }\ else ++((tmp_mock->info_mock)->failed_call);\ }\ return (returntype)0;/* default return */\ } char* extract_name_func_mock(char *input); /* * used in mock functions to check the conditions */ #define EXPECT_EQ_IN_MOCKF(var1,var2, name_f_mocked)\ do{ \ if((list_mo_ ## name_f_mocked.info_mock)->str_caller) {\ HANDLE_OP_EXPECT_NAME(EQ,TYPE_INT,var1,var2,(list_mo_ ## name_f_mocked.info_mock)->str_caller,"mock test");\ }\ else\ HANDLE_OP_EXPECT_NAME(EQ,TYPE_INT,var1,var2,__func__,"mock test");\ }while(0) /* * to inject the name TEST caller in the mock attribute info, usefull in logs and stats */ #define INIT_CALLER_MOCK(namefunction)/* */\ do{\ struct list_mock_return_ ## namefunction *tmp_mock = &list_mo_ ## namefunction;\ while(tmp_mock){\ (tmp_mock->info_mock)->str_caller=malloc(strlen(__func__)+1);\ strcpy((tmp_mock->info_mock)->str_caller,__func__);\ tmp_mock = tmp_mock->next;\ }\ }while(0); /* * to create/ define str_print_current_variables functions * prototype: char* str_print_current_variables (prototype of mock function) * the args of the macro are the same of MOCK_FUNC without the returntype which is always (char*). * It need to be defined after MOCK_FUNC but need to be before EXPECT_MOCK_CALL or WILL_MOCK_CALL */ #define STR_PRINT_CUR_VAR(namefunction, args_prototype_with_parenthesis, args_call_with_parenthesis)\ char* str_print_variables ## namefunction args_prototype_with_parenthesis;\ __attribute__((constructor)) void create_str_print_variables ## namefunction(){\ list_mo_ ## namefunction .str_print_current_variables = str_print_variables ## namefunction;\ }\ char* str_print_variables ## namefunction args_prototype_with_parenthesis #define FILL_MOCK_INFO(tmp_new_mock, namefunction, condition_on_args_expression , repeat, f_expect_call, pre_id, id, is_init) \ (tmp_new_mock)->run = CONCAT(run_ ## namefunction ## pre_id, id);\ (tmp_new_mock)->call_mock_condition = CONCAT(namefunction ## _cond_, id);\ if(!is_init)\ (tmp_new_mock)->str_print_current_variables = list_mo_ ## namefunction .str_print_current_variables;\ /*(tmp_new_mock)->info_mock = malloc(sizeof(struct func_mock_info_struct));*/\ ((tmp_new_mock)->info_mock)->expect_call = f_expect_call;\ ((tmp_new_mock)->info_mock)->used = true;\ ((tmp_new_mock)->info_mock)->call = 0;\ ((tmp_new_mock)->info_mock)->failed_call = 0;\ ((tmp_new_mock)->info_mock)->init_times_left = repeat;\ ((tmp_new_mock)->info_mock)->times_left = repeat;\ ((tmp_new_mock)->info_mock)->str_namefunc = malloc(strlen(#namefunction) + 43 + strlen(#pre_id));\ sprintf(((tmp_new_mock)->info_mock)->str_namefunc,"%s%s%d",#namefunction,#pre_id,id);\ ((tmp_new_mock)->info_mock)->str_conditions = malloc(strlen(#condition_on_args_expression)+1);\ strcpy(((tmp_new_mock)->info_mock)->str_conditions, #condition_on_args_expression);\ ((tmp_new_mock)->info_mock)->str_caller = NULL;\ ((tmp_new_mock)->info_mock)->l_current_var= NULL;\ ((tmp_new_mock)->info_mock)->next = NULL;\ (tmp_new_mock)->next = NULL;\ append_fmock_to_listmock(&f_mock_glist, (tmp_new_mock)->info_mock); #define ADD_RESPONSE_(returntype, namefunction, args_prototype_with_parenthesis, condition_on_args_expression , repeat, f_expect_call, pre_id, id)\ /*FUNC_type_ ## namefunction CONCAT(run_ ## namefunction ## pre_id , id);*/\ returntype CONCAT(run_ ## namefunction ## pre_id , id) args_prototype_with_parenthesis; \ int CONCAT(namefunction ## _cond_ , id) args_prototype_with_parenthesis {/*LOG("cond:%d\n",condition_on_args_expression);*/ return condition_on_args_expression;}\ __attribute__((constructor)) void CONCAT(append_list_ ## namefunction , id)(void){\ PRINT_DEBUG(" in constructor fmock : func :%s\n",#namefunction);\ struct list_mock_return_ ## namefunction *tmp_mock = &list_mo_ ## namefunction;\ if((tmp_mock->info_mock)->times_left == INITSTATE){/* init state */\ FILL_MOCK_INFO(tmp_mock, namefunction, condition_on_args_expression , repeat, f_expect_call, pre_id, id, true);\ append_list_base_fmock( &g_list_base_fmock ,(tmp_mock->info_mock));\ }\ else{\ while(tmp_mock->next) tmp_mock = tmp_mock->next;\ tmp_mock->next = malloc(sizeof(list_mo_ ## namefunction));\ (tmp_mock->next)->info_mock = malloc(sizeof(struct func_mock_info_struct));\ FILL_MOCK_INFO(tmp_mock->next, namefunction, condition_on_args_expression , repeat, f_expect_call, pre_id, id, false);\ /*(tmp_mock->info_mock)->next = (tmp_mock->next)->info_mock ;*/\ }\ }\ returntype CONCAT(run_ ## namefunction ## pre_id, id) args_prototype_with_parenthesis /* * have to define this below macro to rewrite the right macro identifier (PRE_ID) */ #define ADD_RESPONSE(returntype, namefunction, args_prototype_with_parenthesis, condition_on_args_expression , repeat, f_expect_call, pre_id, id)\ ADD_RESPONSE_(returntype, namefunction, args_prototype_with_parenthesis, condition_on_args_expression , repeat, f_expect_call, pre_id, id)\ #define EXPECT_MOCK_CALL(returntype, namefunction, args_prototype_with_parenthesis, condition_on_args_expression ,repeat) \ ADD_RESPONSE(returntype,namefunction, args_prototype_with_parenthesis, condition_on_args_expression, repeat, 1, PRE_ID, __LINE__) #define WILL_MOCK_CALL(returntype, namefunction, args_prototype_with_parenthesis, condition_on_args_expression ,repeat) \ ADD_RESPONSE(returntype,namefunction, args_prototype_with_parenthesis, condition_on_args_expression, repeat, 0, PRE_ID, __LINE__) #endif /* __MOCK_C_H__ */