1 /*
2  * Convert debug output from running the regression tests
3  * on ReactOS to an xml document.
4  * Casper S. Hornstrup <chorns@users.sourceforge.net>
5  */
6 
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #ifdef WIN32
14 #include <io.h>
15 #include <dos.h>
16 #else
17 #include <sys/io.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <unistd.h>
22 #endif
23 #include <ctype.h>
24 #ifndef WIN32
25 #ifndef MAX_PATH
26 #define MAX_PATH 260
27 #endif
28 #define DIR_SEPARATOR_CHAR '/'
29 #define DIR_SEPARATOR_STRING "/"
30 #else
31 #define DIR_SEPARATOR_CHAR '\\'
32 #define DIR_SEPARATOR_STRING "\\"
33 #endif
34 
35 typedef struct _TEST_RESULT_INFO
36 {
37   struct _TEST_RESULT_INFO *next;
38   char testname[100];
39   char result[200];
40   int succeeded; /* 0 = failed, 1 = succeeded */
41 } TEST_RESULT_INFO, *PTEST_RESULT_INFO;
42 
43 
44 static FILE *out;
45 static FILE *file_handle = NULL;
46 static char *file_buffer = NULL;
47 static unsigned int file_size = 0;
48 static int file_pointer = 0;
49 static PTEST_RESULT_INFO test_result_info_list = NULL;
50 
51 
52 static char*
53 convert_path(char* origpath)
54 {
55    char* newpath;
56    int i;
57 
58    newpath = strdup(origpath);
59 
60    i = 0;
61    while (newpath[i] != 0)
62      {
63 #ifndef WIN32
64 	if (newpath[i] == '\\')
65 	  {
66 	     newpath[i] = '/';
67 	  }
68 #else
69 #ifdef WIN32
70 	if (newpath[i] == '/')
71 	  {
72 	     newpath[i] = '\\';
73 	  }
74 #endif
75 #endif
76 	i++;
77      }
78    return(newpath);
79 }
80 
81 static void
82 write_line(char *line)
83 {
84   char buf[200];
85 
86   memset(buf, 0, sizeof(buf));
87   strcpy(buf, line);
88   /* Terminate the line */
89   buf[strlen(buf)] = '\r';
90   buf[strlen(buf)] = '\n';
91 
92   (void)fwrite(&buf[0], 1, strlen(buf), out);
93 }
94 
95 
96 static void
97 read_file(char *filename)
98 {
99   file_handle = fopen(filename, "rb");
100   if (file_handle == NULL)
101     {
102       printf("Can't open %s\n", filename);
103       exit(1);
104     }
105 
106   // Get the size of the file
107   fseek(file_handle, 0, SEEK_END);
108   file_size = ftell(file_handle);
109 
110   // Load it all into memory
111   file_buffer = malloc(file_size);
112   if (file_buffer == NULL)
113     {
114       fclose(file_handle);
115       printf("Out of memory\n");
116       exit(1);
117     }
118   fseek(file_handle, 0, SEEK_SET);
119   if (file_size > 0)
120     {
121       if (fread (file_buffer, 1, file_size, file_handle) < 1)
122         {
123           fclose(file_handle);
124           printf("Read error in file %s\n", filename);
125           exit(1);
126         }
127     }
128 
129   file_pointer = 0;
130 }
131 
132 static void
133 close_file()
134 {
135   free(file_buffer);
136   file_buffer = NULL;
137   fclose(file_handle);
138   file_handle = NULL;
139   file_pointer = 0;
140 }
141 
142 static int
143 is_whitespace(char ch)
144 {
145   if (ch == ' ')
146     {
147       return 1;
148     }
149   if (ch == '\t')
150     {
151       return 1;
152     }
153   return 0;
154 }
155 
156 static int
157 is_eol_char(char ch)
158 {
159   if (ch == '\r')
160     {
161       return 1;
162     }
163   if (ch == '\n')
164     {
165       return 1;
166     }
167   return 0;
168 }
169 
170 static void
171 skip_line()
172 {
173   while ((file_pointer < file_size) && (!is_eol_char(file_buffer[file_pointer])))
174     {
175       file_pointer++;
176     }
177   if ((file_pointer < file_size) && (is_eol_char(file_buffer[file_pointer])))
178     {
179       file_pointer++;
180       if ((file_pointer < file_size) && (file_buffer[file_pointer] == '\n'))
181         {
182           file_pointer++;
183         }
184     }
185 }
186 
187 static void
188 skip_whitespace()
189 {
190   while ((file_pointer < file_size) && !is_eol_char(file_buffer[file_pointer])
191     && is_whitespace(file_buffer[file_pointer]))
192     {
193       file_pointer++;
194     }
195 }
196 
197 static int
198 skip_to_next_test()
199 {
200   static char test_marker[] = "ROSREGTEST:";
201   int found_test = 0;
202 
203   while ((file_pointer < file_size) && (!found_test))
204     {
205 	  skip_whitespace();
206       found_test = 1;
207 	  int i = 0;
208       while (1)
209 	    {
210 		  if (i >= strlen(test_marker))
211             {
212               break;
213             }
214 		  if (is_eol_char(file_buffer[file_pointer]))
215 		    {
216               found_test = 0;
217 			  break;
218 		    }
219 		  if (file_buffer[file_pointer] != test_marker[i])
220             {
221               found_test = 0;
222 			  break;
223             }
224           file_pointer++;
225           i++;
226 	    }
227 	  if (!found_test)
228         {
229           skip_line();
230         }
231     }
232   return found_test;
233 }
234 
235 static int
236 read_until(char ch, char* buf)
237 {
238   int start = file_pointer;
239   while ((file_pointer < file_size))
240     {
241       if (file_buffer[file_pointer] == ch)
242         {
243 		  strncpy(buf, &file_buffer[start], file_pointer - start);
244 		  buf[file_pointer - start] = 0;
245           return 1;
246         }
247       file_pointer++;
248     }
249   return 0;
250 }
251 
252 static int
253 read_until_end(char* buf)
254 {
255   int start = file_pointer;
256   while ((file_pointer < file_size))
257     {
258       if (is_eol_char(file_buffer[file_pointer]))
259         {
260 		  strncpy(buf, &file_buffer[start], file_pointer - start);
261 		  buf[file_pointer - start] = 0;
262 		  skip_line();
263           return 1;
264         }
265       file_pointer++;
266     }
267   return 0;
268 }
269 
270 static void
271 parse_file(char *filename)
272 {
273   PTEST_RESULT_INFO test_result_info;
274 
275   read_file(filename);
276 
277   do
278     {
279       if (!skip_to_next_test())
280         {
281           break;
282         }
283 
284 	  /*
285 	   * FORMAT:
286 	   * [ROSREGTEST:][space][|][<testname>][|][space][Status:][space][<result of running test>]
287 	   */
288 
289       test_result_info = malloc(sizeof(TEST_RESULT_INFO));
290       if (test_result_info == NULL)
291         {
292 	      printf("Out of memory\n");
293 	      exit(1);
294         }
295 
296       /* Skip whitespaces */
297       skip_whitespace();
298 
299   	  /* [|] */
300       file_pointer++;
301 
302 	  /* <testname> */
303 	  read_until(')', test_result_info->testname);
304 
305    	  /* [|] */
306       file_pointer++;
307 
308 	  /* [space] */
309       file_pointer++;
310 
311   	  /* Status: */
312       file_pointer += 7;
313 
314   	  /* [space] */
315       file_pointer++;
316 
317   	  /* <result of running test> */
318 	  read_until_end(test_result_info->result);
319 
320 	  if (strncmp(test_result_info->result, "Success", 7) == 0)
321         {
322 	      test_result_info->succeeded = 1;
323         }
324       else
325         {
326           test_result_info->succeeded = 0;
327         }
328 
329       test_result_info->next = test_result_info_list;
330       test_result_info_list = test_result_info;
331     } while (1);
332 
333   close_file();
334 }
335 
336 static void
337 generate_xml()
338 {
339   PTEST_RESULT_INFO test_result_info;
340   char buf[200];
341   int success_rate;
342   int succeeded_total;
343   int failed_total;
344 
345   succeeded_total = 0;
346   failed_total = 0;
347 
348   test_result_info = test_result_info_list;
349   while (test_result_info != NULL)
350     {
351       if (test_result_info->succeeded)
352         {
353           succeeded_total++;
354         }
355       else
356         {
357           failed_total++;
358         }
359       test_result_info = test_result_info->next;
360     }
361 
362   if (succeeded_total + failed_total > 0)
363     {
364       success_rate = ((succeeded_total) * 100) / (succeeded_total + failed_total);
365     }
366   else
367     {
368       success_rate = 100;
369     }
370 
371   write_line("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");
372   write_line("");
373 
374   sprintf(buf, "<testresults success_rate=\"%d\" succeeded_total=\"%d\" failed_total=\"%d\">",
375     success_rate, succeeded_total, failed_total);
376   write_line(buf);
377 
378   if (test_result_info_list != NULL)
379     {
380       test_result_info = test_result_info_list;
381       while (test_result_info != NULL)
382         {
383           sprintf(buf, "<testresult testname=\"%s\" succeeded=\"%s\" result=\"%s\">",
384             test_result_info->testname,
385             test_result_info->succeeded == 1 ? "true" : "false",
386             test_result_info->result);
387           write_line(buf);
388           write_line("</testresult>");
389           test_result_info = test_result_info->next;
390         }
391     }
392 
393   write_line("</testresults>");
394 }
395 
396 static char HELP[] =
397   "REGTESTS2XML input-filename output-filename\n"
398   "\n"
399   "  input-filename   File containing output from running regression tests\n"
400   "  output-filename  File to create\n";
401 
402 int main(int argc, char **argv)
403 {
404   char *input_file;
405   char *output_file;
406 
407   if (argc < 3)
408     {
409       puts(HELP);
410       return 1;
411     }
412 
413   input_file = convert_path(argv[1]);
414   if (input_file[0] == 0)
415     {
416       free(input_file);
417       printf("Missing input-filename\n");
418       return 1;
419     }
420 
421   output_file = convert_path(argv[2]);
422   if (output_file[0] == 0)
423     {
424       free(output_file);
425       free(input_file);
426       printf("Missing output-filename\n");
427       return 1;
428     }
429 
430   out = fopen(output_file, "wb");
431   if (out == NULL)
432     {
433         free(input_file);
434         free(output_file);
435     	printf("Cannot open output file");
436     	return 1;
437      }
438 
439   parse_file(input_file);
440 
441   generate_xml();
442 
443   free(input_file);
444   free(output_file);
445   fclose(out);
446 
447   return 0;
448 }
449