Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 completer = procId == 0 ? (new Completer()) : null; | |
| 143 var timer = null; | |
| 144 var processFuture = Process.start(command, args); | |
| 145 processFuture.then((process) { | |
| 146 | |
| 147 timer = new Timer(new Duration(seconds: timeout), () { | |
| 148 timer = null; | |
| 149 process.kill(); | |
| 150 }); | |
| 151 | |
| 152 process.exitCode.then((exitCode) { | |
| 153 if (timer != null) { | |
| 154 timer.cancel(); | |
| 155 } | |
| 156 if (completer != null) { | |
| 157 completer.complete(exitCode); | |
|
Siggi Cherem (dart-lang)
2013/04/19 21:39:39
can we get rid of using completer?
I think it sho
gram
2013/04/22 23:54:27
Done.
| |
| 158 } | |
| 159 }); | |
| 160 | |
| 161 if (raw) { | |
| 162 process.stdout.listen((c) { stdout.addAll(c); }); | |
| 163 } else { | |
| 164 _pipeStream(process.stdout, stdout, outputMonitor); | |
| 165 } | |
| 166 _pipeStream(process.stderr, stderr, outputMonitor); | |
| 167 }) | |
| 168 .catchError((e) { | |
| 169 stderr.add("#Error starting process $command: ${e.error}"); | |
| 170 }); | |
| 171 | |
| 172 return completer.future; | |
|
Siggi Cherem (dart-lang)
2013/04/19 21:39:39
wouldn't this crash when procId != 0 (since comple
gram
2013/04/22 23:54:27
Yes - but thankfully there is no completer now :-)
| |
| 173 } | |
| 174 | |
| 175 void _pipeStream(Stream stream, List<String> destination, | |
| 176 Function outputMonitor) { | |
| 177 stream | |
| 178 .transform(new StringDecoder()) | |
| 179 .transform(new LineTransformer()) | |
| 180 .listen((String line) { | |
| 181 if (outputMonitor != null) { | |
| 182 outputMonitor(line); | |
| 183 } | |
| 184 destination.add(line); | |
| 185 }); | |
| 186 } | |
| 187 | |
| 188 /** | |
| 189 * Run an external process [cmd] with command line arguments [args]. | |
| 190 * [timeout] can be used to forcefully terminate the process after | |
| 191 * some number of seconds. | |
| 192 * Returns a [Future] for when the process terminates. | |
| 193 */ | |
| 194 Future runCommand(String command, List<String> args, | |
| 195 List stdout, List stderr, | |
| 196 {int timeout: 300, Function outputMonitor, | |
| 197 bool raw: false}) { | |
| 198 return _processHelper(command, args, stdout, stderr, | |
| 199 timeout, 0, outputMonitor, raw); | |
| 200 } | |
| 201 | |
| 202 String parseLabel(String line) { | |
| 203 if (line.startsWith('CONSOLE MESSAGE')) { | |
| 204 var idx = line.indexOf('#TEST '); | |
| 205 if (idx > 0) { | |
| 206 return line.substring(idx + 6); | |
| 207 } | |
| 208 } | |
| 209 return null; | |
| 210 } | |
| 211 | |
| 127 runTextLayoutTest(testNum) { | 212 runTextLayoutTest(testNum) { |
| 128 var url = '$baseUrl?test=$testNum'; | 213 var url = '$baseUrl?test=$testNum'; |
| 129 var stdout = new List(); | 214 var stdout = new List(); |
| 215 var stderr = new List(); | |
| 130 start = new DateTime.now(); | 216 start = new DateTime.now(); |
| 131 Process.start(drt, [url]).then((process) { | 217 runCommand(drt, [url], stdout, stderr).then((e) { |
| 132 // Drain stderr to not leak resources. | 218 if (stdout.length > 0 && stdout[stdout.length-1].startsWith('#EOF')) { |
| 133 process.stderr.onData = process.stderr.read; | 219 stdout.removeLast(); |
| 134 StringInputStream stdoutStringStream = | 220 } |
| 135 new StringInputStream(process.stdout); | 221 var done = false; |
| 136 stdoutStringStream.onLine = () { | 222 var i = 0; |
| 137 if (stdoutStringStream.closed) return; | 223 var label = null; |
| 138 var line = stdoutStringStream.readLine(); | 224 var contentMarker = 'layer at '; |
| 139 while (null != line) { | 225 while (i < stdout.length) { |
| 140 stdout.add(line); | 226 if (label == null && (label = parseLabel(stdout[i])) != null) { |
| 141 line = stdoutStringStream.readLine(); | 227 if (label == 'NONEXISTENT') { |
| 142 } | 228 complete(); |
| 143 }; | 229 return; |
| 144 process.onExit = (exitCode) { | 230 } |
| 145 process.close(); | 231 } else if (stdout[i].startsWith(contentMarker)) { |
| 146 if (stdout.length > 0 && stdout[stdout.length-1].startsWith('#EOF')) { | 232 if (label == null) { |
| 147 stdout.removeLast(); | 233 complete(); |
| 148 } | 234 return; |
| 149 var done = false; | 235 } |
| 150 var i = 0; | 236 var expectedFileName = |
| 151 var label = null; | 237 '$sourceDir${Platform.pathSeparator}' |
| 152 var labelMarker = 'CONSOLE MESSAGE: #TEST '; | 238 '${label.replaceAll("###", "_") |
| 153 var contentMarker = 'layer at '; | 239 .replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.txt'; |
| 154 while (i < stdout.length) { | 240 var expected = new File(expectedFileName); |
| 155 if (label == null && stdout[i].startsWith(labelMarker)) { | 241 if (regenerate) { |
| 156 label = stdout[i].substring(labelMarker.length); | 242 var osink = expected.openWrite(); |
| 157 if (label == 'NONEXISTENT') { | 243 while (i < stdout.length) { |
| 158 complete(); | 244 osink.write(stdout[i]); |
| 159 } | 245 osink.write('\n'); |
| 160 } else if (stdout[i].startsWith(contentMarker)) { | 246 i++; |
| 161 if (label == null) { | 247 } |
| 162 complete(); | 248 osink.close(); |
| 163 } | 249 pass(start, label); |
| 164 var expectedFileName = | 250 } else if (!expected.existsSync()) { |
| 165 '$sourceDir${Platform.pathSeparator}' | 251 fail(start, label, 'No expectation file'); |
| 166 '${label.replaceAll("###", "_") | 252 } else { |
| 167 .replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.txt'; | 253 var lines = expected.readAsLinesSync(); |
| 168 var expected = new File(expectedFileName); | 254 var actualLength = stdout.length - i; |
| 169 if (regenerate) { | 255 var compareCount = min(lines.length, actualLength); |
| 170 var ostream = expected.openOutputStream(FileMode.WRITE); | 256 var match = true; |
| 171 while (i < stdout.length) { | 257 for (var j = 0; j < compareCount; j++) { |
| 172 ostream.writeString(stdout[i]); | 258 if (lines[j] != stdout[i + j]) { |
| 173 ostream.writeString('\n'); | 259 fail(start, label, 'Expectation differs at line ${j + 1}'); |
| 174 i++; | 260 match = false; |
| 261 break; | |
| 175 } | 262 } |
| 176 ostream.close(); | 263 } |
| 177 pass(start, label); | 264 if (match) { |
| 178 } else if (!expected.existsSync()) { | 265 if (lines.length != actualLength) { |
| 179 fail(start, label, 'No expectation file'); | 266 fail(start, label, 'Expectation file has wrong length'); |
| 267 } else { | |
| 268 pass(start, label); | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 done = true; | |
| 273 break; | |
| 274 } | |
| 275 i++; | |
| 276 } | |
| 277 if (label != null) { | |
| 278 if (!done) error(start, label, 'Failed to parse output'); | |
| 279 runTextLayoutTest(testNum + 1); | |
| 280 } | |
| 281 }); | |
| 282 } | |
| 283 | |
| 284 runPixelLayoutTest(int testNum) { | |
| 285 var url = '$baseUrl?test=$testNum'; | |
| 286 var stdout = new List(); | |
| 287 var stderr = new List(); | |
| 288 start = new DateTime.now(); | |
| 289 runCommand(drt, ["$url'-p"], stdout, stderr, raw:true).then((exitCode) { | |
| 290 var contentMarker = 'Content-Length: '; | |
| 291 var eol = '\n'.codeUnitAt(0); | |
| 292 var pos = 0; | |
| 293 var label = null; | |
| 294 var done = false; | |
| 295 | |
| 296 while(pos < stdout.length) { | |
| 297 StringBuffer sb = new StringBuffer(); | |
| 298 while (pos < stdout.length && stdout[pos] != eol) { | |
| 299 sb.writeCharCode(stdout[pos++]); | |
| 300 } | |
| 301 if (++pos >= stdout.length && line == '') break; | |
| 302 var line = sb.toString(); | |
| 303 | |
| 304 if (label == null && (label = parseLabel(line)) != null) { | |
| 305 if (label == 'NONEXISTENT') { | |
| 306 complete(); | |
| 307 } | |
| 308 } else if (line.startsWith(contentMarker)) { | |
| 309 if (label == null) { | |
| 310 complete(); | |
| 311 } | |
| 312 var len = int.parse(line.substring(contentMarker.length)); | |
| 313 var expectedFileName = | |
| 314 '$sourceDir${Platform.pathSeparator}' | |
| 315 '${label.replaceAll("###","_"). | |
| 316 replaceAll(new RegExp("[^A-Za-z0-9]"),"_")}.png'; | |
| 317 var expected = new File(expectedFileName); | |
| 318 if (regenerate) { | |
| 319 var osink = expected.openWrite(); | |
| 320 stdout.removeRange(0, pos); | |
| 321 stdout.length = len; | |
| 322 osink.add(stdout); | |
| 323 osink.close(); | |
| 324 pass(start, label); | |
| 325 } else if (!expected.existsSync()) { | |
| 326 fail(start, label, 'No expectation file'); | |
| 327 } else { | |
| 328 var bytes = expected.readAsBytesSync(); | |
| 329 if (bytes.length != len) { | |
| 330 fail(start, label, 'Expectation file has wrong length'); | |
| 180 } else { | 331 } else { |
| 181 var lines = expected.readAsLinesSync(); | |
| 182 var actualLength = stdout.length - i; | |
| 183 var compareCount = min(lines.length, actualLength); | |
| 184 var match = true; | 332 var match = true; |
| 185 for (var j = 0; j < compareCount; j++) { | 333 for (var j = 0; j < len; j++) { |
| 186 if (lines[j] != stdout[i + j]) { | 334 if (bytes[j] != stdout[pos + j]) { |
| 187 fail(start, label, 'Expectation differs at line ${j + 1}'); | 335 fail(start, label, 'Expectation differs at byte ${j + 1}'); |
| 188 match = false; | 336 match = false; |
| 189 break; | 337 break; |
| 190 } | 338 } |
| 191 } | 339 } |
| 192 if (match) { | 340 if (match) pass(start, label); |
| 193 if (lines.length != actualLength) { | 341 } |
| 194 fail(start, label, 'Expectation file has wrong length'); | 342 } |
| 195 } else { | 343 done = true; |
| 196 pass(start, label); | 344 break; |
| 197 } | 345 } |
| 198 } | 346 } |
| 199 } | 347 if (label != null) { |
| 200 done = true; | 348 if (!done) error(start, label, 'Failed to parse output'); |
| 201 break; | 349 runPixelLayoutTest(testNum + 1); |
| 202 } | 350 } |
| 203 i++; | |
| 204 } | |
| 205 if (label != null) { | |
| 206 if (!done) error(start, label, 'Failed to parse output'); | |
| 207 runTextLayoutTest(testNum + 1); | |
| 208 } | |
| 209 }; | |
| 210 }); | 351 }); |
| 211 } | 352 } |
| 212 | 353 |
| 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() { | 354 void init() { |
| 302 // Get the name of the directory that has the expectation files | 355 // Get the name of the directory that has the expectation files |
| 303 // (by stripping .dart suffix from test file path). | 356 // (by stripping .dart suffix from test file path). |
| 304 // Create it if it does not exist. | 357 // Create it if it does not exist. |
| 305 sourceDir = testfile.substring(0, testfile.length - 5); | 358 sourceDir = testfile.substring(0, testfile.length - 5); |
| 306 if (regenerate) { | 359 if (regenerate) { |
| 307 var d = new Directory(sourceDir); | 360 var d = new Directory(sourceDir); |
| 308 if (!d.existsSync()) { | 361 if (!d.existsSync()) { |
| 309 d.createSync(); | 362 d.createSync(); |
| 310 } | 363 } |
| 311 } | 364 } |
| 312 } | 365 } |
| 313 | 366 |
| 314 void runPixelLayoutTests() { | 367 void runPixelLayoutTests() { |
| 315 init(); | 368 init(); |
| 316 runPixelLayoutTest(0); | 369 runPixelLayoutTest(0); |
| 317 } | 370 } |
| 318 | 371 |
| 319 void runTextLayoutTests() { | 372 void runTextLayoutTests() { |
| 320 init(); | 373 init(); |
| 321 runTextLayoutTest(0); | 374 runTextLayoutTest(0); |
| 322 } | 375 } |
| OLD | NEW |