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

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

Issue 14247033: Updated testrunner: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 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
« no previous file with comments | « utils/testrunner/http_server.dart ('k') | utils/testrunner/layout_test_runner.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // The following set of variables should be set by the caller that 5 // The following set of variables should be set by the caller that
6 // #sources this file. 6 // #sources this file.
7 /** Whether to include elapsed time. */ 7 /** Whether to include elapsed time. */
8 8
9 part of test_controller; 9 part of test_controller;
10 10
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 } 117 }
118 } 118 }
119 119
120 complete() { 120 complete() {
121 if (summarize) { 121 if (summarize) {
122 printSummary(testfile, passCount, failCount, errorCount); 122 printSummary(testfile, passCount, failCount, errorCount);
123 } 123 }
124 notifyDone(failCount > 0 ? -1 : 0); 124 notifyDone(failCount > 0 ? -1 : 0);
125 } 125 }
126 126
127 /*
128 * Run an external process [cmd] with command line arguments [args].
129 * [timeout] can be used to forcefully terminate the process after
130 * some number of seconds. This is used by runCommand and startProcess.
131 * If [procId] is non-zero (i.e. called from startProcess) then a reference
132 * to the [Process] will be put in a map with key [procId]; in this case
133 * the process can be terminated later by calling [stopProcess] and
134 * passing in the [procId].
135 * [outputMonitor] is an optional function that will be called back with each
136 * line of output from the process.
137 * Returns a [Future] for when the process terminates.
138 */
139 Future _processHelper(String command, List<String> args,
140 List stdout, List stderr,
141 int timeout, int procId, Function outputMonitor, bool raw) {
142 var timer = null;
143 return Process.start(command, args).then((process) {
144
145 timer = new Timer(new Duration(seconds: timeout), () {
146 timer = null;
147 process.kill();
148 });
149
150 if (raw) {
151 process.stdout.listen((c) { stdout.addAll(c); });
152 } else {
153 _pipeStream(process.stdout, stdout, outputMonitor);
154 }
155 _pipeStream(process.stderr, stderr, outputMonitor);
156 return process.exitCode;
157 }).then((exitCode) {
158 if (timer != null) {
159 timer.cancel();
160 }
161 return exitCode;
162 })
163 .catchError((e) {
164 stderr.add("#Error starting process $command: ${e.error}");
165 });
166 }
167
168 void _pipeStream(Stream stream, List<String> destination,
169 Function outputMonitor) {
170 stream
171 .transform(new StringDecoder())
172 .transform(new LineTransformer())
173 .listen((String line) {
174 if (outputMonitor != null) {
175 outputMonitor(line);
176 }
177 destination.add(line);
178 });
179 }
180
181 /**
182 * Run an external process [cmd] with command line arguments [args].
183 * [timeout] can be used to forcefully terminate the process after
184 * some number of seconds.
185 * Returns a [Future] for when the process terminates.
186 */
187 Future runCommand(String command, List<String> args,
188 List stdout, List stderr,
189 {int timeout: 300, Function outputMonitor,
190 bool raw: false}) {
191 return _processHelper(command, args, stdout, stderr,
192 timeout, 0, outputMonitor, raw);
193 }
194
195 String parseLabel(String line) {
196 if (line.startsWith('CONSOLE MESSAGE')) {
197 var idx = line.indexOf('#TEST ');
198 if (idx > 0) {
199 return line.substring(idx + 6);
200 }
201 }
202 return null;
203 }
204
127 runTextLayoutTest(testNum) { 205 runTextLayoutTest(testNum) {
128 var url = '$baseUrl?test=$testNum'; 206 var url = '$baseUrl?test=$testNum';
129 var stdout = new List(); 207 var stdout = new List();
208 var stderr = new List();
130 start = new DateTime.now(); 209 start = new DateTime.now();
131 Process.start(drt, [url]).then((process) { 210 runCommand(drt, [url], stdout, stderr).then((e) {
132 // Drain stderr to not leak resources. 211 if (stdout.length > 0 && stdout[stdout.length-1].startsWith('#EOF')) {
133 process.stderr.onData = process.stderr.read; 212 stdout.removeLast();
134 StringInputStream stdoutStringStream = 213 }
135 new StringInputStream(process.stdout); 214 var done = false;
136 stdoutStringStream.onLine = () { 215 var i = 0;
137 if (stdoutStringStream.closed) return; 216 var label = null;
138 var line = stdoutStringStream.readLine(); 217 var contentMarker = 'layer at ';
139 while (null != line) { 218 while (i < stdout.length) {
140 stdout.add(line); 219 if (label == null && (label = parseLabel(stdout[i])) != null) {
141 line = stdoutStringStream.readLine(); 220 if (label == 'NONEXISTENT') {
221 complete();
222 return;
223 }
224 } else if (stdout[i].startsWith(contentMarker)) {
225 if (label == null) {
226 complete();
227 return;
228 }
229 var expectedFileName =
230 '$sourceDir${Platform.pathSeparator}'
231 '${label.replaceAll("###", "_")
232 .replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.txt';
233 var expected = new File(expectedFileName);
234 if (regenerate) {
235 var osink = expected.openWrite();
236 while (i < stdout.length) {
237 osink.write(stdout[i]);
238 osink.write('\n');
239 i++;
240 }
241 osink.close();
242 pass(start, label);
243 } else if (!expected.existsSync()) {
244 fail(start, label, 'No expectation file');
245 } else {
246 var lines = expected.readAsLinesSync();
247 var actualLength = stdout.length - i;
248 var compareCount = min(lines.length, actualLength);
249 var match = true;
250 for (var j = 0; j < compareCount; j++) {
251 if (lines[j] != stdout[i + j]) {
252 fail(start, label, 'Expectation differs at line ${j + 1}');
253 match = false;
254 break;
255 }
256 }
257 if (match) {
258 if (lines.length != actualLength) {
259 fail(start, label, 'Expectation file has wrong length');
260 } else {
261 pass(start, label);
262 }
263 }
264 }
265 done = true;
266 break;
142 } 267 }
143 }; 268 i++;
144 process.onExit = (exitCode) { 269 }
145 process.close(); 270 if (label != null) {
146 if (stdout.length > 0 && stdout[stdout.length-1].startsWith('#EOF')) { 271 if (!done) error(start, label, 'Failed to parse output');
147 stdout.removeLast(); 272 runTextLayoutTest(testNum + 1);
273 }
274 });
275 }
276
277 runPixelLayoutTest(int testNum) {
278 var url = '$baseUrl?test=$testNum';
279 var stdout = new List();
280 var stderr = new List();
281 start = new DateTime.now();
282 runCommand(drt, ["$url'-p"], stdout, stderr, raw:true).then((exitCode) {
283 var contentMarker = 'Content-Length: ';
284 var eol = '\n'.codeUnitAt(0);
285 var pos = 0;
286 var label = null;
287 var done = false;
288
289 while(pos < stdout.length) {
290 StringBuffer sb = new StringBuffer();
291 while (pos < stdout.length && stdout[pos] != eol) {
292 sb.writeCharCode(stdout[pos++]);
148 } 293 }
149 var done = false; 294 if (++pos >= stdout.length && line == '') break;
150 var i = 0; 295 var line = sb.toString();
151 var label = null; 296
152 var labelMarker = 'CONSOLE MESSAGE: #TEST '; 297 if (label == null && (label = parseLabel(line)) != null) {
153 var contentMarker = 'layer at '; 298 if (label == 'NONEXISTENT') {
154 while (i < stdout.length) { 299 complete();
155 if (label == null && stdout[i].startsWith(labelMarker)) { 300 }
156 label = stdout[i].substring(labelMarker.length); 301 } else if (line.startsWith(contentMarker)) {
157 if (label == 'NONEXISTENT') { 302 if (label == null) {
158 complete(); 303 complete();
159 } 304 }
160 } else if (stdout[i].startsWith(contentMarker)) { 305 var len = int.parse(line.substring(contentMarker.length));
161 if (label == null) { 306 var expectedFileName =
162 complete(); 307 '$sourceDir${Platform.pathSeparator}'
163 } 308 '${label.replaceAll("###","_").
164 var expectedFileName = 309 replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.png';
165 '$sourceDir${Platform.pathSeparator}' 310 var expected = new File(expectedFileName);
166 '${label.replaceAll("###", "_") 311 if (regenerate) {
167 .replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.txt'; 312 var osink = expected.openWrite();
168 var expected = new File(expectedFileName); 313 stdout.removeRange(0, pos);
169 if (regenerate) { 314 stdout.length = len;
170 var ostream = expected.openOutputStream(FileMode.WRITE); 315 osink.add(stdout);
171 while (i < stdout.length) { 316 osink.close();
172 ostream.writeString(stdout[i]); 317 pass(start, label);
173 ostream.writeString('\n'); 318 } else if (!expected.existsSync()) {
174 i++; 319 fail(start, label, 'No expectation file');
175 } 320 } else {
176 ostream.close(); 321 var bytes = expected.readAsBytesSync();
177 pass(start, label); 322 if (bytes.length != len) {
178 } else if (!expected.existsSync()) { 323 fail(start, label, 'Expectation file has wrong length');
179 fail(start, label, 'No expectation file');
180 } else { 324 } else {
181 var lines = expected.readAsLinesSync();
182 var actualLength = stdout.length - i;
183 var compareCount = min(lines.length, actualLength);
184 var match = true; 325 var match = true;
185 for (var j = 0; j < compareCount; j++) { 326 for (var j = 0; j < len; j++) {
186 if (lines[j] != stdout[i + j]) { 327 if (bytes[j] != stdout[pos + j]) {
187 fail(start, label, 'Expectation differs at line ${j + 1}'); 328 fail(start, label, 'Expectation differs at byte ${j + 1}');
188 match = false; 329 match = false;
189 break; 330 break;
190 } 331 }
191 } 332 }
192 if (match) { 333 if (match) pass(start, label);
193 if (lines.length != actualLength) { 334 }
194 fail(start, label, 'Expectation file has wrong length'); 335 }
195 } else { 336 done = true;
196 pass(start, label); 337 break;
197 }
198 }
199 }
200 done = true;
201 break;
202 }
203 i++;
204 } 338 }
205 if (label != null) { 339 }
206 if (!done) error(start, label, 'Failed to parse output'); 340 if (label != null) {
207 runTextLayoutTest(testNum + 1); 341 if (!done) error(start, label, 'Failed to parse output');
208 } 342 runPixelLayoutTest(testNum + 1);
209 }; 343 }
210 }); 344 });
211 } 345 }
212 346
213 runPixelLayoutTest(int testNum) {
214 var url = '$baseUrl?test=$testNum';
215 var stdout = new List();
216 start = new DateTime.now();
217 Process.start(drt, ["$url'-p"]).then((process) {
218 // Drain stderr to not leak resources.
219 process.stderr.onData = process.stderr.read;
220 ListInputStream stdoutStream = process.stdout;
221 stdoutStream.onData = () {
222 if (!stdoutStream.closed) {
223 var data = stdoutStream.read();
224 stdout.addAll(data);
225 }
226 };
227 stdoutStream.onError = (e) {
228 print(e);
229 };
230 process.onExit = (exitCode) {
231 stdout.addAll(process.stdout.read());
232 process.close();
233 var labelMarker = 'CONSOLE MESSAGE: #TEST ';
234 var contentMarker = 'Content-Length: ';
235 var eol = '\n'.codeUnitAt(0);
236 var pos = -1;
237 var label = null;
238 var done = false;
239
240 while(pos < stdout.length) {
241 var idx = stdout.indexOf(eol, ++pos);
242 if (idx < 0) break;
243 StringBuffer sb = new StringBuffer();
244 for (var i = pos; i < idx; i++) {
245 sb.writeCharCode(stdout[i]);
246 }
247 var line = sb.toString();
248
249 if (label == null && line.startsWith(labelMarker)) {
250 label = line.substring(labelMarker.length);
251 if (label == 'NONEXISTENT') {
252 complete();
253 }
254 } else if (line.startsWith(contentMarker)) {
255 if (label == null) {
256 complete();
257 }
258 var len = int.parse(line.substring(contentMarker.length));
259 pos = idx + 1;
260 var expectedFileName =
261 '$sourceDir${Platform.pathSeparator}'
262 '${label.replaceAll("###","_").
263 replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.png';
264 var expected = new File(expectedFileName);
265 if (regenerate) {
266 var ostream = expected.openOutputStream(FileMode.WRITE);
267 ostream.writeFrom(stdout, pos, len);
268 ostream.close();
269 pass(start, label);
270 } else if (!expected.existsSync()) {
271 fail(start, label, 'No expectation file');
272 } else {
273 var bytes = expected.readAsBytesSync();
274 if (bytes.length != len) {
275 fail(start, label, 'Expectation file has wrong length');
276 } else {
277 var match = true;
278 for (var j = 0; j < len; j++) {
279 if (bytes[j] != stdout[pos + j]) {
280 fail(start, label, 'Expectation differs at byte ${j + 1}');
281 match = false;
282 break;
283 }
284 }
285 if (match) pass(start, label);
286 }
287 }
288 done = true;
289 break;
290 }
291 pos = idx;
292 }
293 if (label != null) {
294 if (!done) error(start, label, 'Failed to parse output');
295 runPixelLayoutTest(testNum + 1);
296 }
297 };
298 });
299 }
300
301 void init() { 347 void init() {
302 // Get the name of the directory that has the expectation files 348 // Get the name of the directory that has the expectation files
303 // (by stripping .dart suffix from test file path). 349 // (by stripping .dart suffix from test file path).
304 // Create it if it does not exist. 350 // Create it if it does not exist.
305 sourceDir = testfile.substring(0, testfile.length - 5); 351 sourceDir = testfile.substring(0, testfile.length - 5);
306 if (regenerate) { 352 if (regenerate) {
307 var d = new Directory(sourceDir); 353 var d = new Directory(sourceDir);
308 if (!d.existsSync()) { 354 if (!d.existsSync()) {
309 d.createSync(); 355 d.createSync();
310 } 356 }
311 } 357 }
312 } 358 }
313 359
314 void runPixelLayoutTests() { 360 void runPixelLayoutTests() {
315 init(); 361 init();
316 runPixelLayoutTest(0); 362 runPixelLayoutTest(0);
317 } 363 }
318 364
319 void runTextLayoutTests() { 365 void runTextLayoutTests() {
320 init(); 366 init();
321 runTextLayoutTest(0); 367 runTextLayoutTest(0);
322 } 368 }
OLDNEW
« no previous file with comments | « utils/testrunner/http_server.dart ('k') | utils/testrunner/layout_test_runner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698