| Index: test/backend/metadata_test.dart | 
| diff --git a/test/backend/metadata_test.dart b/test/backend/metadata_test.dart | 
| index ab14a74bde550a52a9b895f5b73e4085b75c0a37..44156feb9eaa60803c800899d6fb0aa888a6b2cc 100644 | 
| --- a/test/backend/metadata_test.dart | 
| +++ b/test/backend/metadata_test.dart | 
| @@ -9,6 +9,91 @@ import 'package:test/src/frontend/skip.dart'; | 
| import 'package:test/test.dart'; | 
|  | 
| void main() { | 
| +  group("Metadata", () { | 
| +    expectTags(tags, expected) { | 
| +      expect(new Metadata(tags: tags).tags, unorderedEquals(expected)); | 
| +      expect(new Metadata.parse(tags: tags).tags, unorderedEquals(expected)); | 
| +      var serialized = { | 
| +        "tags": tags, | 
| +        "timeout": "none", | 
| +        "onPlatform": [], | 
| +      }; | 
| +      expect(new Metadata.deserialize(serialized).tags, | 
| +          unorderedEquals(expected)); | 
| +    } | 
| + | 
| +    expectTagsError({tags, String message}) { | 
| +      [ | 
| +        () => new Metadata(tags: tags), | 
| +        () => new Metadata.parse(tags: tags), | 
| +      ].forEach((fn()) { | 
| +        try { | 
| +          fn(); | 
| +          fail("Expected ArgumentError for $tags"); | 
| +        } on ArgumentError catch(e) { | 
| +          expect(e.message, message); | 
| +          expect(e.invalidValue, tags); | 
| +          expect(e.name, "tags"); | 
| +        } | 
| +      }); | 
| +    } | 
| + | 
| +    test("takes no tags", () { | 
| +      expectTags(null, []); | 
| +      expectTags("", []); | 
| +      expectTags(" ", []); | 
| +      expectTags([], []); | 
| +    }); | 
| + | 
| +    test("takes some tags as Iterable", () { | 
| +      var tags = ["a", "b"]; | 
| +      expectTags(tags, tags); | 
| +      expectTags(new Set.from(tags), tags); | 
| +    }); | 
| + | 
| +    test("takes some tags as String", () { | 
| +      expectTags("a", ["a"]); | 
| +      expectTags("a,b", ["a", "b"]); | 
| +      expectTags(" a,,,b , c\n,d\t", ["a", "b", "c", "d"]); | 
| +    }); | 
| + | 
| +    test("refuses bad tag types", () { | 
| +      expectTagsError( | 
| +          tags: 1, | 
| +          message: "must be either String or Iterable"); | 
| +    }); | 
| + | 
| +    test("refuses non-String tag names", () { | 
| +      expectTagsError( | 
| +          tags: [1], | 
| +          message: "tag name must be String"); | 
| +      expectTagsError( | 
| +          tags: [null], | 
| +          message: "tag name must be String"); | 
| +    }); | 
| + | 
| +    test("refuses blank tag names", () { | 
| +      var errorMsg = "tag name must contain non-whitespace characters"; | 
| +      expectTagsError( | 
| +          tags: [""], | 
| +          message: errorMsg); | 
| +      expectTagsError( | 
| +          tags: [" "], | 
| +          message: errorMsg); | 
| +    }); | 
| + | 
| +    test("merges tags by computing the union of the two tag sets", () { | 
| +      expect(new Metadata(tags: "a,b").merge(new Metadata(tags: "b,c")).tags, | 
| +        unorderedEquals(["a", "b", "c"])); | 
| +    }); | 
| + | 
| +    test("serializes tags to a List", () { | 
| +      var serialized = new Metadata(tags: "a,b").serialize()['tags']; | 
| +      expect(serialized, new isInstanceOf<List>()); | 
| +      expect(serialized, ["a", "b"]); | 
| +    }); | 
| +  }); | 
| + | 
| group("onPlatform", () { | 
| test("parses a valid map", () { | 
| var metadata = new Metadata.parse(onPlatform: { | 
|  |