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

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

Issue 10909240: Support for pixel layout tests. (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
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * The DartWrapTask generates a Dart wrapper for a test file, that has a 6 * The DartWrapTask generates a Dart wrapper for a test file, that has a
7 * test Configuration customized for the options specified by the user. 7 * test Configuration customized for the options specified by the user.
8 */ 8 */
9 class DartWrapTask extends PipelineTask { 9 class DartWrapTask extends PipelineTask {
10 final String _sourceFileTemplate; 10 final String _sourceFileTemplate;
11 final String _tempDartFileTemplate; 11 final String _tempDartFileTemplate;
12 12
13 DartWrapTask(this._sourceFileTemplate, this._tempDartFileTemplate); 13 DartWrapTask(this._sourceFileTemplate, this._tempDartFileTemplate);
14 14
15 void execute(Path testfile, List stdout, List stderr, bool logging, 15 void execute(Path testfile, List stdout, List stderr, bool logging,
16 Function exitHandler) { 16 Function exitHandler) {
17 // Get the source test file and canonicalize the path. 17 // Get the source test file and canonicalize the path.
18 var sourceName = makePathAbsolute( 18 var sourceName = makePathAbsolute(
19 expandMacros(_sourceFileTemplate, testfile)); 19 expandMacros(_sourceFileTemplate, testfile));
20 // Get the destination file. 20 // Get the destination file.
21 var destFile = expandMacros(_tempDartFileTemplate, testfile); 21 var destFile = expandMacros(_tempDartFileTemplate, testfile);
22 22
23 var p = new Path(sourceName); 23 var p = new Path(sourceName);
24 if (isLayoutRenderTest(sourceName) || config.generateRenders) { 24
25 makeLayoutTestWrapper(sourceName, destFile, p.filenameWithoutExtension); 25 if (config.layoutText || config.layoutPixel) {
26 exitHandler(0); 26 // Layout tests are more complicated, as we have a 'meta'
27 return; 27 // wrapped Dart program that in turn invokes DRT to run the
Siggi Cherem (dart-lang) 2012/09/14 20:01:23 we've talked about this before, but I think we sho
28 // normal wrapped Dart program, once for each test. So we generate
29 // a layout test wrapper file for the real tests and a controller
30 // wrapper to manage overall execution.
31 var childFile = '${destFile.substring(0, destFile.length-5)}-child.dart';
Siggi Cherem (dart-lang) 2012/09/14 20:01:23 style: please add spaces around operators (destFil
gram 2012/09/19 23:24:38 Done.
32 makeLayoutTestWrapper(sourceName, childFile,
33 p.filenameWithoutExtension);
34 makeLayoutTestControllerWrapper(sourceName, destFile, childFile,
35 p.filenameWithoutExtension,
36 sourceName.substring(0, sourceName.length-5)); // Strip .dart.
Siggi Cherem (dart-lang) 2012/09/14 20:01:23 ditto
gram 2012/09/19 23:24:38 Done.
37 } else {
38 makeNonLayoutTestWrapper(sourceName, destFile,
39 p.filenameWithoutExtension);
28 } 40 }
41 exitHandler(0);
42 }
43
44 void makeNonLayoutTestWrapper(String sourceName, String destFile,
45 String sourceNameWithoutExtension) {
29 46
30 // Working buffer for the Dart wrapper. 47 // Working buffer for the Dart wrapper.
31 StringBuffer sbuf = new StringBuffer(); 48 StringBuffer sbuf = new StringBuffer();
32 49
33 // Add the common header stuff. 50 // Add the common header stuff.
34 sbuf.add(directives(p.filenameWithoutExtension, 51 sbuf.add(directives(sourceNameWithoutExtension,
35 config.unittestPath, 52 config.unittestPath,
36 sourceName)); 53 sourceName));
37 54
38 // Add the test configuration and determine the action function. 55 // Add the test configuration and determine the action function.
39 var action; 56 var action;
40 if (config.listTests) { 57 if (config.listTests) {
41 action = 'listTests'; 58 action = 'listTests';
42 sbuf.add(barebonesConfig()); 59 sbuf.add(barebonesConfig());
43 sbuf.add(listTestsFunction); 60 sbuf.add(listTestsFunction);
44 sbuf.add(formatListMessageFunction(config.listFormat)); 61 sbuf.add(formatListMessageFunction(config.listFormat));
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 } else { 108 } else {
92 sbuf.add(filterTestFunction(config.excludeFilter, 'false')); 109 sbuf.add(filterTestFunction(config.excludeFilter, 'false'));
93 } 110 }
94 } 111 }
95 112
96 // Add the common trailer stuff. 113 // Add the common trailer stuff.
97 sbuf.add(dartMain(sourceName, action, config.filtering)); 114 sbuf.add(dartMain(sourceName, action, config.filtering));
98 115
99 // Save the Dart file. 116 // Save the Dart file.
100 createFile(destFile, sbuf.toString()); 117 createFile(destFile, sbuf.toString());
101 exitHandler(0);
102 } 118 }
103 119
104 void cleanup(Path testfile, List stdout, List stderr, 120 void cleanup(Path testfile, List stdout, List stderr,
105 bool logging, bool keepFiles) { 121 bool logging, bool keepFiles) {
106 deleteFiles([_tempDartFileTemplate], testfile, logging, keepFiles, stdout); 122 deleteFiles([_tempDartFileTemplate], testfile, logging, keepFiles, stdout);
107 } 123 }
108 124
109 void makeLayoutTestWrapper(String sourceName, String destFile, 125 void makeLayoutTestWrapper(String sourceName, String destFile,
110 String libraryName) { 126 String libraryName) {
111 StringBuffer sbuf = new StringBuffer(); 127 StringBuffer sbuf = new StringBuffer();
112 var cfg = config.unittestPath.
113 replaceAll('unittest.dart', 'html_layout_config.dart');
114 sbuf.add(""" 128 sbuf.add("""
115 #library('$libraryName'); 129 #library('$libraryName');
116 #import('dart:math'); 130 #import('dart:math');
117 #import('dart:isolate'); 131 #import('dart:isolate');
118 #import('dart:html'); 132 #import('dart:html');
133 #import('dart:uri');
119 #import('${config.unittestPath}', prefix:'unittest'); 134 #import('${config.unittestPath}', prefix:'unittest');
120 #import('$cfg', prefix:'unittest');
121 #import('$sourceName', prefix: 'test'); 135 #import('$sourceName', prefix: 'test');
122 """); 136 """);
137
123 // Add the filter, if applicable. 138 // Add the filter, if applicable.
124 if (config.filtering) { 139 if (config.filtering) {
125 if (config.includeFilter.length > 0) { 140 if (config.includeFilter.length > 0) {
126 sbuf.add(filterTestFunction(config.includeFilter, 'true')); 141 sbuf.add(filterTestFunction(config.includeFilter, 'true'));
127 } else { 142 } else {
128 sbuf.add(filterTestFunction(config.excludeFilter, 'false')); 143 sbuf.add(filterTestFunction(config.excludeFilter, 'false'));
129 } 144 }
130 } 145 }
131 sbuf.add(""" 146 sbuf.add("""
147
148 class LayoutTestConfiguration extends unittest.Configuration {
149 get autoStart => false;
150 void onTestResult(TestCase testCase) {
151 window.postMessage('done', '*'); // Unblock DRT
152 }
153 }
154
132 main() { 155 main() {
133 unittest.groupSep = '###'; 156 unittest.groupSep = '###';
134 unittest.useHtmlLayoutConfiguration(); 157 unittest.configure(new LayoutTestConfiguration());
135 unittest.group('', test.main); 158 // Create the set of test cases.
136 ${config.filtering ? 'unittest.filterTests(filterTest);' : ''} 159 unittest.group('', test.main);
137 if (window.location.search == '') unittest.runTests(); 160 // Do any user-specified test filtering.
161 ${config.filtering ? 'unittest.filterTests(filterTest);' : ''}
162 // Filter to the test number in the search query.
163 var testNum = parseInt(window.location.search.substring(6));
164 if (testNum < 0 || testNum >= unittest.testCases.length) {
165 print('#TEST NONEXISTENT');
166 } else {
167 var name = unittest.testCases[testNum].description;
168 print('#TEST \$name');
169 unittest.filterTests(name);
170 // Run the test.
171 unittest.runTests();
172 }
138 } 173 }
139 """); 174 """);
140 // Save the Dart file. 175 // Save the Dart file.
141 createFile(destFile, sbuf.toString()); 176 createFile(destFile, sbuf.toString());
142 } 177 }
143 178
179 void makeLayoutTestControllerWrapper(String sourceName,
180 String destName, String childName, String libraryName,
181 String expectedDirectory) {
182 if (config.regenerate) {
183 var d = new Directory(expectedDirectory);
184 if (!d.existsSync()) {
185 d.createSync();
186 }
187 }
188 StringBuffer sbuf = new StringBuffer();
189 var htmlFile = childName.replaceFirst('-child.dart', '.html');
190 // Add common prefix.
191 sbuf.add("""
Siggi Cherem (dart-lang) 2012/09/14 20:01:23 could we move a lot of this 'generated code' into
192 #library('$libraryName');
193 #import('dart:uri');
194 #import('dart:io');
195 #import('dart:math');
196
197 var label;
198
199 main() {
200 runTest(0);
201 }
202
203 var passCount = 0, failCount = 0, errorCount = 0;
204
205 outputResult(start, label, result, [message = '']) {
206 var idx = label.lastIndexOf('###');
207 var group = '', test = '';
208 if (idx >= 0) {
209 group = '\${label.substring(0, idx).replaceAll("###", " ")} ';
210 test = '\${label.substring(idx+3)} ';
211 } else {
212 test = '\$label ';
213 }
214 var elapsed = '';
215 if (${config.includeTime}) {
216 var end = new Date.now();
217 double duration = (end - start).inMilliseconds.toDouble();
218 duration /= 1000;
219 elapsed = '\${duration.toStringAsFixed(3)}s ';
220 }
221 tprint(formatMessage('$sourceName ', group, test, elapsed, result, message));
222 }
223
224 pass(start, label) {
225 ++passCount;
226 outputResult(start, label, 'pass');
227 }
228
229 fail(start, label, message) {
230 ++failCount;
231 outputResult(start, label, 'fail', message);
232 }
233
234 error(start, label, message) {
235 ++errorCount;
236 outputResult(start, label, 'error', message);
237 }
238
239 complete() {
240 printSummary('$sourceName', passCount, failCount, errorCount);
241 exit(failCount > -0 ? -1 : 0);
242 }
243
244 """);
245
246 sbuf.add(nonBrowserTestPrintFunction);
247 sbuf.add(formatMessageFunction(config.passFormat,
248 config.failFormat,
249 config.errorFormat));
250
251 sbuf.add(config.produceSummary ?
252 printSummaryFunction : stubPrintSummaryFunction);
253
254 if (config.layoutText) {
255 sbuf.add("""
256 runTest(testNum) {
257 var url = 'file://$htmlFile?test=\$testNum';
258 var stdout = new List();
259 Date start = new Date.now();
260 var process = Process.start('${config.drtPath}', [ url ]);
261 StringInputStream stdoutStringStream = new StringInputStream(process.stdout);
262 stdoutStringStream.onLine = () {
263 if (stdoutStringStream.closed) return;
264 var line = stdoutStringStream.readLine();
265 while (null != line) {
266 stdout.add(line);
267 line = stdoutStringStream.readLine();
268 }
269 };
270 process.onExit = (exitCode) {
271 process.close();
272 if (stdout.length > 0 && stdout[stdout.length-1].startsWith('#EOF')) {
273 stdout.removeLast();
274 }
275 var done = false;
276 var i = 0;
277 var label = null;
278 var labelMarker = 'CONSOLE MESSAGE: #TEST ';
279 var contentMarker = 'layer at ';
280 while (i < stdout.length) {
281 if (label == null && stdout[i].startsWith(labelMarker)) {
282 label = stdout[i].substring(labelMarker.length);
283 if (label == 'NONEXISTENT') {
284 complete();
285 }
286 } else if (stdout[i].startsWith(contentMarker)) {
287 if (label == null) {
288 complete();
289 }
290 var expectedFileName =
291 '$expectedDirectory${Platform.pathSeparator}'
292 '\${label.replaceAll("###", "_")
293 .replaceAll(const RegExp("[^A-Za-z0-9]"),"_")}.txt';
294 var expected = new File(expectedFileName);
295 if (${config.regenerate}) {
296 var ostream = expected.openOutputStream(FileMode.WRITE);
297 while (i < stdout.length) {
298 ostream.writeString(stdout[i]);
299 ostream.writeString('\\n');
300 i++;
301 }
302 ostream.close();
303 pass(start, label);
304 } else {
305 if (!expected.existsSync()) {
306 fail(start, label, 'No expectation file');
307 } else {
308 var lines = expected.readAsLinesSync();
309 if (lines.length != stdout.length - i) {
310 fail(start, label, 'Expectation file has wrong length');
311 } else {
312 var match = true;
313 for (var j = 0; j < lines.length; j++) {
314 if (lines[j] != stdout[i+j]) {
315 fail(start, label, 'Expectation differs at line \${j+1}');
316 match = false;
317 break;
318 }
319 }
320 if (match) pass(start, label);
321 }
322 }
323 }
324 done = true;
325 break;
326 }
327 i++;
328 }
329 if (label != null) {
330 if (!done) error(start, label, 'Failed to parse output');
331 runTest(testNum+1);
332 }
333 };
334 }
335 """);
336 } else {
337 sbuf.add("""
338 runTest(testNum) {
339 var url = 'file://$htmlFile?test=\$testNum';
340 var stdout = new List();
341 Date start = new Date.now();
342 var process = Process.start('${config.drtPath}', [ "\$url'-p" ]);
343 ListInputStream stdoutStream = process.stdout;
344 stdoutStream.onData = () {
345 if (!stdoutStream.closed) {
346 var data = stdoutStream.read();
347 stdout.addAll(data);
348 }
349 };
350 stdoutStream.onError = (e) {
351 print(e);
352 };
353 process.onExit = (exitCode) {
354 stdout.addAll(process.stdout.read());
355 process.close();
356 var labelMarker = 'CONSOLE MESSAGE: #TEST ';
357 var contentMarker = 'Content-Length: ';
358 var eol = '\\n'.charCodeAt(0);
359 var pos = -1;
360 var label = null;
361 var done = false;
362
363 while(pos < stdout.length) {
364 var idx = stdout.indexOf(eol, ++pos);
365 if (idx < 0) break;
366 StringBuffer sb = new StringBuffer();
367 for (var i = pos; i < idx; i++) {
368 sb.addCharCode(stdout[i]);
369 }
370 var line = sb.toString();
371
372 if (label == null && line.startsWith(labelMarker)) {
373 label = line.substring(labelMarker.length);
374 if (label == 'NONEXISTENT') {
375 complete();
376 }
377 } else if (line.startsWith(contentMarker)) {
378 if (label == null) {
379 complete();
380 }
381 var len = parseInt(line.substring(contentMarker.length));
382 pos = idx+1;
383 var expectedFileName =
384 '$expectedDirectory${Platform.pathSeparator}'
385 '\${label.replaceAll("###","_").
386 replaceAll(const RegExp("[^A-Za-z0-9]"),"_")}.png';
387 var expected = new File(expectedFileName);
388 if (${config.regenerate}) {
389 var ostream = expected.openOutputStream(FileMode.WRITE);
390 ostream.writeFrom(stdout, pos, len);
391 ostream.close();
392 pass(start, label);
393 } else {
394 if (!expected.existsSync()) {
395 fail(start, label, 'No expectation file');
396 } else {
397 var bytes = expected.readAsBytesSync();
398 if (bytes.length != len) {
399 fail(start, label, 'Expectation file has wrong length');
400 } else {
401 var match = true;
402 for (var j = 0; j < len; j++) {
403 if (bytes[j] != stdout[pos+j]) {
404 fail(start, label, 'Expectation differs at byte \${j+1}');
405 match = false;
406 break;
407 }
408 }
409 if (match) pass(start, label);
410 }
411 }
412 }
413 done = true;
414 break;
415 }
416 pos = idx;
417 }
418 if (label != null) {
419 if (!done) error(start, label, 'Failed to parse output');
420 runTest(testNum+1);
421 }
422 };
423 }
424 """);
425 }
426 createFile(destName, sbuf.toString());
427 }
428
144 String directives(String library, String unittest, String sourceName) { 429 String directives(String library, String unittest, String sourceName) {
145 return """ 430 return """
146 #library('$library'); 431 #library('$library');
147 #import('dart:math'); 432 #import('dart:math');
148 #import('dart:isolate'); 433 #import('dart:isolate');
149 #import('$unittest', prefix:'unittest'); 434 #import('$unittest', prefix:'unittest');
150 #import('$sourceName', prefix: 'test'); 435 #import('$sourceName', prefix: 'test');
151 """; 436 """;
152 } 437 }
153 438
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 var message = (t.message.length > 0) ? '\$t.message ' : ''; 536 var message = (t.message.length > 0) ? '\$t.message ' : '';
252 var duration = elapsed(t); 537 var duration = elapsed(t);
253 tprint(formatMessage(source, '\$groupName ', '\$testName ', 538 tprint(formatMessage(source, '\$groupName ', '\$testName ',
254 duration, t.result, message, stack)); 539 duration, t.result, message, stack));
255 } 540 }
256 """; 541 """;
257 542
258 // A function to print the test summary. 543 // A function to print the test summary.
259 final String printSummaryFunction = """ 544 final String printSummaryFunction = """
260 void printSummary(String testFile, int passed, int failed, int errors, 545 void printSummary(String testFile, int passed, int failed, int errors,
261 String uncaughtError) { 546 [String uncaughtError = '']) {
262 tprint(''); 547 tprint('');
263 if (passed == 0 && failed == 0 && errors == 0) { 548 if (passed == 0 && failed == 0 && errors == 0) {
264 tprint('\$testFile: No tests found.'); 549 tprint('\$testFile: No tests found.');
265 } else if (failed == 0 && errors == 0 && uncaughtError == null) { 550 } else if (failed == 0 && errors == 0 && uncaughtError == null) {
266 tprint('\$testFile: All \$passed tests passed.'); 551 tprint('\$testFile: All \$passed tests passed.');
267 } else { 552 } else {
268 if (uncaughtError != null) { 553 if (uncaughtError != null) {
269 tprint('\$testFile: Top-level uncaught error: \$uncaughtError'); 554 tprint('\$testFile: Top-level uncaught error: \$uncaughtError');
270 } 555 }
271 tprint('\$testFile: \$passed PASSED, \$failed FAILED, \$errors ERRORS'); 556 tprint('\$testFile: \$passed PASSED, \$failed FAILED, \$errors ERRORS');
272 } 557 }
273 } 558 }
274 """; 559 """;
275 560
276 final String stubPrintSummaryFunction = """ 561 final String stubPrintSummaryFunction = """
277 void printSummary(String testFile, int passed, int failed, int errors, 562 void printSummary(String testFile, int passed, int failed, int errors,
278 String uncaughtError) { 563 [String uncaughtError = '']) {
279 } 564 }
280 """; 565 """;
281 566
282 // A function to print all test results. 567 // A function to print all test results.
283 final String printAllTestResultsFunction = """ 568 final String printAllTestResultsFunction = """
284 void printResults(testfile, List<unittest.TestCase> results) { 569 void printResults(testfile, List<unittest.TestCase> results) {
285 for (final testCase in results) { 570 for (final testCase in results) {
286 dumpTestResult('\$testfile ', testCase); 571 dumpTestResult('\$testfile ', testCase);
287 } 572 }
288 } 573 }
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 """; 762 """;
478 763
479 // Code for running all tests in the normal (non-isolate) way. 764 // Code for running all tests in the normal (non-isolate) way.
480 final String runTestsFunction = """ 765 final String runTestsFunction = """
481 runTests() { 766 runTests() {
482 unittest.runTests(); 767 unittest.runTests();
483 } 768 }
484 """; 769 """;
485 770
486 } 771 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698