Chromium Code Reviews| 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 library test.backend.metadata; | 5 library test.backend.metadata; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import '../frontend/skip.dart'; | 9 import '../frontend/skip.dart'; |
| 10 import '../frontend/timeout.dart'; | 10 import '../frontend/timeout.dart'; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 /// Whether the test or suite should be skipped. | 27 /// Whether the test or suite should be skipped. |
| 28 final bool skip; | 28 final bool skip; |
| 29 | 29 |
| 30 /// Whether to use verbose stack traces. | 30 /// Whether to use verbose stack traces. |
| 31 final bool verboseTrace; | 31 final bool verboseTrace; |
| 32 | 32 |
| 33 /// The reason the test or suite should be skipped, if given. | 33 /// The reason the test or suite should be skipped, if given. |
| 34 final String skipReason; | 34 final String skipReason; |
| 35 | 35 |
| 36 /// A set of tags attached to a test | 36 /// A set of tags attached to a test |
| 37 final List<String> tags; | 37 final Set<String> tags; |
| 38 | 38 |
| 39 /// Platform-specific metadata. | 39 /// Platform-specific metadata. |
| 40 /// | 40 /// |
| 41 /// Each key identifies a platform, and its value identifies the specific | 41 /// Each key identifies a platform, and its value identifies the specific |
| 42 /// metadata for that platform. These can be applied by calling [forPlatform]. | 42 /// metadata for that platform. These can be applied by calling [forPlatform]. |
| 43 final Map<PlatformSelector, Metadata> onPlatform; | 43 final Map<PlatformSelector, Metadata> onPlatform; |
| 44 | 44 |
| 45 /// Parses a user-provided map into the value for [onPlatform]. | 45 /// Parses a user-provided map into the value for [onPlatform]. |
| 46 static Map<PlatformSelector, Metadata> _parseOnPlatform( | 46 static Map<PlatformSelector, Metadata> _parseOnPlatform( |
| 47 Map<String, dynamic> onPlatform) { | 47 Map<String, dynamic> onPlatform) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 result[selector] = new Metadata.parse(timeout: timeout, skip: skip); | 84 result[selector] = new Metadata.parse(timeout: timeout, skip: skip); |
| 85 }); | 85 }); |
| 86 return result; | 86 return result; |
| 87 } | 87 } |
| 88 | 88 |
| 89 /// Creates new Metadata. | 89 /// Creates new Metadata. |
| 90 /// | 90 /// |
| 91 /// [testOn] defaults to [PlatformSelector.all]. | 91 /// [testOn] defaults to [PlatformSelector.all]. |
| 92 Metadata({PlatformSelector testOn, Timeout timeout, bool skip: false, | 92 Metadata({PlatformSelector testOn, Timeout timeout, bool skip: false, |
| 93 this.verboseTrace: false, this.skipReason, | 93 this.verboseTrace: false, this.skipReason, |
| 94 Map<PlatformSelector, Metadata> onPlatform, List<String> tags}) | 94 Map<PlatformSelector, Metadata> onPlatform, tags}) |
| 95 : testOn = testOn == null ? PlatformSelector.all : testOn, | 95 : testOn = testOn == null ? PlatformSelector.all : testOn, |
| 96 timeout = timeout == null ? const Timeout.factor(1) : timeout, | 96 timeout = timeout == null ? const Timeout.factor(1) : timeout, |
| 97 skip = skip, | 97 skip = skip, |
| 98 onPlatform = onPlatform == null | 98 onPlatform = onPlatform == null |
| 99 ? const {} | 99 ? const {} |
| 100 : new UnmodifiableMapView(onPlatform), | 100 : new UnmodifiableMapView(onPlatform), |
| 101 this.tags = tags ?? const <String>[]; | 101 this.tags = _makeSetOfTags(tags); |
|
nweiz
2015/11/03 00:43:16
The type-normalization should only happen in [new
yjbanov
2015/11/11 06:40:20
Done.
| |
| 102 | 102 |
| 103 /// Creates a new Metadata, but with fields parsed from caller-friendly values | 103 /// Creates a new Metadata, but with fields parsed from caller-friendly values |
| 104 /// where applicable. | 104 /// where applicable. |
| 105 /// | 105 /// |
| 106 /// Throws a [FormatException] if any field is invalid. | 106 /// Throws a [FormatException] if any field is invalid. |
| 107 Metadata.parse({String testOn, Timeout timeout, skip, | 107 Metadata.parse({String testOn, Timeout timeout, skip, |
| 108 this.verboseTrace: false, Map<String, dynamic> onPlatform, | 108 this.verboseTrace: false, Map<String, dynamic> onPlatform, |
| 109 List<String> tags}) | 109 tags}) |
| 110 : testOn = testOn == null | 110 : testOn = testOn == null |
| 111 ? PlatformSelector.all | 111 ? PlatformSelector.all |
| 112 : new PlatformSelector.parse(testOn), | 112 : new PlatformSelector.parse(testOn), |
| 113 timeout = timeout == null ? const Timeout.factor(1) : timeout, | 113 timeout = timeout == null ? const Timeout.factor(1) : timeout, |
| 114 skip = skip != null && skip != false, | 114 skip = skip != null && skip != false, |
| 115 skipReason = skip is String ? skip : null, | 115 skipReason = skip is String ? skip : null, |
| 116 onPlatform = _parseOnPlatform(onPlatform), | 116 onPlatform = _parseOnPlatform(onPlatform), |
| 117 this.tags = tags ?? const <String>[] { | 117 this.tags = _makeSetOfTags(tags) { |
| 118 if (skip != null && skip is! String && skip is! bool) { | 118 if (skip != null && skip is! String && skip is! bool) { |
| 119 throw new ArgumentError( | 119 throw new ArgumentError( |
| 120 '"skip" must be a String or a bool, was "$skip".'); | 120 '"skip" must be a String or a bool, was "$skip".'); |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 | 123 |
| 124 /// Dezerializes the result of [Metadata.serialize] into a new [Metadata]. | 124 /// Deserializes the result of [Metadata.serialize] into a new [Metadata]. |
| 125 Metadata.deserialize(serialized) | 125 Metadata.deserialize(serialized) |
| 126 : testOn = serialized['testOn'] == null | 126 : testOn = serialized['testOn'] == null |
| 127 ? PlatformSelector.all | 127 ? PlatformSelector.all |
| 128 : new PlatformSelector.parse(serialized['testOn']), | 128 : new PlatformSelector.parse(serialized['testOn']), |
| 129 timeout = _deserializeTimeout(serialized['timeout']), | 129 timeout = _deserializeTimeout(serialized['timeout']), |
| 130 skip = serialized['skip'], | 130 skip = serialized['skip'], |
| 131 skipReason = serialized['skipReason'], | 131 skipReason = serialized['skipReason'], |
| 132 verboseTrace = serialized['verboseTrace'], | 132 verboseTrace = serialized['verboseTrace'], |
| 133 tags = serialized['tags'] ?? const <String>[], | 133 tags = _makeSetOfTags(serialized['tags']), |
| 134 onPlatform = new Map.fromIterable(serialized['onPlatform'], | 134 onPlatform = new Map.fromIterable(serialized['onPlatform'], |
| 135 key: (pair) => new PlatformSelector.parse(pair.first), | 135 key: (pair) => new PlatformSelector.parse(pair.first), |
| 136 value: (pair) => new Metadata.deserialize(pair.last)); | 136 value: (pair) => new Metadata.deserialize(pair.last)); |
| 137 | 137 |
| 138 /// Deserializes timeout from the format returned by [_serializeTimeout]. | 138 /// Deserializes timeout from the format returned by [_serializeTimeout]. |
| 139 static _deserializeTimeout(serialized) { | 139 static _deserializeTimeout(serialized) { |
| 140 if (serialized == 'none') return Timeout.none; | 140 if (serialized == 'none') return Timeout.none; |
| 141 var scaleFactor = serialized['scaleFactor']; | 141 var scaleFactor = serialized['scaleFactor']; |
| 142 if (scaleFactor != null) return new Timeout.factor(scaleFactor); | 142 if (scaleFactor != null) return new Timeout.factor(scaleFactor); |
| 143 return new Timeout( | 143 return new Timeout( |
| 144 new Duration(microseconds: serialized['duration'])); | 144 new Duration(microseconds: serialized['duration'])); |
| 145 } | 145 } |
| 146 | 146 |
| 147 /// Return a new [Metadata] that merges [this] with [other]. | 147 /// Return a new [Metadata] that merges [this] with [other]. |
| 148 /// | 148 /// |
| 149 /// If the two [Metadata]s have conflicting properties, [other] wins. | 149 /// If the two [Metadata]s have conflicting properties, [other] wins. |
| 150 Metadata merge(Metadata other) => | 150 Metadata merge(Metadata other) => |
| 151 new Metadata( | 151 new Metadata( |
| 152 testOn: testOn.intersect(other.testOn), | 152 testOn: testOn.intersect(other.testOn), |
| 153 timeout: timeout.merge(other.timeout), | 153 timeout: timeout.merge(other.timeout), |
| 154 skip: skip || other.skip, | 154 skip: skip || other.skip, |
| 155 verboseTrace: verboseTrace || other.verboseTrace, | 155 verboseTrace: verboseTrace || other.verboseTrace, |
| 156 skipReason: other.skipReason == null ? skipReason : other.skipReason, | 156 skipReason: other.skipReason == null ? skipReason : other.skipReason, |
| 157 onPlatform: mergeMaps(onPlatform, other.onPlatform), | 157 onPlatform: mergeMaps(onPlatform, other.onPlatform), |
| 158 tags: mergeLists(tags, other.tags)); | 158 tags: tags.union(other.tags)); |
| 159 | 159 |
| 160 /// Returns a copy of [this] with the given fields changed. | 160 /// Returns a copy of [this] with the given fields changed. |
| 161 Metadata change({PlatformSelector testOn, Timeout timeout, bool skip, | 161 Metadata change({PlatformSelector testOn, Timeout timeout, bool skip, |
| 162 bool verboseTrace, String skipReason, | 162 bool verboseTrace, String skipReason, |
| 163 Map<PlatformSelector, Metadata> onPlatform}) { | 163 Map<PlatformSelector, Metadata> onPlatform}) { |
| 164 if (testOn == null) testOn = this.testOn; | 164 if (testOn == null) testOn = this.testOn; |
| 165 if (timeout == null) timeout = this.timeout; | 165 if (timeout == null) timeout = this.timeout; |
| 166 if (skip == null) skip = this.skip; | 166 if (skip == null) skip = this.skip; |
| 167 if (verboseTrace == null) verboseTrace = this.verboseTrace; | 167 if (verboseTrace == null) verboseTrace = this.verboseTrace; |
| 168 if (skipReason == null) skipReason = this.skipReason; | 168 if (skipReason == null) skipReason = this.skipReason; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 194 serializedOnPlatform.add([key.toString(), value.serialize()]); | 194 serializedOnPlatform.add([key.toString(), value.serialize()]); |
| 195 }); | 195 }); |
| 196 | 196 |
| 197 return { | 197 return { |
| 198 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), | 198 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), |
| 199 'timeout': _serializeTimeout(timeout), | 199 'timeout': _serializeTimeout(timeout), |
| 200 'skip': skip, | 200 'skip': skip, |
| 201 'skipReason': skipReason, | 201 'skipReason': skipReason, |
| 202 'verboseTrace': verboseTrace, | 202 'verboseTrace': verboseTrace, |
| 203 'onPlatform': serializedOnPlatform, | 203 'onPlatform': serializedOnPlatform, |
| 204 'tags': tags.isEmpty ? null : tags, | 204 'tags': tags.toList(), |
| 205 }; | 205 }; |
| 206 } | 206 } |
| 207 | 207 |
| 208 /// Serializes timeout into a JSON-safe object. | 208 /// Serializes timeout into a JSON-safe object. |
| 209 _serializeTimeout(Timeout timeout) { | 209 _serializeTimeout(Timeout timeout) { |
| 210 if (timeout == Timeout.none) return 'none'; | 210 if (timeout == Timeout.none) return 'none'; |
| 211 return { | 211 return { |
| 212 'duration': timeout.duration == null | 212 'duration': timeout.duration == null |
| 213 ? null | 213 ? null |
| 214 : timeout.duration.inMicroseconds, | 214 : timeout.duration.inMicroseconds, |
| 215 'scaleFactor': timeout.scaleFactor | 215 'scaleFactor': timeout.scaleFactor |
| 216 }; | 216 }; |
| 217 } | 217 } |
| 218 } | 218 } |
| 219 | |
| 220 /// Converts [tags] to a [Set] of unique tags, unless it is already a [Set]. | |
| 221 /// | |
| 222 /// `null` becomes an empty set. [String] is split on commas. | |
| 223 Set<String> _makeSetOfTags(tags) => tags != null | |
| 224 ? tags is Iterable | |
| 225 ? _tagsFromIterable(tags) | |
| 226 : tags is String | |
| 227 ? _tagsFromString(tags) | |
| 228 : throw new ArgumentError.value(tags, "tags", | |
| 229 "must be either String or Iterable") | |
| 230 : new Set<String>(); | |
| 231 | |
| 232 Set<String> _tagsFromIterable(Iterable tags) { | |
| 233 for (var tag in tags) { | |
| 234 if (tag is! String) { | |
| 235 throw new ArgumentError.value(tags, "tags", "tag name must be String"); | |
| 236 } | |
| 237 if (tag.trim().isEmpty) { | |
|
nweiz
2015/11/03 00:43:16
I'd rather not trim here. If users want to use whi
yjbanov
2015/11/11 06:40:20
I thought it would be more practical given we acce
nweiz
2015/11/16 21:59:44
I'd like to keep the semantics on the Dart side in
yjbanov
2015/11/26 06:30:27
Done.
| |
| 238 throw new ArgumentError.value(tags, "tags", | |
| 239 "tag name must contain non-whitespace characters"); | |
| 240 } | |
| 241 } | |
| 242 return tags is Set<String> ? tags : new Set<String>.from(tags); | |
| 243 } | |
| 244 | |
| 245 Set<String> _tagsFromString(String tags) { | |
| 246 if (tags.trim().isEmpty) return new Set<String>(); | |
| 247 return _tagsFromIterable( | |
| 248 tags.split(",").map((tag) => tag.trim()).where((tag) => tag.isNotEmpty)); | |
|
nweiz
2015/11/03 00:43:16
I'd rather require users to use a real list if the
yjbanov
2015/11/11 06:40:20
I thought it would make it consistent with the com
yjbanov
2015/11/26 06:30:27
Done.
| |
| 249 } | |
| OLD | NEW |