OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:io'; | 5 import 'dart:io'; |
6 | 6 |
7 import 'package:args/args.dart'; | 7 import 'package:args/args.dart'; |
| 8 import 'package:boolean_selector/boolean_selector.dart'; |
8 | 9 |
9 import '../../backend/test_platform.dart'; | 10 import '../../backend/test_platform.dart'; |
10 import '../../frontend/timeout.dart'; | 11 import '../../frontend/timeout.dart'; |
11 import '../../utils.dart'; | |
12 import '../configuration.dart'; | 12 import '../configuration.dart'; |
13 import 'values.dart'; | 13 import 'values.dart'; |
14 | 14 |
15 /// The parser used to parse the command-line arguments. | 15 /// The parser used to parse the command-line arguments. |
16 final ArgParser _parser = (() { | 16 final ArgParser _parser = (() { |
17 var parser = new ArgParser(allowTrailingOptions: true); | 17 var parser = new ArgParser(allowTrailingOptions: true); |
18 | 18 |
19 var allPlatforms = TestPlatform.all.toList(); | 19 var allPlatforms = TestPlatform.all.toList(); |
20 if (!Platform.isMacOS) allPlatforms.remove(TestPlatform.safari); | 20 if (!Platform.isMacOS) allPlatforms.remove(TestPlatform.safari); |
21 if (!Platform.isWindows) allPlatforms.remove(TestPlatform.internetExplorer); | 21 if (!Platform.isWindows) allPlatforms.remove(TestPlatform.internetExplorer); |
(...skipping 13 matching lines...) Expand all Loading... |
35 abbr: 'n', | 35 abbr: 'n', |
36 help: 'A substring of the name of the test to run.\n' | 36 help: 'A substring of the name of the test to run.\n' |
37 'Regular expression syntax is supported.'); | 37 'Regular expression syntax is supported.'); |
38 parser.addOption("plain-name", | 38 parser.addOption("plain-name", |
39 abbr: 'N', | 39 abbr: 'N', |
40 help: 'A plain-text substring of the name of the test to run.'); | 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 | 41 // TODO(nweiz): Support the full platform-selector syntax for choosing which |
42 // tags to run. In the shorter term, disallow non-"identifier" tags. | 42 // tags to run. In the shorter term, disallow non-"identifier" tags. |
43 parser.addOption("tags", | 43 parser.addOption("tags", |
44 abbr: 't', | 44 abbr: 't', |
45 help: 'Run only tests with all of the specified tags.', | 45 help: 'Run only tests with all of the specified tags.\n' |
| 46 'Supports boolean selector syntax.', |
46 allowMultiple: true); | 47 allowMultiple: true); |
47 parser.addOption("tag", hide: true, allowMultiple: true); | 48 parser.addOption("tag", hide: true, allowMultiple: true); |
48 parser.addOption("exclude-tags", | 49 parser.addOption("exclude-tags", |
49 abbr: 'x', | 50 abbr: 'x', |
50 help: "Don't run tests with any of the specified tags.", | 51 help: "Don't run tests with any of the specified tags.\n" |
| 52 "Supports boolean selector syntax.", |
51 allowMultiple: true); | 53 allowMultiple: true); |
52 parser.addOption("exclude-tag", hide: true, allowMultiple: true); | 54 parser.addOption("exclude-tag", hide: true, allowMultiple: true); |
53 | 55 |
54 parser.addSeparator("======== Running Tests"); | 56 parser.addSeparator("======== Running Tests"); |
55 parser.addOption("platform", | 57 parser.addOption("platform", |
56 abbr: 'p', | 58 abbr: 'p', |
57 help: 'The platform(s) on which to run the tests.', | 59 help: 'The platform(s) on which to run the tests.', |
58 defaultsTo: 'vm', | 60 defaultsTo: 'vm', |
59 allowed: allPlatforms.map((platform) => platform.identifier).toList(), | 61 allowed: allPlatforms.map((platform) => platform.identifier).toList(), |
60 allowMultiple: true); | 62 allowMultiple: true); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 throw new FormatException( | 113 throw new FormatException( |
112 "--name and --plain-name may not both be passed."); | 114 "--name and --plain-name may not both be passed."); |
113 } | 115 } |
114 | 116 |
115 pattern = _wrapFormatException( | 117 pattern = _wrapFormatException( |
116 options, 'name', (value) => new RegExp(value)); | 118 options, 'name', (value) => new RegExp(value)); |
117 } else if (options['plain-name'] != null) { | 119 } else if (options['plain-name'] != null) { |
118 pattern = options['plain-name']; | 120 pattern = options['plain-name']; |
119 } | 121 } |
120 | 122 |
121 var tags = new Set(); | 123 var includeTagSet = new Set.from(options['tags'] ?? []) |
122 tags.addAll(options['tags'] ?? []); | 124 ..addAll(options['tag'] ?? []); |
123 tags.addAll(options['tag'] ?? []); | |
124 | 125 |
125 var excludeTags = new Set(); | 126 var includeTags = includeTagSet.fold(BooleanSelector.all, (selector, tag) { |
126 excludeTags.addAll(options['exclude-tags'] ?? []); | 127 var tagSelector = new BooleanSelector.parse(tag); |
127 excludeTags.addAll(options['exclude-tag'] ?? []); | 128 return selector.intersection(tagSelector); |
| 129 }); |
128 | 130 |
129 var tagIntersection = tags.intersection(excludeTags); | 131 var excludeTagSet = new Set.from(options['exclude-tags'] ?? []) |
130 if (tagIntersection.isNotEmpty) { | 132 ..addAll(options['exclude-tag'] ?? []); |
131 throw new FormatException( | 133 |
132 'The ${pluralize('tag', tagIntersection.length)} ' | 134 var excludeTags = excludeTagSet.fold(BooleanSelector.none, (selector, tag) { |
133 '${toSentence(tagIntersection)} ' | 135 var tagSelector = new BooleanSelector.parse(tag); |
134 '${pluralize('was', tagIntersection.length, plural: 'were')} ' | 136 return selector.union(tagSelector); |
135 'both included and excluded.'); | 137 }); |
136 } | |
137 | 138 |
138 // If the user hasn't explicitly chosen a value, we want to pass null values | 139 // 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 // to [new Configuration] so that it considers those fields unset when merging |
140 // with configuration from the config file. | 141 // with configuration from the config file. |
141 ifParsed(name) => options.wasParsed(name) ? options[name] : null; | 142 ifParsed(name) => options.wasParsed(name) ? options[name] : null; |
142 | 143 |
143 return new Configuration( | 144 return new Configuration( |
144 help: ifParsed('help'), | 145 help: ifParsed('help'), |
145 version: ifParsed('version'), | 146 version: ifParsed('version'), |
146 verboseTrace: ifParsed('verbose-trace'), | 147 verboseTrace: ifParsed('verbose-trace'), |
147 jsTrace: ifParsed('js-trace'), | 148 jsTrace: ifParsed('js-trace'), |
148 pauseAfterLoad: ifParsed('pause-after-load'), | 149 pauseAfterLoad: ifParsed('pause-after-load'), |
149 color: ifParsed('color'), | 150 color: ifParsed('color'), |
150 packageRoot: ifParsed('package-root'), | 151 packageRoot: ifParsed('package-root'), |
151 reporter: ifParsed('reporter'), | 152 reporter: ifParsed('reporter'), |
152 pubServePort: _wrapFormatException(options, 'pub-serve', int.parse), | 153 pubServePort: _wrapFormatException(options, 'pub-serve', int.parse), |
153 concurrency: _wrapFormatException(options, 'concurrency', int.parse), | 154 concurrency: _wrapFormatException(options, 'concurrency', int.parse), |
154 timeout: _wrapFormatException(options, 'timeout', | 155 timeout: _wrapFormatException(options, 'timeout', |
155 (value) => new Timeout.parse(value)), | 156 (value) => new Timeout.parse(value)), |
156 pattern: pattern, | 157 pattern: pattern, |
157 platforms: ifParsed('platform')?.map(TestPlatform.find), | 158 platforms: ifParsed('platform')?.map(TestPlatform.find), |
158 paths: options.rest.isEmpty ? null : options.rest, | 159 paths: options.rest.isEmpty ? null : options.rest, |
159 includeTags: tags, | 160 includeTags: includeTags, |
160 excludeTags: excludeTags); | 161 excludeTags: excludeTags); |
161 } | 162 } |
162 | 163 |
163 /// Runs [parse] on the value of the option [name], and wraps any | 164 /// Runs [parse] on the value of the option [name], and wraps any |
164 /// [FormatException] it throws with additional information. | 165 /// [FormatException] it throws with additional information. |
165 _wrapFormatException(ArgResults options, String name, parse(value)) { | 166 _wrapFormatException(ArgResults options, String name, parse(value)) { |
166 if (!options.wasParsed(name)) return null; | 167 if (!options.wasParsed(name)) return null; |
167 | 168 |
168 var value = options[name]; | 169 var value = options[name]; |
169 if (value == null) return null; | 170 if (value == null) return null; |
170 | 171 |
171 try { | 172 try { |
172 return parse(value); | 173 return parse(value); |
173 } on FormatException catch (error) { | 174 } on FormatException catch (error) { |
174 throw new FormatException('Couldn\'t parse --$name "${options[name]}": ' | 175 throw new FormatException('Couldn\'t parse --$name "${options[name]}": ' |
175 '${error.message}'); | 176 '${error.message}'); |
176 } | 177 } |
177 } | 178 } |
OLD | NEW |