OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** Create and return an options parser for the test runner. */ |
| 6 ArgParser getOptionParser() { |
| 7 var parser = new ArgParser(); |
| 8 |
| 9 parser.addOption('help', abbr: '?', |
| 10 help: 'Show usage information.'); |
| 11 |
| 12 parser.addOption('runtime', abbr: 'r', defaultsTo: 'vm', |
| 13 help: 'Where the tests should be run.', |
| 14 allowed: ['vm', 'drt-dart', 'drt-js'], |
| 15 allowedHelp: { |
| 16 'vm': 'Run Dart code natively on the standalone dart vm.', |
| 17 'drt-dart': 'Run Dart code natively in the headless version of\n' |
| 18 'Chrome, DumpRenderTree.', |
| 19 'drt-js': 'Run Dart compiled to JavaScript in the headless version\n' |
| 20 'of Chrome, DumpRenderTree.' |
| 21 }); |
| 22 |
| 23 parser.addFlag('checked', defaultsTo: false, |
| 24 help: 'Run tests in checked mode.'); |
| 25 |
| 26 parser.addOption('timeout', abbr: 't', |
| 27 help: 'Timeout in seconds', defaultsTo: '60'); |
| 28 |
| 29 parser.addOption('tasks', abbr: 'j', |
| 30 defaultsTo: Platform.numberOfProcessors.toString(), |
| 31 help: 'The number of parallel tasks to run.'); |
| 32 |
| 33 parser.addOption('out', abbr: 'o', defaultsTo: 'stdout', |
| 34 help: 'File to send test results. This should be a ' |
| 35 'file name or one of stdout, stderr, or none.'); |
| 36 |
| 37 parser.addOption('list-format', |
| 38 defaultsTo: '${Macros.testfile}${Macros.testGroup}${Macros.testDescription
}', |
| 39 help: 'Format for test list result output.'); |
| 40 |
| 41 parser.addOption('pass-format', |
| 42 defaultsTo: 'PASS ${Macros.testTime}' |
| 43 '${Macros.testfile}${Macros.testGroup}' |
| 44 '${Macros.testDescription}${Macros.testMessage}', |
| 45 help: 'Format for passing test result output.'); |
| 46 |
| 47 parser.addOption('fail-format', |
| 48 defaultsTo: 'FAIL ${Macros.testTime}' |
| 49 '${Macros.testfile}${Macros.testGroup}' |
| 50 '${Macros.testDescription}${Macros.testMessage}', |
| 51 help: 'Format for failed test result output.'); |
| 52 |
| 53 parser.addOption('error-format', |
| 54 defaultsTo: 'ERROR ${Macros.testTime}' |
| 55 '${Macros.testfile}${Macros.testGroup}' |
| 56 '${Macros.testDescription}${Macros.testMessage}', |
| 57 help: 'Format for tests with errors result output.'); |
| 58 |
| 59 parser.addFlag('summary', defaultsTo: false, |
| 60 help: 'Print a summary of tests passed/failed for each test file.'); |
| 61 |
| 62 parser.addOption('log', abbr: 'l', defaultsTo: 'none', |
| 63 help: 'File to send test log/print output to. This should be a ' |
| 64 'file name or one of stdout, stderr, or none.'); |
| 65 |
| 66 // TODO(gram) - add loglevel once we have switched unittest to use the log |
| 67 // library. |
| 68 |
| 69 parser.addFlag('list-files', defaultsTo: false, |
| 70 help: 'List test files only, do not run them.'); |
| 71 |
| 72 parser.addFlag('list-tests', defaultsTo: false, |
| 73 help: 'List tests only, do not run them.'); |
| 74 |
| 75 parser.addFlag('list-groups', defaultsTo: false, |
| 76 help: 'List test groups only, do not run tests.'); |
| 77 |
| 78 parser.addFlag('keep-files', defaultsTo: false, |
| 79 help: 'Keep the generated files in the temporary directory.'); |
| 80 |
| 81 parser.addFlag('list-options', defaultsTo: false, |
| 82 help: 'Print non-default option settings, usable as a test.config.'); |
| 83 |
| 84 parser.addFlag('list-all-options', defaultsTo: false, |
| 85 help: 'Print all option settings, usable as a test.config.'); |
| 86 |
| 87 parser.addFlag('time', |
| 88 help: 'Print timing information after running tests', |
| 89 defaultsTo: false); |
| 90 |
| 91 parser.addFlag('stop-on-failure', defaultsTo: false, |
| 92 help: 'Stop execution upon first failure.'); |
| 93 |
| 94 parser.addFlag('isolate', defaultsTo: false, |
| 95 help: 'Runs each test in a separate isolate.'); |
| 96 |
| 97 parser.addOption('configfile', help: 'Path to an argument file to load.'); |
| 98 |
| 99 parser.addOption('dartsdk', help: 'Path to dart SDK.'); |
| 100 |
| 101 // The defaults here should be the name of the executable, with |
| 102 // the assumption that it is available on the PATH. |
| 103 parser.addOption('dart2js', help: 'Path to dart2js executable.', |
| 104 defaultsTo: 'dart2js'); |
| 105 parser.addOption('dart', help: 'Path to dart executable.', |
| 106 defaultsTo: 'dart'); |
| 107 parser.addOption('drt', help: 'Path to DumpRenderTree executable.', |
| 108 defaultsTo: 'drt'); |
| 109 |
| 110 parser.addOption('tempdir', help: 'Directory to store temp files.', |
| 111 defaultsTo: '${Platform.pathSeparator}tmp' |
| 112 '${Platform.pathSeparator}testrunner'); |
| 113 |
| 114 parser.addOption('test-file-pattern', |
| 115 help: 'A regular expression that test file names must match ' |
| 116 'to be considered', defaultsTo: '_test.dart\$'); |
| 117 |
| 118 parser.addOption('include', |
| 119 help: 'Only run tests from the specified group(s).', |
| 120 allowMultiple: true); |
| 121 |
| 122 parser.addOption('exclude', |
| 123 help: 'Exclude tests from the specified group(s).', |
| 124 allowMultiple: true); |
| 125 |
| 126 parser.addFlag('recurse', abbr: 'R', |
| 127 help: 'Recurse through child directories looking for tests.', |
| 128 defaultsTo: false); |
| 129 |
| 130 parser.addFlag('immediate', |
| 131 help: 'Print test results immediately, instead of at the end of a test ' |
| 132 'file. Note that in some async cases this may result in multiple ' |
| 133 'messages for a single test.', |
| 134 defaultsTo: false); |
| 135 |
| 136 parser.addOption('unittest', help: '#import path for unit test library.'); |
| 137 |
| 138 return parser; |
| 139 } |
| 140 |
| 141 /** Print a value option, quoting it if it has embedded spaces. */ |
| 142 _printValueOption(String name, value, OutputStream stream) { |
| 143 if (value.indexOf(' ') >= 0) { |
| 144 stream.writeString("--$name='$value'\n"); |
| 145 } else { |
| 146 stream.writeString("--$name=$value\n"); |
| 147 } |
| 148 } |
| 149 |
| 150 /** Print the current option values. */ |
| 151 printOptions(ArgParser parser, ArgResults arguments, |
| 152 bool includeDefaults, OutputStream stream) { |
| 153 if (stream == null) return; |
| 154 for (var name in arguments.options) { |
| 155 if (!name.startsWith('list-')) { |
| 156 var value = arguments[name]; |
| 157 var defaultValue = parser.getDefault(name); |
| 158 if (value is bool) { |
| 159 if (includeDefaults || (value != defaultValue)) { |
| 160 stream.writeString('--${value ? "" : "no-"}$name\n'); |
| 161 } |
| 162 } else if (value is List) { |
| 163 if (value.length > 0) { |
| 164 for (var v in value) { |
| 165 _printValueOption(name, v, stream); |
| 166 } |
| 167 } |
| 168 } else if (value != null && (includeDefaults || value != defaultValue)) { |
| 169 _printValueOption(name, value, stream); |
| 170 } |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 /** |
| 176 * Get the test runner configuration. This loads options from multiple |
| 177 * sources, in increasing order of priority: a test.config file in the |
| 178 * current directory, a test config file specified with --configfile on |
| 179 * the command line, and other arguments specified on the command line. |
| 180 */ |
| 181 ArgResults loadConfiguration(optionsParser) { |
| 182 var options = new List(); |
| 183 // We first load options from a test.config file in the working directory. |
| 184 options.addAll(getFileContents('test.config', false). |
| 185 filter((e) => e.trim().length > 0 && e[0] != '#')); |
| 186 // Next we look to see if the command line included a -testconfig argument, |
| 187 // and if so, load options from that file too; where these are not |
| 188 // multi-valued they will take precedence over the ones in test.config. |
| 189 var commandLineArgs = new Options().arguments; |
| 190 var cfgarg = '--configfile'; |
| 191 for (var i = 0; i < commandLineArgs.length; i++) { |
| 192 if (commandLineArgs[i].startsWith(cfgarg)) { |
| 193 if (commandLineArgs[i] == cfgarg) { |
| 194 if (i == commandLineArgs.length - 1) { |
| 195 throw new Exception('Missing argument to $cfgarg'); |
| 196 } |
| 197 options.addAll(getFileContents(commandLineArgs[++i], true). |
| 198 filter((e) => e.trim().length > 0 && e[0] != '#')); |
| 199 } else if (commandLineArgs[i].startsWith('$cfgarg=')) { |
| 200 options.addAll( |
| 201 getFileContents(commandLineArgs[i].substring(cfgarg.length), true). |
| 202 filter((e) => e.trim().length > 0 && e[0] != '#')); |
| 203 } else { |
| 204 throw new Exception('Missing argument to $cfgarg'); |
| 205 } |
| 206 } |
| 207 } |
| 208 // Finally, we add options from the command line. These have the highest |
| 209 // precedence of all. |
| 210 options.addAll(commandLineArgs); |
| 211 // Now try parse the whole collection of options, and if this fails, |
| 212 // issue a usage message. |
| 213 try { |
| 214 return optionsParser.parse(options); |
| 215 } catch (var e) { |
| 216 print(e); |
| 217 print('Usage: testrunner <options> [<directory or file> ...]'); |
| 218 print(optionsParser.getUsage()); |
| 219 return null; |
| 220 } |
| 221 } |
| 222 |
| 223 /** Perform some sanity checking of the configuration. */ |
| 224 bool isSane(ArgResults config) { |
| 225 if (config == null) { |
| 226 return false; |
| 227 } |
| 228 if (config['runtime'] == null) { |
| 229 print('Missing required option --runtime'); |
| 230 return false; |
| 231 } |
| 232 if (config['unittest'] == null) { |
| 233 print('Missing required option --unittest'); |
| 234 return false; |
| 235 } |
| 236 if (config['include'].length > 0 && |
| 237 config['exclude'].length > 0) { |
| 238 print('--include and --exclude are mutually exclusive.'); |
| 239 return false; |
| 240 } |
| 241 return true; |
| 242 } |
| 243 |
| 244 |
OLD | NEW |