Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
If the length of the description is more than 76 characters replace it by the name...
[simgrid.git] / tools / tesh2 / src / unit.c
index 1f540d6..afadd9b 100644 (file)
-#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