-#include <unit.h>
-#include <suite.h>
-#include <command.h>
-#include <context.h>
-#include <fstream.h>
-
-
-
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
-
-
-/* the unit thread start routine */
-static void*
-unit_start(void* p);
-
-unit_t
-unit_new(runner_t runner, suite_t owner, fstream_t fstream)
-{
- unit_t unit = xbt_new0(s_unit_t, 1);
-
- /* set the owner of the unit */
- unit->runner = runner;
-
- unit->fstream = fstream;
-
- unit->sem = NULL;
-
- unit->commands = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)command_free);
-
- unit->thread = NULL;
-
- unit->number_of_started_commands = 0;
- unit->number_of_interrupted_commands = 0;
- unit->number_of_failed_commands = 0;
- unit->number_of_successeded_commands = 0;
- unit->number_of_terminated_commands = 0;
- unit->interrupted = 0;
- unit->failed = 0;
- unit->successeded = 0;
- unit->parsed = 0;
- unit->released = 0;
- unit->parsing_include_file = 0;
-
-
- unit->owner = owner;
- unit->number = 0;
- unit->suites = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)suite_free);
- unit->owner = owner;
-
- unit->running_suite = 0;
-
- return unit;
-
-}
-
-void
-unit_add_suite(unit_t unit, suite_t suite)
-{
- vector_push_back(unit->suites, suite);
-}
-
-int
-unit_free(void** unitptr)
-{
- unit_t* __unitptr = (unit_t*)unitptr;
-
- vector_free(&((*__unitptr)->commands));
-
- vector_free(&((*__unitptr)->suites));
-
- /* if the unit is interrupted during its run, the semaphore is NULL */
- if((*__unitptr)->sem)
- xbt_os_sem_destroy((*__unitptr)->sem);
-
-
- free((*__unitptr)->suites);
-
- free(*__unitptr);
-
- *__unitptr = NULL;
-
- return 0;
-}
-
-static void*
-unit_start(void* p)
-{
-
- xbt_os_thread_t thread;
- xbt_os_mutex_t mutex;
- context_t context;
- int i;
-
- unit_t unit = (unit_t)p;
-
- xbt_os_mutex_acquire(unit->mutex);
- unit->runner->number_of_runned_units++;
- xbt_os_mutex_release(unit->mutex);
-
- /* try to acquire the jobs semaphore to start */
- xbt_os_sem_acquire(jobs_sem);
-
- mutex = xbt_os_mutex_init();
- context = context_new();
-
- if(want_dry_run)
- INFO1("checking unit %s...",unit->fstream->name);
-
- /* parse the file */
- unit_parse(unit, context, mutex, unit->fstream->name, unit->fstream->stream);
-
- /* if the unit is not interrupted and not failed the unit, all the file is parsed
- * so all the command are launched
- */
- if(!unit->interrupted)
- {
- unit->parsed = 1;
-
- /* all the commands have terminate before the end of the parsing of the tesh file
- * so the unit release the semaphore itself
- */
- if(!unit->released && (unit->number_of_started_commands == (unit->number_of_failed_commands + unit->number_of_interrupted_commands + unit->number_of_successeded_commands)))
- xbt_os_sem_release(unit->sem);
-
- }
-
- /* wait the end of all the commands or a command failure or an interruption */
-
-
- xbt_os_sem_acquire(unit->sem);
-
- if(unit->interrupted)
- {
- command_t command;
-
- /* interrupt all the running commands of the unit */
- for(i = 0; i < unit->number_of_commands; i++)
- {
- /*command = unit->commands[i];*/
- command = vector_get_at(unit->commands, i);
-
- if(command->status == cs_in_progress)
- /*command_interrupt(unit->commands[i]);*/
- command_interrupt(command);
- }
- }
-
-
- /* wait the end of the threads */
- for(i = 0; i < unit->number_of_commands; i++)
- {
- /*thread = unit->commands[i]->thread;*/
-
- command_t command = vector_get_at(unit->commands, i);
- thread = command->thread;
-
- if(thread)
- xbt_os_thread_join(thread,NULL);
- }
-
- context_free(&context);
-
- xbt_os_mutex_destroy(mutex);
-
- xbt_os_mutex_acquire(unit->mutex);
-
- /* increment the number of ended units */
- unit->runner->number_of_ended_units++;
-
- /* it's the last unit, release the runner */
- if(/*!unit->interrupted &&*/ (unit->runner->number_of_runned_units == unit->runner->number_of_ended_units))
- {
- if(unit->number_of_successeded_commands == unit->number_of_commands)
- unit->successeded = 1;
-
- /* first release the mutex */
- xbt_os_mutex_release(unit->mutex);
- xbt_os_sem_release(units_sem);
- }
- else
- xbt_os_mutex_release(unit->mutex);
-
- /* release the jobs semaphore, then the next unit can start */
- xbt_os_sem_release(jobs_sem);
-
- return NULL;
-
-}
-
-void
-unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, FILE* stream)
-{
- size_t len;
- char * line = NULL;
- int line_num=0;
- char file_pos[256];
- xbt_strbuff_t buff;
- int buffbegin = 0;
-
- /* Count the line length while checking wheather it's blank */
- int blankline;
- int linelen;
- /* Deal with \ at the end of the line, and call handle_line on result */
- int to_be_continued;
-
- buff=xbt_strbuff_new();
-
- while(!unit->interrupted && getline(&line, &len, stream) != -1)
- {
- blankline=1;
- linelen = 0;
- to_be_continued = 0;
-
- line_num++;
-
- while(line[linelen] != '\0')
- {
- if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')
- blankline = 0;
-
- linelen++;
- }
-
- if(blankline)
- {
- if(!context->command_line && (context->input->used || context->output->used))
- {
- ERROR1("[%d] Error: no command found in this chunk of lines.",buffbegin);
-
- if(unit->parsing_include_file)
- ERROR1("Unit `%s': NOK (syntax error)", unit->fstream->name);
- else
- ERROR2("Unit `%s' inclued in `%s' : NOK (syntax error)", file_name, unit->fstream->name);
-
- exit_code = ESYNTAX;
- unit_handle_failure(unit);
- break;
- }
-
- if(context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
-
- continue;
-
- }
-
- if(linelen>1 && line[linelen-2]=='\\')
- {
- if (linelen>2 && line[linelen-3] == '\\')
- {
- /* Damn. Escaped \ */
- line[linelen-2] = '\n';
- line[linelen-1] = '\0';
- }
- else
- {
- to_be_continued = 1;
- line[linelen-2] = '\0';
- linelen -= 2;
-
- if (!buff->used)
- buffbegin = line_num;
- }
- }
-
- if(buff->used || to_be_continued)
- {
- xbt_strbuff_append(buff,line);
-
- if (!to_be_continued)
- {
- snprintf(file_pos,256,"%s:%d",file_name,buffbegin);
- unit_handle_line(unit, context, mutex, file_pos, buff->data);
- xbt_strbuff_empty(buff);
- }
- }
- else
- {
- snprintf(file_pos,256,"%s:%d",file_name,line_num);
- unit_handle_line(unit, context, mutex, file_pos, line);
- }
- }
-
- /* Check that last command of the file ran well */
- if(context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
- /* Clear buffers */
- if (line)
- free(line);
-
- xbt_strbuff_free(buff);
-}
-
-void
-unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line)
-{
- /* Search end */
- xbt_str_rtrim(line+2,"\n");
-
- switch (line[0])
- {
- case '#':
- break;
-
- case '$':
- case '&':
-
- context->async = (line[0] == '&');
-
- /* further trim useless chars which are significant for in/output */
- xbt_str_rtrim(line+2," \t");
-
- /* Deal with CD commands here, not in rctx */
- if (!strncmp("cd ",line+2,3))
- {
- char *dir=line+4;
-
- if (context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
- /* search begining */
- while (*(dir++) == ' ');
-
- dir--;
-
- VERB1("Saw cd '%s'",dir);
-
- /*if(want_dry_run)
- {
- unit->number_of_successeded_commands++;
- }*/
- if(!want_dry_run)
- {
- if(chdir(dir))
- {
- ERROR2("Chdir to %s failed: %s",dir,strerror(errno));
- ERROR1("Test suite `%s': NOK (system error)", unit->fstream->name);
- exit_code = ECHDIR;
- unit_handle_failure(unit);
- }
- }
-
- break;
- } /* else, pushline */
- else
- {
- unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);
- break;
- }
-
- case '<':
- case '>':
- case '!':
- unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);
- break;
-
- case 'p':
- if(!want_dry_run)
- INFO2("[%s] %s",filepos,line+2);
- break;
-
- case 'P':
- if(!want_dry_run)
- CRITICAL2("[%s] %s",filepos,line+2);
- break;
-
- default:
- ERROR2("[%s] Syntax error: %s",filepos, line);
- ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
- exit_code = ESYNTAX;
- unit_handle_failure(unit);
- break;
- }
-}
-
-void
-unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* filepos, char kind, char *line)
-{
- switch (kind)
- {
- case '$':
- case '&':
-
- if(context->command_line)
- {
- command_t command;
-
- if(context->output->used || context->input->used)
- {
- ERROR2("[%s] More than one command in this chunk of lines (previous: %s).\nDunno which input/output belongs to which command.",filepos,context->command_line);
- ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
- exit_code = ESYNTAX;
- unit_handle_failure(unit);
- return;
- }
-
- if(!want_dry_run)
- {
- command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
-
- VERB1("[%s] More than one command in this chunk of lines",filepos);
- }
-
- context->command_line = strdup(line);
-
-
- context->line = strdup(filepos);
- /*INFO2("[%s] %s",filepos,context->command_line);*/
-
- break;
-
- case '<':
- xbt_strbuff_append(context->input,line);
- xbt_strbuff_append(context->input,"\n");
- break;
-
- case '>':
- xbt_strbuff_append(context->output,line);
- xbt_strbuff_append(context->output,"\n");
- break;
-
- case '!':
-
- if(context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
- if(!strncmp(line,"timeout no",strlen("timeout no")))
- {
- VERB1("[%s] (disable timeout)", filepos);
- context->timeout = INDEFINITE;
- }
- else if(!strncmp(line,"timeout ",strlen("timeout ")))
- {
- int i = 0;
- char* p = line + strlen("timeout ");
-
- while(p[i] != '\0')
- {
- if(!isdigit(p[i]))
- {
- exit_code = ESYNTAX;
- ERROR2("Invalid timeout value `%s' at %s ", line + strlen("timeout "), filepos);
- unit_handle_failure(unit);
- }
-
- i++;
- }
-
- context->timeout = atoi(line + strlen("timeout"));
- VERB2("[%s] (new timeout value: %d)",filepos,context->timeout);
-
- }
- else if (!strncmp(line,"expect signal ",strlen("expect signal ")))
- {
- context->signal = strdup(line + strlen("expect signal "));
-
- #ifdef WIN32
- if(!strstr(context->signal,"SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL"))
- {
- exit_code = ESYNTAX;
- /*ERROR2("Signal `%s' not supported at %s", line + strlen("expect signal "), filepos);*/
- unit_handle_failure(unit);
- }
- #endif
-
- xbt_str_trim(context->signal," \n");
- VERB2("[%s] (next command must raise signal %s)", filepos, context->signal);
-
- }
- else if (!strncmp(line,"expect return ",strlen("expect return ")))
- {
-
- int i = 0;
- char* p = line + strlen("expect return ");
-
-
- while(p[i] != '\0')
- {
- if(!isdigit(p[i]))
- {
- exit_code = ESYNTAX;
- ERROR2("Invalid exit code value `%s' at %s ", line + strlen("expect return "), filepos);
- unit_handle_failure(unit);
- }
-
- i++;
- }
-
- context->exit_code = atoi(line+strlen("expect return "));
- VERB2("[%s] (next command must return code %d)",filepos, context->exit_code);
-
- }
- else if (!strncmp(line,"output ignore",strlen("output ignore")))
- {
- context->output_handling = oh_ignore;
- VERB1("[%s] (ignore output of next command)", filepos);
-
- }
- else if (!strncmp(line,"output display",strlen("output display")))
- {
- context->output_handling = oh_display;
- VERB1("[%s] (ignore output of next command)", filepos);
-
- }
- else if(!strncmp(line,"include", strlen("include")))
- {
- unit_handle_include(unit, context, mutex, line + strlen("include "));
- }
-
- else if(!strncmp(line,"suite", strlen("suite")))
- {
- unit_handle_suite(unit, context, mutex, line + strlen("suite "));
- }
- else
- {
- ERROR2("%s: Malformed metacommand: %s",filepos,line);
- ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
- exit_code = ESYNTAX;
- unit_handle_failure(unit);
- return;
- }
-
- break;
- }
-}
-
-
-void
-unit_handle_failure(unit_t unit)
-{
- if(!want_keep_going_unit)
- {
- if(!unit->interrupted)
- {
- /* the unit interrupted (exit for the loop) */
- unit->interrupted = 1;
-
- /* release the unit */
- xbt_os_sem_release(unit->sem);
- }
-
- /* if the --keep-going option is not specified */
- if(!want_keep_going)
- {
- if(!interrupted)
- {
- /* request an global interruption by the runner */
- interrupted = 1;
-
- /* release the runner */
- xbt_os_sem_release(units_sem);
- }
- }
- }
-}
-
-void
-unit_run(unit_t unit, xbt_os_mutex_t mutex)
-{
- if(!interrupted)
- {
- unit->mutex = mutex;
-
- unit->sem = xbt_os_sem_init(0);
-
- /* start the unit */
- unit->thread = xbt_os_thread_create("", unit_start, unit);
- }
- else
- /* the unit is interrupted by the runner before its starting
- * in this case the unit semaphore is NULL take care of that
- * in the function unit_free()
- */
- unit->interrupted = 1;
-
-
-}
-
-void
-unit_interrupt(unit_t unit)
-{
- /* interrupt the loop */
- unit->interrupted = 1;
- xbt_os_sem_release(unit->sem);
-}
-
-void
-unit_verbose(unit_t unit)
-{
- int i, test_count;
- command_t command;
-
- printf("\nUnit : %s (%s)\n", unit->fstream->name, unit->fstream->directory);
- printf("Status informations :");
-
- if(unit->parsed && unit->number_of_successeded_commands == unit->number_of_started_commands)
- printf(" - (success)");
- else
- {
- if(unit->interrupted)
- printf(" - (interruped)");
- else
- printf(" - (failed)");
- }
-
- printf("\n");
-
- printf(" number of commands : %d\n", unit->number_of_commands);
- printf(" number of runned commands : %d\n", unit->number_of_started_commands);
- printf(" number of successeded commands : %d\n", unit->number_of_successeded_commands);
- printf(" number of failed commands : %d\n", unit->number_of_failed_commands);
- printf(" number of interrupted commands : %d\n", unit->number_of_interrupted_commands);
-
- test_count = unit->number_of_commands;
-
-
- for(i = 0; i < test_count; i++)
- {
- command = vector_get_at(unit->commands, i);
-
- /*command_display_status(unit->commands[i]);*/
- command_display_status(command);
- }
-
-
-}
-
-void
-unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name)
-{
- directory_t include;
- char* prev_directory = NULL;
- fstream_t fstream = NULL;
- struct stat buffer = {0};
-
-
- if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
- {
- INFO1("the file stream %s is in the current directory", file_name);
-
- fstream = fstream_new(getcwd(NULL, 0), file_name);
- fstream_open(fstream);
- }
- /* the file to include is not in the current directory, check if it is in a include directory */
- else
- {
- prev_directory = getcwd(NULL, 0);
-
- vector_rewind(includes);
-
- while((include = vector_get(includes)))
- {
- chdir(include->name);
-
- if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
- {
- fstream = fstream_new(include->name, file_name);
- fstream_open(fstream);
- break;
- }
-
-
- vector_move_next(includes);
- }
-
- chdir(prev_directory);
- free(prev_directory);
- }
-
-
-
- /* the file to include is not found handle the failure */
- if(!fstream)
- {
- exit_code = EINCLUDENOTFOUND;
- ERROR1("Include file %s not found",file_name);
- unit_handle_failure(unit);
- }
- else
- {
- /* parse the include file */
-
- /*unit_t __unit = unit_new(unit->runner, NULL, fstream);*/
- unit->parsing_include_file = 1;
-
- /* add the unit to the list of the runned units */
-
- /*xbt_os_mutex_acquire(unit->mutex);
- vector_push_back(__unit->runner->units->items, __unit);
- xbt_os_mutex_release(unit->mutex);*/
-
-
- if(want_dry_run)
- INFO2("checking unit %s including in %s...",fstream->name, unit->fstream->name);
-
- unit_parse(unit, context_new(), mutex, fstream->name, fstream->stream);
-
- fstream_free((void**)&fstream);
- unit->parsing_include_file = 0;
- }
-}
-
-void
-unit_handle_suite(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* description)
-{
- suite_t suite = suite_new(unit, description);
- unit_add_suite(unit, suite);
- unit->running_suite = 1;
-}
-
-int
-unit_reset(unit_t unit)
-{
- fseek(unit->fstream->stream,0L, SEEK_SET);
- unit->parsed = 0;
- unit->number_of_commands = 0;
-
- return 0;
-}
+/*\r
+ * src/unit.c - type representing the tesh unit concept.\r
+ *\r
+ * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. \r
+ *\r
+ * This program is free software; you can redistribute it and/or modify it \r
+ * under the terms of the license (GNU LGPL) which comes with this package.\r
+ *\r
+ * Purpose:\r
+ * This file contains all the definitions of the functions related with\r
+ * the tesh unit concept.\r
+ *\r
+ */\r
+ \r
+#include <unit.h>\r
+#include <command.h>\r
+#include <context.h>\r
+#include <fstream.h>\r
+#include <variable.h>\r
+#include <str_replace.h>\r
+#include <xerrno.h>\r
+\r
+\r
+\r
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
+\r
+/*! \brief unit_start - start the processing of the tesh file representing by the unit\r
+ *\r
+ * \param p A void pointer to the unit representing the tesh file to process.\r
+ *\r
+ * \return This function (thread routine always returns NULL)\r
+ *\r
+ * Scenario :\r
+ * \r
+ * 1) The unit increment the number of running unit of the runner.\r
+ * 2) The unit wait for the jobs semaphore to realy start its job.\r
+ * 3) The unit runs the parsing of its tesh file using an fstream object.\r
+ * 3.1) The fstream object parse the tesh file an launch each command with its context of execution.\r
+ * 3.2) If a syntax error is detected the fstream object handle the failure and signals it by setting\r
+ * the flag interrupted of the unit to one (depending of the keep-going and keep-going-unit flag values)\r
+ * 3.3) If a command failed (exit code do not match, timeout, ouptupt different from the expected..)\r
+ * the command handle the failure (see command_handle_failure() for more details).\r
+ * 4) After the parsing of the tesh file.\r
+ * 4.1) If all commands are successeded the last command release the unit by releasing its semaphore. \r
+ * 4.2) If a command failed or if the tesh file is malformated the unit interrupt all the commands in progress.\r
+ * 5) The unit wait for the end of all the threads associated with a command.\r
+ * 6) Its release the next waiting unit (if any) by releasing the jobs semaphore.\r
+ * 7) If its the last unit, it release the runner by releasing the semaphore used to wait for the end of all the units.\r
+ * \r
+ */\r
+static void*\r
+unit_start(void* p) \r
+{\r
+ xbt_os_thread_t thread;\r
+ xbt_os_mutex_t mutex;\r
+ unit_t include, suite;\r
+ unsigned int itc, itu, its;\r
+ int include_nb, suite_nb;\r
+ command_t command;\r
+ \r
+ unit_t root = (unit_t)p;\r
+ \r
+ /* increment the number of running units */\r
+ xbt_os_mutex_acquire(root->mutex);\r
+ root->runner->number_of_runned_units++;\r
+ xbt_os_mutex_release(root->mutex);\r
+\r
+ /* must acquire the jobs semaphore to start */\r
+ /*xbt_os_sem_acquire(jobs_sem);*/\r
+ \r
+ /* initialize the mutex used to synchronize the access to the properties of this unit */\r
+ mutex = xbt_os_mutex_init();\r
+ \r
+ if(!dry_run_flag)\r
+ INFO1("Test unit from %s",root->fstream->name);\r
+ else\r
+ INFO1("Checking unit %s...",root->fstream->name); \r
+ \r
+ /* launch the parsing of the unit */\r
+ fstream_parse(root->fstream, mutex);\r
+ \r
+ /* if the unit is not interrupted and not failed the unit, all the file is parsed\r
+ * so all the command are launched\r
+ */\r
+ if(!root->interrupted)\r
+ {\r
+ root->parsed = 1;\r
+ \r
+ /* all the commands have terminated before the end of the parsing of the tesh file\r
+ * so the unit release the semaphore itself\r
+ */\r
+ if(!root->released && (root->started_cmd_nb == (root->failed_cmd_nb + root->interrupted_cmd_nb + root->successeded_cmd_nb)))\r
+ xbt_os_sem_release(root->sem); \r
+ }\r
+ \r
+ /* wait the end of all the commands or a command failure or an interruption */\r
+\r
+ xbt_os_sem_acquire(root->sem);\r
+ \r
+\r
+ if(root->interrupted)\r
+ {\r
+\r
+ xbt_dynar_foreach(root->commands, itc , command)\r
+ {\r
+ if(command->status == cs_in_progress)\r
+ command_interrupt(command);\r
+ }\r
+\r
+ /* interrupt all the running commands of the included units */\r
+ include_nb = xbt_dynar_length(root->includes);\r
+ \r
+ xbt_dynar_foreach(root->includes, itu, include)\r
+ {\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ if(command->status == cs_in_progress)\r
+ command_interrupt(command);\r
+ }\r
+ }\r
+ \r
+ /* interrupt all the running commands of the unit */\r
+ suite_nb = xbt_dynar_length(root->suites);\r
+ \r
+ xbt_dynar_foreach(root->suites, its, suite)\r
+ {\r
+ include_nb = xbt_dynar_length(suite->includes);\r
+\r
+ xbt_dynar_foreach(suite->includes, itu, include)\r
+ {\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ if(command->status == cs_in_progress)\r
+ command_interrupt(command);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* wait the end of the command threads of the unit */\r
+ xbt_dynar_foreach(root->commands, itc, command)\r
+ {\r
+ thread = command->thread;\r
+ \r
+ if(thread)\r
+ xbt_os_thread_join(thread,NULL);\r
+ }\r
+ \r
+ /* wait the end of the command threads of the included units of the unit */\r
+ include_nb = xbt_dynar_length(root->includes);\r
+ \r
+ xbt_dynar_foreach(root->includes, itu, include)\r
+ {\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ thread = command->thread;\r
+ \r
+ if(thread)\r
+ xbt_os_thread_join(thread,NULL);\r
+ }\r
+\r
+ if(!dry_run_flag)\r
+ {\r
+ if(!include->exit_code && !include->interrupted)\r
+ INFO1("Include from %s OK",include->fstream->name);\r
+ else if(include->exit_code)\r
+ ERROR3("Include `%s' NOK : (<%s> %s)", include->fstream->name, include->err_line, error_to_string(include->exit_code, include->err_kind));\r
+ else if(include->interrupted && !include->exit_code)\r
+ INFO1("Include `(%s)' INTR",include->fstream->name);\r
+ }\r
+ }\r
+ \r
+ /* interrupt all the running commands of the unit */\r
+ suite_nb = xbt_dynar_length(root->suites);\r
+ \r
+ xbt_dynar_foreach(root->suites, its, suite)\r
+ {\r
+ include_nb = xbt_dynar_length(suite->includes);\r
+\r
+ if(!include_nb)\r
+ {\r
+ if(!suite->exit_code)\r
+ {\r
+ unit_set_error(suite, ESYNTAX, 1, suite->filepos);\r
+ ERROR2("[%s] Empty suite `(%s)' detected (no includes added)", suite->filepos, suite->description);\r
+\r
+ /* if the --keep-going option is not specified */\r
+ if(!keep_going_flag)\r
+ {\r
+ if(!interrupted)\r
+ {\r
+ /* request an global interruption by the runner */\r
+ interrupted = 1;\r
+\r
+ /* release the runner */\r
+ xbt_os_sem_release(units_sem);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ xbt_dynar_foreach(suite->includes, itu, include)\r
+ {\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ thread = command->thread;\r
+ \r
+ if(thread)\r
+ xbt_os_thread_join(thread,NULL);\r
+ }\r
+ \r
+ if(!include->exit_code && !include->interrupted)\r
+ {\r
+ if(!dry_run_flag)\r
+ INFO1("Include from %s OK",include->fstream->name);\r
+ }\r
+ else if(include->exit_code)\r
+ {\r
+ if(!dry_run_flag)\r
+ ERROR3("Include `%s' NOK : (<%s> %s)", include->fstream->name, command->context->pos, error_to_string(include->exit_code, include->err_kind));\r
+\r
+ suite->exit_code = include->exit_code;\r
+ suite->err_kind = include->err_kind;\r
+ suite->err_line = strdup(include->err_line);\r
+ }\r
+ else if(include->interrupted && !include->exit_code)\r
+ {\r
+ if(!dry_run_flag)\r
+ INFO1("Include `(%s)' INTR",include->fstream->name);\r
+\r
+ suite->interrupted = 1;\r
+ }\r
+ \r
+ }\r
+ \r
+ if(!dry_run_flag )\r
+ {\r
+ if(!suite->exit_code && !suite->interrupted)\r
+ INFO1("Test suite from %s OK",suite->description);\r
+ else if(suite->exit_code)\r
+ ERROR3("Test suite `%s' NOK : (<%s> %s) ", suite->description, suite->err_line, error_to_string(suite->exit_code, suite->err_kind));\r
+ else if(suite->interrupted && !suite->exit_code)\r
+ INFO1("Test suite `(%s)' INTR",suite->description);\r
+ }\r
+ }\r
+ \r
+ /* you can now destroy the mutex used to synchrone the command accesses to the properties of the unit */\r
+ xbt_os_mutex_destroy(mutex);\r
+\r
+ /* update the number of ended units of the runner */\r
+ xbt_os_mutex_acquire(root->mutex);\r
+ \r
+ /* increment the number of ended units */\r
+ root->runner->number_of_ended_units++;\r
+ \r
+ if(!dry_run_flag )\r
+ {\r
+ if(root->interrupted && !root->exit_code)\r
+ INFO1("Test unit from %s INTR",root->fstream->name);\r
+ else if(!root->exit_code)\r
+ INFO1("Test unit from %s OK",root->fstream->name);\r
+ else if(root->exit_code)\r
+ ERROR3("Test unit `%s': NOK (<%s> %s)",root->fstream->name, root->err_line, error_to_string(root->exit_code, root->err_kind)); \r
+ }\r
+ \r
+ /* if it's the last unit, release the runner */\r
+ if((root->runner->number_of_runned_units == root->runner->number_of_ended_units))\r
+ {\r
+ /* if all the commands of the unit are successeded itc's a successeded unit */\r
+ if(root->successeded_cmd_nb == root->cmd_nb && !root->exit_code /* case of only one cd : nb = successeded = 0)*/)\r
+ root->successeded = 1; \r
+ \r
+ /* first release the mutex */\r
+ xbt_os_mutex_release(root->mutex);\r
+ \r
+ /* release the runner */\r
+ xbt_os_sem_release(units_sem);\r
+ }\r
+ else\r
+ xbt_os_mutex_release(root->mutex);\r
+ \r
+ /* release the jobs semaphore, then the next waiting unit can start */\r
+ xbt_os_sem_release(jobs_sem);\r
+ \r
+ return NULL;\r
+\r
+}\r
+\r
+\r
+unit_t\r
+unit_new(runner_t runner, unit_t root, unit_t owner, fstream_t fstream)\r
+{\r
+ unit_t unit;\r
+ \r
+ unit = xbt_new0(s_unit_t, 1);\r
+ \r
+ /* instantiate the vector used to store all the commands of the unit */\r
+ unit->commands = xbt_dynar_new(sizeof(command_t), (void_f_pvoid_t)command_free);\r
+ \r
+ /* instantiate the vector used to store all the included units */\r
+ unit->includes = xbt_dynar_new(sizeof(unit_t), (void_f_pvoid_t)unit_free);\r
+ \r
+ /* instantiate the vector used to store all the included suites */\r
+ unit->suites = xbt_dynar_new(sizeof(unit_t), (void_f_pvoid_t)unit_free);\r
+ \r
+ /* the runner used to launch the tesh unit */\r
+ unit->runner = runner;\r
+ \r
+ /* the file stream object to use to parse the tesh file */\r
+ unit->fstream = fstream;\r
+ \r
+ if(fstream)\r
+ fstream->unit = unit;\r
+ \r
+ /* if no root parameter specified assume that itc's the root of all the units */\r
+ unit->root = root ? root : unit;\r
+ \r
+ /* the owner of the suite */\r
+ unit->owner = owner;\r
+ \r
+ unit->thread = NULL;\r
+ unit->started_cmd_nb = 0;\r
+ unit->interrupted_cmd_nb = 0;\r
+ unit->failed_cmd_nb = 0;\r
+ unit->successeded_cmd_nb = 0;\r
+ unit->terminated_cmd_nb = 0;\r
+ unit->waiting_cmd_nb = 0;\r
+ unit->interrupted = 0;\r
+ unit->failed = 0;\r
+ unit->successeded = 0;\r
+ unit->parsed = 0;\r
+ unit->released = 0;\r
+ unit->owner = owner;\r
+ unit->is_running_suite = 0;\r
+ unit->description = NULL;\r
+ unit->sem = NULL;\r
+ unit->exit_code = 0;\r
+ unit->err_kind = 0;\r
+ unit->err_line = NULL;\r
+ unit->filepos = NULL;\r
+ \r
+ \r
+\r
+ return unit;\r
+}\r
+\r
+void\r
+unit_set_error(unit_t unit, int errcode, int kind, const char* line)\r
+{\r
+ if(!unit->exit_code)\r
+ {\r
+ unit->exit_code = errcode;\r
+ unit->err_kind = kind;\r
+ unit->err_line = strdup(line);\r
+\r
+ if(unit->root && !unit->root->exit_code)\r
+ {\r
+ unit->root->exit_code = errcode;\r
+ unit->root->err_kind = kind;\r
+ unit->root->err_line = strdup(line);\r
+ }\r
+ \r
+ if(!exit_code)\r
+ {\r
+ \r
+ exit_code = errcode;\r
+ err_kind = kind;\r
+ err_line = strdup(line);\r
+ }\r
+ }\r
+ \r
+}\r
+\r
+int\r
+unit_free(unit_t* ptr)\r
+{\r
+ if(!(*ptr))\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ if((*ptr)->commands)\r
+ xbt_dynar_free(&((*ptr)->commands));\r
+ \r
+ if((*ptr)->includes)\r
+ xbt_dynar_free(&((*ptr)->includes));\r
+ \r
+ if((*ptr)->suites)\r
+ xbt_dynar_free(&((*ptr)->suites));\r
+ \r
+ /* if the unit is interrupted during its run, the semaphore is NULL */\r
+ if((*ptr)->sem)\r
+ xbt_os_sem_destroy((*ptr)->sem);\r
+ \r
+ if((*ptr)->description)\r
+ free((*ptr)->description);\r
+\r
+ if((*ptr)->err_line)\r
+ free((*ptr)->err_line);\r
+\r
+ if((*ptr)->filepos)\r
+ free((*ptr)->filepos);\r
+\r
+ free(*ptr);\r
+ *ptr = NULL;\r
+ \r
+ return 0;\r
+}\r
+\r
+int\r
+unit_run(unit_t unit, xbt_os_mutex_t mutex)\r
+{\r
+ /* check the parameters */\r
+ if(!(unit) || !mutex)\r
+ {\r
+ errno = EINVAL;\r
+ xbt_os_sem_release(jobs_sem);\r
+ return -1;\r
+ \r
+ }\r
+\r
+ if(!interrupted)\r
+ {\r
+ unit->mutex = mutex;\r
+ \r
+ unit->sem = xbt_os_sem_init(0);\r
+\r
+ /* start the unit */\r
+ unit->thread = xbt_os_thread_create("", unit_start, unit);\r
+ }\r
+ else\r
+ {\r
+ /* the unit is interrupted by the runner before its starting \r
+ * in this case the unit semaphore is NULL take care of that\r
+ * in the function unit_free()\r
+ */\r
+ unit->interrupted = 1;\r
+ xbt_os_sem_release(jobs_sem);\r
+ }\r
+ \r
+ return 0;\r
+ \r
+}\r
+\r
+int\r
+unit_interrupt(unit_t unit)\r
+{\r
+ /* check the parameter */\r
+ if(!(unit))\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ /* if the unit is already interrupted, signal the error */\r
+ if(unit->interrupted)\r
+ {\r
+ errno = EALREADY;\r
+ return -1;\r
+ }\r
+ \r
+ /* interrupt the run of the specified unit */\r
+ unit->interrupted = 1;\r
+ xbt_os_sem_release(unit->sem);\r
+ \r
+ return 0;\r
+}\r
+\r
+/* just print the title of the root unit or a suite (if any) */\r
+static void \r
+print_title(const char* description)\r
+{\r
+ register int i;\r
+ char title[80];\r
+ size_t len = strlen(description);\r
+ \r
+ title[0]=' ';\r
+ \r
+ for (i = 1; i < 79; i++)\r
+ title[i]='=';\r
+ \r
+ title[i++]='\n';\r
+ title[79]='\0';\r
+ \r
+ sprintf(title + 40 - (len + 4)/2, "[ %s ]",description);\r
+ title[40 + (len + 5 ) / 2] = '=';\r
+ \r
+ printf("\n%s\n",title); \r
+}\r
+\r
+int\r
+unit_summuarize(unit_t unit)\r
+{\r
+ command_t command;\r
+ unsigned int itc, itu, its;\r
+ unit_t include;\r
+ unit_t suite;\r
+ char* p;\r
+ char title[PATH_MAX + 1] = {0};\r
+ \r
+ int number_of_tests = 0; /* number of tests of a unit contained by this unit */\r
+ int number_of_failed_tests = 0; /* number of failed test of a unit contained by this unit */\r
+ int number_of_successeded_tests = 0; /* number of successeded tests of a unit contained by this unit */\r
+ int number_of_interrupted_tests = 0; /* number of interrupted tests of a unit contained by this unit */\r
+ \r
+ int number_of_tests_of_suite = 0; /* number of tests of a suite contained by this unit */\r
+ int number_of_interrupted_tests_of_suite = 0; /* number of interrupted tests of a suite contained by this unit */ \r
+ int number_of_failed_tests_of_suite = 0; /* number of failed tests of a suite contained by this unit */\r
+ int number_of_successeded_tests_of_suite = 0; /* number of successeded tests of a suite contained by this */\r
+ \r
+ int number_of_units = 0; /* number of units contained by a suite */\r
+ int number_of_failed_units = 0; /* number of failed units contained by a suite */\r
+ int number_of_successeded_units = 0; /* number of successeded units contained by a suite */\r
+ int number_of_interrupted_units = 0; /* number of interrupted units contained by a suite */\r
+ \r
+ int total_of_tests = 0; /* total of the tests contained by this unit */\r
+ int total_of_failed_tests = 0; /* total of failed tests contained by this unit */\r
+ int total_of_successeded_tests = 0; /* total of successeded tests contained by this unit */\r
+ int total_of_interrupted_tests = 0; /* total of interrupted tests contained by this unit */\r
+ \r
+ int total_of_units = 0; /* total of units contained by this unit */\r
+ int total_of_failed_units = 0; /* total of failed units contained by this unit */\r
+ int total_of_successeded_units = 0; /* total of successeded units contained by this unit */\r
+ int total_of_interrupted_units = 0; /* total of interrutped units contained by this unit */\r
+ \r
+ int total_of_suites = 0; /* total of suites contained by this unit */\r
+ int total_of_failed_suites = 0; /* total of failed suites contained by this unit */\r
+ int total_of_successeded_suites = 0; /* total of successeded suites contained by this unit */ \r
+ int total_of_interrupted_suites = 0; /* total of interrupted suites contained by this unit */\r
+ \r
+ /* check the parameter */\r
+ if(!(unit))\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ if((unit->description) && strlen(unit->description) < 76)\r
+ strcpy(title, unit->description);\r
+ else\r
+ sprintf(title, "file : %s",unit->fstream->name);\r
+ \r
+ if(unit->interrupted)\r
+ {\r
+ if(strlen(title) + strlen(" (interrupted)") < 76)\r
+ strcat(title, " (interrupted)");\r
+ else\r
+ {\r
+ memset(title, 0, PATH_MAX + 1);\r
+ sprintf(title, "file : %s",unit->fstream->name);\r
+ strcat(title, " (interrupted)");\r
+\r
+ }\r
+ }\r
+ \r
+ print_title(title);\r
+ \r
+ number_of_tests = xbt_dynar_length(unit->commands);\r
+ \r
+ /* tests */\r
+ xbt_dynar_foreach(unit->commands, itc, command)\r
+ {\r
+ if(command->status == cs_interrupted)\r
+ number_of_interrupted_tests++;\r
+ else if(command->status == cs_failed)\r
+ number_of_failed_tests++;\r
+ else if(command->status == cs_successeded)\r
+ number_of_successeded_tests++;\r
+ }\r
+\r
+ \r
+ if(number_of_tests)\r
+ {\r
+ asprintf(&p," Test(s): .........................................................................");\r
+ \r
+ p[70] = '\0';\r
+ printf("%s", p);\r
+ free(p); \r
+ \r
+ if(number_of_failed_tests > 0) \r
+ printf(".. failed\n");\r
+ else if(number_of_interrupted_tests > 0) \r
+ printf("interrupt\n");\r
+ else \r
+ printf(".... ..ok\n"); \r
+\r
+ xbt_dynar_foreach(unit->commands, itc, command)\r
+ {\r
+ printf(" %s: %s [%s]\n", \r
+ command->status == cs_interrupted ? "INTR " \r
+ : command->status == cs_failed ? "FAILED" \r
+ : command->status == cs_successeded ? "PASS " \r
+ : "UNKNWN",\r
+ command->context->command_line, \r
+ command->context->pos);\r
+ \r
+ if(detail_summary_flag)\r
+ command_summarize(command);\r
+ }\r
+ \r
+ printf(" =====================================================================%s\n",\r
+ number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK");\r
+ \r
+ printf(" Summary: Test(s): %.0f%% ok (%d test(s): %d ok",\r
+ ((1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0),\r
+ number_of_tests, number_of_successeded_tests);\r
+ \r
+ if(number_of_failed_tests > 0)\r
+ printf(", %d failed", number_of_failed_tests);\r
+ \r
+ if(number_of_interrupted_tests > 0)\r
+ printf(", %d interrupted)", number_of_interrupted_tests);\r
+ \r
+ printf(")\n\n");\r
+ \r
+ total_of_tests = number_of_tests;\r
+ total_of_failed_tests = number_of_failed_tests;\r
+ total_of_interrupted_tests = number_of_interrupted_tests;\r
+ total_of_successeded_tests = number_of_successeded_tests;\r
+ }\r
+ \r
+ \r
+ \r
+ /* includes */\r
+ total_of_failed_units = total_of_interrupted_units = total_of_successeded_units = 0;\r
+ number_of_failed_units = number_of_successeded_units = number_of_interrupted_units = 0;\r
+ number_of_units = xbt_dynar_length(unit->includes);\r
+ \r
+ xbt_dynar_foreach(unit->includes, itu, include)\r
+ {\r
+ \r
+ number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0;\r
+ \r
+ number_of_tests = xbt_dynar_length(include->commands);\r
+\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ if(command->status == cs_interrupted)\r
+ number_of_interrupted_tests++;\r
+ else if(command->status == cs_failed)\r
+ number_of_failed_tests++;\r
+ else if(command->status == cs_successeded)\r
+ number_of_successeded_tests++; \r
+ }\r
+ \r
+ asprintf(&p," Unit: %s ............................................................................", include->description && strlen(include->description) < 60 ? include->description : include->fstream->name);\r
+ \r
+ p[70] = '\0';\r
+ printf("%s", p);\r
+ free(p); \r
+ \r
+ if(number_of_failed_tests > 0) \r
+ {\r
+ total_of_failed_units++;\r
+ printf(".. failed\n");\r
+ }\r
+ else if(number_of_interrupted_tests > 0) \r
+ {\r
+ total_of_interrupted_units++;\r
+ printf("interrupt\n");\r
+ }\r
+ else \r
+ {\r
+ total_of_successeded_units++;\r
+ printf(".... ..ok\n"); \r
+ }\r
+ \r
+ if(detail_summary_flag)\r
+ { \r
+\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ printf(" %s: %s [%s]\n", \r
+ command->status == cs_interrupted ? "INTR " \r
+ : command->status == cs_failed ? "FAILED" \r
+ : command->status == cs_successeded ? "PASS " \r
+ : "UNKNWN",\r
+ command->context->command_line, \r
+ command->context->pos);\r
+ \r
+ command_summarize(command);\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ printf(" =====================================================================%s\n",\r
+ number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK");\r
+ \r
+ \r
+ printf(" Summary: Test(s): %.0f%% ok (%d test(s): %d ok",\r
+ (number_of_tests ? (1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0 : 100.0),\r
+ number_of_tests, number_of_successeded_tests);\r
+ \r
+ if(number_of_failed_tests > 0)\r
+ printf(", %d failed", number_of_failed_tests);\r
+ \r
+ if(number_of_interrupted_tests > 0)\r
+ printf(", %d interrupted)", number_of_interrupted_tests);\r
+ \r
+ printf(")\n\n"); \r
+ \r
+ \r
+ total_of_tests += number_of_tests;\r
+ total_of_failed_tests += number_of_failed_tests;\r
+ total_of_interrupted_tests += number_of_interrupted_tests;\r
+ total_of_successeded_tests += number_of_successeded_tests;\r
+ }\r
+ \r
+ /* suites */\r
+ total_of_units = number_of_units;\r
+ \r
+ total_of_failed_suites = total_of_successeded_suites = total_of_interrupted_suites = 0;\r
+ \r
+ total_of_suites = xbt_dynar_length(unit->suites);\r
+\r
+ xbt_dynar_foreach(unit->suites, its, suite)\r
+ {\r
+ print_title(suite->description);\r
+ \r
+ number_of_tests_of_suite = number_of_interrupted_tests_of_suite = number_of_failed_tests_of_suite = number_of_successeded_tests_of_suite = 0;\r
+ \r
+ number_of_interrupted_units = number_of_failed_units = number_of_successeded_units = 0;\r
+ \r
+ number_of_units = xbt_dynar_length(suite->includes);\r
+ \r
+ xbt_dynar_foreach(suite->includes, itu, include)\r
+ {\r
+ number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0;\r
+ \r
+ number_of_tests = xbt_dynar_length(include->commands);\r
+ \r
+ \r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ if(command->status == cs_interrupted)\r
+ number_of_interrupted_tests++;\r
+ else if(command->status == cs_failed)\r
+ number_of_failed_tests++;\r
+ else if(command->status == cs_successeded)\r
+ number_of_successeded_tests++;\r
+ }\r
+ \r
+ asprintf(&p," Unit: %s ............................................................................", include->description && strlen(include->description) < 60 ? include->description : include->fstream->name);\r
+ \r
+ p[70] = '\0';\r
+ printf("%s", p);\r
+ free(p); \r
+ \r
+ if(number_of_failed_tests > 0) \r
+ {\r
+ number_of_failed_units++;\r
+ printf(".. failed\n");\r
+ }\r
+ else if(number_of_interrupted_tests > 0) \r
+ {\r
+ number_of_interrupted_units++;\r
+ printf("interrupt\n");\r
+ }\r
+ else \r
+ {\r
+ number_of_successeded_units++;\r
+ printf(".... ..ok\n"); \r
+ } \r
+ \r
+ number_of_interrupted_tests_of_suite += number_of_interrupted_tests;\r
+ number_of_failed_tests_of_suite += number_of_failed_tests;\r
+ number_of_successeded_tests_of_suite += number_of_successeded_tests;\r
+ \r
+ number_of_tests_of_suite += number_of_tests;\r
+ \r
+ total_of_tests += number_of_tests;\r
+ total_of_failed_tests += number_of_failed_tests;\r
+ total_of_interrupted_tests += number_of_interrupted_tests;\r
+ total_of_successeded_tests += number_of_successeded_tests;\r
+ \r
+ if(detail_summary_flag)\r
+ {\r
+\r
+ xbt_dynar_foreach(include->commands, itc, command)\r
+ {\r
+ printf(" %s: %s [%s]\n", \r
+ command->status == cs_interrupted ? "INTR " \r
+ : command->status == cs_failed ? "FAILED" \r
+ : command->status == cs_successeded ? "PASS " \r
+ : "UNKNWN",\r
+ command->context->command_line, \r
+ command->context->pos);\r
+ \r
+ command_summarize(command);\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ }\r
+ \r
+ printf(" =====================================================================%s\n",\r
+ number_of_failed_tests_of_suite ? "== FAILED": number_of_interrupted_tests_of_suite ? "==== INTR" : "====== OK");\r
+ \r
+ if(number_of_failed_tests_of_suite > 0)\r
+ total_of_failed_suites++;\r
+ else if(number_of_interrupted_tests_of_suite)\r
+ total_of_interrupted_suites++;\r
+ else\r
+ total_of_successeded_suites++;\r
+ \r
+ total_of_failed_units += number_of_failed_units;\r
+ total_of_interrupted_units += number_of_interrupted_units;\r
+ total_of_successeded_units += number_of_successeded_units;\r
+ \r
+ total_of_units += number_of_units;\r
+ \r
+ printf(" Summary: Unit(s): %.0f%% ok (%d unit(s): %d ok",\r
+ (number_of_units ? (1-((double)number_of_failed_units + (double)number_of_interrupted_units)/(double)number_of_units)*100.0 : 100.0),\r
+ number_of_units, number_of_successeded_units);\r
+ \r
+ if(number_of_failed_units > 0)\r
+ printf(", %d failed", number_of_failed_units);\r
+ \r
+ if(number_of_interrupted_units > 0)\r
+ printf(", %d interrupted)", number_of_interrupted_units);\r
+ \r
+ printf(")\n"); \r
+ \r
+ printf(" Test(s): %.0f%% ok (%d test(s): %d ok",\r
+ (number_of_tests_of_suite ? (1-((double)number_of_failed_tests_of_suite + (double)number_of_interrupted_tests_of_suite)/(double)number_of_tests_of_suite)*100.0 : 100.0),\r
+ number_of_tests_of_suite, number_of_successeded_tests_of_suite);\r
+ \r
+ if(number_of_failed_tests_of_suite > 0)\r
+ printf(", %d failed", number_of_failed_tests_of_suite);\r
+ \r
+ if(number_of_interrupted_tests_of_suite > 0)\r
+ printf(", %d interrupted)", number_of_interrupted_tests_of_suite);\r
+ \r
+ printf(")\n\n"); \r
+ }\r
+ \r
+ printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",\r
+ (total_of_suites ? (1-((double)total_of_failed_suites + (double)total_of_interrupted_suites)/(double)total_of_suites)*100.0 : 100.0),\r
+ total_of_suites, total_of_successeded_suites);\r
+ \r
+ if(total_of_failed_suites > 0)\r
+ printf(", %d failed", total_of_failed_suites);\r
+ \r
+ if(total_of_interrupted_suites > 0)\r
+ printf(", %d interrupted)", total_of_interrupted_suites);\r
+ \r
+ printf(")\n"); \r
+ \r
+ printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",\r
+ (total_of_units ? (1-((double)total_of_failed_units + (double)total_of_interrupted_units)/(double)total_of_units)*100.0 : 100.0),\r
+ total_of_units, total_of_successeded_units);\r
+ \r
+ if(total_of_failed_units > 0)\r
+ printf(", %d failed", total_of_failed_units);\r
+ \r
+ if(total_of_interrupted_units > 0)\r
+ printf(", %d interrupted)", total_of_interrupted_units);\r
+ \r
+ printf(")\n");\r
+ \r
+ printf(" Test(s): %.0f%% ok (%d test(s): %d ok",\r
+ (total_of_tests ? (1-((double)total_of_failed_tests + (double)total_of_interrupted_tests)/(double)total_of_tests)*100.0 : 100.0),\r
+ total_of_tests, total_of_successeded_tests); \r
+ \r
+ if(total_of_failed_tests > 0)\r
+ printf(", %d failed", total_of_failed_tests);\r
+ \r
+ if(total_of_interrupted_tests > 0)\r
+ printf(", %d interrupted)", total_of_interrupted_tests);\r
+ \r
+ printf(")\n\n");\r
+ \r
+ if(unit->interrupted)\r
+ unit->runner->total_of_interrupted_units++;\r
+ else if(total_of_failed_tests > 0)\r
+ unit->runner->total_of_failed_units++;\r
+ else\r
+ unit->runner->total_of_successeded_units++;\r
+ \r
+ unit->runner->total_of_tests += total_of_tests;\r
+ unit->runner->total_of_failed_tests += total_of_failed_tests;\r
+ unit->runner->total_of_successeded_tests += total_of_successeded_tests;\r
+ unit->runner->total_of_interrupted_tests += total_of_interrupted_tests;\r
+ \r
+ unit->runner->total_of_units += total_of_units + 1;\r
+ unit->runner->total_of_successeded_units += total_of_successeded_units;\r
+ unit->runner->total_of_failed_units += total_of_failed_units;\r
+ unit->runner->total_of_interrupted_units += total_of_interrupted_units;\r
+ \r
+ unit->runner->total_of_suites += total_of_suites;\r
+ unit->runner->total_of_successeded_suites += total_of_successeded_suites;\r
+ unit->runner->total_of_failed_suites += total_of_failed_suites;\r
+ unit->runner->total_of_interrupted_suites += total_of_interrupted_suites;\r
+ \r
+ return 0;\r
+}\r
+\r
+int\r
+unit_reset(unit_t unit)\r
+{\r
+ unit_t cur;\r
+ unsigned int i;\r
+\r
+ /* reset all the suites of the unit */\r
+ xbt_dynar_foreach(unit->suites, i, cur)\r
+ {\r
+ unit_reset(cur);\r
+ }\r
+\r
+\r
+ /* reset all the includes of the unit */\r
+ xbt_dynar_foreach(unit->includes, i, cur)\r
+ {\r
+ unit_reset(cur);\r
+ }\r
+\r
+ fseek(unit->fstream->stream,0L, SEEK_SET);\r
+ unit->parsed = 0;\r
+ unit->cmd_nb = 0;\r
+ unit->started_cmd_nb = 0;\r
+ unit->interrupted_cmd_nb = 0;\r
+ unit->failed_cmd_nb = 0;\r
+ unit->successeded_cmd_nb = 0;\r
+ unit->terminated_cmd_nb = 0;\r
+ unit->waiting_cmd_nb = 0;\r
+ unit->interrupted = 0;\r
+ unit->failed = 0;\r
+ unit->successeded = 0;\r
+ unit->parsed = 0;\r
+ unit->released = 0;\r
+ unit->is_running_suite = 0;\r
+ \r
+ if(unit->description)\r
+ {\r
+ free(unit->description);\r
+ unit->description = NULL;\r
+ }\r
+\r
+ unit->exit_code = 0;\r
+ \r
+ return 0;\r
+}\r