Properly preserve tags through Metadata.change(). (#466)

Closes #461
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc412c3..7d413aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.12.15+7
+
+* Fix a bug where tags would be dropped when `on_platform` was defined in a
+  config file.
+
 ## 0.12.15+6
 
 * Fix a broken link in the `--help` documentation.
diff --git a/lib/src/backend/metadata.dart b/lib/src/backend/metadata.dart
index 77d69e0..299a6b3 100644
--- a/lib/src/backend/metadata.dart
+++ b/lib/src/backend/metadata.dart
@@ -262,18 +262,26 @@
               value: (metadata1, metadata2) => metadata1.merge(metadata2)));
 
   /// Returns a copy of [this] with the given fields changed.
-  Metadata change({PlatformSelector testOn, Timeout timeout, bool skip,
-      bool verboseTrace, 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 (verboseTrace == null) verboseTrace = this.verboseTrace;
-    if (skipReason == null) skipReason = this.skipReason;
-    if (onPlatform == null) onPlatform = this.onPlatform;
+  Metadata change(
+      {PlatformSelector testOn,
+      Timeout timeout,
+      bool skip,
+      bool verboseTrace,
+      String skipReason,
+      Map<PlatformSelector, Metadata> onPlatform,
+      Set<String> tags,
+      Map<BooleanSelector, Metadata> forTag}) {
+    testOn ??= this.testOn;
+    timeout ??= this.timeout;
+    skip ??= this.skip;
+    verboseTrace ??= this.verboseTrace;
+    skipReason ??= this.skipReason;
+    onPlatform ??= this.onPlatform;
+    tags ??= this.tags;
+    forTag ??= this.forTag;
     return new Metadata(testOn: testOn, timeout: timeout, skip: skip,
         verboseTrace: verboseTrace, skipReason: skipReason,
-        onPlatform: onPlatform);
+        onPlatform: onPlatform, tags: tags, forTag: forTag);
   }
 
   /// Returns a copy of [this] with all platform-specific metadata from
diff --git a/pubspec.yaml b/pubspec.yaml
index 3438955..6f79adc 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test
-version: 0.12.16-dev
+version: 0.12.15+7
 author: Dart Team <misc@dartlang.org>
 description: A library for writing dart unit tests.
 homepage: https://github.com/dart-lang/test
diff --git a/test/backend/metadata_test.dart b/test/backend/metadata_test.dart
index d0eff90..72d0ff3 100644
--- a/test/backend/metadata_test.dart
+++ b/test/backend/metadata_test.dart
@@ -5,6 +5,7 @@
 import 'package:boolean_selector/boolean_selector.dart';
 
 import 'package:test/src/backend/metadata.dart';
+import 'package:test/src/backend/platform_selector.dart';
 import 'package:test/src/backend/test_platform.dart';
 import 'package:test/src/frontend/skip.dart';
 import 'package:test/src/frontend/timeout.dart';
@@ -186,4 +187,30 @@
       }, throwsArgumentError);
     });
   });
+
+  group("change", () {
+    test("preserves all fields if no parameters are passed", () {
+      var metadata = new Metadata(
+          testOn: new PlatformSelector.parse("linux"),
+          timeout: new Timeout.factor(2),
+          skip: true,
+          skipReason: "just because",
+          verboseTrace: true,
+          tags: ["foo", "bar"],
+          onPlatform: {
+            new PlatformSelector.parse("mac-os"): new Metadata(skip: false)
+          },
+          forTag: {
+            new BooleanSelector.parse("slow"):
+                new Metadata(timeout: new Timeout.factor(4))
+          });
+      expect(metadata.serialize(), equals(metadata.change().serialize()));
+    });
+
+    test("updates a changed field", () {
+      var metadata = new Metadata(timeout: new Timeout.factor(2));
+      expect(metadata.change(timeout: new Timeout.factor(3)).timeout,
+          equals(new Timeout.factor(3)));
+    });
+  });
 }