OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2016, 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 | |
7 import 'package:args/args.dart'; | |
8 | |
9 import '../../frontend/timeout.dart'; | |
10 import '../../backend/test_platform.dart'; | |
11 import '../../utils.dart'; | |
12 import '../configuration.dart'; | |
13 import 'values.dart'; | |
14 | |
15 /// The parser used to parse the command-line arguments. | |
16 final ArgParser _parser = (() { | |
17 var parser = new ArgParser(allowTrailingOptions: true); | |
18 | |
19 var allPlatforms = TestPlatform.all.toList(); | |
20 if (!Platform.isMacOS) allPlatforms.remove(TestPlatform.safari); | |
21 if (!Platform.isWindows) allPlatforms.remove(TestPlatform.internetExplorer); | |
22 | |
23 parser.addFlag("help", abbr: "h", negatable: false, | |
24 help: "Shows this usage information."); | |
25 parser.addFlag("version", negatable: false, | |
26 help: "Shows the package's version."); | |
27 parser.addOption("package-root", hide: true); | |
28 | |
29 // Note that defaultsTo declarations here are only for documentation purposes. | |
30 // We pass null values rather than defaults to [new Configuration] so that it | |
31 // merges properly with the config file. | |
32 | |
33 parser.addSeparator("======== Selecting Tests"); | |
34 parser.addOption("name", | |
35 abbr: 'n', | |
36 help: 'A substring of the name of the test to run.\n' | |
37 'Regular expression syntax is supported.'); | |
38 parser.addOption("plain-name", | |
39 abbr: 'N', | |
40 help: 'A plain-text substring of the name of the test to run.'); | |
41 // TODO(nweiz): Support the full platform-selector syntax for choosing which | |
42 // tags to run. In the shorter term, disallow non-"identifier" tags. | |
43 parser.addOption("tags", | |
44 abbr: 't', | |
45 help: 'Run only tests with all of the specified tags.', | |
46 allowMultiple: true); | |
47 parser.addOption("tag", hide: true, allowMultiple: true); | |
48 parser.addOption("exclude-tags", | |
49 abbr: 'x', | |
50 help: "Don't run tests with any of the specified tags.", | |
51 allowMultiple: true); | |
52 parser.addOption("exclude-tag", hide: true, allowMultiple: true); | |
53 | |
54 parser.addSeparator("======== Running Tests"); | |
55 parser.addOption("platform", | |
56 abbr: 'p', | |
57 help: 'The platform(s) on which to run the tests.', | |
58 defaultsTo: 'vm', | |
59 allowed: allPlatforms.map((platform) => platform.identifier).toList(), | |
60 allowMultiple: true); | |
61 parser.addOption("concurrency", | |
62 abbr: 'j', | |
63 help: 'The number of concurrent test suites run.', | |
64 defaultsTo: defaultConcurrency, | |
kevmoo
2016/02/03 23:01:56
defaultConcurrency must be a String
| |
65 valueHelp: 'threads'); | |
66 parser.addOption("pub-serve", | |
67 help: 'The port of a pub serve instance serving "test/".', | |
68 valueHelp: 'port'); | |
69 parser.addOption("timeout", | |
70 help: 'The default test timeout. For example: 15s, 2x, none', | |
71 defaultsTo: '30s'); | |
72 parser.addFlag("pause-after-load", | |
73 help: 'Pauses for debugging before any tests execute.\n' | |
74 'Implies --concurrency=1 and --timeout=none.\n' | |
75 'Currently only supported for browser tests.', | |
76 negatable: false); | |
77 | |
78 parser.addSeparator("======== Output"); | |
79 parser.addOption("reporter", | |
80 abbr: 'r', | |
81 help: 'The runner used to print test results.', | |
82 defaultsTo: defaultReporter, | |
83 allowed: allReporters, | |
84 allowedHelp: { | |
85 'compact': 'A single line, updated continuously.', | |
86 'expanded': 'A separate line for each update.', | |
87 'json': 'A machine-readable format (see https://goo.gl/0HRhdZ).' | |
88 }); | |
89 parser.addFlag("verbose-trace", negatable: false, | |
90 help: 'Whether to emit stack traces with core library frames.'); | |
91 parser.addFlag("js-trace", negatable: false, | |
92 help: 'Whether to emit raw JavaScript stack traces for browser tests.'); | |
93 parser.addFlag("color", | |
94 help: 'Whether to use terminal colors.\n(auto-detected by default)'); | |
95 | |
96 return parser; | |
97 })(); | |
98 | |
99 /// The usage string for the command-line arguments. | |
100 String get usage => _parser.usage; | |
101 | |
102 /// Parses the configuration from [args]. | |
103 /// | |
104 /// Throws a [FormatException] if [args] are invalid. | |
105 Configuration parse(List<String> args) { | |
106 var options = _parser.parse(args); | |
107 | |
108 var pattern; | |
109 if (options['name'] != null) { | |
110 if (options["plain-name"] != null) { | |
111 throw new FormatException( | |
112 "--name and --plain-name may not both be passed."); | |
113 } | |
114 | |
115 pattern = _wrapFormatException( | |
116 options, 'name', (value) => new RegExp(value)); | |
117 } else if (options['plain-name'] != null) { | |
118 pattern = options['plain-name']; | |
119 } | |
120 | |
121 var tags = new Set(); | |
122 tags.addAll(options['tags'] ?? []); | |
123 tags.addAll(options['tag'] ?? []); | |
124 | |
125 var excludeTags = new Set(); | |
126 excludeTags.addAll(options['exclude-tags'] ?? []); | |
127 excludeTags.addAll(options['exclude-tag'] ?? []); | |
128 | |
129 var tagIntersection = tags.intersection(excludeTags); | |
130 if (tagIntersection.isNotEmpty) { | |
131 throw new FormatException( | |
132 'The ${pluralize('tag', tagIntersection.length)} ' | |
133 '${toSentence(tagIntersection)} ' | |
134 '${pluralize('was', tagIntersection.length, plural: 'were')} ' | |
135 'both included and excluded.'); | |
136 } | |
137 | |
138 // If the user hasn't explicitly chosen a value, we want to pass null values | |
139 // to [new Configuration] so that it considers those fields unset when merging | |
140 // with configuration from the config file. | |
141 ifParsed(name) => options.wasParsed(name) ? options[name] : null; | |
142 | |
143 return new Configuration( | |
144 help: ifParsed('help'), | |
145 version: ifParsed('version'), | |
146 verboseTrace: ifParsed('verbose-trace'), | |
147 jsTrace: ifParsed('js-trace'), | |
148 pauseAfterLoad: ifParsed('pause-after-load'), | |
149 color: ifParsed('color'), | |
150 packageRoot: ifParsed('package-root'), | |
151 reporter: ifParsed('reporter'), | |
152 pubServePort: _wrapFormatException(options, 'pub-serve', int.parse), | |
153 concurrency: _wrapFormatException(options, 'concurrency', int.parse), | |
154 timeout: _wrapFormatException(options, 'timeout', | |
155 (value) => new Timeout.parse(value)), | |
156 pattern: pattern, | |
157 platforms: ifParsed('platform')?.map(TestPlatform.find), | |
158 paths: options.rest.isEmpty ? null : options.rest, | |
159 tags: tags, | |
160 excludeTags: excludeTags); | |
161 } | |
162 | |
163 /// Runs [parse] on the value of the option [name], and wraps any | |
164 /// [FormatException] it throws with additional information. | |
165 _wrapFormatException(ArgResults options, String name, parse(value)) { | |
166 if (!options.wasParsed(name)) return null; | |
167 | |
168 var value = options[name]; | |
169 if (value == null) return null; | |
170 | |
171 try { | |
172 return parse(value); | |
173 } on FormatException catch (error) { | |
174 throw new FormatException('Couldn\'t parse --$name "${options[name]}": ' | |
175 '${error.message}'); | |
176 } | |
177 } | |
OLD | NEW |