diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 295b7a1..8fbf2c4 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -2,19 +2,17 @@ MAINTAINERCLEANFILES = Makefile.in bin_PROGRAMS = exactness exactness_helper exactness_play exactness_record -exactness_SOURCES = exactness.c +exactness_SOURCES = exactness.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c -exactness_helper_SOURCES = exactness_helper.c +exactness_helper_SOURCES = exactness_helper.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c exactness_play_SOURCES = player.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c exactness_record_SOURCES = recorder.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c -exactness_LDADD = \ - @EFL_LIBS@ ../lib/libexactness_player.la +exactness_LDADD = @EFL_LIBS@ -exactness_helper_LDADD = \ - @EFL_LIBS@ ../lib/libexactness_player.la +exactness_helper_LDADD = @EFL_LIBS@ exactness_play_LDADD = @EFL_LIBS@ diff --git a/src/bin/exactness.c b/src/bin/exactness.c index af30a2e..2aa2c91 100644 --- a/src/bin/exactness.c +++ b/src/bin/exactness.c @@ -5,44 +5,8 @@ #include "exactness_private.h" - -typedef struct _List_Entry List_Entry; - -struct _List_Entry -{ - EINA_INLIST; - char *name; - const char *command; -}; - -typedef struct _Exactness_Config Exactness_Config; - -struct _Exactness_Config -{ - unsigned short jobs; - char *base_dir; - char *dest_dir; - char *wrap_command; - Eina_Bool verbose; - Eina_Bool store_objects; -}; - -typedef struct _Exactness_Ctx Exactness_Ctx; - -struct _Exactness_Ctx -{ - unsigned int tests_executed; - Eina_List *errors; - Eina_List *compare_errors; -}; - #define SCHEDULER_CMD_SIZE 1024 -typedef void (*Scheduler_Cb)(const List_Entry *, char *); - -Exactness_Config exactness_config; -Exactness_Ctx exactness_ctx; - #define ORIG_SUBDIR "orig" #define CURRENT_SUBDIR "current" @@ -52,155 +16,78 @@ Exactness_Ctx exactness_ctx; #define CONFIG "ELM_SCALE=1 ELM_FINGER_SIZE=10" +typedef struct +{ + EINA_INLIST; + char *name; + const char *command; +} List_Entry; + typedef enum { RUN_SIMULATION, RUN_PLAY, - RUN_RECORD, RUN_INIT } Run_Mode; -typedef struct -{ - Scheduler_Cb prepare_func; - List_Entry *last; - unsigned short jobs; -} Scheduler_Ctx; +static unsigned short _running_jobs, _max_jobs; +static char *_base_dir; +static char *_dest_dir; +static char *_wrap_command; +static int _verbose = 0; -static Ecore_Event_Handler *_job_del_callback_handler = NULL; +static Run_Mode _mode; +static List_Entry *_next_test_to_run = NULL; +static unsigned int _tests_executed = 0; -static Eina_Bool _job_dispatch(List_Entry *ent, Scheduler_Ctx *ctx); +static Eina_List *_errors; +static Eina_List *_compare_errors; -static Eina_Bool -_job_deleted_cb(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Exe_Event_Del *msg = (Ecore_Exe_Event_Del *) event; - Scheduler_Ctx *ctx = data; +static Eina_Bool _job_consume(); - if ((msg->exit_code != 0) || (msg->exit_signal != 0)) - { - List_Entry *ent = ecore_exe_data_get(msg->exe); - exactness_ctx.errors = eina_list_append(exactness_ctx.errors, ent); - } - - ctx->jobs++; - - exactness_ctx.tests_executed++; - - if (ctx->last && EINA_INLIST_GET(ctx->last)->next) - { - ctx->last = EINA_INLIST_CONTAINER_GET( - EINA_INLIST_GET(ctx->last)->next, List_Entry); - - _job_dispatch(ctx->last, ctx); - } - - /* If all jobs are done. */ - if (ctx->jobs == exactness_config.jobs) - { - free(ctx); - ecore_main_loop_quit(); - return ECORE_CALLBACK_DONE; - } - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_job_dispatch(List_Entry *ent, Scheduler_Ctx *ctx) -{ - char buf[SCHEDULER_CMD_SIZE]; - Ecore_Exe *exe; - - if (ctx->jobs == 0) - return EINA_FALSE; - ctx->jobs--; - - ctx->prepare_func(ent, buf); - - if (!_job_del_callback_handler) - { - _job_del_callback_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, - _job_deleted_cb, ctx); - } - - exe = ecore_exe_pipe_run(buf, ECORE_EXE_TERM_WITH_PARENT, ent); - - if (!exe) - { - fprintf(stderr, "Failed executing test '%s'\n", ent->name); - } - - return EINA_TRUE; -} - -void -scheduler_run(Scheduler_Cb prepare_func, List_Entry *list) -{ - Scheduler_Ctx *ctx = calloc(1, sizeof(*ctx)); - List_Entry *list_itr; - ctx->jobs = exactness_config.jobs; - ctx->prepare_func = prepare_func; - - EINA_INLIST_FOREACH(list, list_itr) - { - if (!_job_dispatch(list_itr, ctx)) - break; - ctx->last = list_itr; - } -} static void -_run_command_prepare(const List_Entry *ent, Run_Mode mode, char *buf) +_printf(int verbose, const char *fmt, ...) +{ + va_list ap; + if (!_verbose || verbose > _verbose) return; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +static void +_run_command_prepare(const List_Entry *ent, char *buf) { Eina_Strbuf *sbuf = eina_strbuf_new(); - eina_strbuf_append_printf(sbuf, "TSUITE_VERBOSE=%d ", exactness_config.verbose); + eina_strbuf_append_printf(sbuf, "TSUITE_VERBOSE=%d ", _verbose); eina_strbuf_append_printf(sbuf, "TSUITE_FILE_NAME='%s/%s.rec' ", - exactness_config.base_dir, ent->name); + _base_dir, ent->name); eina_strbuf_append_printf(sbuf, "TSUITE_TEST_NAME='%s' ", ent->name); - switch (mode) + switch (_mode) { - case RUN_SIMULATION: - { - break; - } case RUN_PLAY: { eina_strbuf_append(sbuf, "ELM_ENGINE='buffer' "); eina_strbuf_append_printf(sbuf, "TSUITE_DEST_DIR='%s/%s' ", - exactness_config.dest_dir, CURRENT_SUBDIR); - if (exactness_config.store_objects) - eina_strbuf_append(sbuf, "TSUITE_STORE_OBJECTS=1 "); + _dest_dir, CURRENT_SUBDIR); break; } case RUN_INIT: { eina_strbuf_append(sbuf, "ELM_ENGINE='buffer' "); eina_strbuf_append_printf(sbuf, "TSUITE_DEST_DIR='%s/%s' ", - exactness_config.dest_dir, ORIG_SUBDIR); - if (exactness_config.store_objects) - eina_strbuf_append(sbuf, "TSUITE_STORE_OBJECTS=1 "); - break; - } - case RUN_RECORD: - { - eina_strbuf_append_printf(sbuf, "TSUITE_DEST_DIR='%s' ", - exactness_config.dest_dir); + _dest_dir, ORIG_SUBDIR); break; } default: break; } eina_strbuf_append_printf(sbuf, "LD_PRELOAD='%s/exactness/libexactness_%s.so' %s %s %s", - PACKAGE_LIBDIR, mode == RUN_RECORD ? "recorder" : "player", - CONFIG, exactness_config.wrap_command, ent->command); + PACKAGE_LIBDIR, "player", + CONFIG, _wrap_command, ent->command); strncpy(buf, eina_strbuf_string_get(sbuf), SCHEDULER_CMD_SIZE-1); eina_strbuf_free(sbuf); - if (exactness_config.verbose) printf("Command: %s\n", buf); -} - -void -run_test_simulation(const List_Entry *ent, char *buf) -{ - _run_command_prepare(ent, RUN_SIMULATION, buf); + _printf(1, "Command: %s\n", buf); } static Eina_Bool @@ -226,36 +113,91 @@ _prefix_rm_cb(const char *name, const char *path, void *data) } } -void -run_test_prefix_rm(const char *dir, const char *prefix) +static void +_run_test_prefix_rm(const char *dir, const char *prefix) { eina_file_dir_list(dir, 0, _prefix_rm_cb, (void *) prefix); } -void -run_test_play(const List_Entry *ent, char *buf) +static Eina_Bool +_job_deleted_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { - _run_command_prepare(ent, RUN_PLAY, buf); + Ecore_Exe_Event_Del *msg = (Ecore_Exe_Event_Del *) event; - run_test_prefix_rm(CURRENT_SUBDIR, ent->name); - if (exactness_config.verbose) - { - printf("Running %s\n", ent->name); + if ((msg->exit_code != 0) || (msg->exit_signal != 0)) + { + List_Entry *ent = ecore_exe_data_get(msg->exe); + _errors = eina_list_append(_errors, ent); } + + _running_jobs--; + + _job_consume(); + + /* If all jobs are done. */ + if (!_running_jobs) + { + ecore_main_loop_quit(); + return ECORE_CALLBACK_DONE; + } + + return ECORE_CALLBACK_RENEW; } -void -run_test_record(const List_Entry *ent, char *buf) +static Eina_Bool +_job_consume() { - _run_command_prepare(ent, RUN_RECORD, buf); + static Ecore_Event_Handler *job_del_callback_handler = NULL; + char buf[SCHEDULER_CMD_SIZE]; + Ecore_Exe *exe; + List_Entry *ent = _next_test_to_run; + + if (_running_jobs == _max_jobs) return EINA_FALSE; + if (!ent) return EINA_FALSE; + + _running_jobs++; + _tests_executed++; + + _run_command_prepare(ent, buf); + switch (_mode) + { + case RUN_PLAY: + { + _run_test_prefix_rm(CURRENT_SUBDIR, ent->name); + _printf(1, "Running %s\n", ent->name); + break; + } + case RUN_INIT: + { + _run_test_prefix_rm(ORIG_SUBDIR, ent->name); + break; + } + default: break; + } + + if (!job_del_callback_handler) + { + job_del_callback_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, + _job_deleted_cb, NULL); + } + + exe = ecore_exe_pipe_run(buf, ECORE_EXE_TERM_WITH_PARENT, ent); + + _next_test_to_run = EINA_INLIST_CONTAINER_GET( + EINA_INLIST_GET(ent)->next, List_Entry); + + if (!exe) + { + fprintf(stderr, "Failed executing test '%s'\n", ent->name); + } + + return EINA_TRUE; } -void -run_test_init(const List_Entry *ent, char *buf) +static void +_scheduler_run() { - _run_command_prepare(ent, RUN_INIT, buf); - - run_test_prefix_rm(ORIG_SUBDIR, ent->name); + while (_job_consume()); } static Eina_Bool @@ -316,20 +258,18 @@ _compare_list_cb(const char *name, const char *path EINA_UNUSED, void *data) if (_check_prefix(prefix, name)) { char filename1[EXACTNESS_PATH_MAX], filename2[EXACTNESS_PATH_MAX]; - snprintf(filename1, EXACTNESS_PATH_MAX, "%s/%s/%s", exactness_config.dest_dir, ORIG_SUBDIR, name); - snprintf(filename2, EXACTNESS_PATH_MAX, "%s/%s/%s", exactness_config.dest_dir, CURRENT_SUBDIR, name); + snprintf(filename1, EXACTNESS_PATH_MAX, "%s/%s/%s", _dest_dir, ORIG_SUBDIR, name); + snprintf(filename2, EXACTNESS_PATH_MAX, "%s/%s/%s", _dest_dir, CURRENT_SUBDIR, name); if (!_is_equal(filename1, filename2)) { char buf[EXACTNESS_PATH_MAX]; - exactness_ctx.compare_errors = - eina_list_append(exactness_ctx.compare_errors, - strdup(name)); + _compare_errors = eina_list_append(_compare_errors, strdup(name)); /* FIXME: Clean up. */ snprintf(buf, EXACTNESS_PATH_MAX, "compare '%s' '%s' '%s/%s/comp_%s'", filename1, filename2, - exactness_config.dest_dir, + _dest_dir, CURRENT_SUBDIR, name); if (system(buf)) { @@ -339,16 +279,16 @@ _compare_list_cb(const char *name, const char *path EINA_UNUSED, void *data) } } -void -run_test_compare(const List_Entry *ent) +static void +_run_test_compare(const List_Entry *ent) { char origdir[EXACTNESS_PATH_MAX]; - snprintf(origdir, EXACTNESS_PATH_MAX, "%s/%s", exactness_config.dest_dir, ORIG_SUBDIR); + snprintf(origdir, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, ORIG_SUBDIR); eina_file_dir_list(origdir, 0, _compare_list_cb, ent->name); } -List_Entry * -list_file_load(const char *filename) +static List_Entry * +_list_file_load(const char *filename) { List_Entry *ret = NULL; char buf[BUF_SIZE] = ""; @@ -398,8 +338,8 @@ list_file_load(const char *filename) return ret; } -void -list_file_free(List_Entry *list) +static void +_list_file_free(List_Entry *list) { while (list) { @@ -419,15 +359,6 @@ _errors_sort_cb(List_Entry *a, List_Entry *b) return strcmp(a->name, b->name); } -static void -_exactness_errors_sort(Exactness_Ctx *ctx) -{ - ctx->errors = - eina_list_sort(ctx->errors, 0, (Eina_Compare_Cb) _errors_sort_cb); - ctx->compare_errors = - eina_list_sort(ctx->compare_errors, 0, (Eina_Compare_Cb) strcmp); -} - static const Ecore_Getopt optdesc = { "exactness", "%prog [options] <-r|-p|-i|-s> ", @@ -441,12 +372,10 @@ static const Ecore_Getopt optdesc = { ECORE_GETOPT_STORE_STR('d', "dest-dir", "The location of the images."), ECORE_GETOPT_STORE_STR('w', "wrap", "Use a custom command to launch the tests (e.g valgrind)."), ECORE_GETOPT_STORE_USHORT('j', "jobs", "The number of jobs to run in parallel."), - ECORE_GETOPT_STORE_TRUE('r', "record", "Run in record mode."), ECORE_GETOPT_STORE_TRUE('p', "play", "Run in play mode."), ECORE_GETOPT_STORE_TRUE('i', "init", "Run in init mode."), ECORE_GETOPT_STORE_TRUE('s', "simulation", "Run in simulation mode."), - ECORE_GETOPT_STORE_TRUE('S', "store-objects", "Store information about objects at every screen shot time."), - ECORE_GETOPT_STORE_TRUE('v', "verbose", "Turn verbose messages on."), + ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."), ECORE_GETOPT_LICENSE('L', "license"), ECORE_GETOPT_COPYRIGHT('C', "copyright"), @@ -464,19 +393,17 @@ main(int argc, char *argv[]) int args = 0; const char *list_file = ""; char tmp[EXACTNESS_PATH_MAX]; - Eina_Bool mode_record, mode_play, mode_init, mode_simulation; - Eina_Bool want_quit; + Eina_Bool mode_play = EINA_FALSE, mode_init = EINA_FALSE, mode_simulation = EINA_FALSE; + Eina_Bool want_quit = EINA_FALSE; Ecore_Getopt_Value values[] = { - ECORE_GETOPT_VALUE_STR(exactness_config.base_dir), - ECORE_GETOPT_VALUE_STR(exactness_config.dest_dir), - ECORE_GETOPT_VALUE_STR(exactness_config.wrap_command), - ECORE_GETOPT_VALUE_USHORT(exactness_config.jobs), - ECORE_GETOPT_VALUE_BOOL(mode_record), + ECORE_GETOPT_VALUE_STR(_base_dir), + ECORE_GETOPT_VALUE_STR(_dest_dir), + ECORE_GETOPT_VALUE_STR(_wrap_command), + ECORE_GETOPT_VALUE_USHORT(_max_jobs), ECORE_GETOPT_VALUE_BOOL(mode_play), ECORE_GETOPT_VALUE_BOOL(mode_init), ECORE_GETOPT_VALUE_BOOL(mode_simulation), - ECORE_GETOPT_VALUE_BOOL(exactness_config.store_objects), - ECORE_GETOPT_VALUE_BOOL(exactness_config.verbose), + ECORE_GETOPT_VALUE_INT(_verbose), ECORE_GETOPT_VALUE_BOOL(want_quit), ECORE_GETOPT_VALUE_BOOL(want_quit), @@ -486,13 +413,13 @@ main(int argc, char *argv[]) }; ecore_init(); - mode_record = mode_play = mode_init = mode_simulation = EINA_FALSE; + mode_play = mode_init = mode_simulation = EINA_FALSE; want_quit = EINA_FALSE; - exactness_config.base_dir = "./recordings"; - exactness_config.dest_dir = "./"; - exactness_config.wrap_command = ""; - exactness_config.jobs = 1; - exactness_config.verbose = EINA_FALSE; + _base_dir = "./recordings"; + _dest_dir = "./"; + _wrap_command = ""; + _max_jobs = 1; + _verbose = 0; args = ecore_getopt_parse(&optdesc, values, argc, argv); if (args < 0) @@ -513,7 +440,7 @@ main(int argc, char *argv[]) ret = 1; goto end; } - else if (mode_record + mode_play + mode_init + mode_simulation != 1) + else if (mode_play + mode_init + mode_simulation != 1) { fprintf(stderr, "At least and only one of the running modes can be set.\n"); ecore_getopt_help(stderr, &optdesc); @@ -525,7 +452,8 @@ main(int argc, char *argv[]) /* Load the list file and start iterating over the records. */ - test_list = list_file_load(list_file); + test_list = _list_file_load(list_file); + _next_test_to_run = test_list; if (!test_list) { @@ -536,18 +464,15 @@ main(int argc, char *argv[]) /* Pre-run summary */ fprintf(stderr, "Running with settings:\n"); - fprintf(stderr, "\tConcurrent jobs: %d\n", exactness_config.jobs); + fprintf(stderr, "\tConcurrent jobs: %d\n", _max_jobs); fprintf(stderr, "\tTest list: %s\n", list_file); - fprintf(stderr, "\tBase dir: %s\n", exactness_config.base_dir); - fprintf(stderr, "\tDest dir: %s\n", exactness_config.dest_dir); + fprintf(stderr, "\tBase dir: %s\n", _base_dir); + fprintf(stderr, "\tDest dir: %s\n", _dest_dir); - if (mode_record) + if (mode_play) { - scheduler_run(run_test_record, test_list); - } - else if (mode_play) - { - if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", exactness_config.dest_dir, CURRENT_SUBDIR) + _mode = RUN_PLAY; + if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, CURRENT_SUBDIR) >= EXACTNESS_PATH_MAX) { fprintf(stderr, "Path too long: %s", tmp); @@ -555,11 +480,11 @@ main(int argc, char *argv[]) goto end; } mkdir(tmp, 0744); - scheduler_run(run_test_play, test_list); } else if (mode_init) { - if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", exactness_config.dest_dir, ORIG_SUBDIR) + _mode = RUN_INIT; + if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, ORIG_SUBDIR) >= EXACTNESS_PATH_MAX) { fprintf(stderr, "Path too long: %s", tmp); @@ -567,12 +492,12 @@ main(int argc, char *argv[]) goto end; } mkdir(tmp, 0744); - scheduler_run(run_test_init, test_list); } else if (mode_simulation) { - scheduler_run(run_test_simulation, test_list); + _mode = RUN_SIMULATION; } + _scheduler_run(); ecore_main_loop_begin(); @@ -585,25 +510,26 @@ main(int argc, char *argv[]) EINA_INLIST_FOREACH(test_list, list_itr) { - run_test_compare(list_itr); + _run_test_compare(list_itr); } } printf("Finished executing %u out of %u tests.\n", - exactness_ctx.tests_executed, + _tests_executed, eina_inlist_count(EINA_INLIST_GET(test_list))); /* Sort the errors and the compare_errors. */ - _exactness_errors_sort(&exactness_ctx); + _errors = eina_list_sort(_errors, 0, (Eina_Compare_Cb) _errors_sort_cb); + _compare_errors = eina_list_sort(_compare_errors, 0, (Eina_Compare_Cb) strcmp); - if (exactness_ctx.errors || exactness_ctx.compare_errors) + if (_errors || _compare_errors) { FILE *report_file; char report_filename[EXACTNESS_PATH_MAX] = ""; /* Generate the filename. */ snprintf(report_filename, EXACTNESS_PATH_MAX, "%s/%s/errors.html", - exactness_config.dest_dir, mode_init ? ORIG_SUBDIR : CURRENT_SUBDIR); + _dest_dir, mode_init ? ORIG_SUBDIR : CURRENT_SUBDIR); report_file = fopen(report_filename, "w+"); if (report_file) { @@ -612,14 +538,14 @@ main(int argc, char *argv[]) "" "Exactness report"); - if (exactness_ctx.errors) + if (_errors) { fprintf(report_file, "

Tests that failed execution:

"); } - if (exactness_ctx.compare_errors) + if (_compare_errors) { fprintf(report_file, "

Images that failed comparison: (Original, Current, Diff)