Chromium Code Reviews| Index: lib/src/backend/metadata.dart |
| diff --git a/lib/src/backend/metadata.dart b/lib/src/backend/metadata.dart |
| index ecce4404601c0f59672c6a64e411d9409c09b7f8..2ffd3167c5c4d162d8ac6c4947dec42b4f98e33d 100644 |
| --- a/lib/src/backend/metadata.dart |
| +++ b/lib/src/backend/metadata.dart |
| @@ -4,7 +4,11 @@ |
| library test.backend.metadata; |
| +import 'dart:collection'; |
| + |
| +import '../frontend/skip.dart'; |
| import '../frontend/timeout.dart'; |
| +import '../utils.dart'; |
| import 'platform_selector.dart'; |
| /// Metadata for a test or test suite. |
| @@ -24,26 +28,81 @@ class Metadata { |
| /// The reason the test or suite should be skipped, if given. |
| final String skipReason; |
| + /// Platform-specific metadata. |
| + /// |
| + /// Each key identifies a platform, and its value identifies the specific |
| + /// metadata for that platform. These can be applied by calling [forPlatform]. |
| + final Map<PlatformSelector, Metadata> onPlatform; |
| + |
| + /// Parses a user-provided map into the value for [onPlatform]. |
| + static Map<PlatformSelector, Metadata> _parseOnPlatform( |
| + Map<String, dynamic> onPlatform) { |
| + if (onPlatform == null) return {}; |
| + |
| + var result = {}; |
| + onPlatform.forEach((platform, metadata) { |
| + if (metadata is Timeout || metadata is Skip) { |
| + metadata = [metadata]; |
| + } else if (metadata is! List) { |
| + throw new ArgumentError('Metadata for platform "$platform" must be a ' |
| + 'Timeout, Skip, or List of those; was "$metadata".'); |
| + } |
| + |
| + var selector = new PlatformSelector.parse(platform); |
| + |
| + var timeout; |
| + var skip; |
| + for (var metadatum in metadata) { |
| + if (metadatum is Timeout) { |
| + if (timeout != null) { |
| + throw new ArgumentError('Only a single Timeout may be declared for ' |
| + '"$platform".'); |
| + } |
| + |
| + timeout = metadatum; |
| + } else if (metadatum is Skip) { |
| + if (skip != null) { |
| + throw new ArgumentError('Only a single Skip may be declared for ' |
| + '"$platform".'); |
| + } |
| + |
| + skip = metadatum.reason == null ? true : metadatum.reason; |
| + } else { |
| + throw new ArgumentError('Metadata for platform "$platform" must be a ' |
| + 'Timeout, Skip, or List of those; was "$metadata".'); |
| + } |
| + } |
| + |
| + result[selector] = new Metadata.parse(timeout: timeout, skip: skip); |
| + }); |
| + return result; |
| + } |
| + |
| /// Creates new Metadata. |
| /// |
| /// [testOn] defaults to [PlatformSelector.all]. |
| Metadata({PlatformSelector testOn, Timeout timeout, bool skip: false, |
| - this.skipReason}) |
| + this.skipReason, Map<PlatformSelector, Metadata> onPlatform}) |
| : testOn = testOn == null ? PlatformSelector.all : testOn, |
| timeout = timeout == null ? const Timeout.factor(1) : timeout, |
| - skip = skip; |
| + skip = skip, |
| + onPlatform = onPlatform == null |
| + ? const {} |
| + : new UnmodifiableMapView(onPlatform); |
| - /// Creates a new Metadata, but with fields parsed from strings where |
| - /// applicable. |
| + /// Creates a new Metadata, but with fields parsed from caller-friendly values |
| + /// where applicable. |
| /// |
| /// Throws a [FormatException] if any field is invalid. |
| - Metadata.parse({String testOn, Timeout timeout, skip}) |
| + Metadata.parse({String testOn, Timeout timeout, skip, |
| + Map<String, dynamic> onPlatform}) |
| : testOn = testOn == null |
| ? PlatformSelector.all |
| : new PlatformSelector.parse(testOn), |
| timeout = timeout == null ? const Timeout.factor(1) : timeout, |
| skip = skip != null && skip != false, |
| - skipReason = skip is String ? skip : null { |
| + skipReason = skip is String ? skip : null, |
| + onPlatform = _parseOnPlatform(onPlatform) { |
| if (skip != null && skip is! String && skip is! bool) { |
| throw new ArgumentError( |
| '"skip" must be a String or a bool, was "$skip".'); |
| @@ -52,15 +111,18 @@ class Metadata { |
| /// Dezerializes the result of [Metadata.serialize] into a new [Metadata]. |
| Metadata.deserialize(serialized) |
| - : this.parse( |
| - testOn: serialized['testOn'], |
| - timeout: serialized['timeout']['duration'] == null |
| - ? new Timeout.factor(serialized['timeout']['scaleFactor']) |
| - : new Timeout(new Duration( |
| - microseconds: serialized['timeout']['duration'])), |
| - skip: serialized['skipReason'] == null |
| - ? serialized['skip'] |
| - : serialized['skipReason']); |
| + : testOn = serialized['testOn'] == null |
| + ? PlatformSelector.all |
| + : new PlatformSelector.parse(serialized['testOn']), |
| + timeout = serialized['timeout']['duration'] == null |
| + ? new Timeout.factor(serialized['timeout']['scaleFactor']) |
| + : new Timeout(new Duration( |
| + microseconds: serialized['timeout']['duration'])), |
| + skip = serialized['skip'], |
| + skipReason = serialized['skipReason'], |
| + onPlatform = new Map.fromIterable(serialized['onPlatform'], |
| + key: (pair) => new PlatformSelector.parse(pair.first), |
| + value: (pair) => new Metadata.deserialize(pair.last)); |
| /// Return a new [Metadata] that merges [this] with [other]. |
| /// |
| @@ -70,19 +132,52 @@ class Metadata { |
| testOn: testOn.intersect(other.testOn), |
| timeout: timeout.merge(other.timeout), |
| skip: skip || other.skip, |
| - skipReason: other.skipReason == null ? skipReason : other.skipReason); |
| + skipReason: other.skipReason == null ? skipReason : other.skipReason, |
| + onPlatform: mergeMaps(onPlatform, other.onPlatform)); |
| + |
| + /// Returns a copy of [this] with the given fields changed. |
| + Metadata change({PlatformSelector testOn, Timeout timeout, bool skip, |
| + String skipReason, Map<PlatformSelector, Metadata> onPlatform}) { |
| + if (testOn == null) testOn = this.testOn; |
| + if (timeout == null) timeout = this.timeout; |
| + if (skip == null) skip = this.skip; |
| + if (skipReason == null) skipReason = this.skipReason; |
| + if (onPlatform == null) onPlatform = this.onPlatform; |
| + return new Metadata(testOn: testOn, timeout: timeout, skip: skip, |
| + skipReason: skipReason, onPlatform: onPlatform); |
| + } |
| + |
| + /// Returns a copy of [this] with all platform-specific metadata from |
| + /// [onPlatform] resolved. |
| + Metadata forPlatform(TestPlatform platform, {OperatingSystem os}) { |
|
kevmoo
2015/04/20 22:42:30
TestPlatform and OperatingSystem are not defined
nweiz
2015/04/20 22:57:53
Done.
|
| + var metadata = this; |
| + test.metadata.onPlatform.forEach((platformSelector, platformMetadata) { |
|
kevmoo
2015/04/20 22:42:30
test is not defined
nweiz
2015/04/20 22:57:53
Done.
|
| + if (!platformSelector.evaluate(platform, os: os)) return; |
| + metadata = metadata.merge(platformMetadata); |
| + }); |
| + return metadata.change(onPlatform: {}); |
| + } |
| /// Serializes [this] into a JSON-safe object that can be deserialized using |
| /// [new Metadata.deserialize]. |
| - serialize() => { |
| - 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), |
| - 'timeout': { |
| - 'duration': timeout.duration == null |
| - ? null |
| - : timeout.duration.inMicroseconds, |
| - 'scaleFactor': timeout.scaleFactor |
| - }, |
| - 'skip': skip, |
| - 'skipReason': skipReason |
| - }; |
| + serialize() { |
| + // Make this a list to guarantee that the order is preserved. |
| + var serializedOnPlatform = []; |
| + onPlatform.forEach((key, value) { |
| + serializedOnPlatform.add([key.toString(), value.serialize()]); |
| + }); |
| + |
| + return { |
| + 'testOn': testOn == PlatformSelector.all ? null : testOn.toString(), |
| + 'timeout': { |
| + 'duration': timeout.duration == null |
| + ? null |
| + : timeout.duration.inMicroseconds, |
| + 'scaleFactor': timeout.scaleFactor |
| + }, |
| + 'skip': skip, |
| + 'skipReason': skipReason, |
| + 'onPlatform': serializedOnPlatform |
| + }; |
| + } |
| } |