Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
19557d1e857386ef0a87cb60c5ecc81abfaa2f69
[simgrid.git] / tools / tesh / tesh.c
1 /* $Id$ */
2
3 /* TESH (Test Shell) -- mini shell specialized in running test units        */
4
5 /* Copyright (c) 2007 Martin Quinson.                                       */
6 /* All rights reserved.                                                     */
7
8 /* This program is free software; you can redistribute it and/or modify it
9  * under the terms of the license (GNU LGPL) which comes with this package. */
10
11 /* specific to Borland Compiler */
12 #ifdef __BORLANDDC__
13 #pragma hdrstop
14 #endif
15
16 #include "tesh.h"
17 #include "xbt.h"
18
19 XBT_LOG_NEW_DEFAULT_CATEGORY(tesh,"TEst SHell utility");
20
21 /*** Options ***/
22 int timeout_value = 5; /* child timeout value */
23
24 char *testsuite_name;
25 static void handle_line(const char * filepos, char *line) {
26   int pos;
27
28   /* Search end */
29   xbt_str_rtrim(line+2,"\n");
30
31   /*
32   DEBUG7("rctx={%s,in={%d,>>%10s<<},exp={%d,>>%10s<<},got={%d,>>%10s<<}}",
33          rctx->cmd,
34          rctx->input->used,        rctx->input->data,
35          rctx->output_wanted->used,rctx->output_wanted->data,
36          rctx->output_got->used,   rctx->output_got->data);
37   */
38   DEBUG2("[%s] %s",filepos,line);
39
40   switch (line[0]) {
41   case '#': break;
42
43   case '$':
44     /* further trim useless chars which are significant for in/output */
45     xbt_str_rtrim(line+2," \t");
46
47     /* Deal with CD commands here, not in rctx */
48     if (!strncmp("cd ",line+2,3)) {
49       char *dir=line+4;
50
51       if (rctx->cmd)
52         rctx_start();
53       
54       /* search begining */
55       while (*(dir++) == ' ');
56       dir--;
57       VERB1("Saw cd '%s'",dir);
58       if (chdir(dir)) {
59         char buff[256];
60         strerror_r(errno, buff, 256);
61
62         perror(bprintf("Chdir to %s failed: %s",dir+pos+2,buff));
63         ERROR1("Test suite `%s': NOK (system error)",testsuite_name);    
64         exit(4);
65       }
66       break;
67     } /* else, pushline */
68   case '&':
69   case '<':
70   case '>':
71   case '!':
72     rctx_pushline(filepos, line[0], line+2 /* pass '$ ' stuff*/);    
73     break;
74
75   case 'p':
76     INFO2("[%s] %s",filepos,line+2);
77     break;
78   case 'P':
79     CRITICAL2("[%s] %s",filepos,line+2);
80     break;
81
82   default:
83     ERROR2("[%s] Syntax error: %s",filepos, line);
84     ERROR1("Test suite `%s': NOK (syntax error)",testsuite_name);
85     exit(1);
86     break;
87   }
88 }
89
90 static void handle_suite(const char* filename, FILE* IN) {
91   size_t len;
92   char * line = NULL;
93   int line_num=0;
94   char file_pos[256];
95
96   buff_t buff=buff_new();
97   int buffbegin = 0;   
98
99   rctx = rctx_new();
100
101   while (getline(&line, &len, IN) != -1) {
102     line_num++;
103
104     /* Count the line length while checking wheather it's blank */
105     int blankline=1;
106     int linelen = 0;    
107     while (line[linelen] != '\0') {
108       if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n')
109         blankline = 0;
110       linelen++;
111     }
112     
113     if (blankline) {
114       if (!rctx->cmd && !rctx->is_empty) {
115         ERROR1("[%d] Error: no command found in this chunk of lines.",
116                buffbegin);
117         ERROR1("Test suite `%s': NOK (syntax error)",testsuite_name);
118         exit(1);
119       }
120       if (rctx->cmd)
121         rctx_start();
122
123       continue;
124     }
125
126     /* Deal with \ at the end of the line, and call handle_line on result */
127     int to_be_continued = 0;
128     if (linelen>1 && line[linelen-2]=='\\') {
129       if (linelen>2 && line[linelen-3] == '\\') {
130         /* Damn. Escaped \ */
131         line[linelen-2] = '\n';
132         line[linelen-1] = '\0';
133       } else {
134         to_be_continued = 1;
135         line[linelen-2] = '\0';
136         linelen -= 2;  
137         if (!buff->used)
138           buffbegin = line_num;
139       }
140     }
141
142     if (buff->used || to_be_continued) { 
143       buff_append(buff,line);
144
145       if (!to_be_continued) {
146         snprintf(file_pos,256,"%s:%d",filename,buffbegin);
147         handle_line(file_pos, buff->data);    
148         buff_empty(buff);
149       }
150         
151     } else {
152       snprintf(file_pos,256,"%s:%d",filename,line_num);
153       handle_line(file_pos, line);    
154     }
155   }
156   /* Check that last command of the file ran well */
157   if (rctx->cmd) 
158     rctx_start();
159
160   /* Wait all background commands */
161
162   rctx_free(rctx);
163
164   /* Clear buffers */
165   if (line)
166     free(line);
167   buff_free(buff);
168
169 }
170
171 int main(int argc,char *argv[]) {
172
173   FILE *IN;
174
175   /* Ignore pipe issues.
176      They will show up when we try to send data to dead buddies, 
177      but we will stop doing so when we're done with provided input */
178   struct sigaction newact;
179   memset(&newact,0, sizeof(newact));
180   newact.sa_handler=SIG_IGN;
181   sigaction(SIGPIPE,&newact,NULL);
182    
183   xbt_init(&argc,argv);
184   rctx_init();
185
186   /* Find the description file */
187   if (argc == 1) {
188     INFO0("Test suite from stdin");
189     handle_suite("stdin",stdin);
190     INFO0("Test suite from stdin OK");
191      
192   } else {
193     int i;
194      
195     for (i=1; i<argc; i++) {
196       char *suitename=xbt_strdup(argv[i]);
197       if (!strcmp("./",suitename))
198         memmove(suitename, suitename+2, strlen(suitename+2));
199
200       if (!strcmp(".tesh",suitename+strlen(suitename)-5))
201         suitename[strlen(suitename)-5] = '\0';
202
203       INFO1("Test suite `%s'",suitename);
204       testsuite_name = suitename;
205       IN=fopen(argv[i], "r");
206       if (!IN) {
207         perror(bprintf("Impossible to open the suite file `%s'",argv[i]));
208         ERROR1("Test suite `%s': NOK (system error)",testsuite_name);
209         exit(1);
210        }
211       handle_suite(suitename,IN);
212       rctx_wait_bg();
213       fclose(IN); //->leads to segfault on amd64...
214       INFO1("Test suite `%s' OK",suitename);
215       free(suitename);
216     }
217   }
218
219   rctx_exit();
220   xbt_exit();
221   return 0;  
222 }
223