| OLD | NEW |
| 1 //#!/usr/bin/env dart | 1 //#!/usr/bin/env dart |
| 2 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 /** | 6 /** |
| 7 * testrunner is a program to run Dart unit tests. Unlike $DART/tools/test.dart, | 7 * testrunner is a program to run Dart unit tests. Unlike $DART/tools/test.dart, |
| 8 * this program is intended for 3rd parties to be able to run unit tests in | 8 * this program is intended for 3rd parties to be able to run unit tests in |
| 9 * a batched fashion. As such, it adds some features and removes others. Some | 9 * a batched fashion. As such, it adds some features and removes others. Some |
| 10 * of the removed features are: | 10 * of the removed features are: |
| 11 * | 11 * |
| 12 * - No support for test.status files. The assumption is that tests are | 12 * - No support for test.status files. The assumption is that tests are |
| 13 * expected to pass. | 13 * expected to pass. Status file support will be added in the future. |
| 14 * - A restricted set of runtimes. The assumption here is that the Dart | 14 * - A restricted set of runtimes. The assumption here is that the Dart |
| 15 * libraries deal with platform dependencies, and so the primary | 15 * libraries deal with platform dependencies, and so the primary |
| 16 * SKUs that a user of this app would be concerned with would be | 16 * SKUs that a user of this app would be concerned with would be |
| 17 * Dart-native versus compiled, and client (browser) vs server. To | 17 * Dart-native versus compiled, and client (browser) vs server. To |
| 18 * support these, three runtimes are allowed: 'drt-dart' and 'drt-js' (for | 18 * support these, three runtimes are allowed: 'drt-dart' and 'drt-js' (for |
| 19 * client native and client-compiled, respectively), and 'vm' | 19 * client native and client-compiled, respectively), and 'vm' |
| 20 * (for server-side native). | 20 * (for server-side native). |
| 21 * - No sharding of test processes. | 21 * - No sharding of test processes. |
| 22 * | 22 * |
| 23 * On the other hand, a number of features have been added: | 23 * On the other hand, a number of features have been added: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 36 * | 36 * |
| 37 * Options can be specified on the command line, via a configuration | 37 * Options can be specified on the command line, via a configuration |
| 38 * file (`--config`) or via a test.config file in the test directory, | 38 * file (`--config`) or via a test.config file in the test directory, |
| 39 * in decreasing order of priority. | 39 * in decreasing order of priority. |
| 40 * | 40 * |
| 41 * The three runtimes are: | 41 * The three runtimes are: |
| 42 * | 42 * |
| 43 * vm - run native Dart in the VM; i.e. using $DARTSDK/dart-sdk/bin/dart. | 43 * vm - run native Dart in the VM; i.e. using $DARTSDK/dart-sdk/bin/dart. |
| 44 * drt-dart - run native Dart in DumpRenderTree, the headless version of | 44 * drt-dart - run native Dart in DumpRenderTree, the headless version of |
| 45 * Dartium, which is located in $DARTSDK/chromium/DumpRenderTree, if | 45 * Dartium, which is located in $DARTSDK/chromium/DumpRenderTree, if |
| 46 * you intsalled the SDK that is bundled with the editor, or available | 46 * you installed the SDK that is bundled with the editor, or available |
| 47 * from http://gsdview.appspot.com/dartium-archive/continuous/ | 47 * from http://gsdview.appspot.com/dartium-archive/continuous/ |
| 48 * otherwise. | 48 * otherwise. |
| 49 * | 49 * |
| 50 * drt-js - run Dart compiled to Javascript in DumpRenderTree. | 50 * drt-js - run Dart compiled to Javascript in DumpRenderTree. |
| 51 * | 51 * |
| 52 * testrunner supports simple DOM render tests. These can use expected values | 52 * testrunner supports simple DOM render tests. These can use expected values |
| 53 * for the render output from DumpRenderTree, either are textual DOM | 53 * for the render output from DumpRenderTree, either are textual DOM |
| 54 * descriptions (`--layout-tests`) or pixel renderings (`--pixel-tests`). | 54 * descriptions (`--layout-tests`) or pixel renderings (`--pixel-tests`). |
| 55 * When running layout tests, testrunner will see if there is a file with | 55 * When running layout tests, testrunner will see if there is a file with |
| 56 * a .png or a .txt extension in a directory with the same name as the | 56 * a .png or a .txt extension in a directory with the same name as the |
| 57 * test file (without extension) and with the test name as the file name. | 57 * test file (without extension) and with the test name as the file name. |
| 58 * For example, if there is a test file foo_test.dart with tests 'test1' | 58 * For example, if there is a test file foo_test.dart with tests 'test1' |
| 59 * and 'test2', it will look for foo_test/test1.txt and foo_test/test2.txt | 59 * and 'test2', it will look for foo_test/test1.txt and foo_test/test2.txt |
| 60 * for text render layout files. If these exist it will do additional checks | 60 * for text render layout files. If these exist it will do additional checks |
| 61 * of the rendered layout; if not, the test will fail. | 61 * of the rendered layout; if not, the test will fail. |
| 62 * | 62 * |
| 63 * Layout file (re)generation can be done using `--regenerate`. This will | 63 * Layout file (re)generation can be done using `--regenerate`. This will |
| 64 * create or update the layout files (and implicitly pass the tests). | 64 * create or update the layout files (and implicitly pass the tests). |
| 65 * | 65 * |
| 66 * The wrapping and execution of test files is handled by test_pipeline.dart, | 66 * The wrapping and execution of test files is handled by test_pipeline.dart, |
| 67 * which is run in an isolate. The `--pipeline` argument can be used to | 67 * which is run in an isolate. The `--pipeline` argument can be used to |
| 68 * specify a different script for running a test file pipeline, allowing | 68 * specify a different script for running a test file pipeline, allowing |
| 69 * customization of the pipeline. | 69 * customization of the pipeline. |
| 70 * |
| 71 * Wrapper files are created for tests in the tmp directory, which can be |
| 72 * overridden with --tempdir. These files are not removed after the tests |
| 73 * are complete, primarily to reduce the amount of times pub must be |
| 74 * executed. You can use --clean-files to force file cleanup. The temp |
| 75 * directories will have pubspec.yaml files auto-generated unless the |
| 76 * original test file directories have such files; in that case the existing |
| 77 * files will be copied. Whenever a new pubspec file is copied or |
| 78 * created pub will be run (but not otherwise - so if you want to do |
| 79 * the equivelent of pub update you should use --clean-files and the rerun |
| 80 * the tests). |
| 81 * |
| 82 * TODO(gram): if the user has a pubspec.yaml file, we should inspect the |
| 83 * pubspec.lock file and give useful errors: |
| 84 * - if the lock file doesn't exit, then run pub install |
| 85 * - if it exists and it doesn't have the required packages (unittest or |
| 86 * browser), ask the user to add them and run pub install again. |
| 70 */ | 87 */ |
| 71 | 88 |
| 72 // TODO - layout tests that use PNGs rather than DRT text render dumps. | |
| 73 library testrunner; | 89 library testrunner; |
| 90 import 'dart:async'; |
| 74 import 'dart:io'; | 91 import 'dart:io'; |
| 75 import 'dart:isolate'; | 92 import 'dart:isolate'; |
| 76 import 'dart:math'; | 93 import 'dart:math'; |
| 77 import 'package:args/args.dart'; | 94 import 'package:args/args.dart'; |
| 78 | 95 |
| 79 part 'options.dart'; | 96 part 'options.dart'; |
| 80 part 'utils.dart'; | 97 part 'utils.dart'; |
| 81 | 98 |
| 82 /** The set of [PipelineRunner]s to execute. */ | 99 /** The set of [PipelineRunner]s to execute. */ |
| 83 List _tasks; | 100 List _tasks; |
| 84 | 101 |
| 85 /** The maximum number of pipelines that can run concurrently. */ | 102 /** The maximum number of pipelines that can run concurrently. */ |
| 86 int _maxTasks; | 103 int _maxTasks; |
| 87 | 104 |
| 88 /** The number of pipelines currently running. */ | 105 /** The number of pipelines currently running. */ |
| 89 int _numTasks; | 106 int _numTasks; |
| 90 | 107 |
| 91 /** The index of the next pipeline runner to execute. */ | 108 /** The index of the next pipeline runner to execute. */ |
| 92 int _nextTask; | 109 int _nextTask; |
| 93 | 110 |
| 94 /** The stream to use for high-value messages, like test results. */ | 111 /** The sink to use for high-value messages, like test results. */ |
| 95 OutputStream _outStream; | 112 IOSink _outSink; |
| 96 | 113 |
| 97 /** The stream to use for low-value messages, like verbose output. */ | 114 /** The sink to use for low-value messages, like verbose output. */ |
| 98 OutputStream _logStream; | 115 IOSink _logSink; |
| 99 | 116 |
| 100 /** | 117 /** |
| 118 * The last temp test directory we accessed; we use this to know if we |
| 119 * need to check the pub configuration. |
| 120 */ |
| 121 String _testDir; |
| 122 |
| 123 /** |
| 101 * The user can specify output streams on the command line, using 'none', | 124 * The user can specify output streams on the command line, using 'none', |
| 102 * 'stdout', 'stderr', or a file path; [getStream] will take such a name | 125 * 'stdout', 'stderr', or a file path; [getSink] will take such a name |
| 103 * and return an appropriate [OutputStream]. | 126 * and return an appropriate [IOSink]. |
| 104 */ | 127 */ |
| 105 OutputStream getStream(String name) { | 128 IOSink getSink(String name) { |
| 106 if (name == null || name == 'none') { | 129 if (name == null || name == 'none') { |
| 107 return null; | 130 return null; |
| 108 } | 131 } |
| 109 if (name == 'stdout') { | 132 if (name == 'stdout') { |
| 110 return stdout; | 133 return stdout; |
| 111 } | 134 } |
| 112 if (name == 'stderr') { | 135 if (name == 'stderr') { |
| 113 return stderr; | 136 return stderr; |
| 114 } | 137 } |
| 115 return new File(name).openOutputStream(FileMode.WRITE); | 138 var f = new File(name); |
| 139 return f.openWrite(); |
| 116 } | 140 } |
| 117 | 141 |
| 118 /** | 142 /** |
| 119 * Given a [List] of [testFiles], either print the list or create | 143 * Given a [List] of [testFiles], either print the list or create |
| 120 * and execute pipelines for the files. | 144 * and execute pipelines for the files. |
| 121 */ | 145 */ |
| 122 void processTests(Map config, List testFiles) { | 146 void processTests(Map config, List testFiles) { |
| 123 _outStream = getStream(config['out']); | 147 _outSink = getSink(config['out']); |
| 124 _logStream = getStream(config['log']); | 148 _logSink = getSink(config['log']); |
| 125 if (config['list-files']) { | 149 if (config['list-files']) { |
| 126 if (_outStream != null) { | 150 if (_outSink != null) { |
| 127 for (var i = 0; i < testFiles.length; i++) { | 151 for (var i = 0; i < testFiles.length; i++) { |
| 128 _outStream.writeString(testFiles[i]); | 152 _outSink.write(testFiles[i]); |
| 129 _outStream.writeString('\n'); | 153 _outSink.write('\n'); |
| 130 } | 154 } |
| 131 } | 155 } |
| 132 } else { | 156 } else { |
| 133 _maxTasks = min(config['tasks'], testFiles.length); | 157 _maxTasks = min(config['tasks'], testFiles.length); |
| 134 _numTasks = 0; | 158 _numTasks = 0; |
| 135 _nextTask = 0; | 159 _nextTask = 0; |
| 136 spawnTasks(config, testFiles); | 160 spawnTasks(config, testFiles); |
| 137 } | 161 } |
| 138 } | 162 } |
| 139 | 163 |
| 164 /** |
| 165 * Create or update a pubspec for the target test directory. We use the |
| 166 * source directory pubspec if available; otherwise we create a minimal one. |
| 167 * We return a Future if we are running pub install, or null otherwise. |
| 168 */ |
| 169 Future doPubConfig(Path sourcePath, String sourceDir, |
| 170 Path targetPath, String targetDir, |
| 171 String pub, String runtime) { |
| 172 // Make sure the target directory exists. |
| 173 var d = new Directory(targetDir); |
| 174 if (!d.existsSync()) { |
| 175 d.createSync(recursive: true); |
| 176 } |
| 177 |
| 178 // If the source has no pubspec, but the dest does, leave |
| 179 // things as they are. If neither do, create one in dest. |
| 180 |
| 181 var sourcePubSpecName = new Path(sourceDir).append("pubspec.yaml"). |
| 182 toNativePath(); |
| 183 var targetPubSpecName = new Path(targetDir).append("pubspec.yaml"). |
| 184 toNativePath(); |
| 185 var sourcePubSpec = new File(sourcePubSpecName); |
| 186 var targetPubSpec = new File(targetPubSpecName); |
| 187 |
| 188 if (!sourcePubSpec.existsSync()) { |
| 189 if (targetPubSpec.existsSync()) { |
| 190 return null; |
| 191 } else { |
| 192 // Create one. |
| 193 if (runtime == 'vm') { |
| 194 writeFile(targetPubSpecName, |
| 195 "name: testrunner\ndependencies:\n unittest: any\n"); |
| 196 } else { |
| 197 writeFile(targetPubSpecName, |
| 198 "name: testrunner\ndependencies:\n unittest: any\n browser: any\n"); |
| 199 } |
| 200 } |
| 201 } else { |
| 202 if (targetPubSpec.existsSync()) { |
| 203 // If there is a source one, and it is older than the target, |
| 204 // leave the target as is. |
| 205 if (sourcePubSpec.lastModifiedSync().millisecondsSinceEpoch < |
| 206 targetPubSpec.lastModifiedSync().millisecondsSinceEpoch) { |
| 207 return null; |
| 208 } |
| 209 } |
| 210 // Source exists and is newer than target or there is no target; |
| 211 // copy the source to the target. If there is a pubspec.lock file, |
| 212 // copy that too. |
| 213 var s = sourcePubSpec.readAsStringSync(); |
| 214 targetPubSpec.writeAsStringSync(s); |
| 215 var sourcePubLock = new File(sourcePubSpecName.replaceAll(".yaml", ".lock"))
; |
| 216 if (sourcePubLock.existsSync()) { |
| 217 var targetPubLock = |
| 218 new File(targetPubSpecName.replaceAll(".yaml", ".lock")); |
| 219 s = sourcePubLock.readAsStringSync(); |
| 220 targetPubLock.writeAsStringSync(s); |
| 221 } |
| 222 } |
| 223 // A new target pubspec was created so run pub install. |
| 224 return _processHelper(pub, [ 'install' ], workingDir: targetDir); |
| 225 } |
| 226 |
| 140 /** Execute as many tasks as possible up to the maxTasks limit. */ | 227 /** Execute as many tasks as possible up to the maxTasks limit. */ |
| 141 void spawnTasks(Map config, List testFiles) { | 228 void spawnTasks(Map config, List testFiles) { |
| 142 var verbose = config['verbose']; | 229 var verbose = config['verbose']; |
| 143 // If we were running in the VM and the immediate flag was set, we have | 230 // If we were running in the VM and the immediate flag was set, we have |
| 144 // already printed the important messages (i.e. prefixed with ###), | 231 // already printed the important messages (i.e. prefixed with ###), |
| 145 // so we should skip them now. | 232 // so we should skip them now. |
| 146 var skipNonVerbose = config['immediate'] && config['runtime'] == 'vm'; | 233 var skipNonVerbose = config['immediate'] && config['runtime'] == 'vm'; |
| 147 while (_numTasks < _maxTasks && _nextTask < testFiles.length) { | 234 while (_numTasks < _maxTasks && _nextTask < testFiles.length) { |
| 148 ++_numTasks; | 235 ++_numTasks; |
| 149 var testfile = testFiles[_nextTask++]; | 236 var testfile = testFiles[_nextTask++]; |
| 150 config['testfile'] = testfile; | 237 config['testfile'] = testfile; |
| 151 ReceivePort port = new ReceivePort(); | 238 ReceivePort port = new ReceivePort(); |
| 152 port.receive((msg, _) { | 239 port.receive((msg, _) { |
| 153 List stdout = msg[0]; | 240 List stdout = msg[0]; |
| 154 List stderr = msg[1]; | 241 List stderr = msg[1]; |
| 155 List log = msg[2]; | 242 List log = msg[2]; |
| 156 int exitCode = msg[3]; | 243 int exitCode = msg[3]; |
| 157 writelog(stdout, _outStream, _logStream, verbose, skipNonVerbose); | 244 writelog(stdout, _outSink, _logSink, verbose, skipNonVerbose); |
| 158 writelog(stderr, _outStream, _logStream, true, skipNonVerbose); | 245 writelog(stderr, _outSink, _logSink, true, skipNonVerbose); |
| 159 writelog(log, _outStream, _logStream, verbose, skipNonVerbose); | 246 writelog(log, _outSink, _logSink, verbose, skipNonVerbose); |
| 160 port.close(); | 247 port.close(); |
| 161 --_numTasks; | 248 --_numTasks; |
| 162 if (exitCode == 0 || !config['stopOnFailure']) { | 249 if (exitCode == 0 || !config['stop-on-failure']) { |
| 163 spawnTasks(config, testFiles); | 250 spawnTasks(config, testFiles); |
| 164 } | 251 } |
| 165 if (_numTasks == 0) { | 252 if (_numTasks == 0) { |
| 166 // No outstanding tasks; we're all done. | 253 // No outstanding tasks; we're all done. |
| 167 // We could later print a summary report here. | 254 // We could later print a summary report here. |
| 168 } | 255 } |
| 169 }); | 256 }); |
| 170 SendPort s = spawnUri(config['pipeline']); | 257 SendPort s = spawnUri(config['pipeline']); |
| 171 s.send(config, port.toSendPort()); | 258 |
| 259 // Get the names of the source and target test files and containing |
| 260 // directories. |
| 261 var testPath = new Path(testfile); |
| 262 var sourcePath = testPath.directoryPath; |
| 263 var sourceDir = sourcePath.toNativePath(); |
| 264 |
| 265 var targetPath = new Path(config["tempdir"]); |
| 266 var normalizedTarget = testPath.directoryPath.toNativePath() |
| 267 .replaceAll(Platform.pathSeparator, '_') |
| 268 .replaceAll(':', '_'); |
| 269 targetPath = targetPath.append("${normalizedTarget}_${config['runtime']}"); |
| 270 var targetDir = targetPath.toNativePath(); |
| 271 |
| 272 config['targetDir'] = targetDir; |
| 273 // If this is a new target dir, we need to redo the pub check. |
| 274 var f = null; |
| 275 if (targetDir != _testDir) { |
| 276 f = doPubConfig(sourcePath, sourceDir, targetPath, targetDir, |
| 277 config['pub'], config['runtime']); |
| 278 _testDir = targetDir; |
| 279 } |
| 280 if (f == null) { |
| 281 s.send(config, port.toSendPort()); |
| 282 } else { |
| 283 f.then((_) { |
| 284 s.send(config, port.toSendPort()); |
| 285 }); |
| 286 break; // Don't do any more until pub is done. |
| 287 } |
| 172 } | 288 } |
| 173 } | 289 } |
| 174 | 290 |
| 175 /** | 291 /** |
| 176 * Our tests are configured so that critical messages have a '###' prefix. | 292 * Our tests are configured so that critical messages have a '###' prefix. |
| 177 * [writeLog] takes the output from a pipeline execution and writes it to | 293 * [writelog] takes the output from a pipeline execution and writes it to |
| 178 * our output streams. It will strip the '###' if necessary on critical | 294 * our output sinks. It will strip the '###' if necessary on critical |
| 179 * messages; other messages will only be written if verbose output was | 295 * messages; other messages will only be written if verbose output was |
| 180 * specified. | 296 * specified. |
| 181 */ | 297 */ |
| 182 void writelog(List messages, OutputStream out, OutputStream log, | 298 void writelog(List messages, IOSink out, IOSink log, |
| 183 bool includeVerbose, bool skipNonVerbose) { | 299 bool includeVerbose, bool skipNonVerbose) { |
| 184 for (var i = 0; i < messages.length; i++) { | 300 for (var i = 0; i < messages.length; i++) { |
| 185 var msg = messages[i]; | 301 var msg = messages[i]; |
| 186 if (msg.startsWith('###')) { | 302 if (msg.startsWith('###')) { |
| 187 if (!skipNonVerbose && out != null) { | 303 if (!skipNonVerbose && out != null) { |
| 188 out.writeString(msg.substring(3)); | 304 out.write(msg.substring(3)); |
| 189 out.writeString('\n'); | 305 out.write('\n'); |
| 190 } | 306 } |
| 191 } else if (msg.startsWith('CONSOLE MESSAGE:')) { | 307 } else if (msg.startsWith('CONSOLE MESSAGE:')) { |
| 192 if (!skipNonVerbose && out != null) { | 308 if (!skipNonVerbose && out != null) { |
| 193 int idx = msg.indexOf('###'); | 309 int idx = msg.indexOf('###'); |
| 194 if (idx > 0) { | 310 if (idx > 0) { |
| 195 out.writeString(msg.substring(idx + 3)); | 311 out.write(msg.substring(idx + 3)); |
| 196 out.writeString('\n'); | 312 out.write('\n'); |
| 197 } | 313 } |
| 198 } | 314 } |
| 199 } else if (includeVerbose && log != null) { | 315 } else if (includeVerbose && log != null) { |
| 200 log.writeString(msg); | 316 log.write(msg); |
| 201 log.writeString('\n'); | 317 log.write('\n'); |
| 202 } | 318 } |
| 203 } | 319 } |
| 204 } | 320 } |
| 205 | 321 |
| 206 sanitizeConfig(Map config, ArgParser parser) { | 322 normalizeFilter(List filter) { |
| 323 // We want the filter to be a quoted string or list of quoted |
| 324 // strings. |
| 325 for (var i = 0; i < filter.length; i++) { |
| 326 var f = filter[i]; |
| 327 if (f[0] != "'" && f[0] != '"') { |
| 328 filter[i] = "'$f'"; // TODO(gram): Quote embedded quotes. |
| 329 } |
| 330 } |
| 331 return filter; |
| 332 } |
| 333 |
| 334 void sanitizeConfig(Map config, ArgParser parser) { |
| 207 config['layout'] = config['layout-text'] || config['layout-pixel']; | 335 config['layout'] = config['layout-text'] || config['layout-pixel']; |
| 208 | |
| 209 // TODO - check if next three are actually used. | |
| 210 config['runInBrowser'] = (config['runtime'] != 'vm'); | |
| 211 config['verbose'] = (config['log'] != 'none' && !config['list-groups']); | 336 config['verbose'] = (config['log'] != 'none' && !config['list-groups']); |
| 212 config['filtering'] = (config['include'].length > 0 || | |
| 213 config['exclude'].length > 0); | |
| 214 | |
| 215 config['timeout'] = int.parse(config['timeout']); | 337 config['timeout'] = int.parse(config['timeout']); |
| 216 config['tasks'] = int.parse(config['tasks']); | 338 config['tasks'] = int.parse(config['tasks']); |
| 217 | 339 |
| 218 var dartsdk = config['dartsdk']; | 340 var dartsdk = config['dartsdk']; |
| 219 var pathSep = Platform.pathSeparator; | 341 var pathSep = Platform.pathSeparator; |
| 220 | 342 |
| 221 if (dartsdk != null) { | 343 if (dartsdk == null) { |
| 222 if (parser.getDefault('dart2js') == config['dart2js']) { | 344 var opt = new Options(); |
| 223 config['dart2js'] = | 345 var runner = opt.executable; |
| 224 '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js'; | 346 var idx = runner.indexOf('dart-sdk'); |
| 347 if (idx < 0) { |
| 348 print("Please use --dartsdk option or run using the dart executable " |
| 349 "from the Dart SDK"); |
| 350 exit(0); |
| 225 } | 351 } |
| 226 if (parser.getDefault('dart') == config['dart']) { | 352 dartsdk = runner.substring(0, idx); |
| 227 config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart'; | 353 } |
| 228 } | 354 if (Platform.operatingSystem == 'macos') { |
| 229 if (parser.getDefault('drt') == config['drt']) { | 355 config['dart2js'] = |
| 230 config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree'; | 356 '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js'; |
| 231 } | 357 config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart'; |
| 358 config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub'; |
| 359 config['drt'] = |
| 360 '$dartsdk/chromium/DumpRenderTree.app/Contents/MacOS/DumpRenderTree'; |
| 361 } else if (Platform.operatingSystem == 'linux') { |
| 362 config['dart2js'] = |
| 363 '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js'; |
| 364 config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart'; |
| 365 config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub'; |
| 366 config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree'; |
| 367 } else { |
| 368 config['dart2js'] = |
| 369 '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js.bat'; |
| 370 config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart.exe'
; |
| 371 config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub.bat'; |
| 372 config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree.exe'; |
| 232 } | 373 } |
| 233 | 374 |
| 234 config['unittest'] = makePathAbsolute(config['unittest']); | 375 for (var prog in [ 'drt', 'dart', 'pub', 'dart2js' ]) { |
| 235 config['drt'] = makePathAbsolute(config['drt']); | 376 config[prog] = makePathAbsolute(config[prog]); |
| 236 config['dart'] = makePathAbsolute(config['dart']); | 377 } |
| 237 config['dart2js'] = makePathAbsolute(config['dart2js']); | |
| 238 config['runnerDir'] = runnerDirectory; | 378 config['runnerDir'] = runnerDirectory; |
| 379 config['include'] = normalizeFilter(config['include']); |
| 380 config['exclude'] = normalizeFilter(config['exclude']); |
| 239 } | 381 } |
| 240 | 382 |
| 241 main() { | 383 main() { |
| 242 var optionsParser = getOptionParser(); | 384 var optionsParser = getOptionParser(); |
| 243 var options = loadConfiguration(optionsParser); | 385 var options = loadConfiguration(optionsParser); |
| 244 if (isSane(options)) { | 386 if (isSane(options)) { |
| 245 if (options['list-options']) { | 387 if (options['list-options']) { |
| 246 printOptions(optionsParser, options, false, stdout); | 388 printOptions(optionsParser, options, false, stdout); |
| 247 } else if (options['list-all-options']) { | 389 } else if (options['list-all-options']) { |
| 248 printOptions(optionsParser, options, true, stdout); | 390 printOptions(optionsParser, options, true, stdout); |
| 249 } else { | 391 } else { |
| 250 var config = new Map(); | 392 var config = new Map(); |
| 251 for (var option in options.options) { | 393 for (var option in options.options) { |
| 252 config[option] = options[option]; | 394 config[option] = options[option]; |
| 253 } | 395 } |
| 254 var rest = []; | 396 var rest = []; |
| 255 // Process the remmaining command line args. If they look like | 397 // Process the remmaining command line args. If they look like |
| 256 // options then split them up and add them to the map; they may be for | 398 // options then split them up and add them to the map; they may be for |
| 257 // custom pipelines. | 399 // custom pipelines. |
| 258 for (var other in options.rest) { | 400 for (var other in options.rest) { |
| 259 var idx; | 401 var idx; |
| 260 if (other.startsWith('--') && (idx = other.indexOf('=')) > 0) { | 402 if (other.startsWith('--') && (idx = other.indexOf('=')) > 0) { |
| 261 var optName = other.substring(2, idx); | 403 var optName = other.substring(2, idx); |
| 262 var optValue = other.substring(idx+1); | 404 var optValue = other.substring(idx+1); |
| 263 config[optName] = optValue; | 405 config[optName] = optValue; |
| 264 } else { | 406 } else { |
| 265 rest.add(other); | 407 rest.add(other); |
| 266 } | 408 } |
| 267 } | 409 } |
| 268 | 410 |
| 269 sanitizeConfig(config, optionsParser); | 411 sanitizeConfig(config, optionsParser); |
| 270 | 412 |
| 271 // Build the list of tests and then execute them. | 413 // Build the list of tests and then execute them. |
| 272 List dirs = rest; | 414 List dirs = rest; |
| 273 if (dirs.length == 0) { | 415 if (dirs.length == 0) { |
| 274 dirs.add('.'); // Use current working directory as default. | 416 dirs.add('.'); // Use current working directory as default. |
| 275 } | 417 } |
| 276 buildFileList(dirs, | 418 var f = buildFileList(dirs, |
| 277 new RegExp(options['test-file-pattern']), options['recurse'], | 419 new RegExp(config['test-file-pattern']), config['recurse']); |
| 278 (f) => processTests(config, f)); | 420 if (config['sort']) f.sort(); |
| 421 processTests(config, f); |
| 279 } | 422 } |
| 280 } | 423 } |
| 281 } | 424 } |
| OLD | NEW |