#include "ftest/ftest.h" //#include /* * by default display in millisecond */ /* */ #define NANOSECOND (timeunit[0]=='n') #define SECOND (timeunit[0]=='s') #define LOCK(mutex_var) pthread_mutex_lock(&mutex_var); #define UNLOCK(mutex_var) pthread_mutex_unlock(&mutex_var); #define INCREMENT(variable)\ do{\ if(is_parallel_nb){\ LOCK(mut_##variable); \ ++variable;\ UNLOCK(mut_##variable);\ }\ else ++variable;\ }while(0); /* * struct to store tests failed */ struct failed_lists{ char *name; struct failed_lists *next; }; void clear_all_falied_list(struct failed_lists **flist); #define default_ordered 0 #define default_unicolour 0 #define default_removelog 0 //#define default_parallel_nb 1 #define default_parallel_nb_opt 1 #define default_verb NORMAL /* * global variables * if not exported, it only exists in ftest.c */ /* * begin variable option */ long int verb=NORMAL; bool some_thing_wrong = 0; bool help=0; bool only_usage=0; bool ordered= 0; bool gtestlike=0; bool debug=0; bool unicolour = 0; bool removelog = 0; char *timeunit="ms"; char *savelog=NULL; char *default_timeunit="ms"; char *default_savelog="log_all_tests"; char *default_bar_progress=" c"; bool bar_progress_has_to_be_freed = 0; bool default_bar_progress_has_to_be_freed = 0; //size_t width = 80; char *colors_f[]={DEFAULT_K, GREEN_K, RED_K, YELLOW_K, BLUE_K, ""}; int k_DEFAULT=0, k_GREEN=1, k_RED=2, k_YELLOW=3, k_BLUE=4, k_NOTHING=Dknothing; char *tab_hk_f[]={ HK_EQ, HK_TR, HK_RN, HK_DN, HK_OK, HK_FL, HK_PS, HK_SK }; char *g_tab_hk_f[]={ gHK_EQ, gHK_TR, gHK_RN, gHK_DN, gHK_OK, gHK_FL, gHK_PS, gHK_SK }; int hk_EQ=0, hk_TR=1, hk_RN=2, hk_DN=3, hk_OK=4, hk_FL=5, hk_PS=6, hk_SK=7 ; //char *varHK_EQ=HK_EQ, *varHK_TR=HK_TR, *varHK_RN=HK_RN, *varHK_DN=HK_DN, *varHK_OK=HK_OK, *varHK_FL=HK_FL, *varHK_PS=HK_PS, *varHK_SK=HK_SK; bool some_tests_selected=0; size_t *array_TYPE_SIZE_T=NULL; /* if active, size = count_tests */ char **array_TYPE_STRING=NULL; size_t cur_array_TYPE_SIZE_T=0; /* < count_tests */ size_t cur_array_TYPE_STRING=0; /* * number of threads */ size_t parallel_nb = 0; size_t parallel_nb_opt = 0; /* to solve debug option */ /* * end variable option */ bool is_parallel_nb = 0; bool is_parallel_nb_opt = 0; bool is_verb = 0; bool log_parallel = true; bool progress = true; // false; char *bar_progress = " c"; /*{fill_bar,fill_dot,colored} */ bool is_bar_progress = true; size_t count_para_progress = 0; FILE **f_ou_th; size_t count_tests = 0; size_t count_pass_global = 0; size_t count_pass_local = 0; size_t count_fail_global = 0; size_t count_fail_local = 0; /* * count in local test * using array [count_test] global variable */ size_t *count_pass_test = NULL; size_t *count_fail_test = NULL; /* * count on each thread [PARALLEL] */ size_t *count_pass_thread = NULL; size_t *count_fail_thread = NULL; size_t *id_thread_self = NULL; char **log_name_file_thrd = NULL; /* * the first instance of the func struct, * it containis the first test */ struct func *f_beging = NULL; /* * current test : used by parallel tests */ struct func *current_fn = NULL; /* * list of all failed tests */ struct failed_lists *failed_l = NULL; /* * list of failed test on each thread */ struct failed_lists **thread_test_failed_l = NULL; /* * mutex to add global failed test */ pthread_mutex_t mut_global_list_fail; /* * mutex to have current test to do */ pthread_mutex_t mut_current_test; pthread_mutex_t mut_count_pass_global; pthread_mutex_t mut_count_fail_global; pthread_mutex_t mut_count_pass_local; pthread_mutex_t mut_count_fail_local; pthread_mutex_t mut_count_para_progress; pthread_cond_t cond_count_para_progress; /* * end of the global variables of test_t.c */ /* * */ void append_failed_list(struct failed_lists **fn_failed_list ,const char *name_failed){ if(*fn_failed_list){ struct failed_lists *tmp_failed_l = *fn_failed_list, *rec_tmp; while(tmp_failed_l){ rec_tmp = tmp_failed_l; tmp_failed_l = tmp_failed_l->next; } tmp_failed_l = malloc(sizeof(struct failed_lists)); tmp_failed_l->name = malloc(strlen(name_failed)+1); strcpy(tmp_failed_l->name, name_failed); tmp_failed_l->next = NULL; rec_tmp->next = tmp_failed_l; } else{ *fn_failed_list = malloc(sizeof(struct failed_lists)); (*fn_failed_list)->name = malloc(strlen(name_failed)+1); strcpy((*fn_failed_list)->name, name_failed); (*fn_failed_list)->next = NULL; } } /* * match the id global (gives by OS) of the thread with the local (the program) id of thread */ long int id_of_thread_executed(const char * func_call_name){ size_t id_from_self = pthread_self(); for(long int i=0; i<= parallel_nb; ++i){ if(id_thread_self[i] == id_from_self) return i; } /*if(id_thread_self){ for(long int i=0; i<= parallel_nb; ++i) PRINT_DEBUG(" id_thread_self[%ld] = %ld \n", i, id_thread_self[i]); }*/ /* no error, when pthread is call in a test, we will not have a match! */ PRINT_DEBUG("\n debug [%s]: called by <%s>, id_from_self: %ld\n",__func__, func_call_name,id_from_self); return -1; } /* * format name of TEST(name_f) is: 'TEST_name_f____NUM|', * and name attribute is 'TEST(name_f): test N° NUM!' (! at the end is random): * we extract NUM here * to have hash_table of the count when parallel test! */ size_t extract_num__f(const char *name_f){ size_t len = strlen(name_f); size_t val = 0, p = 1; for(long i= len-1; i>=0; --i){ PRINT_DEBUG(" name_f(%s)[%ld] = %c\n",name_f,i,name_f[i]); if(name_f[i]=='|') val = 0; if(name_f[i] >= '0' && name_f[i] <= '9'){ val += p * (name_f[i]-'0'); p *= 10; } else if( name_f[i] == ' ' || name_f[i] == '_' || name_f[i] == '=' ) break; } return val; } /* TEST_funcname___NUM -> TEST(funcname) */ char* extract_func_edited_TEST_from_exec_func_name(char* func_name){ size_t len=strlen(func_name); char *ret_name=malloc(len+1); strcpy(ret_name, func_name); char *pad="____"; size_t len_pad=strlen(pad); ret_name[4]='('; for(size_t i=5;i= len_db ){ char *tmp_bp=malloc(len_bp+1); strcpy(tmp_bp,bar_progress); tmp_bp[2]='u'; bar_progress=tmp_bp; bar_progress_has_to_be_freed = 1; } else{ char *tmp_bp=malloc(len_db+1); strcpy(tmp_bp,default_bar_progress); tmp_bp[2]='u'; default_bar_progress=tmp_bp; default_bar_progress_has_to_be_freed = 1; } } if(gtestlike){ for(int i=0; i<=hk_SK; ++i) tab_hk_f[i]=g_tab_hk_f[i]; } parallel_nb = parallel_nb_opt; is_parallel_nb = is_parallel_nb_opt; /*if(savelog){ f_savelog=fopen(savelog, "w+"); }*/ } // ===================================== begin options handle ======================================================= void usage(int argc, char **argv){ printf("usage: %s [OPTIONS] [] \n\n" " or : %s [OPTIONS]=[]\n\n",argv[0],argv[0]); printf("OPTIONS\n"); printf( "\t -h, --help \n" "\t\tprint help, options variables\n\n"); printf( "\t -g, --gtestlike \n" "\t\tto have gtest hook like!\n\n"); printf( "\t -p , --parallel , -p=, --parallel=\n" "\t\tby default the program ran in sequantial all test, \n" "\t\tif this option is set, the program run tests on NB threads.\n" "\t\tEach thread pull up one test out the list of all test not yet executed,\n" "\t\tand execute it, until the list is empty \n\n"); printf( "\t -t , --time , -t=, --time= \n" "\t\tby default unit is millisecons ms, the other of unit are choices are second (or s), and nanosecond (or ns)\n" "\t\tex: -t ns or -t=nanosecond or --time=n to set nanosecond unit\n\n"); printf( "\t -u , --unicolour\n" "\t\tby default, the result is colored, if you choice this option, it prints with default color\n\n"); printf( "\t -r , --remove\n" "\t\tif the option parallel is choosen the result on each thread is record in separate files,\n" "\t\tthis option remove the file logs of each thread after all tests.\n\n"); printf( "\t -s , --savelog , -s=file, --savelog=file\n" "\t\tthis option save the global ordered result in 'file',\n" "\t\t \n\n"); printf( "\t -n=, ... ,--numtests=,...\n" "\t\tthis option allow to execute only the selected numbers of tests (in the order in file test)\n" "\t\tex: -n=0,6,3 8 to execute the tests 0,3,6,8 (if the number is less than the count of all tests)\n\n"); printf( "\t -l=, ... ,--listests=,...\n" "\t\tthis option allow to execute only the selected name of tests. It allows empty name by using '-l=,'\n" "\t\tex: -l=name0,,name2 : execute only (if they exist): TEST(name0),TEST(),TEST(name2)\n\n"); printf( "\t -b , --bar_progress , -b=BPRGSS, --bar_progress=BPRGSS. Example: -b=\"#_c\"\n" "\t\tthis option change progression bar if it is active. The first character (\'#\') fills the bar\n" "\t\tthe second char (\'_\') fills the other part of bar. the bar is colored if the 3rd char is \'c\' and not if different.\n" "\t\tby default the progress bar is active and the option is -b=\" c\", if need not colored, we can put -b=\" n\" option.\n\n"); printf( "\t -z=