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

Side by Side Diff: tools/testing/dart/options.dart

Issue 2902023002: Refactor test option parsing code. (Closed)
Patch Set: Created 3 years, 6 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
« no previous file with comments | « tools/testing/dart/main.dart ('k') | tools/testing/dart/package_testing_support.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'dart:io';
6 import 'drt_updater.dart';
7 import 'test_suite.dart';
8 import 'path.dart';
9 import 'compiler_configuration.dart' show CompilerConfiguration;
10 import 'runtime_configuration.dart' show RuntimeConfiguration;
11
12 const _defaultTestSelectors = const [
13 'samples',
14 'standalone',
15 'corelib',
16 'co19',
17 'language',
18 'isolate',
19 'vm',
20 'html',
21 'benchmark_smoke',
22 'utils',
23 'lib',
24 'analyze_library',
25 'service',
26 'kernel',
27 'observatory_ui'
28 ];
29
30 /// Specifies a single command line option.
31 ///
32 /// The name of the specification is used as the key for the option in the Map
33 /// returned from the [TestOptionParser] parse method.
34 class _Option {
35 // TODO(rnystrom): Some string options use "" to mean "no value" and others
36 // use null. Clean that up.
37 _Option(this.name, this.description,
38 {String abbr, List<String> values, String defaultsTo = ""})
39 : abbreviation = abbr,
40 values = values ?? [],
41 defaultValue = defaultsTo,
42 type = _OptionValueType.string;
43
44 _Option.bool(this.name, this.description, [this.abbreviation])
45 : values = [],
46 defaultValue = false,
47 type = _OptionValueType.bool;
48
49 _Option.int(this.name, this.description, {String abbr, int defaultsTo})
50 : abbreviation = abbr,
51 values = [],
52 defaultValue = defaultsTo,
53 type = _OptionValueType.int;
54
55 final String name;
56 final String description;
57 final String abbreviation;
58 final List<String> values;
59 final Object defaultValue;
60 final _OptionValueType type;
61
62 /// Gets the shortest command line argument used to refer to this option.
63 String get shortCommand => abbreviation != null ? "-$abbreviation" : command;
64
65 /// Gets the canonical long command line argument used to refer to this
66 /// option.
67 String get command => "--${name.replaceAll('_', '-')}";
68 }
69
70 enum _OptionValueType { bool, int, string }
71
72 /// Parses command line arguments and produces a test runner configuration.
73 class OptionsParser {
74 static final List<_Option> _options = [
75 new _Option('mode', 'Mode in which to run the tests.',
76 abbr: 'm',
77 values: ['all', 'debug', 'release', 'product'],
78 defaultsTo: 'debug'),
79 new _Option(
80 'compiler',
81 '''Specify any compilation step (if needed).
82
83 none: Do not compile the Dart code (run native Dart code
84 on the VM).
85 (Only valid with runtimes vm, flutter, or drt.)
86
87 precompiler: Compile into AOT snapshot before running the test.
88 (Only valid with runtime dart_precompiled.)
89
90 dart2js: Compile dart code to JavaScript by running dart2js.
91 (Only valid with runtimes: d8, drt, chrome, safari,
92 ie9, ie10, ie11, firefox, opera, chromeOnAndroid,
93 and none [compile only].)
94
95 dart2analyzer: Perform static analysis on Dart code by running the
96 analyzer.
97 (Only valid with runtime none.)
98
99 app_jit: Compile the Dart code into an app snapshot before
100 running test.
101 (Only valid with dart_app runtime.)
102
103 dartk: Compile the Dart source into Kernel before running
104 test.
105
106 dartkp: Compile the Dart source into Kernel and then Kernel
107 into AOT snapshot before running the test.
108 (Only valid with runtime dart_precompiled.)''',
109 abbr: 'c',
110 values: [
111 'none',
112 'precompiler',
113 'dart2js',
114 'dart2analyzer',
115 'app_jit',
116 'dartk',
117 'dartkp'
118 ],
119 defaultsTo: 'none'),
120 new _Option(
121 'runtime',
122 '''Where the tests should be run.
123 vm: Run Dart code on the standalone dart vm.
124
125 flutter: Run Dart code on the flutter engine.
126
127 dart_precompiled: Run a precompiled snapshot on a variant of the
128 standalone dart VM lacking a JIT.
129
130 d8: Run JavaScript from the command line using v8.
131
132 jsshell: Run JavaScript from the command line using
133 Firefox js-shell.
134
135 drt: Run Dart or JavaScript in the headless version
136 of Chrome, Content shell.
137
138 dartium: Run Dart or JavaScript in Dartium.
139
140 ContentShellOnAndroid: Run Dart or JavaScript in Dartium content
141 shell on Android.
142
143 DartiumOnAndroid: Run Dart or Javascript in Dartium on Android.
144
145 ff:
146 chrome:
147 safari:
148 ie9:
149 ie10:
150 ie11:
151 opera:
152 chromeOnAndroid: Run JavaScript in the specified browser.
153
154 self_check: Pass each test or its compiled output to every
Siggi Cherem (dart-lang) 2017/05/25 21:57:19 (optional) I understand this is from before but ho
Bob Nystrom 2017/05/26 18:03:22 I honestly have no idea what this is or how it's u
155 file under `pkg` whose name ends with
156 `_self_check.dart`. Each test is given to the
157 self_check tester as a filename on stdin using
158 the batch-mode protocol.
159
160 none: No runtime, compile only. (For example, used
161 for dart2analyzer static analysis tests).''',
162 abbr: 'r',
163 values: [
164 'vm',
165 'flutter',
166 'dart_precompiled',
167 'd8',
168 'jsshell',
169 'drt',
170 'dartium',
171 'ff',
172 'firefox',
173 'chrome',
174 'safari',
175 'ie9',
176 'ie10',
177 'ie11',
178 'opera',
179 'chromeOnAndroid',
180 'safarimobilesim',
181 'ContentShellOnAndroid',
182 'DartiumOnAndroid',
183 'self_check',
184 'none'
185 ],
186 defaultsTo: 'vm'),
187 new _Option(
188 'arch',
189 '''The architecture to run tests for.
190
191 Allowed values are:
192 all
193 ia32, x64
194 arm, armv6, armv5te, arm64,
195 simarm, simarmv6, simarmv5te, simarm64,
196 mips, simmips
197 simdbc, simdbc64''',
198 abbr: 'a',
199 values: [
200 'all',
201 'ia32',
202 'x64',
203 'arm',
204 'armv6',
205 'armv5te',
206 'arm64',
207 'mips',
208 'simarm',
209 'simarmv6',
210 'simarmv5te',
211 'simarm64',
212 'simmips',
213 'simdbc',
214 'simdbc64',
215 ],
216 defaultsTo: 'x64'),
217 new _Option('system', 'The operating system to run tests on.',
218 abbr: 's',
219 values: ['linux', 'macos', 'windows', 'android'],
220 defaultsTo: Platform.operatingSystem),
221 new _Option.bool('checked', 'Run tests in checked mode.'),
222 new _Option.bool('strong', 'Run tests in strong mode.'),
223 new _Option.bool('host_checked', 'Run compiler in checked mode.'),
224 new _Option.bool('minified', 'Enable minification in the compiler.'),
225 new _Option.bool(
226 'csp', 'Run tests under Content Security Policy restrictions.'),
227 new _Option.bool('cps_ir', 'Run the compiler with the cps based backend.'),
Siggi Cherem (dart-lang) 2017/05/25 21:57:19 I believe all uses of this flag are gone, so it is
Bob Nystrom 2017/05/26 18:03:22 Done. It did show up in a couple of status files,
228 new _Option.bool(
229 'fast_startup', 'Pass the --fast-startup flag to dart2js.'),
230 new _Option.bool('dart2js_with_kernel',
231 'Enable the internal pipeline in dart2js to use kernel.'),
232 new _Option.bool('hot_reload', 'Run hot reload stress tests.'),
233 new _Option.bool(
234 'hot_reload_rollback', 'Run hot reload rollback stress tests.'),
235 new _Option.bool('use_blobs',
236 'Use mmap instead of shared libraries for precompilation.'),
237 new _Option.int('timeout', 'Timeout in seconds.',
238 abbr: 't', defaultsTo: -1),
239 new _Option(
240 'progress',
241 '''Progress indication mode.
242
243 Allowed values are:
244 compact, color, line, verbose, silent, status, buildbot, diff
245 ''',
246 abbr: 'p',
247 values: [
248 'compact',
249 'color',
250 'line',
251 'verbose',
252 'silent',
253 'status',
254 'buildbot',
255 'diff'
256 ],
257 defaultsTo: 'compact'),
258 new _Option('step_name', 'Step name for use by -pbuildbot.',
259 defaultsTo: null),
260 new _Option.bool('report',
261 'Print a summary report of the number of tests, by expectation.'),
262 new _Option.int('tasks', 'The number of parallel tasks to run.',
263 abbr: 'j', defaultsTo: Platform.numberOfProcessors),
264 new _Option.int('shards',
265 'The number of instances that the tests will be sharded over.',
266 defaultsTo: 1),
267 new _Option.int(
268 'shard', 'The index of this instance when running in sharded mode.',
269 defaultsTo: 1),
270 new _Option.bool('help', 'Print list of options.', 'h'),
271 new _Option.bool('verbose', 'Verbose output.', 'v'),
272 new _Option.bool('verify-ir', 'Verify kernel IR.'),
273 new _Option.bool('no-tree-shake', 'Disable kernel IR tree shaking.'),
274 new _Option.bool('list', 'List tests only, do not run them.'),
275 new _Option.bool('report_in_json',
276 'When listing with --list, output result summary in JSON.'),
277 new _Option.bool('time', 'Print timing information after running tests.'),
278 new _Option('dart', 'Path to dart executable.'),
279 new _Option('flutter', 'Path to flutter executable.'),
280 new _Option(
281 'drt', // TODO(antonm): fix the option name.
282 'Path to content shell executable.'),
283 new _Option('dartium', 'Path to Dartium Chrome executable.'),
284 new _Option('firefox', 'Path to firefox browser executable.'),
285 new _Option('chrome', 'Path to chrome browser executable.'),
286 new _Option('safari', 'Path to safari browser executable.'),
287 new _Option.bool(
288 'use_sdk',
289 '''Use compiler or runtime from the SDK.
290
291 Normally, the compiler or runtimes in PRODUCT_DIR is tested, with
292 this option, the compiler or runtime in PRODUCT_DIR/dart-sdk/bin
293 is tested.
294
295 (Note: currently only implemented for dart2js.)'''),
296 new _Option('build_directory',
297 'The name of the build directory, where products are placed.'),
298 new _Option.bool('noBatch', 'Do not run tests in batch mode.', 'n'),
299 new _Option.bool('dart2js_batch', 'Run dart2js tests in batch mode.'),
300 new _Option.bool(
301 'append_logs', 'Do not delete old logs but rather append to them.'),
302 new _Option.bool('write_debug_log',
303 'Don\'t write debug messages to stdout but rather to a logfile.'),
304 new _Option.bool('write_test_outcome_log',
305 'Write test outcomes to a "${TestUtils.testOutcomeFileName}" file.'),
306 new _Option.bool(
307 'reset_browser_configuration',
308 '''Browser specific reset of configuration.
309
310 Warning: Using this option may remove your bookmarks and other
311 settings.'''),
312 new _Option.bool(
313 'copy_coredumps',
314 '''If we see a crash that we did not expect, copy the core dumps to
315 "/tmp".'''),
316 new _Option(
317 'local_ip',
318 '''IP address the HTTP servers should listen on. This address is also
319 used for browsers to connect to.''',
320 defaultsTo: '127.0.0.1'),
321 new _Option.int('test_server_port', 'Port for test http server.',
322 defaultsTo: 0),
323 new _Option.int('test_server_cross_origin_port',
324 'Port for test http server cross origin.',
325 defaultsTo: 0),
326 new _Option.int('test_driver_port', 'Port for http test driver server.',
327 defaultsTo: 0),
328 new _Option.int(
329 'test_driver_error_port', 'Port for http test driver server errors.',
330 defaultsTo: 0),
331 new _Option('record_to_file',
332 'Records all commands to be executed and writes to a file.',
333 defaultsTo: null),
334 new _Option(
335 'replay_from_file', 'Replays a previously recorded list of commands.',
336 defaultsTo: null),
337 new _Option(
338 'builder_tag',
339 '''Machine specific options that is not captured by the regular test
340 options. Used to be able to make sane updates to the status files.'''),
341 new _Option('vm_options', 'Extra options to send to the vm when running.',
342 defaultsTo: null),
343 new _Option(
344 'dart2js_options', 'Extra options for dart2js compilation step.',
345 defaultsTo: null),
346 new _Option(
347 'suite_dir', 'Additional directory to add to the testing matrix.',
348 defaultsTo: null),
349 new _Option('package_root', 'The package root to use for testing.',
350 defaultsTo: null),
351 new _Option('packages', 'The package spec file to use for testing.',
352 defaultsTo: null),
353 new _Option(
354 'exclude_suite',
355 '''Exclude suites from default selector, only works when no selector
356 has been specified on the command line.''',
357 defaultsTo: null),
358 new _Option.bool(
359 'skip-compilation',
360 '''
361 Skip the compilation step, using the compilation artifacts left in
362 the output folder from a previous run. This flag will often cause
363 false positves and negatives, but can be useful for quick and
364 dirty offline testing when not making changes that affect the
365 compiler.''')
366 ];
367
368 /// For printing out reproducing command lines, we don't want to add these
369 /// options.
370 static final _blacklistedOptions = [
371 'append_logs',
372 'build_directory',
373 'chrome',
374 'copy_coredumps',
375 'dart',
376 'flutter',
377 'dartium',
378 'drt',
379 'exclude_suite',
380 'firefox',
381 'local_ip',
382 'progress',
383 'report',
384 'safari',
385 'shard',
386 'shards',
387 'step_name',
388 'tasks',
389 'time',
390 'verbose',
391 'write_debug_log',
392 'write_test_outcome_log',
393 ].toSet();
394
395 /// Parses a list of strings as test options.
396 ///
397 /// Returns a list of configurations in which to run the tests.
398 /// Configurations are maps mapping from option keys to values. When
399 /// encountering the first non-option string, the rest of the arguments are
400 /// stored in the returned Map under the 'rest' key.
401 List<Map> parse(List<String> arguments) {
402 var configuration = {};
403
404 // Fill in configuration with arguments passed to the test script.
405 for (var i = 0; i < arguments.length; i++) {
406 var arg = arguments[i];
407
408 // Help supersedes all other arguments.
409 if (arg == "--help" || arg == "-h") {
410 _printHelp();
411 return null;
412 }
413
414 // Extract name and value for options.
415 String command;
416 String value;
417 _Option option;
418
419 if (arg.startsWith("--")) {
420 // A long option name.
421 var equals = arg.indexOf("=");
422 if (equals != -1) {
423 // A long option with a value, like "--arch=ia32".
424 command = arg.substring(0, equals);
425 value = arg.substring(equals + 1);
426 } else {
427 command = arg;
428 }
429
430 option = _findByName(command.substring(2));
431 } else if (arg.startsWith("-")) {
432 // An abbreviated option.
433 if (arg.length == 1) {
434 _fail('Missing option name after "-".');
435 }
436
437 command = arg.substring(0, 2);
438
439 if (arg.length > 2) {
440 // An abbreviated option followed by a value, like "-aia32".
441 value = arg.substring(2);
442 }
443
444 option = _findByAbbreviation(command.substring(1));
445 } else {
446 // The argument does not start with "-" or "--" and is therefore not an
447 // option. Use it as a test selector pattern.
448 var patterns = configuration.putIfAbsent("selectors", () => <String>[]);
449 patterns.add(arg);
450 continue;
451 }
452
453 if (option == null) {
454 _fail('Unknown command line option "$command".');
455 }
456
457 // If we need a value, look at the next argument.
458 if (value == null && option.type != _OptionValueType.bool) {
459 if (i + 1 >= arguments.length) {
460 _fail('Missing value for command line option "$command".');
461 }
462 value = arguments[++i];
463 }
464
465 // Multiple uses of a flag are an error, because there is no naturally
466 // correct way to handle conflicting options.
467 if (configuration.containsKey(option.name)) {
468 _fail('Already have value for command line option "$command".');
469 }
470
471 // Parse the value for the option.
472 switch (option.type) {
473 case _OptionValueType.bool:
474 if (value != null) {
475 _fail('Boolean flag "$command" does not take a value.');
476 }
477
478 configuration[option.name] = true;
479 break;
480
481 case _OptionValueType.int:
482 try {
483 configuration[option.name] = int.parse(value);
484 } on FormatException {
485 _fail('Integer value expected for option "$command".');
486 }
487 break;
488
489 case _OptionValueType.string:
490 // Validate against the allowed values.
491 if (!option.values.isEmpty) {
492 for (var v in value.split(",")) {
493 if (!option.values.contains(v)) {
494 _fail('Unknown value "$v" for command line option "$command".');
495 }
496 }
497 }
498
499 // TODO(rnystrom): Store as a list instead of a comma-delimited
500 // string.
501 configuration[option.name] = value;
502 break;
503 }
504 }
505
506 // Apply default values for unspecified options.
507 for (var option in _options) {
508 if (!configuration.containsKey(option.name)) {
509 configuration[option.name] = option.defaultValue;
510 }
511 }
512
513 var expandedConfigs = _expandConfigurations(configuration);
514 var result = expandedConfigs.where(_isValidConfig).toList();
515 for (var config in result) {
516 config['_reproducing_arguments_'] = _reproducingCommand(config);
517 }
518
519 return result.isEmpty ? null : result;
520 }
521
522 /// Prints [message] and exits with a non-zero exit code.
523 void _fail(String message) {
524 print(message);
525 exit(1);
526 }
527
528 /// Given a configuration, returns the list of command line arguments that
529 /// would reproduce that configuration.
530 List<String> _reproducingCommand(Map config) {
531 var arguments = <String>[];
532
533 for (var option in _options) {
534 var name = option.name;
535 if (!config.containsKey(name) || _blacklistedOptions.contains(name)) {
536 continue;
537 }
538
539 var value = config[name];
540 if (config[name] == option.defaultValue ||
541 (name == 'packages' &&
542 value ==
543 TestUtils.dartDirUri.resolve('.packages').toFilePath())) {
544 continue;
545 }
546
547 arguments.add(option.shortCommand);
548 if (option.type != _OptionValueType.bool) {
549 arguments.add(value.toString());
550 }
551 }
552
553 return arguments;
554 }
555
556 /// Determines if a particular configuration has a valid combination of
557 /// compiler and runtime elements.
558 bool _isValidConfig(Map config) {
559 var isValid = true;
560 List<String> validRuntimes;
561 switch (config['compiler']) {
562 case 'dart2js':
563 // Note: by adding 'none' as a configuration, if the user
564 // runs test.py -c dart2js -r drt,none the dart2js_none and
565 // dart2js_drt will be duplicating work. If later we don't need 'none'
566 // with dart2js, we should remove it from here.
567 validRuntimes = const [
568 'd8',
569 'jsshell',
570 'drt',
571 'none',
572 'dartium',
573 'ff',
574 'chrome',
575 'safari',
576 'ie9',
577 'ie10',
578 'ie11',
579 'opera',
580 'chromeOnAndroid',
581 'safarimobilesim'
582 ];
583 break;
584 case 'dart2analyzer':
585 validRuntimes = const ['none'];
586 break;
587 case 'app_jit':
588 case 'dartk':
589 validRuntimes = const ['vm', 'self_check', 'none'];
590 break;
591 case 'precompiler':
592 case 'dartkp':
593 validRuntimes = const ['dart_precompiled'];
594 break;
595 case 'none':
596 validRuntimes = const [
597 'vm',
598 'flutter',
599 'drt',
600 'dartium',
601 'ContentShellOnAndroid',
602 'DartiumOnAndroid'
603 ];
604 break;
605 }
606
607 if (!validRuntimes.contains(config['runtime'])) {
608 isValid = false;
609 print("Warning: combination of compiler '${config['compiler']}' and "
610 "runtime '${config['runtime']}' is invalid. "
611 "Skipping this combination.");
612 }
613
614 if (config['ie'] && Platform.operatingSystem != 'windows') {
615 isValid = false;
616 print("Warning: cannot run Internet Explorer on non-Windows operating"
617 " system.");
618 }
619
620 if (config['shard'] < 1 || config['shard'] > config['shards']) {
621 isValid = false;
622 print("Error: shard index is ${config['shard']} out of "
623 "${config['shards']} shards");
624 }
625
626 if (config['runtime'] == 'flutter' && config['flutter'] == '') {
627 isValid = false;
628 print("-rflutter requires the flutter engine executable to "
629 "be specified using --flutter=");
630 }
631
632 if (config['runtime'] == 'flutter' && config['arch'] != 'x64') {
633 isValid = false;
634 print("-rflutter is applicable only for --arch=x64");
635 }
636
637 return isValid;
638 }
639
640 /// Recursively expands a configuration with multiple values per key into a
641 /// list of configurations with exactly one value per key.
642 List<Map> _expandConfigurations(Map configuration) {
643 // Expand the pseudo-values such as 'all'.
644 if (configuration['arch'] == 'all') {
645 configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips,simdbc64';
646 }
647
648 if (configuration['mode'] == 'all') {
649 configuration['mode'] = 'debug,release,product';
650 }
651
652 if (configuration['report_in_json']) {
653 configuration['list'] = true;
654 configuration['report'] = true;
655 }
656
657 // Use verbose progress indication for verbose output unless buildbot
658 // progress indication is requested.
659 if (configuration['verbose'] && configuration['progress'] != 'buildbot') {
660 configuration['progress'] = 'verbose';
661 }
662
663 // Create the artificial negative options that test status files
664 // expect.
665 configuration['unchecked'] = !configuration['checked'];
666 configuration['host_unchecked'] = !configuration['host_checked'];
667 configuration['unminified'] = !configuration['minified'];
668 configuration['nocsp'] = !configuration['csp'];
669
670 String runtime = configuration['runtime'];
671 if (runtime == 'firefox') {
672 configuration['runtime'] == 'ff';
673 }
674
675 String compiler = configuration['compiler'];
676 configuration['browser'] = TestUtils.isBrowserRuntime(runtime);
677 configuration['analyzer'] = TestUtils.isCommandLineAnalyzer(compiler);
678
679 // Set the javascript command line flag for less verbose status files.
680 configuration['jscl'] = TestUtils.isJsCommandLineRuntime(runtime);
681
682 // Allow suppression that is valid for all ie versions
683 configuration['ie'] = runtime.startsWith('ie');
684
685 // Expand the test selectors into a suite name and a simple
686 // regular expressions to be used on the full path of a test file
687 // in that test suite. If no selectors are explicitly given use
688 // the default suite patterns.
689 var selectors = configuration['selectors'];
690 if (selectors is! Map) {
691 if (selectors == null) {
692 if (configuration['suite_dir'] != null) {
693 var suite_path = new Path(configuration['suite_dir']);
694 selectors = [suite_path.filename];
695 } else {
696 selectors = _defaultTestSelectors.toList();
697 }
698
699 var excludeSuites = configuration['exclude_suite'] != null
700 ? configuration['exclude_suite'].split(',')
701 : [];
702 for (var exclude in excludeSuites) {
703 if (selectors.contains(exclude)) {
704 selectors.remove(exclude);
705 } else {
706 print("Warning: default selectors does not contain $exclude");
707 }
708 }
709 }
710 var selectorMap = <String, RegExp>{};
711 for (var i = 0; i < selectors.length; i++) {
712 var pattern = selectors[i];
713 var suite = pattern;
714 var slashLocation = pattern.indexOf('/');
715 if (slashLocation != -1) {
716 suite = pattern.substring(0, slashLocation);
717 pattern = pattern.substring(slashLocation + 1);
718 pattern = pattern.replaceAll('*', '.*');
719 } else {
720 pattern = ".?";
721 }
722 if (selectorMap.containsKey(suite)) {
723 print("Error: '$suite/$pattern'. Only one test selection"
724 " pattern is allowed to start with '$suite/'");
725 exit(1);
726 }
727 selectorMap[suite] = new RegExp(pattern);
728 }
729 configuration['selectors'] = selectorMap;
730 }
731
732 // Put observatory_ui in a configuration with its own packages override.
733 // Only one value in the configuration map is mutable:
734 selectors = configuration['selectors'];
735 if (selectors.containsKey('observatory_ui')) {
736 if (selectors.length == 1) {
737 configuration['packages'] = TestUtils.dartDirUri
738 .resolve('runtime/observatory/.packages')
739 .toFilePath();
740 } else {
741 // Make a new configuration whose selectors map only contains
742 // observatory_ui, and remove the key from the original selectors.
743 // The only mutable value in the map is the selectors, so a
744 // shallow copy is safe.
745 var observatoryConfiguration = new Map.from(configuration);
746 observatoryConfiguration['selectors'] = {
747 'observatory_ui': selectors['observatory_ui']
748 };
749 selectors.remove('observatory_ui');
750
751 // Set the packages flag.
752 observatoryConfiguration['packages'] = TestUtils.dartDirUri
753 .resolve('runtime/observatory/.packages')
754 .toFilePath();
755
756 // Return the expansions of both configurations. Neither will reach
757 // this line in the recursive call to _expandConfigurations.
758 return _expandConfigurations(configuration)
759 ..addAll(_expandConfigurations(observatoryConfiguration));
760 }
761 }
762
763 // Set the default package spec explicitly.
764 if (configuration['package_root'] == null &&
765 configuration['packages'] == null) {
766 configuration['packages'] =
767 TestUtils.dartDirUri.resolve('.packages').toFilePath();
768 }
769
770 // Expand the architectures.
771 if (configuration['arch'].contains(',')) {
772 return _expandHelper('arch', configuration);
773 }
774
775 // Expand modes.
776 if (configuration['mode'].contains(',')) {
777 return _expandHelper('mode', configuration);
778 }
779
780 // Expand compilers.
781 if (configuration['compiler'].contains(',')) {
782 return _expandHelper('compiler', configuration);
783 }
784
785 // Expand runtimes.
786 var runtimes = configuration['runtime'];
787 if (runtimes.contains(',')) {
788 return _expandHelper('runtime', configuration);
789 } else {
790 // All runtimes eventually go through this path, after expansion.
791 var updater = runtimeUpdater(configuration);
792 if (updater != null) {
793 updater.update();
794 }
795 }
796
797 // Adjust default timeout based on mode, compiler, and sometimes runtime.
798 if (configuration['timeout'] == -1) {
799 var isReload =
800 configuration['hot_reload'] || configuration['hot_reload_rollback'];
801 int compilerMulitiplier =
802 new CompilerConfiguration(configuration).computeTimeoutMultiplier();
803 int runtimeMultiplier = new RuntimeConfiguration(configuration)
804 .computeTimeoutMultiplier(
805 mode: configuration['mode'],
806 isChecked: configuration['checked'],
807 isReload: isReload,
808 arch: configuration['arch']);
809 configuration['timeout'] = 60 * compilerMulitiplier * runtimeMultiplier;
810 }
811
812 return [configuration];
813 }
814
815 /// Helper for _expandConfigurations. Creates a new configuration and adds it
816 /// to a list, for use in a case when a particular configuration has multiple
817 /// results (separated by a ',').
818 /// Arguments:
819 /// option: The particular test option we are expanding.
820 /// configuration: The map containing all test configuration information
821 /// specified.
822 List<Map> _expandHelper(String option, Map configuration) {
823 var result = <Map>[];
824 var configs = configuration[option];
825 for (var config in configs.split(',')) {
826 var newConfiguration = new Map.from(configuration);
827 newConfiguration[option] = config;
828 result.addAll(_expandConfigurations(newConfiguration));
829 }
830 return result;
831 }
832
833 /// Print out usage information.
834 void _printHelp() {
835 var buffer = new StringBuffer();
836
837 buffer.writeln('''usage: dart test.dart [options] [selector]
838
839 The optional selector limits the tests that will be run.
840 For example, the selector "language/issue", or equivalently
841 "language/*issue*", limits to test files matching the regexp
842 ".*issue.*\\.dart" in the "tests/language" directory.
843
844 Options:''');
845
846 for (var option in _options) {
847 if (option.abbreviation != null) {
848 buffer.write("-${option.abbreviation}, ");
849 } else {
850 buffer.write(" ");
851 }
852
853 buffer.write(option.command);
854
855 switch (option.type) {
856 case _OptionValueType.bool:
857 // No value.
858 break;
859 case _OptionValueType.int:
860 buffer.write("=<integer>");
861 break;
862 case _OptionValueType.string:
863 if (option.values.length > 6) {
864 // If there are many options, they won't fit nicely in one line and
865 // should be instead listed in the description.
866 buffer.write("=<...>");
867 } else if (option.values.isNotEmpty) {
868 buffer.write("=<${option.values.join('|')}>");
869 } else {
870 buffer.write("=<string>");
871 }
872 break;
873 }
874
875 if (option.type != _OptionValueType.bool &&
876 option.defaultValue != null &&
877 option.defaultValue != "") {
878 buffer.write(" (defaults to ${option.defaultValue})");
879 }
880
881 buffer.writeln();
882 buffer
883 .writeln(" ${option.description.replaceAll('\n', '\n ')}");
884 buffer.writeln();
885 }
886
887 print(buffer);
888 }
889
890 _Option _findByAbbreviation(String abbreviation) {
891 for (var option in _options) {
892 if (abbreviation == option.abbreviation) return option;
893 }
894
895 return null;
896 }
897
898 _Option _findByName(String name) {
899 for (var option in _options) {
900 if (name == option.name) return option;
901
902 // Allow hyphens instead of underscores as the separator since they are
903 // more common for command line flags.
904 if (name == option.name.replaceAll("_", "-")) return option;
905 }
906
907 return null;
908 }
909 }
OLDNEW
« no previous file with comments | « tools/testing/dart/main.dart ('k') | tools/testing/dart/package_testing_support.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698