Windows test suite & build fixes. VC2003 and VC2008 should both now build. Known...
[dyninst.git] / newtestsuite / src / runTests.C
1 #ifdef os_windows_test
2 //needed for Sleep
3 #include <windows.h>
4 #define sleep(x) Sleep(x * 1000)
5 #define unlink _unlink
6 #endif
7
8 #include <stdlib.h>
9 #include <sstream>
10 #include <string>
11 #include <iostream>
12 #include <stdio.h>
13 #include <vector>
14
15 #include <string.h>
16 #include <errno.h>
17 #include <signal.h>
18
19 #include "runTests-utils.h"
20 #include "error.h"
21 #include "help.h"
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <cstring>
25
26 // To prevent run away never run test_driver more the MAX_ITER times
27 #define MAX_ITER 1000
28
29 // Default name for the resume log file
30 #define DEFAULT_RESUMELOG "bresumelog"
31 // Default name for the crash log file
32 #define DEFAULT_CRASHLOG "crashlog"
33
34 #define MEMCPU_DEFAULT_LOG "memcpu_tmp.log";
35 const char *memcpu_name = NULL;
36 const char *memcpu_orig_name = NULL;
37
38 bool staticTests = false;
39 bool useLog = false;
40 string logfile;
41 string pdscrdir;
42
43 // Run No more than testLimit tests before re-exec'ing test_driver
44 int testLimit = 10;
45
46 vector<char *> child_argv;
47
48 void parseMEMCPUFile()
49 {
50    if (!memcpu_name || !memcpu_orig_name)
51       return;
52
53    signed long mem_total = 0, utime_total = 0, stime_total = 0;
54    FILE *f = fopen(memcpu_name, "r");
55    if (!f)
56       return;
57
58    for (;;)
59    {
60       signed long mem, utime, stime;
61       int res = fscanf(f, "mem=%ld\tutime=%ld\tstime=%ld\n",
62                        &mem, &utime, &stime);
63       if (res != 3)
64          break;
65       mem_total += mem;
66       utime_total += utime;
67       stime_total += stime;
68    }
69    fclose(f);
70    unlink(memcpu_name);
71
72    if (strcmp(memcpu_orig_name, "-") == 0)
73    {
74       f = stdout;
75    }
76    else {
77       f = fopen(memcpu_orig_name, "w");
78       if (!f)
79          return;
80    }
81    
82    fprintf(f, "mem=%ld\tutime=%ld\tstime=%ld\n",
83            mem_total, utime_total, stime_total);
84    if (f != stdout)
85       fclose(f);
86 }
87
88 // isRegFile:
89 // Returns true if filename is a regular file
90 bool isRegFile(const string& filename)
91 {
92    struct stat results;
93
94    if ( stat(filename.c_str(), &results) !=  0 )
95    {
96       return false;
97    }
98
99    return S_ISREG(results.st_mode);
100 }
101
102 // isDir:
103 // Returns true if filename is a directory
104 bool isDir(const string& filename)
105 {
106    struct stat results;
107
108    if ( stat(filename.c_str(), &results) !=  0 )
109    {
110       return false;
111    }
112
113    return S_ISDIR(results.st_mode);
114 }
115
116 // getInput:
117 // Run filename and store stdout in the output string.
118 void getInput(const char *filename, string& output)
119 {
120    FILE *text;
121    char *result;
122    result = (char *) calloc(1024,sizeof(char));
123    text = popen(filename, "r");
124    // Wait for program to terminate
125    fscanf(text, "%s\n", result);
126    pclose(text);
127
128    output = result;
129
130    free(result);
131 }
132
133 // parseParameters:
134 // Interpret arguments, and collect uninterpretted arguments to be passed
135 // to test_driver.
136 void parseParameters(int argc, char *argv[])
137 {
138 #if defined(STATIC_TEST_DRIVER)
139    staticTests = true;
140 #endif
141
142    for ( int i = 1; i < argc; i++ )
143    {
144       if (strncmp(argv[i], "-limit", 6) == 0) {
145          if (i == (argc-1)) {
146             fprintf(stderr, "Error: -limit requires a parameter\n");
147          }
148          else {
149             unsigned int limit = atoi(argv[i+1]);
150             testLimit = limit;
151             i++;
152          }
153       } else if ((strcmp(argv[i], "-help") == 0) ||
154                  (strcmp(argv[i], "--help") == 0)) {
155          print_help();
156          exit(0);
157       } else if (strcmp(argv[i], "-static") == 0) {
158          staticTests = true;
159       } else if (strcmp(argv[i], "-dynamic") == 0) {
160          staticTests = false;
161       }
162       else if ((strcmp(argv[i], "-memcpu") == 0) ||
163                (strcmp(argv[i], "-cpumem") == 0))
164       {
165          memcpu_name = MEMCPU_DEFAULT_LOG;
166          
167          if ((i+1 < argc) &&
168              (argv[i+1][0] != '-' || argv[i+1][1] == '\0'))
169          {
170             i++;
171             memcpu_orig_name = argv[i];
172          }
173          else
174          {
175             memcpu_orig_name = "-";
176          }
177       }
178       else
179       {
180          // Pass uninterpreted arguments to test_driver
181          child_argv.push_back(argv[i]);
182       }
183    }
184 }
185
186 // ReplaceAllWith:
187 // Replaces all occurances of 'replace' in string 'in' with the text in string
188 // 'with', the result is returned.
189 string ReplaceAllWith(const string &in, const string &replace, const string &with)
190 {
191    string cur;
192    
193    string::size_type match_pos = in.find(replace);
194    string::size_type r_len = replace.length();
195    if ( match_pos == string::npos )
196    {
197       return in;
198    } 
199    else
200    {
201       return in.substr(0,match_pos) + with + 
202          ReplaceAllWith(in.substr(match_pos + r_len, in.length()), replace, with);
203    }
204    
205    
206 }
207
208 int main(int argc, char *argv[])
209 {
210    parseParameters(argc, argv);
211    setupVars(useLog, logfile);
212
213    setLibPath();
214
215    int result = 0;
216    int invocation = 0;
217
218    // Remove a stale resumelog, if it exists
219    if ( getenv("RESUMELOG") && isRegFile(string(getenv("RESUMELOG"))) )
220    {
221            if(unlink(getenv("RESUMELOG")) == -1) {
222                    fprintf(stderr, "Couldn't delete resume log: %s\n", getenv("RESUMELOG"));
223            }
224            else {
225                    fprintf(stderr, "Cleaned up resume log OK: %s\n", getenv("RESUMELOG"));
226            }
227    } else if (isRegFile(string(DEFAULT_RESUMELOG))) {
228            if(unlink(DEFAULT_RESUMELOG) == -1) {
229                    fprintf(stderr, "Couldn't delete resume log: %s\n", DEFAULT_RESUMELOG);
230            }
231            else {
232                    fprintf(stderr, "Cleaned up resume log OK: %s\n", DEFAULT_RESUMELOG);
233            }
234    }
235
236    // Remove a stale crashlog, if it exists
237    if (getenv("CRASHLOG") && isRegFile(string(getenv("CRASHLOG")))) {
238            if(unlink(getenv("CRASHLOG")) == -1) {
239                    fprintf(stderr, "Couldn't delete crash log: %s\n", getenv("CRASHLOG"));
240            };
241       unlink(getenv("CRASHLOG"));
242    } else if (isRegFile(string(DEFAULT_CRASHLOG))) {
243            if(unlink(DEFAULT_CRASHLOG) == -1) {
244                    fprintf(stderr, "Couldn't delete crash log: %s\n", DEFAULT_CRASHLOG);
245            };
246    }
247
248    // Create a PIDs file, to track mutatee PIDs
249    char *pidFilename = new char[80];
250    initPIDFilename(pidFilename, 80);
251    // result == 2 indicates that there are no more tests to run
252    while ( result != NOTESTS && invocation < MAX_ITER )
253    {
254       result = RunTest(invocation, useLog, staticTests, logfile, testLimit,
255                        child_argv, pidFilename, memcpu_name);
256       invocation++;
257       // I want to kill any remaining mutatees now, to clean up.  I should also
258       // set a timer in RunTest in case something goes weird with test_driver.
259       // (I think we'd be better off moving away from timer.pl)
260       cleanupMutatees(pidFilename);
261       if (-3 == result) {
262          // User interrupted the test run; allow them a couple of seconds to do
263          // it again and kill runTests
264          // TODO Make sure this is portable to Windows
265          fprintf(stderr, "Press ctrl-c again with-in 2 seconds to abort runTests.\n");
266          sleep(2);
267       }
268       if (-4 == (signed char) result) {
269          fprintf(stderr, "Could not execute test_driver\n");
270          break;
271       }
272       if (-5 == (signed char) result) {
273          break;
274       }
275    }
276
277    // Remove the PID file, now that we're done with it
278    if (pidFilename && isRegFile(string(pidFilename))) {
279       unlink(pidFilename);
280    }
281    unlink(DEFAULT_RESUMELOG);
282    unlink(getenv("RESUMELOG"));
283    
284
285    parseMEMCPUFile();
286    return 0;
287 }