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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/executable.dart ('k') | lib/src/runner/configuration/args.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/runner/configuration.dart
diff --git a/lib/src/runner/configuration.dart b/lib/src/runner/configuration.dart
index aaeb94fbba041502ab40d8b18736d2f41fe20a1e..b8e2ed5eac9aec66797e78620254cd965d6a9374 100644
--- a/lib/src/runner/configuration.dart
+++ b/lib/src/runner/configuration.dart
@@ -21,6 +21,12 @@ import 'configuration/values.dart';
/// A class that encapsulates the command-line configuration of the test runner.
class Configuration {
+ /// An empty configuration with only default values.
+ ///
+ /// Using this is slightly more efficient than manually constructing a new
+ /// configuration with no arguments.
+ static final empty = new Configuration._();
+
/// The usage string for the command-line arguments.
static String get usage => args.usage;
@@ -107,6 +113,14 @@ class Configuration {
List<TestPlatform> get platforms => _platforms ?? [TestPlatform.vm];
final List<TestPlatform> _platforms;
+ /// The set of presets to use.
+ ///
+ /// Any chosen presets for the parent configuration are added to the chosen
+ /// preset sets for child configurations as well.
+ ///
+ /// Note that the order of this set matters.
+ final Set<String> chosenPresets;
+
/// Only run tests whose tags match this selector.
///
/// When [merge]d, this is intersected with the other configuration's included
@@ -142,17 +156,21 @@ class Configuration {
forTag: mapMap(tags, value: (_, config) => config.metadata),
onPlatform: mapMap(onPlatform, value: (_, config) => config.metadata));
- /// The set of tags that have been declaredin any way in this configuration.
+ /// The set of tags that have been declared in any way in this configuration.
Set<String> get knownTags {
if (_knownTags != null) return _knownTags;
var known = includeTags.variables.toSet()
..addAll(excludeTags.variables)
..addAll(addTags);
- tags.forEach((selector, config) {
+
+ for (var selector in tags.keys) {
known.addAll(selector.variables);
- known.addAll(config.knownTags);
- });
+ }
+
+ for (var configuration in _children) {
+ known.addAll(configuration.knownTags);
+ }
_knownTags = new UnmodifiableSetView(known);
return _knownTags;
@@ -166,6 +184,40 @@ class Configuration {
/// configuration fields, but that isn't enforced.
final Map<PlatformSelector, Configuration> onPlatform;
+ /// Configuration presets.
+ ///
+ /// These are configurations that can be explicitly selected by the user via
+ /// the command line. Preset configuration takes precedence over the base
+ /// configuration.
+ ///
+ /// This is guaranteed not to have any keys that match [chosenPresets]; those
+ /// are resolved when the configuration is constructed.
+ final Map<String, Configuration> presets;
+
+ /// All preset names that are known to be valid.
+ ///
+ /// This includes presets that have already been resolved.
+ Set<String> get knownPresets {
+ if (_knownPresets != null) return _knownPresets;
+
+ var known = presets.keys.toSet();
+ for (var configuration in _children) {
+ known.addAll(configuration.knownPresets);
+ }
+
+ _knownPresets = new UnmodifiableSetView(known);
+ return _knownPresets;
+ }
+ Set<String> _knownPresets;
+
+ /// All child configurations of [this] that may be selected under various
+ /// circumstances.
+ Iterable<Configuration> get _children sync* {
+ yield* tags.values;
+ yield* onPlatform.values;
+ yield* presets.values;
+ }
+
/// Parses the configuration from [args].
///
/// Throws a [FormatException] if [args] are invalid.
@@ -177,7 +229,97 @@ class Configuration {
/// a [FormatException] if its contents are invalid.
factory Configuration.load(String path) => load(path);
- Configuration({
+ factory Configuration({
+ bool help,
+ bool version,
+ bool verboseTrace,
+ bool jsTrace,
+ bool skip,
+ String skipReason,
+ PlatformSelector testOn,
+ bool pauseAfterLoad,
+ bool color,
+ String packageRoot,
+ String reporter,
+ int pubServePort,
+ int concurrency,
+ Timeout timeout,
+ Pattern pattern,
+ Iterable<TestPlatform> platforms,
+ Iterable<String> paths,
+ Glob filename,
+ Iterable<String> chosenPresets,
+ BooleanSelector includeTags,
+ BooleanSelector excludeTags,
+ Iterable addTags,
+ Map<BooleanSelector, Configuration> tags,
+ Map<PlatformSelector, Configuration> onPlatform,
+ Map<String, Configuration> presets}) {
+ _unresolved() => new Configuration._(
+ help: help,
+ version: version,
+ verboseTrace: verboseTrace,
+ jsTrace: jsTrace,
+ skip: skip,
+ skipReason: skipReason,
+ testOn: testOn,
+ pauseAfterLoad: pauseAfterLoad,
+ color: color,
+ packageRoot: packageRoot,
+ reporter: reporter,
+ pubServePort: pubServePort,
+ concurrency: concurrency,
+ timeout: timeout,
+ pattern: pattern,
+ platforms: platforms,
+ paths: paths,
+ filename: filename,
+ chosenPresets: chosenPresets,
+ includeTags: includeTags,
+ excludeTags: excludeTags,
+ addTags: addTags,
+
+ // Make sure we pass [chosenPresets] to the child configurations as
+ // well. This ensures that
+ tags: _withChosenPresets(tags, chosenPresets),
+ onPlatform: _withChosenPresets(onPlatform, chosenPresets),
+ presets: _withChosenPresets(presets, chosenPresets));
+
+ if (chosenPresets == null) return _unresolved();
+ chosenPresets = new Set.from(chosenPresets);
+
+ if (presets == null) return _unresolved();
+ presets = new Map.from(presets);
+
+ var knownPresets = presets.keys.toSet();
+
+ var merged = chosenPresets.fold(Configuration.empty, (merged, preset) {
+ if (!presets.containsKey(preset)) return merged;
+ return merged.merge(presets.remove(preset));
+ });
+
+ var result = merged == Configuration.empty
+ ? _unresolved()
+ : _unresolved().merge(merged);
+
+ // Make sure the configuration knows about presets that were selected and
+ // thus removed from [presets].
+ result._knownPresets = result.knownPresets.union(knownPresets);
+
+ return result;
+ }
+
+ static Map<Object, Configuration> _withChosenPresets(
+ Map<Object, Configuration> map, Set<String> chosenPresets) {
+ if (map == null || chosenPresets == null) return map;
+ return mapMap(map, value: (_, config) => config.change(
+ chosenPresets: config.chosenPresets.union(chosenPresets)));
+ }
+
+ /// Creates new Configuration.
+ ///
+ /// Unlike [new Configuration], this assumes [presets] is already resolved.
+ Configuration._({
bool help,
bool version,
bool verboseTrace,
@@ -196,11 +338,13 @@ class Configuration {
Iterable<TestPlatform> platforms,
Iterable<String> paths,
Glob filename,
+ Iterable<String> chosenPresets,
BooleanSelector includeTags,
BooleanSelector excludeTags,
Iterable addTags,
Map<BooleanSelector, Configuration> tags,
- Map<PlatformSelector, Configuration> onPlatform})
+ Map<PlatformSelector, Configuration> onPlatform,
+ Map<String, Configuration> presets})
: _help = help,
_version = version,
_verboseTrace = verboseTrace,
@@ -221,13 +365,13 @@ class Configuration {
_platforms = _list(platforms),
_paths = _list(paths),
_filename = filename,
+ chosenPresets = new Set.from(chosenPresets ?? []),
includeTags = includeTags ?? BooleanSelector.all,
excludeTags = excludeTags ?? BooleanSelector.none,
- addTags = addTags?.toSet() ?? new Set(),
- tags = tags == null ? const {} : new Map.unmodifiable(tags),
- onPlatform = onPlatform == null
- ? const {}
- : new Map.unmodifiable(onPlatform) {
+ addTags = new UnmodifiableSetView(addTags?.toSet() ?? new Set()),
+ tags = _map(tags),
+ onPlatform = _map(onPlatform),
+ presets = _map(presets) {
if (_filename != null && _filename.context.style != p.style) {
throw new ArgumentError(
"filename's context must match the current operating system, was "
@@ -235,24 +379,33 @@ class Configuration {
}
}
- /// Returns a [input] as a list or `null`.
+ /// Returns a [input] as an unmodifiable list or `null`.
///
/// If [input] is `null` or empty, this returns `null`. Otherwise, it returns
/// `input.toList()`.
static List _list(Iterable input) {
if (input == null) return null;
- input = input.toList();
+ input = new List.unmodifiable(input);
if (input.isEmpty) return null;
return input;
}
+ /// Returns an modifiable copy of [input] or an empty unmodifiable map.
+ static Map _map(Map input) {
+ if (input == null) return const {};
+ return new Map.unmodifiable(input);
+ }
+
/// Merges this with [other].
///
/// For most fields, if both configurations have values set, [other]'s value
/// takes precedence. However, certain fields are merged together instead.
/// This is indicated in those fields' documentation.
Configuration merge(Configuration other) {
- return new Configuration(
+ if (this == Configuration.empty) return other;
+ if (other == Configuration.empty) return this;
+
+ var result = new Configuration(
help: other._help ?? _help,
version: other._version ?? _version,
verboseTrace: other._verboseTrace ?? _verboseTrace,
@@ -271,12 +424,84 @@ class Configuration {
platforms: other._platforms ?? _platforms,
paths: other._paths ?? _paths,
filename: other._filename ?? _filename,
+ chosenPresets: chosenPresets.union(other.chosenPresets),
includeTags: includeTags.intersection(other.includeTags),
excludeTags: excludeTags.union(other.excludeTags),
addTags: other.addTags.union(addTags),
- tags: mergeMaps(tags, other.tags,
- value: (config1, config2) => config1.merge(config2)),
- onPlatform: mergeMaps(onPlatform, other.onPlatform,
- value: (config1, config2) => config1.merge(config2)));
+ tags: _mergeConfigMaps(tags, other.tags),
+ onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform),
+ presets: _mergeConfigMaps(presets, other.presets));
+
+ // Make sure the merged config preserves any presets that were chosen and
+ // discarded.
+ result._knownPresets = knownPresets.union(other.knownPresets);
+ return result;
}
+
+ /// Returns a copy of this configuration with the given fields updated.
+ ///
+ /// Note that unlike [merge], this has no merging behavior—the old value is
+ /// always replaced by the new one.
+ Configuration change({
+ bool help,
+ bool version,
+ bool verboseTrace,
+ bool jsTrace,
+ bool skip,
+ String skipReason,
+ PlatformSelector testOn,
+ bool pauseAfterLoad,
+ bool color,
+ String packageRoot,
+ String reporter,
+ int pubServePort,
+ int concurrency,
+ Timeout timeout,
+ Pattern pattern,
+ Iterable<TestPlatform> platforms,
+ Iterable<String> paths,
+ Glob filename,
+ Iterable<String> chosenPresets,
+ BooleanSelector includeTags,
+ BooleanSelector excludeTags,
+ Iterable addTags,
+ Map<BooleanSelector, Configuration> tags,
+ Map<PlatformSelector, Configuration> onPlatform,
+ Map<String, Configuration> presets}) {
+ return new Configuration(
+ help: help ?? _help,
+ version: version ?? _version,
+ verboseTrace: verboseTrace ?? _verboseTrace,
+ jsTrace: jsTrace ?? _jsTrace,
+ skip: skip ?? _skip,
+ skipReason: skipReason ?? this.skipReason,
+ testOn: testOn ?? this.testOn,
+ pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad,
+ color: color ?? _color,
+ packageRoot: packageRoot ?? _packageRoot,
+ reporter: reporter ?? _reporter,
+ pubServePort: pubServePort ?? pubServeUrl?.port,
+ concurrency: concurrency ?? _concurrency,
+ timeout: timeout ?? this.timeout,
+ pattern: pattern ?? this.pattern,
+ platforms: platforms ?? _platforms,
+ paths: paths ?? _paths,
+ filename: filename ?? _filename,
+ chosenPresets: chosenPresets ?? this.chosenPresets,
+ includeTags: includeTags ?? this.includeTags,
+ excludeTags: excludeTags ?? this.excludeTags,
+ addTags: addTags ?? this.addTags,
+ tags: tags ?? this.tags,
+ onPlatform: onPlatform ?? this.onPlatform,
+ presets: presets ?? this.presets);
+ }
+
+ /// Merges two maps whose values are [Configuration]s.
+ ///
+ /// Any overlapping keys in the maps have their configurations merged in the
+ /// returned map.
+ Map<Object, Configuration> _mergeConfigMaps(Map<Object, Configuration> map1,
+ Map<Object, Configuration> map2) =>
+ mergeMaps(map1, map2,
+ value: (config1, config2) => config1.merge(config2));
}
« 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