124
|
1 import std.stdio;
|
|
2 import std.utf;
|
|
3 import std.file;
|
|
4 import std.path;
|
|
5 import std.algorithm;
|
|
6 import std.string;
|
|
7 import std.process;
|
|
8 import core.stdc.ctype;
|
|
9 import std.c.windows.windows;
|
|
10
|
|
11 string compiler = "dmd";
|
|
12
|
|
13 class Test
|
|
14 {
|
|
15 enum EXTRA_SOURCES = "EXTRA_SOURCES";
|
|
16 enum COMPILE_SEPARATELY = "COMPILE_SEPARATELY";
|
|
17 enum PERMUTE_ARGS = "PERMUTE_ARGS";
|
|
18 enum REQUIRED_ARGS = "REQUIRED_ARGS";
|
|
19 enum POST_SCRIPT = "POST_SCRIPT";
|
|
20 enum EXECUTE_ARGS = "EXECUTE_ARGS";
|
|
21
|
|
22 this(string path, string outputDir)
|
|
23 {
|
|
24 this.outputDir = outputDir;
|
|
25 this.baseDir = dirname(path);
|
|
26
|
|
27 this.baseName = getBaseName(path);
|
|
28 this.name = getName(baseName);
|
|
29
|
|
30 this.fileNames ~= baseName;
|
|
31
|
|
32 auto file = File(path);
|
|
33 while (true) {
|
|
34 auto line = file.readln();
|
|
35 if (!line.startsWith("// ")) {
|
|
36 break;
|
|
37 }
|
|
38
|
|
39 line = trim(line[3..$]);
|
|
40 if (line.startsWith(EXTRA_SOURCES)) {
|
|
41 fileNames ~= split(line[EXTRA_SOURCES.length + 2..$], " ");
|
|
42 } else if (line.startsWith(COMPILE_SEPARATELY)) {
|
|
43 compileSeparately = true;
|
|
44 } else if (line.startsWith(EXECUTE_ARGS)) {
|
|
45 executeArgs = line[EXECUTE_ARGS.length + 2..$];
|
|
46 } else if (line.startsWith(PERMUTE_ARGS)) {
|
|
47 // ignore for now
|
|
48 } else if (line.startsWith(REQUIRED_ARGS)) {
|
|
49 requiredArgs = line[REQUIRED_ARGS.length + 2..$];
|
|
50 } else if (line.startsWith(POST_SCRIPT)) {
|
|
51 // ignore for now
|
|
52 } else {
|
|
53 continue;
|
|
54 }
|
|
55 }
|
|
56 }
|
|
57
|
|
58 private string prefix()
|
|
59 {
|
|
60 return std.string.format(compiler ~ " -od%s -I%s %s", outputDir, baseDir, requiredArgs);
|
|
61 }
|
|
62
|
|
63 private string csuffix(string fileName)
|
|
64 {
|
|
65 // output to console
|
|
66 return ""; //std.string.format(" > %s\\%s.clog", outputDir, getBaseName(fileName));
|
|
67 }
|
|
68
|
|
69 private string lsuffix(string fileName)
|
|
70 {
|
|
71 return std.string.format(" > %s\\%s.llog", outputDir, getBaseName(fileName));
|
|
72 }
|
|
73
|
|
74 private string output()
|
|
75 {
|
|
76 return std.string.format(" -of%s\\%s.exe", outputDir, name);
|
|
77 }
|
|
78
|
|
79 private void execute(string command)
|
|
80 {
|
|
81 system(command);
|
|
82 }
|
|
83
|
|
84 void compile()
|
|
85 {
|
|
86 if (compileSeparately) {
|
|
87 string link_command = compiler ~ output();
|
|
88 foreach (fileName; fileNames) {
|
|
89 string compile_command = prefix();
|
|
90
|
|
91 compile_command ~= std.string.format(" %s\\%s -c", baseDir, fileName);
|
|
92 compile_command ~= csuffix(fileName);
|
|
93
|
|
94 execute(compile_command);
|
|
95 link_command ~= std.string.format(" %s\\%s.obj", outputDir, getName(getBaseName(fileName)));
|
|
96 }
|
|
97
|
|
98 link_command ~= lsuffix(baseName);
|
|
99
|
|
100 execute(link_command);
|
|
101 } else {
|
|
102 string compile_command = prefix();
|
|
103 foreach (fileName; fileNames) {
|
|
104 compile_command ~= std.string.format(" %s\\%s", baseDir, fileName);
|
|
105 }
|
|
106
|
|
107 compile_command ~= output();
|
|
108 compile_command ~= csuffix(baseName);
|
|
109
|
|
110 execute(compile_command);
|
|
111 }
|
|
112 }
|
|
113
|
|
114 private string[] fileNames;
|
|
115
|
|
116 private string name;
|
|
117 private string baseName;
|
|
118 private string outputDir;
|
|
119 private string baseDir;
|
|
120 private string requiredArgs;
|
|
121 private string executeArgs;
|
|
122
|
|
123 private bool compileSeparately = false;
|
|
124 }
|
|
125
|
|
126 class RunnableTest : Test
|
|
127 {
|
|
128 this(string path, string outputDir)
|
|
129 {
|
|
130 super(path, outputDir);
|
|
131 }
|
|
132
|
|
133 void run()
|
|
134 {
|
|
135 string run_command = std.string.format("%s\\%s.exe %s > %s\\%s.exe.rlog", outputDir, name, executeArgs, outputDir, name);
|
|
136 execute(run_command);
|
|
137 }
|
|
138 }
|
|
139
|
|
140 int main(string[] args)
|
|
141 {
|
|
142 auto runnable_tests = wildcard("runnable/*.d"/*, "runnable/*.html", "runnable/*.sh"*/);
|
|
143 auto runnable_test_results = map!q{"result/" ~ a ~ ".out"}(runnable_tests);
|
|
144
|
|
145 auto outputDir = "result";
|
|
146
|
|
147 if (args.length >= 2) {
|
|
148 compiler = args[1];
|
|
149 } else {
|
|
150 // compiler = "dmd"; // value by default
|
|
151 }
|
|
152
|
|
153 foreach (fileName; runnable_tests) {
|
|
154 //fileName = "runnable\\a18.d";
|
|
155 writeln("testing ", fileName);
|
|
156 auto test = new RunnableTest(fileName, outputDir);
|
|
157 test.compile();
|
|
158 // test.run();
|
|
159 // break;
|
|
160 }
|
|
161
|
|
162 return 0;
|
|
163 }
|
|
164
|
|
165 string[] wildcard(string[] paths...)
|
|
166 {
|
|
167 string[] fileNames;
|
|
168
|
|
169 foreach (path; paths) {
|
|
170 filter(path, (string fileName) { fileNames ~= fileName; return true; });
|
|
171 }
|
|
172
|
|
173 return fileNames;
|
|
174 }
|
|
175
|
|
176 string trimLeft(string s)
|
|
177 {
|
|
178 for (int i = 0; i < s.length; ++i) {
|
|
179 if (!isspace(s[i])) {
|
|
180 return s[i..$];
|
|
181 }
|
|
182 }
|
|
183
|
|
184 return null;
|
|
185 }
|
|
186
|
|
187 string trimRight(string s)
|
|
188 {
|
|
189 for (int i = s.length - 1; i >= 0; --i) {
|
|
190 if (!isspace(s[i])) {
|
|
191 return s[0..i + 1];
|
|
192 }
|
|
193 }
|
|
194
|
|
195 return null;
|
|
196 }
|
|
197
|
|
198 string trim(string s)
|
|
199 {
|
|
200 return trimLeft(trimRight(s));
|
|
201 }
|
|
202
|
|
203 version(Windows) void filter(string pattern, bool delegate(string fileName) callback)
|
|
204 {
|
|
205 WIN32_FIND_DATAW fileinfo;
|
|
206
|
|
207 auto h = FindFirstFileW(std.utf.toUTF16z(pattern), &fileinfo);
|
|
208 if (h == INVALID_HANDLE_VALUE)
|
|
209 return;
|
|
210
|
|
211 auto path = dirname(pattern);
|
|
212
|
|
213 do
|
|
214 {
|
|
215 // Skip "." and ".."
|
|
216 auto name = fileinfo.cFileName.ptr;
|
|
217 if (name[0] == '.' && (name[1] == 0 || name[1] == '.'))
|
|
218 continue;
|
|
219
|
|
220 size_t clength = std.string.wcslen(fileinfo.cFileName.ptr);
|
|
221 auto fileName = std.path.join(path, std.utf.toUTF8(fileinfo.cFileName[0 .. clength]));
|
|
222
|
|
223 if (!callback(fileName)) {
|
|
224 break;
|
|
225 }
|
|
226 } while (FindNextFileW(h, &fileinfo) != FALSE);
|
|
227
|
|
228 FindClose(h);
|
|
229 }
|
|
230
|
|
231 string getBaseName(string fullname, string extension = null)
|
|
232 {
|
|
233 auto i = fullname.length;
|
|
234 for (; i > 0; i--)
|
|
235 {
|
|
236 version(Windows)
|
|
237 {
|
|
238 if (fullname[i - 1] == ':' || fullname[i - 1] == '\\' || fullname[i - 1] == '/')
|
|
239 break;
|
|
240 }
|
|
241 else version(Posix)
|
|
242 {
|
|
243 if (fullname[i - 1] == '/')
|
|
244 break;
|
|
245 }
|
|
246 else
|
|
247 {
|
|
248 static assert(0);
|
|
249 }
|
|
250 }
|
|
251 return chomp(fullname[i .. fullname.length],
|
|
252 extension.length ? extension : "");
|
|
253 } |