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

Side by Side Diff: lib/src/runner/configuration.dart

Issue 1782473005: Add support for configuration presets. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 4 years, 9 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 | « lib/src/executable.dart ('k') | lib/src/runner/configuration/args.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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:boolean_selector/boolean_selector.dart'; 7 import 'package:boolean_selector/boolean_selector.dart';
8 import 'package:collection/collection.dart'; 8 import 'package:collection/collection.dart';
9 import 'package:glob/glob.dart'; 9 import 'package:glob/glob.dart';
10 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
11 11
12 import '../backend/metadata.dart'; 12 import '../backend/metadata.dart';
13 import '../backend/platform_selector.dart'; 13 import '../backend/platform_selector.dart';
14 import '../backend/test_platform.dart'; 14 import '../backend/test_platform.dart';
15 import '../frontend/timeout.dart'; 15 import '../frontend/timeout.dart';
16 import '../util/io.dart'; 16 import '../util/io.dart';
17 import '../utils.dart'; 17 import '../utils.dart';
18 import 'configuration/args.dart' as args; 18 import 'configuration/args.dart' as args;
19 import 'configuration/load.dart'; 19 import 'configuration/load.dart';
20 import 'configuration/values.dart'; 20 import 'configuration/values.dart';
21 21
22 /// A class that encapsulates the command-line configuration of the test runner. 22 /// A class that encapsulates the command-line configuration of the test runner.
23 class Configuration { 23 class Configuration {
24 /// An empty configuration with only default values.
25 ///
26 /// Using this is slightly more efficient than manually constructing a new
27 /// configuration with no arguments.
28 static final empty = new Configuration._();
29
24 /// The usage string for the command-line arguments. 30 /// The usage string for the command-line arguments.
25 static String get usage => args.usage; 31 static String get usage => args.usage;
26 32
27 /// Whether `--help` was passed. 33 /// Whether `--help` was passed.
28 bool get help => _help ?? false; 34 bool get help => _help ?? false;
29 final bool _help; 35 final bool _help;
30 36
31 /// Whether `--version` was passed. 37 /// Whether `--version` was passed.
32 bool get version => _version ?? false; 38 bool get version => _version ?? false;
33 final bool _version; 39 final bool _version;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 final Glob _filename; 106 final Glob _filename;
101 107
102 /// The pattern to match against test names to decide which to run, or `null` 108 /// The pattern to match against test names to decide which to run, or `null`
103 /// if all tests should be run. 109 /// if all tests should be run.
104 final Pattern pattern; 110 final Pattern pattern;
105 111
106 /// The set of platforms on which to run tests. 112 /// The set of platforms on which to run tests.
107 List<TestPlatform> get platforms => _platforms ?? [TestPlatform.vm]; 113 List<TestPlatform> get platforms => _platforms ?? [TestPlatform.vm];
108 final List<TestPlatform> _platforms; 114 final List<TestPlatform> _platforms;
109 115
116 /// The set of presets to use.
117 ///
118 /// Any chosen presets for the parent configuration are added to the chosen
119 /// preset sets for child configurations as well.
120 ///
121 /// Note that the order of this set matters.
122 final Set<String> chosenPresets;
123
110 /// Only run tests whose tags match this selector. 124 /// Only run tests whose tags match this selector.
111 /// 125 ///
112 /// When [merge]d, this is intersected with the other configuration's included 126 /// When [merge]d, this is intersected with the other configuration's included
113 /// tags. 127 /// tags.
114 final BooleanSelector includeTags; 128 final BooleanSelector includeTags;
115 129
116 /// Do not run tests whose tags match this selector. 130 /// Do not run tests whose tags match this selector.
117 /// 131 ///
118 /// When [merge]d, this is unioned with the other configuration's 132 /// When [merge]d, this is unioned with the other configuration's
119 /// excluded tags. 133 /// excluded tags.
(...skipping 15 matching lines...) Expand all
135 Metadata get metadata => new Metadata( 149 Metadata get metadata => new Metadata(
136 timeout: timeout, 150 timeout: timeout,
137 verboseTrace: verboseTrace, 151 verboseTrace: verboseTrace,
138 skip: skip, 152 skip: skip,
139 skipReason: skipReason, 153 skipReason: skipReason,
140 testOn: testOn, 154 testOn: testOn,
141 tags: addTags, 155 tags: addTags,
142 forTag: mapMap(tags, value: (_, config) => config.metadata), 156 forTag: mapMap(tags, value: (_, config) => config.metadata),
143 onPlatform: mapMap(onPlatform, value: (_, config) => config.metadata)); 157 onPlatform: mapMap(onPlatform, value: (_, config) => config.metadata));
144 158
145 /// The set of tags that have been declaredin any way in this configuration. 159 /// The set of tags that have been declared in any way in this configuration.
146 Set<String> get knownTags { 160 Set<String> get knownTags {
147 if (_knownTags != null) return _knownTags; 161 if (_knownTags != null) return _knownTags;
148 162
149 var known = includeTags.variables.toSet() 163 var known = includeTags.variables.toSet()
150 ..addAll(excludeTags.variables) 164 ..addAll(excludeTags.variables)
151 ..addAll(addTags); 165 ..addAll(addTags);
152 tags.forEach((selector, config) { 166
167 for (var selector in tags.keys) {
153 known.addAll(selector.variables); 168 known.addAll(selector.variables);
154 known.addAll(config.knownTags); 169 }
155 }); 170
171 for (var configuration in _children) {
172 known.addAll(configuration.knownTags);
173 }
156 174
157 _knownTags = new UnmodifiableSetView(known); 175 _knownTags = new UnmodifiableSetView(known);
158 return _knownTags; 176 return _knownTags;
159 } 177 }
160 Set<String> _knownTags; 178 Set<String> _knownTags;
161 179
162 /// Configuration for particular platforms. 180 /// Configuration for particular platforms.
163 /// 181 ///
164 /// The keys are platform selectors, and the values are configurations for 182 /// The keys are platform selectors, and the values are configurations for
165 /// those platforms. These configuration should only contain test-level 183 /// those platforms. These configuration should only contain test-level
166 /// configuration fields, but that isn't enforced. 184 /// configuration fields, but that isn't enforced.
167 final Map<PlatformSelector, Configuration> onPlatform; 185 final Map<PlatformSelector, Configuration> onPlatform;
168 186
187 /// Configuration presets.
188 ///
189 /// These are configurations that can be explicitly selected by the user via
190 /// the command line. Preset configuration takes precedence over the base
191 /// configuration.
192 ///
193 /// This is guaranteed not to have any keys that match [chosenPresets]; those
194 /// are resolved when the configuration is constructed.
195 final Map<String, Configuration> presets;
196
197 /// All preset names that are known to be valid.
198 ///
199 /// This includes presets that have already been resolved.
200 Set<String> get knownPresets {
201 if (_knownPresets != null) return _knownPresets;
202
203 var known = presets.keys.toSet();
204 for (var configuration in _children) {
205 known.addAll(configuration.knownPresets);
206 }
207
208 _knownPresets = new UnmodifiableSetView(known);
209 return _knownPresets;
210 }
211 Set<String> _knownPresets;
212
213 /// All child configurations of [this] that may be selected under various
214 /// circumstances.
215 Iterable<Configuration> get _children sync* {
216 yield* tags.values;
217 yield* onPlatform.values;
218 yield* presets.values;
219 }
220
169 /// Parses the configuration from [args]. 221 /// Parses the configuration from [args].
170 /// 222 ///
171 /// Throws a [FormatException] if [args] are invalid. 223 /// Throws a [FormatException] if [args] are invalid.
172 factory Configuration.parse(List<String> arguments) => args.parse(arguments); 224 factory Configuration.parse(List<String> arguments) => args.parse(arguments);
173 225
174 /// Loads the configuration from [path]. 226 /// Loads the configuration from [path].
175 /// 227 ///
176 /// Throws an [IOException] if [path] does not exist or cannot be read. Throws 228 /// Throws an [IOException] if [path] does not exist or cannot be read. Throws
177 /// a [FormatException] if its contents are invalid. 229 /// a [FormatException] if its contents are invalid.
178 factory Configuration.load(String path) => load(path); 230 factory Configuration.load(String path) => load(path);
179 231
180 Configuration({ 232 factory Configuration({
233 bool help,
234 bool version,
235 bool verboseTrace,
236 bool jsTrace,
237 bool skip,
238 String skipReason,
239 PlatformSelector testOn,
240 bool pauseAfterLoad,
241 bool color,
242 String packageRoot,
243 String reporter,
244 int pubServePort,
245 int concurrency,
246 Timeout timeout,
247 Pattern pattern,
248 Iterable<TestPlatform> platforms,
249 Iterable<String> paths,
250 Glob filename,
251 Iterable<String> chosenPresets,
252 BooleanSelector includeTags,
253 BooleanSelector excludeTags,
254 Iterable addTags,
255 Map<BooleanSelector, Configuration> tags,
256 Map<PlatformSelector, Configuration> onPlatform,
257 Map<String, Configuration> presets}) {
258 _unresolved() => new Configuration._(
259 help: help,
260 version: version,
261 verboseTrace: verboseTrace,
262 jsTrace: jsTrace,
263 skip: skip,
264 skipReason: skipReason,
265 testOn: testOn,
266 pauseAfterLoad: pauseAfterLoad,
267 color: color,
268 packageRoot: packageRoot,
269 reporter: reporter,
270 pubServePort: pubServePort,
271 concurrency: concurrency,
272 timeout: timeout,
273 pattern: pattern,
274 platforms: platforms,
275 paths: paths,
276 filename: filename,
277 chosenPresets: chosenPresets,
278 includeTags: includeTags,
279 excludeTags: excludeTags,
280 addTags: addTags,
281
282 // Make sure we pass [chosenPresets] to the child configurations as
283 // well. This ensures that
284 tags: _withChosenPresets(tags, chosenPresets),
285 onPlatform: _withChosenPresets(onPlatform, chosenPresets),
286 presets: _withChosenPresets(presets, chosenPresets));
287
288 if (chosenPresets == null) return _unresolved();
289 chosenPresets = new Set.from(chosenPresets);
290
291 if (presets == null) return _unresolved();
292 presets = new Map.from(presets);
293
294 var knownPresets = presets.keys.toSet();
295
296 var merged = chosenPresets.fold(Configuration.empty, (merged, preset) {
297 if (!presets.containsKey(preset)) return merged;
298 return merged.merge(presets.remove(preset));
299 });
300
301 var result = merged == Configuration.empty
302 ? _unresolved()
303 : _unresolved().merge(merged);
304
305 // Make sure the configuration knows about presets that were selected and
306 // thus removed from [presets].
307 result._knownPresets = result.knownPresets.union(knownPresets);
308
309 return result;
310 }
311
312 static Map<Object, Configuration> _withChosenPresets(
313 Map<Object, Configuration> map, Set<String> chosenPresets) {
314 if (map == null || chosenPresets == null) return map;
315 return mapMap(map, value: (_, config) => config.change(
316 chosenPresets: config.chosenPresets.union(chosenPresets)));
317 }
318
319 /// Creates new Configuration.
320 ///
321 /// Unlike [new Configuration], this assumes [presets] is already resolved.
322 Configuration._({
181 bool help, 323 bool help,
182 bool version, 324 bool version,
183 bool verboseTrace, 325 bool verboseTrace,
184 bool jsTrace, 326 bool jsTrace,
185 bool skip, 327 bool skip,
186 this.skipReason, 328 this.skipReason,
187 PlatformSelector testOn, 329 PlatformSelector testOn,
188 bool pauseAfterLoad, 330 bool pauseAfterLoad,
189 bool color, 331 bool color,
190 String packageRoot, 332 String packageRoot,
191 String reporter, 333 String reporter,
192 int pubServePort, 334 int pubServePort,
193 int concurrency, 335 int concurrency,
194 Timeout timeout, 336 Timeout timeout,
195 this.pattern, 337 this.pattern,
196 Iterable<TestPlatform> platforms, 338 Iterable<TestPlatform> platforms,
197 Iterable<String> paths, 339 Iterable<String> paths,
198 Glob filename, 340 Glob filename,
341 Iterable<String> chosenPresets,
199 BooleanSelector includeTags, 342 BooleanSelector includeTags,
200 BooleanSelector excludeTags, 343 BooleanSelector excludeTags,
201 Iterable addTags, 344 Iterable addTags,
202 Map<BooleanSelector, Configuration> tags, 345 Map<BooleanSelector, Configuration> tags,
203 Map<PlatformSelector, Configuration> onPlatform}) 346 Map<PlatformSelector, Configuration> onPlatform,
347 Map<String, Configuration> presets})
204 : _help = help, 348 : _help = help,
205 _version = version, 349 _version = version,
206 _verboseTrace = verboseTrace, 350 _verboseTrace = verboseTrace,
207 _jsTrace = jsTrace, 351 _jsTrace = jsTrace,
208 _skip = skip, 352 _skip = skip,
209 testOn = testOn ?? PlatformSelector.all, 353 testOn = testOn ?? PlatformSelector.all,
210 _pauseAfterLoad = pauseAfterLoad, 354 _pauseAfterLoad = pauseAfterLoad,
211 _color = color, 355 _color = color,
212 _packageRoot = packageRoot, 356 _packageRoot = packageRoot,
213 _reporter = reporter, 357 _reporter = reporter,
214 pubServeUrl = pubServePort == null 358 pubServeUrl = pubServePort == null
215 ? null 359 ? null
216 : Uri.parse("http://localhost:$pubServePort"), 360 : Uri.parse("http://localhost:$pubServePort"),
217 _concurrency = concurrency, 361 _concurrency = concurrency,
218 timeout = (pauseAfterLoad ?? false) 362 timeout = (pauseAfterLoad ?? false)
219 ? Timeout.none 363 ? Timeout.none
220 : (timeout == null ? new Timeout.factor(1) : timeout), 364 : (timeout == null ? new Timeout.factor(1) : timeout),
221 _platforms = _list(platforms), 365 _platforms = _list(platforms),
222 _paths = _list(paths), 366 _paths = _list(paths),
223 _filename = filename, 367 _filename = filename,
368 chosenPresets = new Set.from(chosenPresets ?? []),
224 includeTags = includeTags ?? BooleanSelector.all, 369 includeTags = includeTags ?? BooleanSelector.all,
225 excludeTags = excludeTags ?? BooleanSelector.none, 370 excludeTags = excludeTags ?? BooleanSelector.none,
226 addTags = addTags?.toSet() ?? new Set(), 371 addTags = new UnmodifiableSetView(addTags?.toSet() ?? new Set()),
227 tags = tags == null ? const {} : new Map.unmodifiable(tags), 372 tags = _map(tags),
228 onPlatform = onPlatform == null 373 onPlatform = _map(onPlatform),
229 ? const {} 374 presets = _map(presets) {
230 : new Map.unmodifiable(onPlatform) {
231 if (_filename != null && _filename.context.style != p.style) { 375 if (_filename != null && _filename.context.style != p.style) {
232 throw new ArgumentError( 376 throw new ArgumentError(
233 "filename's context must match the current operating system, was " 377 "filename's context must match the current operating system, was "
234 "${_filename.context.style}."); 378 "${_filename.context.style}.");
235 } 379 }
236 } 380 }
237 381
238 /// Returns a [input] as a list or `null`. 382 /// Returns a [input] as an unmodifiable list or `null`.
239 /// 383 ///
240 /// If [input] is `null` or empty, this returns `null`. Otherwise, it returns 384 /// If [input] is `null` or empty, this returns `null`. Otherwise, it returns
241 /// `input.toList()`. 385 /// `input.toList()`.
242 static List _list(Iterable input) { 386 static List _list(Iterable input) {
243 if (input == null) return null; 387 if (input == null) return null;
244 input = input.toList(); 388 input = new List.unmodifiable(input);
245 if (input.isEmpty) return null; 389 if (input.isEmpty) return null;
246 return input; 390 return input;
247 } 391 }
248 392
393 /// Returns an modifiable copy of [input] or an empty unmodifiable map.
394 static Map _map(Map input) {
395 if (input == null) return const {};
396 return new Map.unmodifiable(input);
397 }
398
249 /// Merges this with [other]. 399 /// Merges this with [other].
250 /// 400 ///
251 /// For most fields, if both configurations have values set, [other]'s value 401 /// For most fields, if both configurations have values set, [other]'s value
252 /// takes precedence. However, certain fields are merged together instead. 402 /// takes precedence. However, certain fields are merged together instead.
253 /// This is indicated in those fields' documentation. 403 /// This is indicated in those fields' documentation.
254 Configuration merge(Configuration other) { 404 Configuration merge(Configuration other) {
255 return new Configuration( 405 if (this == Configuration.empty) return other;
406 if (other == Configuration.empty) return this;
407
408 var result = new Configuration(
256 help: other._help ?? _help, 409 help: other._help ?? _help,
257 version: other._version ?? _version, 410 version: other._version ?? _version,
258 verboseTrace: other._verboseTrace ?? _verboseTrace, 411 verboseTrace: other._verboseTrace ?? _verboseTrace,
259 jsTrace: other._jsTrace ?? _jsTrace, 412 jsTrace: other._jsTrace ?? _jsTrace,
260 skip: other._skip ?? _skip, 413 skip: other._skip ?? _skip,
261 skipReason: other.skipReason ?? skipReason, 414 skipReason: other.skipReason ?? skipReason,
262 testOn: testOn.intersection(other.testOn), 415 testOn: testOn.intersection(other.testOn),
263 pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad, 416 pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad,
264 color: other._color ?? _color, 417 color: other._color ?? _color,
265 packageRoot: other._packageRoot ?? _packageRoot, 418 packageRoot: other._packageRoot ?? _packageRoot,
266 reporter: other._reporter ?? _reporter, 419 reporter: other._reporter ?? _reporter,
267 pubServePort: (other.pubServeUrl ?? pubServeUrl)?.port, 420 pubServePort: (other.pubServeUrl ?? pubServeUrl)?.port,
268 concurrency: other._concurrency ?? _concurrency, 421 concurrency: other._concurrency ?? _concurrency,
269 timeout: timeout.merge(other.timeout), 422 timeout: timeout.merge(other.timeout),
270 pattern: other.pattern ?? pattern, 423 pattern: other.pattern ?? pattern,
271 platforms: other._platforms ?? _platforms, 424 platforms: other._platforms ?? _platforms,
272 paths: other._paths ?? _paths, 425 paths: other._paths ?? _paths,
273 filename: other._filename ?? _filename, 426 filename: other._filename ?? _filename,
427 chosenPresets: chosenPresets.union(other.chosenPresets),
274 includeTags: includeTags.intersection(other.includeTags), 428 includeTags: includeTags.intersection(other.includeTags),
275 excludeTags: excludeTags.union(other.excludeTags), 429 excludeTags: excludeTags.union(other.excludeTags),
276 addTags: other.addTags.union(addTags), 430 addTags: other.addTags.union(addTags),
277 tags: mergeMaps(tags, other.tags, 431 tags: _mergeConfigMaps(tags, other.tags),
278 value: (config1, config2) => config1.merge(config2)), 432 onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform),
279 onPlatform: mergeMaps(onPlatform, other.onPlatform, 433 presets: _mergeConfigMaps(presets, other.presets));
280 value: (config1, config2) => config1.merge(config2))); 434
435 // Make sure the merged config preserves any presets that were chosen and
436 // discarded.
437 result._knownPresets = knownPresets.union(other.knownPresets);
438 return result;
281 } 439 }
440
441 /// Returns a copy of this configuration with the given fields updated.
442 ///
443 /// Note that unlike [merge], this has no merging behavior—the old value is
444 /// always replaced by the new one.
445 Configuration change({
446 bool help,
447 bool version,
448 bool verboseTrace,
449 bool jsTrace,
450 bool skip,
451 String skipReason,
452 PlatformSelector testOn,
453 bool pauseAfterLoad,
454 bool color,
455 String packageRoot,
456 String reporter,
457 int pubServePort,
458 int concurrency,
459 Timeout timeout,
460 Pattern pattern,
461 Iterable<TestPlatform> platforms,
462 Iterable<String> paths,
463 Glob filename,
464 Iterable<String> chosenPresets,
465 BooleanSelector includeTags,
466 BooleanSelector excludeTags,
467 Iterable addTags,
468 Map<BooleanSelector, Configuration> tags,
469 Map<PlatformSelector, Configuration> onPlatform,
470 Map<String, Configuration> presets}) {
471 return new Configuration(
472 help: help ?? _help,
473 version: version ?? _version,
474 verboseTrace: verboseTrace ?? _verboseTrace,
475 jsTrace: jsTrace ?? _jsTrace,
476 skip: skip ?? _skip,
477 skipReason: skipReason ?? this.skipReason,
478 testOn: testOn ?? this.testOn,
479 pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad,
480 color: color ?? _color,
481 packageRoot: packageRoot ?? _packageRoot,
482 reporter: reporter ?? _reporter,
483 pubServePort: pubServePort ?? pubServeUrl?.port,
484 concurrency: concurrency ?? _concurrency,
485 timeout: timeout ?? this.timeout,
486 pattern: pattern ?? this.pattern,
487 platforms: platforms ?? _platforms,
488 paths: paths ?? _paths,
489 filename: filename ?? _filename,
490 chosenPresets: chosenPresets ?? this.chosenPresets,
491 includeTags: includeTags ?? this.includeTags,
492 excludeTags: excludeTags ?? this.excludeTags,
493 addTags: addTags ?? this.addTags,
494 tags: tags ?? this.tags,
495 onPlatform: onPlatform ?? this.onPlatform,
496 presets: presets ?? this.presets);
497 }
498
499 /// Merges two maps whose values are [Configuration]s.
500 ///
501 /// Any overlapping keys in the maps have their configurations merged in the
502 /// returned map.
503 Map<Object, Configuration> _mergeConfigMaps(Map<Object, Configuration> map1,
504 Map<Object, Configuration> map2) =>
505 mergeMaps(map1, map2,
506 value: (config1, config2) => config1.merge(config2));
282 } 507 }
OLDNEW
« no previous file with comments | « lib/src/executable.dart ('k') | lib/src/runner/configuration/args.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698