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

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
6 // test Configuration customized for the options specified by the user.
7 class DartWrapTask extends PipelineTask {
8 final String _sourceFileTemplate;
9 final 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(
17 expandMacros(_sourceFileTemplate, testfile));
18 // Get the destination file.
19 var destFile = expandMacros(_tempDartFileTemplate, testfile);
20
21 // Working buffer for the Dart wrapper.
22 StringBuffer sbuf = new StringBuffer();
23
24 // Add the common header stuff.
25 var p = new Path(sourceName);
26 sbuf.add(directives(p.filenameWithoutExtension,
27 config.unittestPath,
28 sourceName));
29
30 // Add the test configuration and determine the action function.
31 var action;
32 if (config.listTests) {
33 action = 'listTests';
34 sbuf.add(barebonesConfig());
35 sbuf.add(listTestsFunction);
36 sbuf.add(formatListMessageFunction(config.listFormat));
37 } else if (config.listGroups) {
38 sbuf.add(barebonesConfig());
39 sbuf.add(listGroupsFunction);
40 sbuf.add(formatListMessageFunction(config.listFormat));
41 action = 'listGroups';
42 } else {
43
44 if (config.runInBrowser) {
45 sbuf.add(browserTestPrintFunction);
46 sbuf.add(unblockDRTFunction);
47 } else {
48 sbuf.add(nonBrowserTestPrintFunction);
49 sbuf.add(stubUnblockDRTFunction);
50 }
51
52 if (config.runIsolated) {
53 sbuf.add(runIsolateTestsFunction);
54 action = 'runIsolateTests';
55 } else {
56 sbuf.add(runTestsFunction);
57 action = 'runTests';
58 }
59
60 sbuf.add(config.includeTime ? elapsedFunction : stubElapsedFunction);
61 sbuf.add(config.produceSummary ?
62 printSummaryFunction : stubPrintSummaryFunction);
63
64 if (config.immediateOutput) {
65 sbuf.add(printResultFunction);
66 sbuf.add(stubPrintResultsFunction);
67 } else {
68 sbuf.add(stubPrintResultFunction);
69 sbuf.add(printResultsFunction);
70 }
71
72 sbuf.add(dumpTestResultFunction);
73 sbuf.add(formatMessageFunction(config.passFormat,
74 config.failFormat,
75 config.errorFormat));
76 sbuf.add(testConfig());
77 }
78
79 // Add the filter, if applicable.
80 if (config.filtering) {
81 if (config.includeFilter.length > 0) {
82 sbuf.add(filterTestFunction(config.includeFilter, 'true'));
83 } else {
84 sbuf.add(filterTestFunction(config.excludeFilter, 'false'));
85 }
86 }
87
88 // Add the common trailer stuff.
89 sbuf.add(dartMain(sourceName, action, config.filtering));
90
91 // Save the Dart file.
92 createFile(destFile, sbuf.toString());
93 exitHandler(0);
94 }
95
96 void cleanup(Path testfile, List stdout, List stderr,
97 bool verboseLogging, bool keepTestFiles) {
98 deleteFiles([ _tempDartFileTemplate ], testfile,
99 verboseLogging, keepTestFiles, stdout);
100 }
101
102 String directives(String library, String unittest, String sourceName) {
103 return """
104 #library('$library');
105 #import('dart:math');
106 #import('dart:isolate');
107 #import('$unittest', prefix:'unittest');
108 #import('$sourceName', prefix: 'test');
109 """;
110 }
111
112 // The core skeleton for a config. Most of the guts is in the
113 // parameter [body].
114 String configuration([String body = '']) {
115 return """
116 class TestRunnerConfiguration extends unittest.Configuration {
117 get name => 'Test runner configuration';
118 get autoStart => false;
119 $body
120 }
121 """;
122 }
123
124 // A barebones config, used for listing tests, not running them.
125 String barebonesConfig() {
126 return configuration();
127 }
128
129 // A more complex config, used for running tests.
130 String testConfig() {
131 return configuration("""
132 void onTestResult(TestCase testCase) {
133 printResult('\$testFile ', testCase);
134 }
135 void onDone(int passed, int failed, int errors, List<TestCase> results,
136 String uncaughtError) {
137 var success = (passed > 0 && failed == 0 && errors == 0 &&
138 uncaughtError == null);
139 printResults(testFile, results);
140 printSummary(testFile, passed, failed, errors, uncaughtError);
141 unblockDRT();
142 }
143 """);
144 }
145
146 // The main function, that creates the config, filters the tests if
147 // necessary, then performs the action (list/run/run-isolated).
148 String dartMain(String sourceName, String action, bool filter) {
149 return """
150 var testFile = '$sourceName';
151 main() {
152 unittest.groupSep = '###';
153 unittest.configure(new TestRunnerConfiguration());
154 unittest.group('', test.main);
155 ${filter?'unittest.filterTests(filterTest);':''}
156 $action();
157 }
158 """;
159 }
160
161 // For 'printing' when we are in the browser, we add text elements
162 // to a DOM element with id 'console'.
163 final String browserTestPrintFunction = """
164 #import('dart:html');
165 void tprint(msg) {
166 var pre = query('#console');
167 pre.elements.add(new Text('###\$msg\\n'));
168 }
169 """;
170
171 // For printing when not in the browser we can just use Dart's print().
172 final String nonBrowserTestPrintFunction = """
173 void tprint(msg) {
174 print('###\$msg');
175 }
176 """;
177
178 // A function to give us the elapsed time for a test.
179 final String elapsedFunction = """
180 String elapsed(TestCase t) {
181 double duration = t.runningTime.inMilliseconds;
182 duration /= 1000;
183 return '\${duration.toStringAsFixed(3)}s ';
184 }
185 """;
186
187 // A dummy version of the elapsed function for when the user
188 // doesn't want test times included.
189 final String stubElapsedFunction = """
190 String elapsed(TestCase t) {
191 return '';
192 }
193 """;
194
195 // A function to print the results of a test.
196 final String dumpTestResultFunction = """
197 void dumpTestResult(source, TestCase t) {
198 var groupName = '', testName = '';
199 var idx = t.description.lastIndexOf('###');
200 if (idx >= 0) {
201 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
202 testName = t.description.substring(idx+3);
203 } else {
204 testName = t.description;
205 }
206 var stack = (t.stackTrace == null) ? '' : '\${t.stackTrace} ';
207 var message = (t.message.length > 0) ? '\$t.message ' : '';
208 var duration = elapsed(t);
209 tprint(formatMessage(source, '\$groupName ', '\$testName ',
210 duration, t.result, message, stack));
211 }
212 """;
213
214 // A function to print the test summary.
215 final String printSummaryFunction = """
216 void printSummary(String testFile, int passed, int failed, int errors,
217 String uncaughtError) {
218 tprint('');
219 if (passed == 0 && failed == 0 && errors == 0) {
220 tprint('\$testFile: No tests found.');
221 } else if (failed == 0 && errors == 0 && uncaughtError == null) {
222 tprint('\$testFile: All \$passed tests passed.');
223 } else {
224 if (uncaughtError != null) {
225 tprint('\$testFile: Top-level uncaught error: \$uncaughtError');
226 }
227 tprint('\$testFile: \$passed PASSED, \$failed FAILED, \$errors ERRORS');
228 }
229 }
230 """;
231
232 final String stubPrintSummaryFunction = """
233 void printSummary(String testFile, int passed, int failed, int errors,
234 String uncaughtError) {
235 }
236 """;
237
238 // A function to print all test results.
239 final String printResultsFunction = """
240 void printResults(testfile, List<TestCase> results) {
241 for (final testCase in results) {
242 dumpTestResult('\$testfile ', testCase);
243 }
244 }
245 """;
246
247 final String stubPrintResultsFunction = """
248 void printResults(testfile, List<TestCase> results) {
249 }
250 """;
251
252 // A function to print a single test result.
253 final String printResultFunction = """
254 void printResult(testfile, TestCase testCase) {
255 dumpTestResult('\$testfile ', testCase);
256 }
257 """;
258
259 final String stubPrintResultFunction = """
260 void printResult(testfile, TestCase testCase) {
261 }
262 """;
263
264 final String unblockDRTFunction = """
265 void unblockDRT() {
266 window.postMessage('done', '*');
267 }
268 """;
269
270 final String stubUnblockDRTFunction = """
271 void unblockDRT() {
272 }
273 """;
274
275 // A simple format function for listing tests.
276 String formatListMessageFunction(String format) {
277 return """
278 String formatMessage(filename, groupname, [ testname = '']) {
279 return '${format}'.
280 replaceAll('${Macros.testfile}', filename).
281 replaceAll('${Macros.testGroup}', groupname).
282 replaceAll('${Macros.testDescription}', testname);
283 }
284 """;
285 }
286
287 // A richer format function for test results.
288 String formatMessageFunction(
289 String passFormat, String failFormat, String errorFormat) {
290 return """
291 String formatMessage(filename, groupname,
292 [ testname = '', testTime = '', result = '',
293 message = '', stack = '' ]) {
294 var format = '$errorFormat';
295 if (result == 'pass') format = '$passFormat';
296 else if (result == 'fail') format = '$failFormat';
297 return format.
298 replaceAll('${Macros.testTime}', testTime).
299 replaceAll('${Macros.testfile}', filename).
300 replaceAll('${Macros.testGroup}', groupname).
301 replaceAll('${Macros.testDescription}', testname).
302 replaceAll('${Macros.testMessage}', message).
303 replaceAll('${Macros.testStacktrace}', stack);
304 }
305 """;
306 }
307
308 // A function to list the test groups.
309 final String listGroupsFunction = """
310 listGroups() {
311 List tests = unittest.testCases;
312 Map groups = {};
313 for (var t in tests) {
314 var groupName, testName = '';
315 var idx = t.description.lastIndexOf('###');
316 if (idx >= 0) {
317 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
318 if (!groups.containsKey(groupName)) {
319 groups[groupName] = '';
320 }
321 }
322 }
323 for (var g in groups.getKeys()) {
324 var msg = formatMessage('\$testfile ', '\$g ');
325 print('###\$msg');
326 }
327 }
328 """;
329
330 // A function to list the tests.
331 final String listTestsFunction = """
332 listTests() {
333 List tests = unittest.testCases;
334 for (var t in tests) {
335 var groupName, testName = '';
336 var idx = t.description.lastIndexOf('###');
337 if (idx >= 0) {
338 groupName = t.description.substring(0, idx).replaceAll('###', ' ');
339 testName = t.description.substring(idx+3);
340 } else {
341 groupName = '';
342 testName = t.description;
343 }
344 var msg = formatMessage('\$testfile ', '\$groupName ', '\$testName ');
345 print('###\$msg');
346 }
347 }
348 """;
349
350 // A function to filter the tests.
351 String filterTestFunction(List filters, String filterReturnValue) {
352 StringBuffer sbuf = new StringBuffer();
353 sbuf.add('filterTest(t) {\n');
354 if (filters != null) {
355 sbuf.add(' var name = t.description.replaceAll("###", " ");\n');
356 for (var f in filters) {
357 sbuf.add(' if (name.indexOf("$f")>=0) return $filterReturnValue;\n');
358 }
359 sbuf.add(' return !$filterReturnValue;\n');
360 } else {
361 sbuf.add(' return true;\n');
362 }
363 sbuf.add('}\n');
364 return sbuf.toString();
365 }
366
367 // Code to support running single tests as master/slave in isolates.
368 final String runIsolateTestsFunction = """
369 class TestRunnerSlaveConfiguration extends unittest.Configuration {
370 get name => 'Test runner slave configuration';
371 get autoStart => false;
372
373 void onDone(int passed, int failed, int errors, List<TestCase> results,
374 String uncaughtError) {
375 slaveport.send('\${results[0].result}\\n'
376 '\${results[0].runningTime.inMilliseconds}\\n'
377 '\${results[0].message}\\n###\\n\${results[0].stackTrace}');
378 }
379 }
380
381 var slaveport;
382 runSlaveTest() {
383 port.receive((testName, sendport) {
384 slaveport = sendport;
385 unittest.configure(new TestRunnerSlaveConfiguration());
386 unittest.groupSep = '###';
387 unittest.group('', test.main);
388 unittest.filterTests(testName);
389 unittest.runTests();
390 });
391 }
392
393 var testNum;
394 var failed;
395 var errors;
396 var passed;
397
398 runMasterTest() {
399 var tests = unittest.testCases;
400 tests[testNum].startTime = new Date.now();
401 SendPort sport = spawnFunction(runSlaveTest);
402 sport.call(tests[testNum].description).then((data) {
403 var lines = data.split('\\n');
404 var result = lines[0];
405 var duration = new Duration(milliseconds: parseInt(lines[1]));
406 int idx = 2;
407 StringBuffer buf = new StringBuffer();
408 var sep = '';
409 while (lines[idx] != '###') {
410 buf.add(sep);
411 sep = '\\n';
412 buf.add(lines[idx]);
413 idx++;
414 }
415 var message = buf.toString();
416 ++idx;
417 buf.clear();
418 sep = '';
419 while (idx < lines.length) {
420 buf.add(sep);
421 sep = '\\n';
422 buf.add(lines[idx]);
423 idx++;
424 }
425 var stack = buf.toString();
426 if (result == 'pass') {
427 tests[testNum].pass();
428 ++passed;
429 } else if (result == 'fail') {
430 tests[testNum].fail(message, stack);
431 ++failed;
432 } else {
433 tests[testNum].error(message, stack);
434 ++errors;
435 }
436 tests[testNum].runningTime = duration;
437 ++testNum;
438 if (testNum < tests.length) {
439 runMasterTest();
440 } else {
441 unittest.config.onDone(passed, failed, errors,
442 unittest.testCases, null);
443 }
444 });
445 }
446
447 runIsolateTests() {
448 testNum = 0;
449 passed = failed = errors = 0;
450 runMasterTest();
451 }
452 """;
453
454 // Code for running all tests in the normal (non-isolate) way.
455 final String runTestsFunction = """
456 runTests() {
457 unittest.runTests();
458 }
459 """;
460 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698