Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
last version of tesh
[simgrid.git] / tools / tesh2 / src / unit.c
index 1f540d6..fefd585 100644 (file)
@@ -3,18 +3,49 @@
 #include <command.h>
 #include <context.h>
 #include <fstream.h>
-
-
+#include <variable.h>
+#include <str_replace.h>
 
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
 
+static void
+replace_variables(unit_t unit, char** line)
+{
+       variable_t variable;
+       char name[MAX_PATH + 1] = {0};
+       
+       /* check if some commands have setted some environment variables */
+       /* TODO */
+       
+       /*printf("repalce all the variables of the line %s\n", *line);*/
+       
+       
+       xbt_os_mutex_acquire(unit->mutex);
+       
+       vector_rewind(unit->runner->variables);
+       
+       while((variable = vector_get(unit->runner->variables)))
+       {
+               sprintf(name, "$%s", variable->name);
+               /*printf("try to replace all the variable %s\n",name);*/
+               str_replace_all(line, name, variable->val);
+               
+               vector_move_next(unit->runner->variables);
+               memset(name, 0, MAX_PATH + 1);
+       }
+       
+       xbt_os_mutex_release(unit->mutex);
+       
+       /*printf("line after the variables replacement %s\n",*line);*/
+       
+}
 
 /* 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_new(runner_t runner, unit_t root, unit_t owner, fstream_t fstream)
 {
        unit_t unit = xbt_new0(s_unit_t, 1);
 
@@ -26,6 +57,7 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream)
        unit->sem = NULL;
 
        unit->commands = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)command_free);
+       unit->includes = vector_new(DEFAULT_INCLUDES, (fn_finalize_t)unit_free);
        
        unit->thread = NULL;
 
@@ -34,6 +66,7 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream)
        unit->number_of_failed_commands = 0;
        unit->number_of_successeded_commands = 0;
        unit->number_of_terminated_commands = 0;
+       unit->number_of_waiting_commands = 0;
        unit->interrupted = 0;
        unit->failed = 0;
        unit->successeded = 0;
@@ -43,21 +76,27 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream)
        
        
        unit->owner = owner;
+       
+       unit->root = root ?  root : unit;
+       
+       
        unit->number = 0;
-       unit->suites = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)suite_free);
+       unit->suites = vector_new(DEFAULT_SUITES_CAPACITY, (fn_finalize_t)unit_free);
        unit->owner = owner;
        
        unit->running_suite = 0;
+       unit->is_suite = 0;
+       unit->description = NULL;
 
        return unit;
 
 }
 
-void
+/*void
 unit_add_suite(unit_t unit, suite_t suite)
 {
        vector_push_back(unit->suites, suite);
-}
+}*/
 
 int
 unit_free(void** unitptr)
@@ -66,13 +105,17 @@ unit_free(void** unitptr)
        
        vector_free(&((*__unitptr)->commands));
        
+       vector_free(&((*__unitptr)->includes));
+       
        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);
                
-               
+       if((*__unitptr)->description)
+               free((*__unitptr)->description);
+       
        free((*__unitptr)->suites);
 
        free(*__unitptr);
@@ -88,10 +131,11 @@ unit_start(void* p)
        
        xbt_os_thread_t thread;
        xbt_os_mutex_t mutex;
-       context_t context;
-       int i;
+       /*context_t context;*/
+       int i, j;
 
        unit_t unit = (unit_t)p;
+       unit_t include;
        
        xbt_os_mutex_acquire(unit->mutex);
        unit->runner->number_of_runned_units++;
@@ -101,17 +145,22 @@ unit_start(void* p)
        xbt_os_sem_acquire(jobs_sem);
        
        mutex = xbt_os_mutex_init();
-       context = context_new();
+       /*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);
+       /*unit_parse(unit, context, mutex, unit->fstream->name, unit->fstream->stream);*/
+       
+       fstream_parse(unit->fstream, unit, mutex);
+       
        
        /* 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;
@@ -120,37 +169,86 @@ unit_start(void* p)
                 * 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)))
+               {
+                       /*INFO1("the unit %s is released", unit->fstream->name);*/
                        xbt_os_sem_release(unit->sem);  
+               }
+               else
+               {
+                       
+                       INFO1("the unit %s is not released", unit->fstream->name);
+                       INFO1("number of started commands %d", unit->number_of_started_commands);
+                       INFO1("number of failed commands %d", unit->number_of_failed_commands);
+                       INFO1("number of interrupted commands %d", unit->number_of_interrupted_commands);
+                       INFO1("number of successeded commands %d", unit->number_of_successeded_commands);
+                       INFO1("number of waiting commands %d", unit->number_of_waiting_commands);
+                       
+                       
+                       if(unit->number_of_waiting_commands)
+                       {
+                               command_t command;
+                               int i, j;
+       
+                               for(i = 0; i < vector_get_size(unit->includes) ; i++)
+                               {
+                                       include = vector_get_at(unit->includes, i);
+                               
+                                       for(j = 0; j < vector_get_size(include->commands); j++)
+                                       {
+                                               command = vector_get_at(include->commands, j);
+                                               
+                                               if(command->status == cs_in_progress)
+                                               {
+                                                       INFO2("the command %s PID %d is in process", command->context->command_line, command->pid);
+                                                       
+                                                       if(command->writer->done)
+                                                               INFO2("the writer of the command %s PID %d done", command->context->command_line, command->pid);        
+                                                       else
+                                                               INFO2("the writer of the command %s PID %d  doesn't done", command->context->command_line, command->pid);
+                                               }
+                                       }
+                                       
+                               }
+                       }
+               }
                
        }
        
        /* 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++)
+               for(i = 0; i < vector_get_size(unit->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);
                }
+               
+               for(i = 0; i < vector_get_size(unit->includes); i++)
+               {
+                       include = vector_get_at(unit->includes, i);
+                       
+                       for(j = 0; j < vector_get_size(include->commands); j++)
+                       {
+                               command = vector_get_at(include->commands, j);
+
+                               if(command->status == cs_in_progress)
+                                       command_interrupt(command);
+                       }
+               }
+               
        }
        
-
        /* wait the end of the threads */
-       for(i = 0; i < unit->number_of_commands; i++)
+       for(i = 0; i < vector_get_size(unit->commands); i++)
        {
-               /*thread = unit->commands[i]->thread;*/
-               
                command_t command = vector_get_at(unit->commands, i);
                thread = command->thread;
                
@@ -158,10 +256,25 @@ unit_start(void* p)
                        xbt_os_thread_join(thread,NULL);
        }
        
-       context_free(&context);
-
+       for(i = 0; i < vector_get_size(unit->includes); i++)
+       {
+               include = vector_get_at(unit->includes, i);
+               
+               for(j = 0; j < vector_get_size(include->commands); j++)
+               {
+                       command_t command = vector_get_at(include->commands, j);
+                       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 */
@@ -175,11 +288,12 @@ unit_start(void* p)
 
                /* 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);
        
@@ -236,6 +350,11 @@ unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* fil
                                unit_handle_failure(unit);
                                break;
                        }
+                       else if(unit->running_suite)
+                       {
+                               /* TODO */
+                       }
+                                       
                        
                        if(context->command_line)
                        {
@@ -309,13 +428,20 @@ unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* fil
        xbt_strbuff_free(buff); 
 }
 
+
+
 void 
 unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line) 
 {
+       char* line2;
        /* Search end */
        xbt_str_rtrim(line+2,"\n");
        
-       switch (line[0]) 
+       line2 = strdup(line);
+       
+       replace_variables(unit, &line2);
+       
+       switch (line2[0]) 
        {
                case '#': 
                break;
@@ -323,17 +449,18 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha
                case '$':
                case '&':
                        
-               context->async = (line[0] == '&');
+               context->async = (line2[0] == '&');
                
                /* further trim useless chars which are significant for in/output */
-               xbt_str_rtrim(line+2," \t");
+               xbt_str_rtrim(line2+2," \t");
                
                /* Deal with CD commands here, not in rctx */
-               if (!strncmp("cd ",line+2,3)) 
+               if(!strncmp("cd ",line2 + 2, 3)) 
                {
-                       char *dir=line+4;
-               
-                       if (context->command_line)
+                       /*char *dir=line2+4; */
+                       char* dir = strdup(line2 + 4);
+                       
+                       if(context->command_line)
                        {
                                if(!want_dry_run)
                                {
@@ -351,12 +478,10 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha
                        
                        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));
@@ -364,39 +489,50 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha
                                        exit_code = ECHDIR;
                                        unit_handle_failure(unit);
                                }
+                               
+                               
                        }
                        
                        break;
                } /* else, pushline */
                else
                {
-                       unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);
+                       unit_pushline(unit, context, mutex, filepos, line2[0], line2+2 /* pass '$ ' stuff*/);
                        break;
                }
                
                case '<':
                case '>':
                case '!':
-               unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);    
+               unit_pushline(unit, context, mutex, filepos, line2[0], line2+2 /* pass '$ ' stuff*/);    
                break;
                
                case 'p':
                if(!want_dry_run)
-                       INFO2("[%s] %s",filepos,line+2);
+                       INFO2("[%s] %s",filepos,line2+2);
                break;
                
                case 'P':
                if(!want_dry_run)
-                       CRITICAL2("[%s] %s",filepos,line+2);
+                       CRITICAL2("[%s] %s",filepos,line2+2);
+               break;
+               
+               case 'D':
+                       if(unit->description)
+                               WARN2("description already specified %s %s", filepos, line2); 
+                       else
+                               unit->description = strdup(line2 + 2);
                break;
                
                default:
-               ERROR2("[%s] Syntax error: %s",filepos, line);
+               ERROR2("[%s] Syntax error: %s",filepos, line2);
                ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
                exit_code = ESYNTAX;
                unit_handle_failure(unit);
                break;
        }
+       
+       free(line2);
 }
 
 void 
@@ -540,23 +676,292 @@ unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char*
                        VERB1("[%s] (ignore output of next command)", filepos);
                
                } 
-               else if(!strncmp(line,"include", strlen("include")))
+               else if(!strncmp(line,"include ", strlen("include ")))
                {
-                       unit_handle_include(unit, context, mutex, line + strlen("include "));
+                       char* p1;
+                       char* p2;
+                       
+                       p1 = line + strlen("include");
+                       
+                       while(*p1 == ' ' || *p1 == '\t')
+                               p1++;
+                               
+                       
+                       if(p1[0] == '\0')
+                       {
+                               
+                               exit_code = ESYNTAX;
+                               ERROR1("include file not specified %s ", filepos);
+                               unit_handle_failure(unit);
+                       }
+                       else
+                       {
+                               char file_name[MAX_PATH + 1] = {0};
+                               
+                               /*INFO1("p1 is %s",p1);*/
+                               
+                               p2 = p1;
+                               
+                               while(*p2 != '\0' && *p2 != ' ' && *p2 != '\t')
+                               {
+                                       /*INFO1("p2 is %s",p2);*/
+                                       p2++;
+                                       
+                               }
+                               /*INFO1("p2 is %s",p2);*/
+                                       
+                               strncpy(file_name, p1, p2 - p1);
+                               
+                               /*INFO1("filename is %s", file_name);*/
+                               
+                               if(p2[0] != '\0')
+                                       while(*p2 == ' ' || *p2 == '\t')
+                                               p2++;
+                                       
+                               unit_handle_include(unit, context, mutex, file_name, p2[0] != '\0' ? p2 : NULL);
+                               
+                       }
                }
-               
-               else if(!strncmp(line,"suite", strlen("suite")))
+               else if(!strncmp(line,"suite ", strlen("suite ")))
                {
                        unit_handle_suite(unit, context, mutex, line + strlen("suite "));
                }
-               else 
+               else if(!strncmp(line,"unsetenv ", strlen("unsetenv ")))
+               {
+                       int i;
+                       int number_of_variables;
+                       int exists = 0;
+                       int env;
+                       variable_t variable;
+                       char* name = line + strlen("unsetenv ");
+                       
+                       xbt_os_mutex_acquire(unit->mutex);
+                       
+                       number_of_variables = vector_get_size(unit->runner->variables);
+                       
+                       for(i = 0; i < number_of_variables; i++)
+                       {
+                               variable = vector_get_at(unit->runner->variables, i);
+                               
+                               if(!strcmp(variable->name, name))
+                               {
+                                       env = variable->env;
+                                       exists = 1;
+                                       break;
+                               }
+                       }
+                               
+                       if(env)
+                       {
+                               if(exists)
+                                       vector_erase_at(unit->runner->variables, i);
+                               else
+                                       WARN3("environment variable %s not found %s %s", name, line, filepos);  
+                       }
+                       else
+                       {
+                               if(exists)
+                                       WARN3("%s is an not environment variable use unset metacommand to delete it %s %s", name, line, filepos);
+                               else
+                                       WARN3("%s environment variable not found %s %s", name, line, filepos);
+                       }
+                       
+                       xbt_os_mutex_release(unit->mutex);      
+                       
+                               
+               }
+               else if(!strncmp(line,"setenv ", strlen("setenv ")))
+               {
+                       char* val;
+                       char name[MAX_PATH + 1] = {0};
+                       char* p;
+                       
+                       p = line + strlen("setenv ");
+                       
+                       val = strchr(p, '=');
+                       
+                       if(val)
+                       {
+                               variable_t variable;
+                               int exists = 0;
+                               int env = 0;
+                               val++;
+                               
+                               /* syntax error */
+                               if(val[0] == '\0')
+                               {
+                                       
+                                       exit_code = ESYNTAX;
+                                       ERROR2("indefinite variable value %s %s", line, filepos);
+                                       unit_handle_failure(unit);      
+                               }
+                               
+                               
+                               
+                               strncpy(name, p, (val - p -1));
+                               
+                               /* test if the variable is already registred */
+                               
+                               xbt_os_mutex_acquire(unit->mutex);
+                               
+                               vector_rewind(unit->runner->variables);
+                               
+                               while((variable = vector_get(unit->runner->variables)))
+                               {
+                                       
+                                       if(!strcmp(variable->name, name))
+                                       {
+                                               variable->env = 1;
+                                               exists = 1;
+                                               break;
+                                       }
+                                       
+                                       vector_move_next(unit->runner->variables);
+                               }
+                               
+                               /* if the variable is already registred, update its value;
+                                * otherwise register it.
+                                */
+                               if(exists)
+                               {
+                                       if(env)
+                                       {
+                                               free(variable->val);
+                                               variable->val = strdup(val);
+                                               setenv(variable->name, variable->val, 1);
+                                       }
+                                       else
+                                               WARN3("%s variable already exists %s %s", name, line, filepos); 
+                               }
+                               else
+                               {
+                                       variable = variable_new(name, val);
+                                       variable->env = 1;
+                                       
+                                       vector_push_back(unit->runner->variables, variable);
+                                       
+                                       setenv(variable->name, variable->val, 0);
+                               }
+                               
+                               xbt_os_mutex_release(unit->mutex);
+                               
+                       }
+               }
+               else if(!strncmp(line,"unset ", strlen("unset ")))
                {
-                       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;
+                       int i;
+                       int number_of_variables;
+                       int exists = 0;
+                       int env;
+                       int err;
+                       variable_t variable;
+                       char* name = line + strlen("unset ");
+                       
+                       xbt_os_mutex_acquire(unit->mutex);
+                       
+                       number_of_variables = vector_get_size(unit->runner->variables);
+                       
+                       for(i = 0; i < number_of_variables; i++)
+                       {
+                               variable = vector_get_at(unit->runner->variables, i);
+                               
+                               if(!strcmp(variable->name, name))
+                               {
+                                       env = variable->env;
+                                       err = variable->err;
+                                       exists = 1;
+                                       break;
+                               }
+                       }
+                               
+                       if(!env)
+                       {
+                               if(exists)
+                                       vector_erase_at(unit->runner->variables, i);
+                               else
+                                       WARN3("variable %s not found %s %s", name, line, filepos);      
+                       }
+                       else if(env)
+                       {
+                               WARN3("%s is an environment variable use unsetenv metacommand to delete it %s %s", name, line, filepos);        
+                       }
+                       else
+                       {
+                               WARN3("%s is an error variable : you are not allowed to delete it %s %s", name, line, filepos);
+                       }
+                       xbt_os_mutex_release(unit->mutex);
+                               
                }
+               else
+               {
+                       /* may be a variable */
+                       char* val;
+                       char name[MAX_PATH + 1] = {0};
+                       
+                       val = strchr(line, '=');
+                       
+                       if(val)
+                       {
+                               variable_t variable;
+                               int exists = 0;
+                               val++;
+                               
+                               /* syntax error */
+                               if(val[0] == '\0')
+                               {
+                                       
+                                       exit_code = ESYNTAX;
+                                       ERROR2("indefinite variable value %s %s", line, filepos);
+                                       unit_handle_failure(unit);      
+                               }
+                               
+                               
+                               /* assume it's a varibale */
+                               strncpy(name, line, (val - line -1));
+                               
+                               xbt_os_mutex_acquire(unit->mutex);
+                               
+                               /* test if the variable is already registred */
+                               
+                               vector_rewind(unit->runner->variables);
+                               
+                               while((variable = vector_get(unit->runner->variables)))
+                               {
+                                       
+                                       if(!strcmp(variable->name, name))
+                                       {
+                                               exists = 1;
+                                               break;
+                                       }
+                                       
+                                       vector_move_next(unit->runner->variables);
+                               }
+                               
+                               /* if the variable is already registred, update its value;
+                                * otherwise register it.
+                                */
+                               if(exists)
+                               {
+                                       free(variable->val);
+                                       variable->val = strdup(val);
+                               }
+                               else
+                                       vector_push_back(unit->runner->variables,variable_new(name, val));
+                                       
+                               xbt_os_mutex_release(unit->mutex);
+                               
+                       }
+                       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;
        }
@@ -566,15 +971,18 @@ unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char*
 void
 unit_handle_failure(unit_t unit)
 {
+       
        if(!want_keep_going_unit)
        {
-               if(!unit->interrupted)
+               unit_t root = unit->root ? unit->root : unit;
+                       
+               if(!root->interrupted)
                {
                        /* the unit interrupted (exit for the loop) */
-                       unit->interrupted = 1;
+                       root->interrupted = 1;
 
                        /* release the unit */
-                       xbt_os_sem_release(unit->sem);
+                       xbt_os_sem_release(root->sem);
                }
 
                /* if the --keep-going option is not specified */
@@ -622,59 +1030,466 @@ unit_interrupt(unit_t unit)
        xbt_os_sem_release(unit->sem);
 }
 
+void 
+display_title(const char* description)
+{
+       int i;
+       char title[80];
+       int len = strlen(description);
+               
+       title[0]=' ';
+               
+       for (i = 1; i < 79; i++)
+               title[i]='=';
+               
+       title[i++]='\n';
+       title[79]='\0';
+       
+       sprintf(title + 40 - (len + 4)/2, "[ %s ]",description);
+       title[40 + (len + 5 ) / 2] = '=';
+               
+       printf("\n%s\n",title); 
+}
+
 void
 unit_verbose(unit_t unit)
 {
-       int i, test_count;
+       int i, j, k;
        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)"); 
+       unit_t include;
+       unit_t suite;
+       char* p;
+       char title[MAX_PATH + 1] = {0};
+       
+       int number_of_tests = 0;                                                /* number of tests of a unit contained by this unit                                     */
+       int number_of_failed_tests = 0;                                 /* number of failed test of a unit contained by this unit                       */
+       int number_of_successeded_tests = 0;                    /* number of successeded tests of a unit contained by this unit         */
+       int number_of_interrupted_tests = 0;                    /* number of interrupted tests of a unit contained by this unit         */
+       
+       int number_of_tests_of_suite = 0;                               /* number of tests of a suite contained by this unit                            */
+       int number_of_interrupted_tests_of_suite = 0;   /* number of interrupted tests of a suite contained by this unit        */      
+       int number_of_failed_tests_of_suite = 0;                /* number of failed tests of a suite contained by this unit                                     */
+       int number_of_successeded_tests_of_suite = 0;   /* number of successeded tests of a suite contained by this                     */
+       
+       int number_of_units = 0;                                                /* number of units contained by a suite                                                         */
+       int number_of_failed_units = 0;                                 /* number of failed units contained by a suite                                          */
+       int number_of_successeded_units = 0;                    /* number of successeded units contained by a suite                                     */
+       int number_of_interrupted_units = 0;                    /* number of interrupted units contained by a suite                                     */
+       
+       int total_of_tests = 0;                                                 /* total of the tests contained by this unit                                            */
+       int total_of_failed_tests = 0;                                  /* total of failed tests contained by this unit                                         */
+       int total_of_successeded_tests = 0;                     /* total of successeded tests contained by this unit                            */
+       int total_of_interrupted_tests = 0;                             /* total of interrupted tests contained by this unit                            */
+       
+       int total_of_units = 0;                                                 /* total of units contained by this unit                                                        */
+       int total_of_failed_units = 0;                                  /* total of failed units contained by this unit                                         */
+       int total_of_successeded_units = 0;                             /* total of successeded units contained by this unit                            */
+       int total_of_interrupted_units = 0;                             /* total of interrutped units contained by this unit                            */
+       
+       int total_of_suites = 0;                                                /* total of suites contained by this unit                                                       */
+       int total_of_failed_suites = 0;                                 /* total of failed suites contained by this unit                                        */
+       int total_of_successeded_suites = 0;                    /* total of successeded suites contained by this unit                           */ 
+       int total_of_interrupted_suites = 0;                    /* total of interrupted suites contained by this unit                           */
+       
+       
+       if(unit->description)
+               strcpy(title, unit->description);
        else
+               sprintf(title, "file : %s",unit->fstream->name);
+               
+       if(unit->interrupted)
+               strcat(title, " (interrupted)");
+               
+       display_title(title);
+       
+       number_of_tests = vector_get_size(unit->commands);
+       
+       
+       /* tests */
+       for(i = 0; i < number_of_tests; i++)
        {
-               if(unit->interrupted)
-                       printf(" - (interruped)");
-               else
-                       printf(" - (failed)");
+               command = vector_get_at(unit->commands, i);
+               
+               if(command->status == cs_interrupted)
+                       number_of_interrupted_tests++;
+               else if(command->status == cs_failed)
+                       number_of_failed_tests++;
+               else if(command->status == cs_successeded)
+                       number_of_successeded_tests++;
+                       
        }
        
-       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);
+       if(number_of_tests)
+       {
+               asprintf(&p," Test(s): .........................................................................");
+                       
+               p[70] = '\0';
+               printf("%s", p);
+               free(p);        
+       
+               if(number_of_failed_tests > 0) 
+                       printf(".. failed\n");
+               else if(number_of_interrupted_tests > 0) 
+                       printf("interrupt\n");
+               else 
+                       printf(".... ..ok\n"); 
+       
+       
+               for(i = 0; i < number_of_tests; i++)
+               {
+                       command = vector_get_at(unit->commands, i);
+                               
+                       printf("        %s: %s [%s]\n", 
+                               command->status == cs_interrupted ? "INTR  " 
+                               : command->status == cs_failed ? "FAILED" 
+                               : command->status == cs_successeded ? "PASS  " 
+                               : "UNKNWN",
+                               command->context->command_line, 
+                               command->context->line);
+                               
+                       if(want_detail_summary)
+                               command_display_status(command);
+                               
+               }
+       
+               printf(" =====================================================================%s\n",
+               number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK");
+               
+               printf("    Summary: Test(s): %.0f%% ok (%d test(s): %d ok",
+               ((1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0),
+                number_of_tests, number_of_successeded_tests);
+               
+               if(number_of_failed_tests > 0)
+                       printf(", %d failed", number_of_failed_tests);
+               
+               if(number_of_interrupted_tests > 0)
+                       printf(", %d interrupted)", number_of_interrupted_tests);
+                       
+                printf(")\n\n");
+                               
+               total_of_tests = number_of_tests;
+               total_of_failed_tests = number_of_failed_tests;
+               total_of_interrupted_tests = number_of_interrupted_tests;
+               total_of_successeded_tests = number_of_successeded_tests;
+       }
        
-       test_count = unit->number_of_commands;
        
        
-       for(i = 0; i < test_count; i++)
+       /* includes */
+       
+       total_of_failed_units = total_of_interrupted_units = total_of_successeded_units = 0;
+       
+       number_of_failed_units = number_of_successeded_units = number_of_interrupted_units = 0;
+       
+       number_of_units = vector_get_size(unit->includes);
+       
+       for(i = 0; i < number_of_units ; i++)
        {
-               command = vector_get_at(unit->commands, i);
+               include = vector_get_at(unit->includes, i);
+               
+               number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0;
+               
+               number_of_tests = vector_get_size(include->commands);
+               
+               for(j = 0; j < number_of_tests; j++)
+               {
+                       command = vector_get_at(include->commands, j);
+                       
+                       if(command->status == cs_interrupted)
+                               number_of_interrupted_tests++;
+                       else if(command->status == cs_failed)
+                               number_of_failed_tests++;
+                       else if(command->status == cs_successeded)
+                               number_of_successeded_tests++;  
+               }
+               
+               asprintf(&p," Unit: %s ............................................................................", include->description ? include->description : include->fstream->name);
+                       
+               p[70] = '\0';
+               printf("%s", p);
+               free(p);        
+               
+               
+               if(number_of_failed_tests > 0) 
+               {
+                       total_of_failed_units++;
+                       printf(".. failed\n");
+               }
+               else if(number_of_interrupted_tests > 0) 
+               {
+                       total_of_interrupted_units++;
+                       printf("interrupt\n");
+               }
+               else 
+               {
+                       total_of_successeded_units++;
+                       printf(".... ..ok\n"); 
+               }
+               
+               if(want_detail_summary)
+               {               
+       
+                       for(j = 0; j < vector_get_size(include->commands); j++)
+                       {
+                               command = vector_get_at(include->commands, j);
+                               
+                               printf("        %s: %s [%s]\n", 
+                               command->status == cs_interrupted ? "INTR  " 
+                               : command->status == cs_failed ? "FAILED" 
+                               : command->status == cs_successeded ? "PASS  " 
+                               : "UNKNWN",
+                               command->context->command_line, 
+                               command->context->line);
+                               
+                               command_display_status(command);
+                       }
+                       
+                                       
+               }
                
-               /*command_display_status(unit->commands[i]);*/
-               command_display_status(command);
+               printf(" =====================================================================%s\n",
+               number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK");
+       
+               
+               printf("    Summary: Test(s): %.0f%% ok (%d test(s): %d ok",
+               (number_of_tests ? (1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0 : 100.0),
+                number_of_tests, number_of_successeded_tests);
+               
+               if(number_of_failed_tests > 0)
+                       printf(", %d failed", number_of_failed_tests);
+               
+               if(number_of_interrupted_tests > 0)
+                       printf(", %d interrupted)", number_of_interrupted_tests);
+                       
+                printf(")\n\n");       
+                
+               
+               total_of_tests += number_of_tests;
+               total_of_failed_tests += number_of_failed_tests;
+               total_of_interrupted_tests += number_of_interrupted_tests;
+               total_of_successeded_tests += number_of_successeded_tests;
+       }
+       
+       /* suites */
+       
+       total_of_units = number_of_units;
+       
+       total_of_failed_suites = total_of_successeded_suites = total_of_interrupted_suites = 0;
+       
+       total_of_suites = vector_get_size(unit->suites);
+       
+       for(k = 0; k < total_of_suites; k++)
+       {
+               suite = vector_get_at(unit->suites, k);
+               
+               display_title(suite->description);
+               
+               number_of_tests_of_suite = number_of_interrupted_tests_of_suite = number_of_failed_tests_of_suite = number_of_successeded_tests_of_suite = 0;
+               
+               number_of_interrupted_units = number_of_failed_units = number_of_successeded_units = 0;
+               
+               number_of_units = vector_get_size(suite->includes);
+               
+               for(i = 0; i < number_of_units; i++)
+               {
+                       number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0;
+                       
+                       number_of_tests = vector_get_size(include->commands);
+                       
+                       for(j = 0; j < vector_get_size(include->commands); j++)
+                       {
+                               command = vector_get_at(include->commands, j);
+                               
+                               if(command->status == cs_interrupted)
+                                       number_of_interrupted_tests++;
+                               else if(command->status == cs_failed)
+                                       number_of_failed_tests++;
+                               else if(command->status == cs_successeded)
+                                       number_of_successeded_tests++;
+                                       
+                       }
+                       
+                       
+                       include = vector_get_at(suite->includes, i);
+                       asprintf(&p," Unit: %s ............................................................................", include->description ? include->description : include->fstream->name);
+                       
+                       p[70] = '\0';
+                       printf("%s", p);
+                       free(p);        
+               
+                       if(number_of_failed_tests > 0) 
+                       {
+                               number_of_failed_units++;
+                               printf(".. failed\n");
+                       }
+                       else if(number_of_interrupted_tests > 0) 
+                       {
+                               number_of_interrupted_units++;
+                               printf("interrupt\n");
+                       }
+                       else 
+                       {
+                               number_of_successeded_units++;
+                               printf(".... ..ok\n"); 
+                       } 
+                       
+                       number_of_interrupted_tests_of_suite += number_of_interrupted_tests;
+                       number_of_failed_tests_of_suite += number_of_failed_tests;
+                       number_of_successeded_tests_of_suite += number_of_successeded_tests;
+                       
+                       number_of_tests_of_suite += number_of_tests;
+                       
+                       total_of_tests += number_of_tests;
+                       total_of_failed_tests += number_of_failed_tests;
+                       total_of_interrupted_tests += number_of_interrupted_tests;
+                       total_of_successeded_tests += number_of_successeded_tests;
+                       
+                       if(want_detail_summary)
+                       {
+                               for(j = 0; j < vector_get_size(include->commands); j++)
+                               {
+                                       command = vector_get_at(include->commands, j);
+                                       
+                                       printf("        %s: %s [%s]\n", 
+                                       command->status == cs_interrupted ? "INTR  " 
+                                       : command->status == cs_failed ? "FAILED" 
+                                       : command->status == cs_successeded ? "PASS  " 
+                                       : "UNKNWN",
+                                       command->context->command_line, 
+                                       command->context->line);
+                                       
+                                       command_display_status(command);
+                                               
+                               }
+                               
+                               
+                       }
+                               
+               }
+               
+               
+               
+               printf(" =====================================================================%s\n",
+               number_of_failed_tests_of_suite ? "== FAILED": number_of_interrupted_tests_of_suite ? "==== INTR" : "====== OK");
+               
+               if(number_of_failed_tests_of_suite > 0)
+                       total_of_failed_suites++;
+               else if(number_of_interrupted_tests_of_suite)
+                       total_of_interrupted_suites++;
+               else
+                       total_of_successeded_suites++;
+                       
+               total_of_failed_units += number_of_failed_units;
+               total_of_interrupted_units += number_of_interrupted_units;
+               total_of_successeded_units += number_of_successeded_units;
+                       
+               total_of_units += number_of_units;
+               
+               printf("    Summary: Unit(s): %.0f%% ok (%d unit(s): %d ok",
+               (number_of_units ? (1-((double)number_of_failed_units + (double)number_of_interrupted_units)/(double)number_of_units)*100.0 : 100.0),
+                number_of_units, number_of_successeded_units);
+                
+               if(number_of_failed_units > 0)
+                       printf(", %d failed", number_of_failed_units);
+               
+               if(number_of_interrupted_units > 0)
+                       printf(", %d interrupted)", number_of_interrupted_units);
+                       
+               printf(")\n");  
+               
+               printf("             Test(s): %.0f%% ok (%d test(s): %d ok",
+               (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),
+               number_of_tests_of_suite, number_of_successeded_tests_of_suite);
+                
+               if(number_of_failed_tests_of_suite > 0)
+                       printf(", %d failed", number_of_failed_tests_of_suite);
+               
+               if(number_of_interrupted_tests_of_suite > 0)
+                       printf(", %d interrupted)", number_of_interrupted_tests_of_suite);
+                       
+                printf(")\n\n");       
        }
+       
+       printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
+               (total_of_suites ? (1-((double)total_of_failed_suites + (double)total_of_interrupted_suites)/(double)total_of_suites)*100.0 : 100.0),
+                total_of_suites, total_of_successeded_suites);
+       
+       if(total_of_failed_suites > 0)
+                       printf(", %d failed", total_of_failed_suites);
+               
+       if(total_of_interrupted_suites > 0)
+               printf(", %d interrupted)", total_of_interrupted_suites);
+               
+       printf(")\n");  
+       
+       printf("         Unit(s):  %.0f%% ok (%d unit(s): %d ok",
+               (total_of_units ? (1-((double)total_of_failed_units + (double)total_of_interrupted_units)/(double)total_of_units)*100.0 : 100.0),
+                total_of_units, total_of_successeded_units);
+       
+       if(total_of_failed_units > 0)
+                       printf(", %d failed", total_of_failed_units);
+               
+       if(total_of_interrupted_units > 0)
+               printf(", %d interrupted)", total_of_interrupted_units);
+               
+       printf(")\n");
+       
+       printf("         Test(s):  %.0f%% ok (%d test(s): %d ok",
+               (total_of_tests ? (1-((double)total_of_failed_tests + (double)total_of_interrupted_tests)/(double)total_of_tests)*100.0 : 100.0),
+                total_of_tests, total_of_successeded_tests); 
+                
+       if(total_of_failed_tests > 0)
+                       printf(", %d failed", total_of_failed_tests);
+               
+       if(total_of_interrupted_tests > 0)
+               printf(", %d interrupted)", total_of_interrupted_tests);
+               
+       printf(")\n\n");
+       
+       
+       if(unit->interrupted)
+               unit->runner->total_of_interrupted_units++;
+       else if(total_of_failed_tests > 0)
+               unit->runner->total_of_failed_units++;
+       else
+               unit->runner->total_of_successeded_units++;
+       
+       
+       unit->runner->total_of_tests += total_of_tests;
+       unit->runner->total_of_failed_tests += total_of_failed_tests;
+       unit->runner->total_of_successeded_tests += total_of_successeded_tests;
+       unit->runner->total_of_interrupted_tests += total_of_interrupted_tests;
+       
+       
+       unit->runner->total_of_units += total_of_units + 1;
+       unit->runner->total_of_successeded_units += total_of_successeded_units;
+       unit->runner->total_of_failed_units += total_of_failed_units;
+       unit->runner->total_of_interrupted_units += total_of_interrupted_units;
+       
+       
+       unit->runner->total_of_suites += total_of_suites;
+       unit->runner->total_of_successeded_suites += total_of_successeded_suites;
+       unit->runner->total_of_failed_suites += total_of_failed_suites;
+       unit->runner->total_of_interrupted_suites += total_of_interrupted_suites;
+       
+       
+       
+}
+
 
 
-}
 
 void
-unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name)
+unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description)
 {
-       directory_t include;
+       directory_t dir;
        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);
+               /* the file is in the current directory */
                
                fstream = fstream_new(getcwd(NULL, 0), file_name);
                fstream_open(fstream);
@@ -684,21 +1499,21 @@ unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const
        {
                prev_directory = getcwd(NULL, 0);
                
-               vector_rewind(includes);
+               vector_rewind(include_dirs);
                
-               while((include = vector_get(includes)))
+               while((dir = vector_get(include_dirs)))
                {
-                       chdir(include->name);
+                       chdir(dir->name);
                        
                        if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
                        {
-                               fstream = fstream_new(include->name, file_name);
+                               fstream = fstream_new(dir->name, file_name);
                                fstream_open(fstream);
                                break;
                        }
                        
                        
-                       vector_move_next(includes);
+                       vector_move_next(include_dirs);
                }
                
                chdir(prev_directory);
@@ -716,34 +1531,53 @@ unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const
        }
        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 */
+               if(!unit->running_suite)
+               {/* it's the unit of a suite */
+                       unit_t include = unit_new(unit->runner,unit->root, unit, fstream);
+                       
+                       include->mutex = unit->root->mutex;
                
-               /*xbt_os_mutex_acquire(unit->mutex);
-               vector_push_back(__unit->runner->units->items, __unit);
-               xbt_os_mutex_release(unit->mutex);*/
+                       if(description)
+                               include->description = strdup(description);
                
+                       vector_push_back(unit->includes, include);
                
-               if(want_dry_run)
-                       INFO2("checking unit %s including in %s...",fstream->name, unit->fstream->name); 
+                       fstream_parse(fstream, include, mutex);
+               }
+               else
+               {/* it's a include */
+                       unit_t owner = vector_get_back(unit->suites);
+                       unit_t include = unit_new(unit->runner,unit->root, owner, fstream);
+                       
+                       include->mutex = unit->root->mutex;
+                       
+                       if(description)
+                               include->description = strdup(description);
                
-               unit_parse(unit, context_new(), mutex, fstream->name, fstream->stream);
+                       vector_push_back(owner->includes, include);
                
-               fstream_free((void**)&fstream);
-               unit->parsing_include_file = 0;
+                       fstream_parse(fstream, include, mutex); 
+               }
        }
 }
 
 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;
+       if(unit->running_suite)
+       {
+               exit_code = ESYNTAX;
+               unit_handle_failure(unit);
+       }
+       else
+       {
+               unit_t suite = unit_new(unit->runner, unit->root, unit, NULL);
+               suite->is_suite = 1;
+               suite->description = strdup(description);
+               vector_push_back(unit->suites, suite);
+               unit->running_suite = 1;
+       }
 }
 
 int