OLD | NEW |
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:collection'; | 5 import 'dart:collection'; |
6 | 6 |
| 7 import 'package:boolean_selector/boolean_selector.dart'; |
7 import 'package:collection/collection.dart'; | 8 import 'package:collection/collection.dart'; |
8 | 9 |
9 import '../frontend/skip.dart'; | 10 import '../frontend/skip.dart'; |
10 import '../frontend/timeout.dart'; | 11 import '../frontend/timeout.dart'; |
11 import '../utils.dart'; | 12 import '../utils.dart'; |
12 import 'operating_system.dart'; | 13 import 'operating_system.dart'; |
13 import 'platform_selector.dart'; | 14 import 'platform_selector.dart'; |
14 import 'test_platform.dart'; | 15 import 'test_platform.dart'; |
15 | 16 |
16 /// Metadata for a test or test suite. | 17 /// Metadata for a test or test suite. |
(...skipping 24 matching lines...) Expand all Loading... |
41 /// Each key identifies a platform, and its value identifies the specific | 42 /// Each key identifies a platform, and its value identifies the specific |
42 /// metadata for that platform. These can be applied by calling [forPlatform]. | 43 /// metadata for that platform. These can be applied by calling [forPlatform]. |
43 final Map<PlatformSelector, Metadata> onPlatform; | 44 final Map<PlatformSelector, Metadata> onPlatform; |
44 | 45 |
45 /// Metadata that applies only when specific tags are applied. | 46 /// Metadata that applies only when specific tags are applied. |
46 /// | 47 /// |
47 /// Tag-specific metadata is applied when merging this with other metadata. | 48 /// Tag-specific metadata is applied when merging this with other metadata. |
48 /// Note that unlike [onPlatform], the base metadata takes precedence over any | 49 /// Note that unlike [onPlatform], the base metadata takes precedence over any |
49 /// tag-specific metadata. | 50 /// tag-specific metadata. |
50 /// | 51 /// |
51 /// This is guaranteed not to have any keys that appear in [tags]; those are | 52 /// This is guaranteed not to have any keys that match [tags]; those are |
52 /// resolved when the metadata is constructed. | 53 /// resolved when the metadata is constructed. |
53 final Map<String, Metadata> forTag; | 54 final Map<BooleanSelector, Metadata> forTag; |
54 | 55 |
55 /// Parses a user-provided map into the value for [onPlatform]. | 56 /// Parses a user-provided map into the value for [onPlatform]. |
56 static Map<PlatformSelector, Metadata> _parseOnPlatform( | 57 static Map<PlatformSelector, Metadata> _parseOnPlatform( |
57 Map<String, dynamic> onPlatform) { | 58 Map<String, dynamic> onPlatform) { |
58 if (onPlatform == null) return {}; | 59 if (onPlatform == null) return {}; |
59 | 60 |
60 var result = {}; | 61 var result = {}; |
61 onPlatform.forEach((platform, metadata) { | 62 onPlatform.forEach((platform, metadata) { |
62 if (metadata is Timeout || metadata is Skip) { | 63 if (metadata is Timeout || metadata is Skip) { |
63 metadata = [metadata]; | 64 metadata = [metadata]; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 throw new ArgumentError.value(tags, "tags", "must contain only Strings."); | 112 throw new ArgumentError.value(tags, "tags", "must contain only Strings."); |
112 } | 113 } |
113 | 114 |
114 return new Set.from(tags); | 115 return new Set.from(tags); |
115 } | 116 } |
116 | 117 |
117 /// Creates new Metadata. | 118 /// Creates new Metadata. |
118 /// | 119 /// |
119 /// [testOn] defaults to [PlatformSelector.all]. | 120 /// [testOn] defaults to [PlatformSelector.all]. |
120 /// | 121 /// |
121 /// If [forTag] contains metadata for any tags in [tags], that metadata is | 122 /// If [forTag] contains metadata that applies to [tags], that metadata is |
122 /// included inline in the returned value. The values directly passed to the | 123 /// included inline in the returned value. The values directly passed to the |
123 /// constructor take precedence over tag-specific metadata. | 124 /// constructor take precedence over tag-specific metadata. |
124 factory Metadata({PlatformSelector testOn, Timeout timeout, bool skip: false, | 125 factory Metadata({PlatformSelector testOn, Timeout timeout, bool skip: false, |
125 bool verboseTrace: false, String skipReason, Iterable<String> tags, | 126 bool verboseTrace: false, String skipReason, Iterable<String> tags, |
126 Map<PlatformSelector, Metadata> onPlatform, | 127 Map<PlatformSelector, Metadata> onPlatform, |
127 Map<String, Metadata> forTag}) { | 128 Map<BooleanSelector, Metadata> forTag}) { |
128 // If there's no tag-specific metadata, or if none of it applies, just | 129 // Returns metadata without forTag resolved at all. |
129 // return the metadata as-is. | 130 _unresolved() => new Metadata._( |
130 if (forTag == null || tags == null || !tags.any(forTag.containsKey)) { | |
131 return new Metadata._( | |
132 testOn: testOn, | |
133 timeout: timeout, | |
134 skip: skip, | |
135 verboseTrace: verboseTrace, | |
136 skipReason: skipReason, | |
137 tags: tags, | |
138 onPlatform: onPlatform, | |
139 forTag: forTag); | |
140 } | |
141 | |
142 // Otherwise, resolve the tag-specific components. Doing this eagerly means | |
143 // we only have to resolve suite- or group-level tags once, rather than | |
144 // doing it for every test individually. | |
145 forTag = new Map.from(forTag); | |
146 var merged = tags.fold(new Metadata._(), (merged, tag) { | |
147 var tagMetadata = forTag.remove(tag); | |
148 return tagMetadata == null ? merged : merged.merge(tagMetadata); | |
149 }); | |
150 | |
151 return merged.merge(new Metadata._( | |
152 testOn: testOn, | 131 testOn: testOn, |
153 timeout: timeout, | 132 timeout: timeout, |
154 skip: skip, | 133 skip: skip, |
155 verboseTrace: verboseTrace, | 134 verboseTrace: verboseTrace, |
156 skipReason: skipReason, | 135 skipReason: skipReason, |
157 tags: tags, | 136 tags: tags, |
158 onPlatform: onPlatform, | 137 onPlatform: onPlatform, |
159 forTag: forTag)); | 138 forTag: forTag); |
| 139 |
| 140 // If there's no tag-specific metadata, or if none of it applies, just |
| 141 // return the metadata as-is. |
| 142 if (forTag == null || tags == null) return _unresolved(); |
| 143 |
| 144 // Otherwise, resolve the tag-specific components. Doing this eagerly means |
| 145 // we only have to resolve suite- or group-level tags once, rather than |
| 146 // doing it for every test individually. |
| 147 var empty = new Metadata._(); |
| 148 var merged = forTag.keys.toList().fold(empty, (merged, selector) { |
| 149 if (!selector.evaluate(tags)) return merged; |
| 150 return merged.merge(forTag.remove(selector)); |
| 151 }); |
| 152 |
| 153 if (merged == empty) return _unresolved(); |
| 154 return merged.merge(_unresolved()); |
160 } | 155 } |
161 | 156 |
162 /// Creates new Metadata. | 157 /// Creates new Metadata. |
163 /// | 158 /// |
164 /// Unlike [new Metadata], this assumes [forTag] is already resolved. | 159 /// Unlike [new Metadata], this assumes [forTag] is already resolved. |
165 Metadata._({PlatformSelector testOn, Timeout timeout, bool skip: false, | 160 Metadata._({PlatformSelector testOn, Timeout timeout, bool skip: false, |
166 this.verboseTrace: false, this.skipReason, Iterable<String> tags, | 161 this.verboseTrace: false, this.skipReason, Iterable<String> tags, |
167 Map<PlatformSelector, Metadata> onPlatform, | 162 Map<PlatformSelector, Metadata> onPlatform, |
168 Map<String, Metadata> forTag}) | 163 Map<BooleanSelector, Metadata> forTag}) |
169 : testOn = testOn == null ? PlatformSelector.all : testOn, | 164 : testOn = testOn == null ? PlatformSelector.all : testOn, |
170 timeout = timeout == null ? const Timeout.factor(1) : timeout, | 165 timeout = timeout == null ? const Timeout.factor(1) : timeout, |
171 skip = skip, | 166 skip = skip, |
172 tags = new UnmodifiableSetView( | 167 tags = new UnmodifiableSetView( |
173 tags == null ? new Set() : tags.toSet()), | 168 tags == null ? new Set() : tags.toSet()), |
174 onPlatform = onPlatform == null | 169 onPlatform = onPlatform == null |
175 ? const {} | 170 ? const {} |
176 : new UnmodifiableMapView(onPlatform), | 171 : new UnmodifiableMapView(onPlatform), |
177 forTag = forTag == null | 172 forTag = forTag == null |
178 ? const {} | 173 ? const {} |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 : new PlatformSelector.parse(serialized['testOn']), | 206 : new PlatformSelector.parse(serialized['testOn']), |
212 timeout = _deserializeTimeout(serialized['timeout']), | 207 timeout = _deserializeTimeout(serialized['timeout']), |
213 skip = serialized['skip'], | 208 skip = serialized['skip'], |
214 skipReason = serialized['skipReason'], | 209 skipReason = serialized['skipReason'], |
215 verboseTrace = serialized['verboseTrace'], | 210 verboseTrace = serialized['verboseTrace'], |
216 tags = new Set.from(serialized['tags']), | 211 tags = new Set.from(serialized['tags']), |
217 onPlatform = new Map.fromIterable(serialized['onPlatform'], | 212 onPlatform = new Map.fromIterable(serialized['onPlatform'], |
218 key: (pair) => new PlatformSelector.parse(pair.first), | 213 key: (pair) => new PlatformSelector.parse(pair.first), |
219 value: (pair) => new Metadata.deserialize(pair.last)), | 214 value: (pair) => new Metadata.deserialize(pair.last)), |
220 forTag = mapMap(serialized['forTag'], | 215 forTag = mapMap(serialized['forTag'], |
| 216 key: (key, _) => new BooleanSelector.parse(key), |
221 value: (_, nested) => new Metadata.deserialize(nested)); | 217 value: (_, nested) => new Metadata.deserialize(nested)); |
222 | 218 |
223 /// Deserializes timeout from the format returned by [_serializeTimeout]. | 219 /// Deserializes timeout from the format returned by [_serializeTimeout]. |
224 static _deserializeTimeout(serialized) { | 220 static _deserializeTimeout(serialized) { |
225 if (serialized == 'none') return Timeout.none; | 221 if (serialized == 'none') return Timeout.none; |
226 var scaleFactor = serialized['scaleFactor']; | 222 var scaleFactor = serialized['scaleFactor']; |
227 if (scaleFactor != null) return new Timeout.factor(scaleFactor); | 223 if (scaleFactor != null) return new Timeout.factor(scaleFactor); |
228 return new Timeout( | 224 return new Timeout( |
229 new Duration(microseconds: serialized['duration'])); | 225 new Duration(microseconds: serialized['duration'])); |
230 } | 226 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 }); | 297 }); |
302 | 298 |
303 return { | 299 return { |
304 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), | 300 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), |
305 'timeout': _serializeTimeout(timeout), | 301 'timeout': _serializeTimeout(timeout), |
306 'skip': skip, | 302 'skip': skip, |
307 'skipReason': skipReason, | 303 'skipReason': skipReason, |
308 'verboseTrace': verboseTrace, | 304 'verboseTrace': verboseTrace, |
309 'tags': tags.toList(), | 305 'tags': tags.toList(), |
310 'onPlatform': serializedOnPlatform, | 306 'onPlatform': serializedOnPlatform, |
311 'forTag': mapMap(forTag, value: (_, metadata) => metadata.serialize()) | 307 'forTag': mapMap(forTag, |
| 308 key: (selector, _) => selector.toString(), |
| 309 value: (_, metadata) => metadata.serialize()) |
312 }; | 310 }; |
313 } | 311 } |
314 | 312 |
315 /// Serializes timeout into a JSON-safe object. | 313 /// Serializes timeout into a JSON-safe object. |
316 _serializeTimeout(Timeout timeout) { | 314 _serializeTimeout(Timeout timeout) { |
317 if (timeout == Timeout.none) return 'none'; | 315 if (timeout == Timeout.none) return 'none'; |
318 return { | 316 return { |
319 'duration': timeout.duration == null | 317 'duration': timeout.duration == null |
320 ? null | 318 ? null |
321 : timeout.duration.inMicroseconds, | 319 : timeout.duration.inMicroseconds, |
322 'scaleFactor': timeout.scaleFactor | 320 'scaleFactor': timeout.scaleFactor |
323 }; | 321 }; |
324 } | 322 } |
325 } | 323 } |
OLD | NEW |