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

Unified Diff: tools/testing/dart/options.dart

Issue 2908833002: Revert "Revert "Refactor test option parsing code."" (Closed)
Patch Set: Ignore "—failure-summary" so it doesn't break the bots. Created 3 years, 7 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/testing/dart/options.dart
diff --git a/tools/testing/dart/options.dart b/tools/testing/dart/options.dart
new file mode 100644
index 0000000000000000000000000000000000000000..685e7c93df36ab32fe097f345557320231c4ad7a
--- /dev/null
+++ b/tools/testing/dart/options.dart
@@ -0,0 +1,916 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'drt_updater.dart';
+import 'test_suite.dart';
+import 'path.dart';
+import 'compiler_configuration.dart' show CompilerConfiguration;
+import 'runtime_configuration.dart' show RuntimeConfiguration;
+
+const _defaultTestSelectors = const [
+ 'samples',
+ 'standalone',
+ 'corelib',
+ 'co19',
+ 'language',
+ 'isolate',
+ 'vm',
+ 'html',
+ 'benchmark_smoke',
+ 'utils',
+ 'lib',
+ 'analyze_library',
+ 'service',
+ 'kernel',
+ 'observatory_ui'
+];
+
+/// Specifies a single command line option.
+///
+/// The name of the specification is used as the key for the option in the Map
+/// returned from the [TestOptionParser] parse method.
+class _Option {
+ // TODO(rnystrom): Some string options use "" to mean "no value" and others
+ // use null. Clean that up.
+ _Option(this.name, this.description,
+ {String abbr, List<String> values, String defaultsTo = ""})
+ : abbreviation = abbr,
+ values = values ?? [],
+ defaultValue = defaultsTo,
+ type = _OptionValueType.string;
+
+ _Option.bool(this.name, this.description, [this.abbreviation])
+ : values = [],
+ defaultValue = false,
+ type = _OptionValueType.bool;
+
+ _Option.int(this.name, this.description, {String abbr, int defaultsTo})
+ : abbreviation = abbr,
+ values = [],
+ defaultValue = defaultsTo,
+ type = _OptionValueType.int;
+
+ final String name;
+ final String description;
+ final String abbreviation;
+ final List<String> values;
+ final Object defaultValue;
+ final _OptionValueType type;
+
+ /// Gets the shortest command line argument used to refer to this option.
+ String get shortCommand => abbreviation != null ? "-$abbreviation" : command;
+
+ /// Gets the canonical long command line argument used to refer to this
+ /// option.
+ String get command => "--${name.replaceAll('_', '-')}";
+}
+
+enum _OptionValueType { bool, int, string }
+
+/// Parses command line arguments and produces a test runner configuration.
+class OptionsParser {
+ static final List<_Option> _options = [
+ new _Option('mode', 'Mode in which to run the tests.',
+ abbr: 'm',
+ values: ['all', 'debug', 'release', 'product'],
+ defaultsTo: 'debug'),
+ new _Option(
+ 'compiler',
+ '''Specify any compilation step (if needed).
+
+none: Do not compile the Dart code (run native Dart code
+ on the VM).
+ (Only valid with runtimes vm, flutter, or drt.)
+
+precompiler: Compile into AOT snapshot before running the test.
+ (Only valid with runtime dart_precompiled.)
+
+dart2js: Compile dart code to JavaScript by running dart2js.
+ (Only valid with runtimes: d8, drt, chrome, safari,
+ ie9, ie10, ie11, firefox, opera, chromeOnAndroid,
+ and none [compile only].)
+
+dart2analyzer: Perform static analysis on Dart code by running the
+ analyzer.
+ (Only valid with runtime none.)
+
+app_jit: Compile the Dart code into an app snapshot before
+ running test.
+ (Only valid with dart_app runtime.)
+
+dartk: Compile the Dart source into Kernel before running
+ test.
+
+dartkp: Compile the Dart source into Kernel and then Kernel
+ into AOT snapshot before running the test.
+ (Only valid with runtime dart_precompiled.)''',
+ abbr: 'c',
+ values: [
+ 'none',
+ 'precompiler',
+ 'dart2js',
+ 'dart2analyzer',
+ 'app_jit',
+ 'dartk',
+ 'dartkp'
+ ],
+ defaultsTo: 'none'),
+ new _Option(
+ 'runtime',
+ '''Where the tests should be run.
+vm: Run Dart code on the standalone dart vm.
+
+flutter: Run Dart code on the flutter engine.
+
+dart_precompiled: Run a precompiled snapshot on a variant of the
+ standalone dart VM lacking a JIT.
+
+d8: Run JavaScript from the command line using v8.
+
+jsshell: Run JavaScript from the command line using
+ Firefox js-shell.
+
+drt: Run Dart or JavaScript in the headless version
+ of Chrome, Content shell.
+
+dartium: Run Dart or JavaScript in Dartium.
+
+ContentShellOnAndroid: Run Dart or JavaScript in Dartium content
+ shell on Android.
+
+DartiumOnAndroid: Run Dart or Javascript in Dartium on Android.
+
+ff:
+chrome:
+safari:
+ie9:
+ie10:
+ie11:
+opera:
+chromeOnAndroid: Run JavaScript in the specified browser.
+
+self_check: Pass each test or its compiled output to every
+ file under `pkg` whose name ends with
+ `_self_check.dart`. Each test is given to the
+ self_check tester as a filename on stdin using
+ the batch-mode protocol.
+
+none: No runtime, compile only. (For example, used
+ for dart2analyzer static analysis tests).''',
+ abbr: 'r',
+ values: [
+ 'vm',
+ 'flutter',
+ 'dart_precompiled',
+ 'd8',
+ 'jsshell',
+ 'drt',
+ 'dartium',
+ 'ff',
+ 'firefox',
+ 'chrome',
+ 'safari',
+ 'ie9',
+ 'ie10',
+ 'ie11',
+ 'opera',
+ 'chromeOnAndroid',
+ 'safarimobilesim',
+ 'ContentShellOnAndroid',
+ 'DartiumOnAndroid',
+ 'self_check',
+ 'none'
+ ],
+ defaultsTo: 'vm'),
+ new _Option(
+ 'arch',
+ '''The architecture to run tests for.
+
+Allowed values are:
+all
+ia32, x64
+arm, armv6, armv5te, arm64,
+simarm, simarmv6, simarmv5te, simarm64,
+mips, simmips
+simdbc, simdbc64''',
+ abbr: 'a',
+ values: [
+ 'all',
+ 'ia32',
+ 'x64',
+ 'arm',
+ 'armv6',
+ 'armv5te',
+ 'arm64',
+ 'mips',
+ 'simarm',
+ 'simarmv6',
+ 'simarmv5te',
+ 'simarm64',
+ 'simmips',
+ 'simdbc',
+ 'simdbc64',
+ ],
+ defaultsTo: 'x64'),
+ new _Option('system', 'The operating system to run tests on.',
+ abbr: 's',
+ values: ['linux', 'macos', 'windows', 'android'],
+ defaultsTo: Platform.operatingSystem),
+ new _Option.bool('checked', 'Run tests in checked mode.'),
+ new _Option.bool('strong', 'Run tests in strong mode.'),
+ new _Option.bool('host_checked', 'Run compiler in checked mode.'),
+ new _Option.bool('minified', 'Enable minification in the compiler.'),
+ new _Option.bool(
+ 'csp', 'Run tests under Content Security Policy restrictions.'),
+ new _Option.bool(
+ 'fast_startup', 'Pass the --fast-startup flag to dart2js.'),
+ new _Option.bool('dart2js_with_kernel',
+ 'Enable the internal pipeline in dart2js to use kernel.'),
+ new _Option.bool('hot_reload', 'Run hot reload stress tests.'),
+ new _Option.bool(
+ 'hot_reload_rollback', 'Run hot reload rollback stress tests.'),
+ new _Option.bool('use_blobs',
+ 'Use mmap instead of shared libraries for precompilation.'),
+ new _Option.int('timeout', 'Timeout in seconds.',
+ abbr: 't', defaultsTo: -1),
+ new _Option(
+ 'progress',
+ '''Progress indication mode.
+
+Allowed values are:
+compact, color, line, verbose, silent, status, buildbot, diff
+''',
+ abbr: 'p',
+ values: [
+ 'compact',
+ 'color',
+ 'line',
+ 'verbose',
+ 'silent',
+ 'status',
+ 'buildbot',
+ 'diff'
+ ],
+ defaultsTo: 'compact'),
+ new _Option('step_name', 'Step name for use by -pbuildbot.',
+ defaultsTo: null),
+ new _Option.bool('report',
+ 'Print a summary report of the number of tests, by expectation.'),
+ new _Option.int('tasks', 'The number of parallel tasks to run.',
+ abbr: 'j', defaultsTo: Platform.numberOfProcessors),
+ new _Option.int('shards',
+ 'The number of instances that the tests will be sharded over.',
+ defaultsTo: 1),
+ new _Option.int(
+ 'shard', 'The index of this instance when running in sharded mode.',
+ defaultsTo: 1),
+ new _Option.bool('help', 'Print list of options.', 'h'),
+ new _Option.bool('verbose', 'Verbose output.', 'v'),
+ new _Option.bool('verify-ir', 'Verify kernel IR.'),
+ new _Option.bool('no-tree-shake', 'Disable kernel IR tree shaking.'),
+ new _Option.bool('list', 'List tests only, do not run them.'),
+ new _Option.bool('report_in_json',
+ 'When listing with --list, output result summary in JSON.'),
+ new _Option.bool('time', 'Print timing information after running tests.'),
+ new _Option('dart', 'Path to dart executable.'),
+ new _Option('flutter', 'Path to flutter executable.'),
+ new _Option(
+ 'drt', // TODO(antonm): fix the option name.
+ 'Path to content shell executable.'),
+ new _Option('dartium', 'Path to Dartium Chrome executable.'),
+ new _Option('firefox', 'Path to firefox browser executable.'),
+ new _Option('chrome', 'Path to chrome browser executable.'),
+ new _Option('safari', 'Path to safari browser executable.'),
+ new _Option.bool(
+ 'use_sdk',
+ '''Use compiler or runtime from the SDK.
+
+Normally, the compiler or runtimes in PRODUCT_DIR is tested, with
+this option, the compiler or runtime in PRODUCT_DIR/dart-sdk/bin
+is tested.
+
+(Note: currently only implemented for dart2js.)'''),
+ new _Option('build_directory',
+ 'The name of the build directory, where products are placed.'),
+ new _Option.bool('noBatch', 'Do not run tests in batch mode.', 'n'),
+ new _Option.bool('dart2js_batch', 'Run dart2js tests in batch mode.'),
+ new _Option.bool(
+ 'append_logs', 'Do not delete old logs but rather append to them.'),
+ new _Option.bool('write_debug_log',
+ 'Don\'t write debug messages to stdout but rather to a logfile.'),
+ new _Option.bool('write_test_outcome_log',
+ 'Write test outcomes to a "${TestUtils.testOutcomeFileName}" file.'),
+ new _Option.bool(
+ 'reset_browser_configuration',
+ '''Browser specific reset of configuration.
+
+Warning: Using this option may remove your bookmarks and other
+settings.'''),
+ new _Option.bool(
+ 'copy_coredumps',
+ '''If we see a crash that we did not expect, copy the core dumps to
+"/tmp".'''),
+ new _Option(
+ 'local_ip',
+ '''IP address the HTTP servers should listen on. This address is also
+used for browsers to connect to.''',
+ defaultsTo: '127.0.0.1'),
+ new _Option.int('test_server_port', 'Port for test http server.',
+ defaultsTo: 0),
+ new _Option.int('test_server_cross_origin_port',
+ 'Port for test http server cross origin.',
+ defaultsTo: 0),
+ new _Option.int('test_driver_port', 'Port for http test driver server.',
+ defaultsTo: 0),
+ new _Option.int(
+ 'test_driver_error_port', 'Port for http test driver server errors.',
+ defaultsTo: 0),
+ new _Option('record_to_file',
+ 'Records all commands to be executed and writes to a file.',
+ defaultsTo: null),
+ new _Option(
+ 'replay_from_file', 'Replays a previously recorded list of commands.',
+ defaultsTo: null),
+ new _Option(
+ 'builder_tag',
+ '''Machine specific options that is not captured by the regular test
+options. Used to be able to make sane updates to the status files.'''),
+ new _Option('vm_options', 'Extra options to send to the vm when running.',
+ defaultsTo: null),
+ new _Option(
+ 'dart2js_options', 'Extra options for dart2js compilation step.',
+ defaultsTo: null),
+ new _Option(
+ 'suite_dir', 'Additional directory to add to the testing matrix.',
+ defaultsTo: null),
+ new _Option('package_root', 'The package root to use for testing.',
+ defaultsTo: null),
+ new _Option('packages', 'The package spec file to use for testing.',
+ defaultsTo: null),
+ new _Option(
+ 'exclude_suite',
+ '''Exclude suites from default selector, only works when no selector
+has been specified on the command line.''',
+ defaultsTo: null),
+ new _Option.bool(
+ 'skip-compilation',
+ '''
+Skip the compilation step, using the compilation artifacts left in
+the output folder from a previous run. This flag will often cause
+false positves and negatives, but can be useful for quick and
+dirty offline testing when not making changes that affect the
+compiler.''')
+ ];
+
+ /// For printing out reproducing command lines, we don't want to add these
+ /// options.
+ static final _blacklistedOptions = [
+ 'append_logs',
+ 'build_directory',
+ 'chrome',
+ 'copy_coredumps',
+ 'dart',
+ 'flutter',
+ 'dartium',
+ 'drt',
+ 'exclude_suite',
+ 'firefox',
+ 'local_ip',
+ 'progress',
+ 'report',
+ 'safari',
+ 'shard',
+ 'shards',
+ 'step_name',
+ 'tasks',
+ 'time',
+ 'verbose',
+ 'write_debug_log',
+ 'write_test_outcome_log',
+ ].toSet();
+
+ /// Parses a list of strings as test options.
+ ///
+ /// Returns a list of configurations in which to run the tests.
+ /// Configurations are maps mapping from option keys to values. When
+ /// encountering the first non-option string, the rest of the arguments are
+ /// stored in the returned Map under the 'rest' key.
+ List<Map> parse(List<String> arguments) {
+ // TODO(rnystrom): The builders on the buildbots still pass this even
Emily Fortuna 2017/05/26 21:17:35 should we file a bug or something? or at least cc
+ // though it does nothing. Until those can be fixed, silently ignore the
+ // option. Remove this once the buildbot scripts are fixed.
+ if (arguments.contains("--failure-summary")) {
+ arguments = arguments.where((arg) => arg != "--failure-summary").toList();
+ print('Note: Ignoring unsupported "--failure-summary" option.');
+ }
+
+ var configuration = {};
+
+ // Fill in configuration with arguments passed to the test script.
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+
+ // Help supersedes all other arguments.
+ if (arg == "--help" || arg == "-h") {
+ _printHelp();
+ return null;
+ }
+
+ // Extract name and value for options.
+ String command;
+ String value;
+ _Option option;
+
+ if (arg.startsWith("--")) {
+ // A long option name.
+ var equals = arg.indexOf("=");
+ if (equals != -1) {
+ // A long option with a value, like "--arch=ia32".
+ command = arg.substring(0, equals);
+ value = arg.substring(equals + 1);
+ } else {
+ command = arg;
+ }
+
+ option = _findByName(command.substring(2));
+ } else if (arg.startsWith("-")) {
+ // An abbreviated option.
+ if (arg.length == 1) {
+ _fail('Missing option name after "-".');
+ }
+
+ command = arg.substring(0, 2);
+
+ if (arg.length > 2) {
+ // An abbreviated option followed by a value, like "-aia32".
+ value = arg.substring(2);
+ }
+
+ option = _findByAbbreviation(command.substring(1));
+ } else {
+ // The argument does not start with "-" or "--" and is therefore not an
+ // option. Use it as a test selector pattern.
+ var patterns = configuration.putIfAbsent("selectors", () => <String>[]);
+ patterns.add(arg);
+ continue;
+ }
+
+ if (option == null) {
+ _fail('Unknown command line option "$command".');
+ }
+
+ // If we need a value, look at the next argument.
+ if (value == null && option.type != _OptionValueType.bool) {
+ if (i + 1 >= arguments.length) {
+ _fail('Missing value for command line option "$command".');
+ }
+ value = arguments[++i];
+ }
+
+ // Multiple uses of a flag are an error, because there is no naturally
+ // correct way to handle conflicting options.
+ if (configuration.containsKey(option.name)) {
+ _fail('Already have value for command line option "$command".');
+ }
+
+ // Parse the value for the option.
+ switch (option.type) {
+ case _OptionValueType.bool:
+ if (value != null) {
+ _fail('Boolean flag "$command" does not take a value.');
+ }
+
+ configuration[option.name] = true;
+ break;
+
+ case _OptionValueType.int:
+ try {
+ configuration[option.name] = int.parse(value);
+ } on FormatException {
+ _fail('Integer value expected for option "$command".');
+ }
+ break;
+
+ case _OptionValueType.string:
+ // Validate against the allowed values.
+ if (!option.values.isEmpty) {
+ for (var v in value.split(",")) {
+ if (!option.values.contains(v)) {
+ _fail('Unknown value "$v" for command line option "$command".');
+ }
+ }
+ }
+
+ // TODO(rnystrom): Store as a list instead of a comma-delimited
+ // string.
+ configuration[option.name] = value;
+ break;
+ }
+ }
+
+ // Apply default values for unspecified options.
+ for (var option in _options) {
+ if (!configuration.containsKey(option.name)) {
+ configuration[option.name] = option.defaultValue;
+ }
+ }
+
+ var expandedConfigs = _expandConfigurations(configuration);
+ var result = expandedConfigs.where(_isValidConfig).toList();
+ for (var config in result) {
+ config['_reproducing_arguments_'] = _reproducingCommand(config);
+ }
+
+ return result.isEmpty ? null : result;
+ }
+
+ /// Prints [message] and exits with a non-zero exit code.
+ void _fail(String message) {
+ print(message);
+ exit(1);
+ }
+
+ /// Given a configuration, returns the list of command line arguments that
+ /// would reproduce that configuration.
+ List<String> _reproducingCommand(Map config) {
+ var arguments = <String>[];
+
+ for (var option in _options) {
+ var name = option.name;
+ if (!config.containsKey(name) || _blacklistedOptions.contains(name)) {
+ continue;
+ }
+
+ var value = config[name];
+ if (config[name] == option.defaultValue ||
+ (name == 'packages' &&
+ value ==
+ TestUtils.dartDirUri.resolve('.packages').toFilePath())) {
+ continue;
+ }
+
+ arguments.add(option.shortCommand);
+ if (option.type != _OptionValueType.bool) {
+ arguments.add(value.toString());
+ }
+ }
+
+ return arguments;
+ }
+
+ /// Determines if a particular configuration has a valid combination of
+ /// compiler and runtime elements.
+ bool _isValidConfig(Map config) {
+ var isValid = true;
+ List<String> validRuntimes;
+ switch (config['compiler']) {
+ case 'dart2js':
+ // Note: by adding 'none' as a configuration, if the user
+ // runs test.py -c dart2js -r drt,none the dart2js_none and
+ // dart2js_drt will be duplicating work. If later we don't need 'none'
+ // with dart2js, we should remove it from here.
+ validRuntimes = const [
+ 'd8',
+ 'jsshell',
+ 'drt',
+ 'none',
+ 'dartium',
+ 'ff',
+ 'chrome',
+ 'safari',
+ 'ie9',
+ 'ie10',
+ 'ie11',
+ 'opera',
+ 'chromeOnAndroid',
+ 'safarimobilesim'
+ ];
+ break;
+ case 'dart2analyzer':
+ validRuntimes = const ['none'];
+ break;
+ case 'app_jit':
+ case 'dartk':
+ validRuntimes = const ['vm', 'self_check', 'none'];
+ break;
+ case 'precompiler':
+ case 'dartkp':
+ validRuntimes = const ['dart_precompiled'];
+ break;
+ case 'none':
+ validRuntimes = const [
+ 'vm',
+ 'flutter',
+ 'drt',
+ 'dartium',
+ 'ContentShellOnAndroid',
+ 'DartiumOnAndroid'
+ ];
+ break;
+ }
+
+ if (!validRuntimes.contains(config['runtime'])) {
+ isValid = false;
+ print("Warning: combination of compiler '${config['compiler']}' and "
+ "runtime '${config['runtime']}' is invalid. "
+ "Skipping this combination.");
+ }
+
+ if (config['ie'] && Platform.operatingSystem != 'windows') {
+ isValid = false;
+ print("Warning: cannot run Internet Explorer on non-Windows operating"
+ " system.");
+ }
+
+ if (config['shard'] < 1 || config['shard'] > config['shards']) {
+ isValid = false;
+ print("Error: shard index is ${config['shard']} out of "
+ "${config['shards']} shards");
+ }
+
+ if (config['runtime'] == 'flutter' && config['flutter'] == '') {
+ isValid = false;
+ print("-rflutter requires the flutter engine executable to "
+ "be specified using --flutter=");
+ }
+
+ if (config['runtime'] == 'flutter' && config['arch'] != 'x64') {
+ isValid = false;
+ print("-rflutter is applicable only for --arch=x64");
+ }
+
+ return isValid;
+ }
+
+ /// Recursively expands a configuration with multiple values per key into a
+ /// list of configurations with exactly one value per key.
+ List<Map> _expandConfigurations(Map configuration) {
+ // Expand the pseudo-values such as 'all'.
+ if (configuration['arch'] == 'all') {
+ configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips,simdbc64';
+ }
+
+ if (configuration['mode'] == 'all') {
+ configuration['mode'] = 'debug,release,product';
+ }
+
+ if (configuration['report_in_json']) {
+ configuration['list'] = true;
+ configuration['report'] = true;
+ }
+
+ // Use verbose progress indication for verbose output unless buildbot
+ // progress indication is requested.
+ if (configuration['verbose'] && configuration['progress'] != 'buildbot') {
+ configuration['progress'] = 'verbose';
+ }
+
+ // Create the artificial negative options that test status files
+ // expect.
+ configuration['unchecked'] = !configuration['checked'];
+ configuration['host_unchecked'] = !configuration['host_checked'];
+ configuration['unminified'] = !configuration['minified'];
+ configuration['nocsp'] = !configuration['csp'];
+
+ String runtime = configuration['runtime'];
+ if (runtime == 'firefox') {
+ configuration['runtime'] == 'ff';
+ }
+
+ String compiler = configuration['compiler'];
+ configuration['browser'] = TestUtils.isBrowserRuntime(runtime);
+ configuration['analyzer'] = TestUtils.isCommandLineAnalyzer(compiler);
+
+ // Set the javascript command line flag for less verbose status files.
+ configuration['jscl'] = TestUtils.isJsCommandLineRuntime(runtime);
+
+ // Allow suppression that is valid for all ie versions
+ configuration['ie'] = runtime.startsWith('ie');
+
+ // Expand the test selectors into a suite name and a simple
+ // regular expressions to be used on the full path of a test file
+ // in that test suite. If no selectors are explicitly given use
+ // the default suite patterns.
+ var selectors = configuration['selectors'];
+ if (selectors is! Map) {
+ if (selectors == null) {
+ if (configuration['suite_dir'] != null) {
+ var suite_path = new Path(configuration['suite_dir']);
+ selectors = [suite_path.filename];
+ } else {
+ selectors = _defaultTestSelectors.toList();
+ }
+
+ var excludeSuites = configuration['exclude_suite'] != null
+ ? configuration['exclude_suite'].split(',')
+ : [];
+ for (var exclude in excludeSuites) {
+ if (selectors.contains(exclude)) {
+ selectors.remove(exclude);
+ } else {
+ print("Warning: default selectors does not contain $exclude");
+ }
+ }
+ }
+ var selectorMap = <String, RegExp>{};
+ for (var i = 0; i < selectors.length; i++) {
+ var pattern = selectors[i];
+ var suite = pattern;
+ var slashLocation = pattern.indexOf('/');
+ if (slashLocation != -1) {
+ suite = pattern.substring(0, slashLocation);
+ pattern = pattern.substring(slashLocation + 1);
+ pattern = pattern.replaceAll('*', '.*');
+ } else {
+ pattern = ".?";
+ }
+ if (selectorMap.containsKey(suite)) {
+ print("Error: '$suite/$pattern'. Only one test selection"
+ " pattern is allowed to start with '$suite/'");
+ exit(1);
+ }
+ selectorMap[suite] = new RegExp(pattern);
+ }
+ configuration['selectors'] = selectorMap;
+ }
+
+ // Put observatory_ui in a configuration with its own packages override.
+ // Only one value in the configuration map is mutable:
+ selectors = configuration['selectors'];
+ if (selectors.containsKey('observatory_ui')) {
+ if (selectors.length == 1) {
+ configuration['packages'] = TestUtils.dartDirUri
+ .resolve('runtime/observatory/.packages')
+ .toFilePath();
+ } else {
+ // Make a new configuration whose selectors map only contains
+ // observatory_ui, and remove the key from the original selectors.
+ // The only mutable value in the map is the selectors, so a
+ // shallow copy is safe.
+ var observatoryConfiguration = new Map.from(configuration);
+ observatoryConfiguration['selectors'] = {
+ 'observatory_ui': selectors['observatory_ui']
+ };
+ selectors.remove('observatory_ui');
+
+ // Set the packages flag.
+ observatoryConfiguration['packages'] = TestUtils.dartDirUri
+ .resolve('runtime/observatory/.packages')
+ .toFilePath();
+
+ // Return the expansions of both configurations. Neither will reach
+ // this line in the recursive call to _expandConfigurations.
+ return _expandConfigurations(configuration)
+ ..addAll(_expandConfigurations(observatoryConfiguration));
+ }
+ }
+
+ // Set the default package spec explicitly.
+ if (configuration['package_root'] == null &&
+ configuration['packages'] == null) {
+ configuration['packages'] =
+ TestUtils.dartDirUri.resolve('.packages').toFilePath();
+ }
+
+ // Expand the architectures.
+ if (configuration['arch'].contains(',')) {
+ return _expandHelper('arch', configuration);
+ }
+
+ // Expand modes.
+ if (configuration['mode'].contains(',')) {
+ return _expandHelper('mode', configuration);
+ }
+
+ // Expand compilers.
+ if (configuration['compiler'].contains(',')) {
+ return _expandHelper('compiler', configuration);
+ }
+
+ // Expand runtimes.
+ var runtimes = configuration['runtime'];
+ if (runtimes.contains(',')) {
+ return _expandHelper('runtime', configuration);
+ } else {
+ // All runtimes eventually go through this path, after expansion.
+ var updater = runtimeUpdater(configuration);
+ if (updater != null) {
+ updater.update();
+ }
+ }
+
+ // Adjust default timeout based on mode, compiler, and sometimes runtime.
+ if (configuration['timeout'] == -1) {
+ var isReload =
+ configuration['hot_reload'] || configuration['hot_reload_rollback'];
+ int compilerMulitiplier =
+ new CompilerConfiguration(configuration).computeTimeoutMultiplier();
+ int runtimeMultiplier = new RuntimeConfiguration(configuration)
+ .computeTimeoutMultiplier(
+ mode: configuration['mode'],
+ isChecked: configuration['checked'],
+ isReload: isReload,
+ arch: configuration['arch']);
+ configuration['timeout'] = 60 * compilerMulitiplier * runtimeMultiplier;
+ }
+
+ return [configuration];
+ }
+
+ /// Helper for _expandConfigurations. Creates a new configuration and adds it
+ /// to a list, for use in a case when a particular configuration has multiple
+ /// results (separated by a ',').
+ /// Arguments:
+ /// option: The particular test option we are expanding.
+ /// configuration: The map containing all test configuration information
+ /// specified.
+ List<Map> _expandHelper(String option, Map configuration) {
+ var result = <Map>[];
+ var configs = configuration[option];
+ for (var config in configs.split(',')) {
+ var newConfiguration = new Map.from(configuration);
+ newConfiguration[option] = config;
+ result.addAll(_expandConfigurations(newConfiguration));
+ }
+ return result;
+ }
+
+ /// Print out usage information.
+ void _printHelp() {
+ var buffer = new StringBuffer();
+
+ buffer.writeln('''usage: dart test.dart [options] [selector]
+
+The optional selector limits the tests that will be run.
+For example, the selector "language/issue", or equivalently
+"language/*issue*", limits to test files matching the regexp
+".*issue.*\\.dart" in the "tests/language" directory.
+
+Options:''');
+
+ for (var option in _options) {
+ if (option.abbreviation != null) {
+ buffer.write("-${option.abbreviation}, ");
+ } else {
+ buffer.write(" ");
+ }
+
+ buffer.write(option.command);
+
+ switch (option.type) {
+ case _OptionValueType.bool:
+ // No value.
+ break;
+ case _OptionValueType.int:
+ buffer.write("=<integer>");
+ break;
+ case _OptionValueType.string:
+ if (option.values.length > 6) {
+ // If there are many options, they won't fit nicely in one line and
+ // should be instead listed in the description.
+ buffer.write("=<...>");
+ } else if (option.values.isNotEmpty) {
+ buffer.write("=<${option.values.join('|')}>");
+ } else {
+ buffer.write("=<string>");
+ }
+ break;
+ }
+
+ if (option.type != _OptionValueType.bool &&
+ option.defaultValue != null &&
+ option.defaultValue != "") {
+ buffer.write(" (defaults to ${option.defaultValue})");
+ }
+
+ buffer.writeln();
+ buffer
+ .writeln(" ${option.description.replaceAll('\n', '\n ')}");
+ buffer.writeln();
+ }
+
+ print(buffer);
+ }
+
+ _Option _findByAbbreviation(String abbreviation) {
+ for (var option in _options) {
+ if (abbreviation == option.abbreviation) return option;
+ }
+
+ return null;
+ }
+
+ _Option _findByName(String name) {
+ for (var option in _options) {
+ if (name == option.name) return option;
+
+ // Allow hyphens instead of underscores as the separator since they are
+ // more common for command line flags.
+ if (name == option.name.replaceAll("_", "-")) return option;
+ }
+
+ return null;
+ }
+}
« 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