Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: utils/testrunner/dart_wrap_task.dart

Issue 10897016: Testrunner for 3rd parties. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // The DartWrapTask generates a Dart wrapper for a test file, that has a
Siggi Cherem (dart-lang) 2012/08/29 20:47:35 use /** */ so we make all these comments valid dar
Siggi Cherem (dart-lang) 2012/08/30 16:46:40 note that this and the comment below are still pen
gram 2012/08/30 17:34:05 Done.
6 // test Configuration customized for the options specified by the user.
7 class DartWrapTask extends PipelineTask {
8 String sourceFileTemplate;
9 String tempDartFileTemplate;
10
11 DartWrapTask(this.sourceFileTemplate, this.tempDartFileTemplate);
12
13 void execute(Path testfile, List stdout, List stderr, bool verboseLogging,
14 Function exitHandler) {
15 // Get the source test file and canonicalize the path.
16 var sourceName = makePathAbsolute(expandMacros(sourceFileTemplate, testfile) );
Siggi Cherem (dart-lang) 2012/08/29 20:47:35 80 col
gram 2012/08/30 17:34:05 Done.
17 // Get the destination file.
18 var destFile = expandMacros(tempDartFileTemplate, testfile);
19
20 // Working buffer for the Dart wrapper.
21 StringBuffer sbuf = new StringBuffer();
22
23 // Add the common header stuff.
24 var p = new Path(sourceName);
25 sbuf.add(directives(p.filenameWithoutExtension,
26 config.unittestPath,
27 sourceName));
28
29 // Add the test configuration and determine the action function.
30 var action;
31 if (config.listTests) {
32 action = 'listTests';
33 sbuf.add(barebonesConfig());
34 sbuf.add(listTestsFunction);
35 sbuf.add(formatListMessageFunction(config.listFormat));
36 } else if (config.listGroups) {
37 sbuf.add(barebonesConfig());
38 sbuf.add(listGroupsFunction);
39 sbuf.add(formatListMessageFunction(config.listFormat));
40 action = 'listGroups';
41 } else {
42 if (config.runInBrowser) {
43 sbuf.add(browserTestPrintFunction);
44 } else {
45 sbuf.add(nonBrowserTestPrintFunction);
46 }
47
48 if (config.includeTime) {
49 sbuf.add(elapsedFunction);
50 } else {
51 sbuf.add(dummyElapsedFunction);
52 }
53 sbuf.add(dumpTestResultFunction);
54 sbuf.add(testConfig(sourceName,
55 config.runInBrowser,
56 config.runIsolated,
57 config.immediateOutput,
58 config.produceSummary));
59 // Add the isolate stuff, if applicable.
60 if (config.runIsolated) {
61 sbuf.add(runIsolateTestsFunction);
62 action = 'runIsolateTests';
63 } else {
64 sbuf.add(runTestsFunction);
65 action = 'runTests';
66 }
67 sbuf.add(formatMessageFunction(config.passFormat,
68 config.failFormat,
69 config.errorFormat));
70 }
71
72 // Add the filter, if applicable.
73 if (config.filtering) {
74 if (config.includeFilter.length > 0) {
75 sbuf.add(filterTestFunction(config.includeFilter, 'true'));
76 } else {
77 sbuf.add(filterTestFunction(config.excludeFilter, 'false'));
78 }
79 }
80
81 // Add the common trailer stuff.
82 sbuf.add(dartMain(sourceName, action, config.filtering));
83
84 // Save the Dart file.
85 createFile(destFile, sbuf.toString());
86 exitHandler(0);
87 }
88
89 String directives(String library, String unittest, String sourceName) {
90 return """
91 #library('$library');
92 #import('dart:isolate');
93 #import('$unittest', prefix:'unittest');
94 #import('$sourceName', prefix: 'test');
95 """;
96 }
97
98 // For 'printing' when we are in the browser, we add text elements
99 // to a DOM element with id 'console'.
100 final String browserTestPrintFunction = """
101 #import('dart:html');
102 void tprint(msg) {
103 var pre = query('#console');
104 pre.elements.add(new Text('###\$msg\\n'));
105 }
106 """;
107
108 // For printing when not in the browser we can just use Dart's print().
109 final String nonBrowserTestPrintFunction = """
110 void tprint(msg) {
111 print('###\$msg');
112 }
113 """;
114
115 // The core skeleton for a config. Most of the guts is in the
116 // parameter [body].
117 String configuration(String body) {
118 return """
119 class TestRunnerConfiguration extends unittest.Configuration {
120 get name => 'Test runner configuration';
121 get autoStart => false;
122 $body
123 }
124 """;
125 }
126
127 // A function to give us the elapsed time for a test.
128 final String elapsedFunction = """
129 String elapsed(TestCase t) {
130 double duration = t.runningTime.inMilliseconds;
131 duration /= 1000;
132 return '\${duration.toStringAsFixed(3)}s ';
133 }
134 """;
135
136 // A dummy version of the elapsed function for when the user
137 // doesn't want test times included.
138 final String dummyElapsedFunction = """
139 String elapsed(TestCase t) {
140 return '';
141 }
142 """;
143
144 // A function to print the results of a test.
145 final String dumpTestResultFunction = """
146 void dumpTestResult(source, TestCase t) {
147 var groupName = '', testName = '';
148 var idx = t.description.lastIndexOf('###');
149 if (idx >= 0) {
150 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
151 testName = t.description.substring(idx+3);
152 } else {
153 testName = t.description;
154 }
155 var stack = (t.stackTrace == null) ? '' : '\${t.stackTrace} ';
156 var message = (t.message.length > 0) ? '\$t.message ' : '';
157 var duration = elapsed(t);
158 tprint(formatMessage(source, '\$groupName ', '\$testName ',
159 duration, t.result, message, stack));
160 }
161 """;
162
163 // A barebones config, used for listing tests, not running them.
164 String barebonesConfig() {
165 return configuration('');
166 }
167
168 // A much more complex config, used for running tests.
169 String testConfig(String sourceName,
170 bool runInBrowser,
171 bool runIsolated,
172 bool immediateOutput,
173 bool summary) {
174 StringBuffer sbuf = new StringBuffer();
175
176 if (runIsolated) {
177 // Add a constructor that saves the isolate port.
178 sbuf.add(" var port;\n TestRunnerConfiguration(this.port);\n");
179 }
180
181 if (immediateOutput) {
182 // Output test results in onTestResult instead of onDone.
183 sbuf.add("""
184 void onTestResult(TestCase testCase) {
185 dumpTestResult('${sourceName} ', testCase);
186 }
187
188 void onDone(int passed, int failed, int errors, List<TestCase> results,
189 String uncaughtError) {
190 """);
191 } else {
192 // Not immediate; we output test results in onDone.
193 sbuf.add("""
194 void onDone(int passed, int failed, int errors, List<TestCase> results,
195 String uncaughtError) {
196 // Print each result.
197 for (final testCase in results) {
198 dumpTestResult('${sourceName} ', testCase);
199 }
200 """);
201 }
202
203 if (summary) {
204 // Add the code to produce the summary for the test file.
205 sbuf.add("""
206 tprint('');
207 var success = false;
208 if (passed == 0 && failed == 0 && errors == 0) {
209 tprint('$sourceName: No tests found.');
210 } else if (failed == 0 && errors == 0 && uncaughtError == null) {
211 tprint('$sourceName: All \$passed tests passed.');
212 success = true;
213 } else {
214 if (uncaughtError != null) {
215 tprint('$sourceName: Top-level uncaught error: \$uncaughtError');
216 }
217 tprint('$sourceName: \$passed PASSED, \$failed FAILED, \$errors ERRORS');
218 }
219 """);
220 }
221
222 if (runIsolated) {
223 // Add the code to tell the master whether we succeeded or not.
224 sbuf.add("""
225 var success = (passed > 0 && failed == 0 && errors == 0 &&
226 uncaughtError == null);
227 port.send(success);
228 """);
229 } else if (runInBrowser) {
230 // Add the code to tell DRT we are done and it can exit.
231 sbuf.add(" window.postMessage('done', '*');\n");
232 }
233 sbuf.add(" }\n");
234 return configuration(sbuf.toString());
235 }
236
237 // A simple format function for listing tests.
238 String formatListMessageFunction(String format) {
239 return """
240 String formatMessage(filename, groupname, [ testname = '']) {
241 return '${format}'.
242 replaceAll('${Macros.testfile}', filename).
243 replaceAll('${Macros.testGroup}', groupname).
244 replaceAll('${Macros.testDescription}', testname);
245 }
246 """;
247 }
248
249 // A richer format function for test results.
250 String formatMessageFunction(
251 String passFormat, String failFormat, String errorFormat) {
252 return """
253 String formatMessage(filename, groupname,
254 [ testname = '', testTime = '', result = '',
255 message = '', stack = '' ]) {
256 var format = '$errorFormat';
257 if (result == 'pass') format = '$passFormat';
258 else if (result == 'fail') format = '$failFormat';
259 return format.
260 replaceAll('${Macros.testTime}', testTime).
261 replaceAll('${Macros.testfile}', filename).
262 replaceAll('${Macros.testGroup}', groupname).
263 replaceAll('${Macros.testDescription}', testname).
264 replaceAll('${Macros.testMessage}', message).
265 replaceAll('${Macros.testStacktrace}', stack);
266 }
267 """;
268 }
269
270 // A function to list the test groups.
271 final String listGroupsFunction = """
272 listGroups(testfile) {
273 List tests = unittest.testCases;
274 Map groups = {};
275 for (var t in tests) {
276 var groupName, testName = '';
277 var idx = t.description.lastIndexOf('###');
278 if (idx >= 0) {
279 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
280 if (!groups.containsKey(groupName)) {
281 groups[groupName] = '';
282 }
283 }
284 }
285 for (var g in groups.getKeys()) {
286 var msg = formatMessage('\$testfile ', '\$g ');
287 print('###\$msg');
288 }
289 }
290 """;
291
292 // A function to list the tests.
293 final String listTestsFunction = """
294 listTests(testfile) {
295 List tests = unittest.testCases;
296 for (var t in tests) {
297 var groupName, testName = '';
298 var idx = t.description.lastIndexOf('###');
299 if (idx >= 0) {
300 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
301 testName = t.description.substring(idx+3);
302 } else {
303 groupName = '';
304 testName = t.description;
305 }
306 var msg = formatMessage('\$testfile ', '\$groupName ',
307 '\$testName ');
308 print('###\$msg');
309 }
310 }
311 """;
312
313 // A function to filter the tests.
314 String filterTestFunction(List filters, String filterReturnValue) {
315 StringBuffer sbuf = new StringBuffer();
316 sbuf.add('filterTest(t) {\n');
317 if (filters != null) {
318 sbuf.add(' var name = t.description.replaceAll("###", " ");\n');
319 for (var f in filters) {
320 sbuf.add(' if (name.indexOf("$f")>=0) return $filterReturnValue;\n');
321 }
322 sbuf.add(' return !$filterReturnValue;\n');
323 } else {
324 // TODO - is this right? Should it be filterReturnValue?
325 sbuf.add(' return true;\n');
326 }
327 sbuf.add('}\n');
328 return sbuf.toString();
329 }
330
331 // Code to support running single tests as master/slave in isolates.
332 final String runIsolateTestsFunction = """
333 runSlaveTest() {
334 port.receive((testName, sendport) {
335 unittest.configure(new TestRunnerConfiguration(sendport));
336 unittest.group('', test.main);
337 unittest.filterTests(testName);
338 unittest.runTests();
339 });
340 }
341
342 var testNum;
343 var failed;
344
345 runMasterTest() {
346 var tests = unittest.testCases;
347 SendPort sport = spawnFunction(runSlaveTest);
348 sport.call(tests[testNum].description).then((result) {
349 if (!result) failed = true;
350 ++testNum;
351 if (testNum < tests.length) {
352 runMasterTest();
353 } else if (failed) {
354 throw new Exception("Some tests failed.");
355 }
356 });
357 }
358
359 runIsolateTests(f) {
360 testNum = 0;
361 failed = false;
362 runMasterTest();
363 }
364 """;
365
366 // Code for running all tests in the normal (non-isolate) way.
367 final String runTestsFunction = "runTests(f) { unittest.runTests(); }\n";
368
369 // The main function, that creates the config, filters the tests if
370 // necessary, then performs the action (list/run/run-isolated).
371 String dartMain(String sourceName, String action, bool filter) {
372 return """
373 main() {
374 unittest.groupSep = '###';
375 unittest.configure(new TestRunnerConfiguration());
376 unittest.group('', test.main);
377 ${filter?'unittest.filterTests(filterTest);':''}
378 $action('$sourceName');
379 }
380 """;
381 }
382
383 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698