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

Side by Side Diff: utils/testrunner/testrunner.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/standard_test_runner.dart ('k') | utils/testrunner/utils.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 //#!/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
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 }
OLDNEW
« no previous file with comments | « utils/testrunner/standard_test_runner.dart ('k') | utils/testrunner/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698