Migrate to pkg/test_descriptor, stop using pkg/scheduled_test

Closes https://github.com/dart-lang/glob/issues/14
diff --git a/pubspec.yaml b/pubspec.yaml
index 6c3e755..10a8b10 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -10,6 +10,6 @@
   string_scanner: ">=0.1.0 <2.0.0"
 dev_dependencies:
   test: ">=0.12.0 <0.13.0"
-  scheduled_test: ">=0.12.0 <0.13.0"
+  test_descriptor: "^1.0.0"
 environment:
   sdk: ">=1.23.0 <2.0.0"
diff --git a/test/list_test.dart b/test/list_test.dart
index 114f2f9..ee9814f 100644
--- a/test/list_test.dart
+++ b/test/list_test.dart
@@ -9,17 +9,12 @@
 import 'package:glob/glob.dart';
 import 'package:glob/src/utils.dart';
 import 'package:path/path.dart' as p;
-import 'package:scheduled_test/descriptor.dart' as d;
-import 'package:scheduled_test/scheduled_test.dart';
-import 'package:test/test.dart' show TestOn;
-
-String sandbox;
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
 
 void main() {
-  setUp(() {
-    scheduleSandbox();
-
-    d.dir("foo", [
+  setUp(() async {
+    await d.dir("foo", [
       d.file("bar"),
       d.dir("baz", [d.file("bang"), d.file("qux")])
     ]).create();
@@ -31,19 +26,14 @@
     });
 
     test("reports exceptions for non-existent case-sensitive directories", () {
-      schedule(() {
-        expect(new Glob("non/existent/**", caseSensitive: true).list().toList(),
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("non/existent/**", caseSensitive: true).list().toList(),
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
 
     test("reports exceptions for non-existent case-insensitive directories",
         () {
-      schedule(() {
-        expect(
-            new Glob("non/existent/**", caseSensitive: false).list().toList(),
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("non/existent/**", caseSensitive: false).list().toList(),
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
   });
 
@@ -53,105 +43,93 @@
     });
 
     test("reports exceptions for non-existent case-sensitive directories", () {
-      schedule(() {
-        expect(new Glob("non/existent/**", caseSensitive: true).listSync,
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("non/existent/**", caseSensitive: true).listSync,
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
 
     test("reports exceptions for non-existent case-insensitive directories",
         () {
-      schedule(() {
-        expect(new Glob("non/existent/**", caseSensitive: false).listSync,
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("non/existent/**", caseSensitive: false).listSync,
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
   });
 
   group("when case-sensitive", () {
     test("lists literals case-sensitively", () {
-      schedule(() {
-        expect(new Glob("foo/BAZ/qux", caseSensitive: true).listSync,
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("foo/BAZ/qux", caseSensitive: true).listSync,
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
 
     test("lists ranges case-sensitively", () {
-      schedule(() {
-        expect(new Glob("foo/[BX][A-Z]z/qux", caseSensitive: true).listSync,
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("foo/[BX][A-Z]z/qux", caseSensitive: true).listSync,
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
 
     test("options preserve case-sensitivity", () {
-      schedule(() {
-        expect(new Glob("foo/{BAZ,ZAP}/qux", caseSensitive: true).listSync,
-            throwsA(new isInstanceOf<FileSystemException>()));
-      });
+      expect(new Glob("foo/{BAZ,ZAP}/qux", caseSensitive: true).listSync,
+          throwsA(new isInstanceOf<FileSystemException>()));
     });
   });
 
-  syncAndAsync((list) {
+  syncAndAsync((ListFn list) {
     group("literals", () {
-      test("lists a single literal", () {
-        expect(list("foo/baz/qux"),
-            completion(equals([p.join("foo", "baz", "qux")])));
+      test("lists a single literal", () async {
+        expect(
+            await list("foo/baz/qux"), equals([p.join("foo", "baz", "qux")]));
       });
 
-      test("lists a non-matching literal", () {
-        expect(list("foo/baz/nothing"), completion(isEmpty));
+      test("lists a non-matching literal", () async {
+        expect(await list("foo/baz/nothing"), isEmpty);
       });
     });
 
     group("star", () {
-      test("lists within filenames but not across directories", () {
-        expect(
-            list("foo/b*"),
-            completion(
-                unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")])));
+      test("lists within filenames but not across directories", () async {
+        expect(await list("foo/b*"),
+            unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")]));
       });
 
-      test("lists the empy string", () {
-        expect(list("foo/bar*"), completion(equals([p.join("foo", "bar")])));
+      test("lists the empy string", () async {
+        expect(await list("foo/bar*"), equals([p.join("foo", "bar")]));
       });
     });
 
     group("double star", () {
-      test("lists within filenames", () {
+      test("lists within filenames", () async {
         expect(
-            list("foo/baz/**"),
-            completion(unorderedEquals(
-                [p.join("foo", "baz", "qux"), p.join("foo", "baz", "bang")])));
+            await list("foo/baz/**"),
+            unorderedEquals(
+                [p.join("foo", "baz", "qux"), p.join("foo", "baz", "bang")]));
       });
 
-      test("lists the empty string", () {
-        expect(list("foo/bar**"), completion(equals([p.join("foo", "bar")])));
+      test("lists the empty string", () async {
+        expect(await list("foo/bar**"), equals([p.join("foo", "bar")]));
       });
 
-      test("lists recursively", () {
+      test("lists recursively", () async {
         expect(
-            list("foo/**"),
-            completion(unorderedEquals([
+            await list("foo/**"),
+            unorderedEquals([
               p.join("foo", "bar"),
               p.join("foo", "baz"),
               p.join("foo", "baz", "qux"),
               p.join("foo", "baz", "bang")
-            ])));
+            ]));
       });
 
-      test("combines with literals", () {
+      test("combines with literals", () async {
         expect(
-            list("foo/ba**"),
-            completion(unorderedEquals([
+            await list("foo/ba**"),
+            unorderedEquals([
               p.join("foo", "bar"),
               p.join("foo", "baz"),
               p.join("foo", "baz", "qux"),
               p.join("foo", "baz", "bang")
-            ])));
+            ]));
       });
 
-      test("lists recursively in the middle of a glob", () {
-        d.dir("deep", [
+      test("lists recursively in the middle of a glob", () async {
+        await d.dir("deep", [
           d.dir("a", [
             d.dir("b", [
               d.dir("c", [d.file("d"), d.file("long-file")]),
@@ -161,65 +139,60 @@
         ]).create();
 
         expect(
-            list("deep/**/?/?"),
-            completion(unorderedEquals([
+            await list("deep/**/?/?"),
+            unorderedEquals([
               p.join("deep", "a", "b", "c"),
               p.join("deep", "a", "b", "c", "d")
-            ])));
+            ]));
       });
     });
 
     group("any char", () {
-      test("matches a character", () {
-        expect(
-            list("foo/ba?"),
-            completion(
-                unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")])));
+      test("matches a character", () async {
+        expect(await list("foo/ba?"),
+            unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")]));
       });
 
-      test("doesn't match a separator", () {
-        expect(list("foo?bar"), completion(isEmpty));
+      test("doesn't match a separator", () async {
+        expect(await list("foo?bar"), isEmpty);
       });
     });
 
     group("range", () {
-      test("matches a range of characters", () {
+      test("matches a range of characters", () async {
+        expect(await list("foo/ba[a-z]"),
+            unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")]));
+      });
+
+      test("matches a specific list of characters", () async {
+        expect(await list("foo/ba[rz]"),
+            unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")]));
+      });
+
+      test("doesn't match outside its range", () async {
         expect(
-            list("foo/ba[a-z]"),
-            completion(
-                unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")])));
+            await list("foo/ba[a-x]"), unorderedEquals([p.join("foo", "bar")]));
       });
 
-      test("matches a specific list of characters", () {
+      test("doesn't match outside its specific list", () async {
         expect(
-            list("foo/ba[rz]"),
-            completion(
-                unorderedEquals([p.join("foo", "bar"), p.join("foo", "baz")])));
-      });
-
-      test("doesn't match outside its range", () {
-        expect(list("foo/ba[a-x]"),
-            completion(unorderedEquals([p.join("foo", "bar")])));
-      });
-
-      test("doesn't match outside its specific list", () {
-        expect(list("foo/ba[rx]"),
-            completion(unorderedEquals([p.join("foo", "bar")])));
+            await list("foo/ba[rx]"), unorderedEquals([p.join("foo", "bar")]));
       });
     });
 
     test("the same file shouldn't be non-recursively listed multiple times",
-        () {
-      d.dir("multi", [
+        () async {
+      await d.dir("multi", [
         d.dir("start-end", [d.file("file")])
       ]).create();
 
-      expect(list("multi/{start-*/f*,*-end/*e}"),
-          completion(equals([p.join("multi", "start-end", "file")])));
+      expect(await list("multi/{start-*/f*,*-end/*e}"),
+          equals([p.join("multi", "start-end", "file")]));
     });
 
-    test("the same file shouldn't be recursively listed multiple times", () {
-      d.dir("multi", [
+    test("the same file shouldn't be recursively listed multiple times",
+        () async {
+      await d.dir("multi", [
         d.dir("a", [
           d.dir("b", [
             d.file("file"),
@@ -232,169 +205,141 @@
       ]).create();
 
       expect(
-          list("multi/{*/*/*/file,a/**/file}"),
-          completion(unorderedEquals([
+          await list("multi/{*/*/*/file,a/**/file}"),
+          unorderedEquals([
             p.join("multi", "a", "b", "file"),
             p.join("multi", "a", "b", "c", "file"),
             p.join("multi", "a", "x", "y", "file")
-          ])));
+          ]));
     });
 
     group("with symlinks", () {
-      setUp(() {
-        schedule(() {
-          return new Link(p.join(sandbox, "dir", "link"))
-              .create(p.join(sandbox, "foo", "baz"), recursive: true);
-        }, "symlink foo/baz to dir/link");
+      setUp(() async {
+        await new Link(p.join(d.sandbox, "dir", "link"))
+            .create(p.join(d.sandbox, "foo", "baz"), recursive: true);
       });
 
-      test("follows symlinks by default", () {
+      test("follows symlinks by default", () async {
         expect(
-            list("dir/**"),
-            completion(unorderedEquals([
+            await list("dir/**"),
+            unorderedEquals([
               p.join("dir", "link"),
               p.join("dir", "link", "bang"),
               p.join("dir", "link", "qux")
-            ])));
+            ]));
       });
 
-      test("doesn't follow symlinks with followLinks: false", () {
-        expect(list("dir/**", followLinks: false),
-            completion(equals([p.join("dir", "link")])));
+      test("doesn't follow symlinks with followLinks: false", () async {
+        expect(await list("dir/**", followLinks: false),
+            equals([p.join("dir", "link")]));
       });
 
-      test("shouldn't crash on broken symlinks", () {
-        schedule(() {
-          return new Directory(p.join(sandbox, "foo")).delete(recursive: true);
-        });
+      test("shouldn't crash on broken symlinks", () async {
+        await new Directory(p.join(d.sandbox, "foo")).delete(recursive: true);
 
-        expect(list("dir/**"), completion(equals([p.join("dir", "link")])));
+        expect(await list("dir/**"), equals([p.join("dir", "link")]));
       });
     });
 
-    test("always lists recursively with recursive: true", () {
+    test("always lists recursively with recursive: true", () async {
       expect(
-          list("foo", recursive: true),
-          completion(unorderedEquals([
+          await list("foo", recursive: true),
+          unorderedEquals([
             "foo",
             p.join("foo", "bar"),
             p.join("foo", "baz"),
             p.join("foo", "baz", "qux"),
             p.join("foo", "baz", "bang")
-          ])));
+          ]));
     });
 
-    test("lists an absolute glob", () {
-      expect(schedule(() {
-        var pattern =
-            separatorToForwardSlash(p.absolute(p.join(sandbox, 'foo/baz/**')));
+    test("lists an absolute glob", () async {
+      var pattern =
+          separatorToForwardSlash(p.absolute(p.join(d.sandbox, 'foo/baz/**')));
 
-        return list(pattern);
-      }),
-          completion(unorderedEquals(
-              [p.join("foo", "baz", "bang"), p.join("foo", "baz", "qux")])));
+      var result = await list(pattern);
+
+      expect(
+          result,
+          unorderedEquals(
+              [p.join("foo", "baz", "bang"), p.join("foo", "baz", "qux")]));
     });
 
     // Regression test for #4.
-    test("lists an absolute case-insensitive glob", () {
-      expect(schedule(() {
-        var pattern =
-            separatorToForwardSlash(p.absolute(p.join(sandbox, 'foo/Baz/**')));
+    test("lists an absolute case-insensitive glob", () async {
+      var pattern =
+          separatorToForwardSlash(p.absolute(p.join(d.sandbox, 'foo/Baz/**')));
 
-        return list(pattern, caseSensitive: false);
-      }),
-          completion(unorderedEquals(
-              [p.join("foo", "baz", "bang"), p.join("foo", "baz", "qux")])));
+      expect(
+          await list(pattern, caseSensitive: false),
+          unorderedEquals(
+              [p.join("foo", "baz", "bang"), p.join("foo", "baz", "qux")]));
     });
 
-    test("lists a subdirectory that sometimes exists", () {
-      d.dir("top", [
+    test("lists a subdirectory that sometimes exists", () async {
+      await d.dir("top", [
         d.dir("dir1", [
           d.dir("subdir", [d.file("file")])
         ]),
         d.dir("dir2", [])
       ]).create();
 
-      expect(list("top/*/subdir/**"),
-          completion(equals([p.join("top", "dir1", "subdir", "file")])));
+      expect(await list("top/*/subdir/**"),
+          equals([p.join("top", "dir1", "subdir", "file")]));
     });
 
     group("when case-insensitive", () {
-      test("lists literals case-insensitively", () {
-        expect(list("foo/baz/qux", caseSensitive: false),
-            completion(equals([p.join("foo", "baz", "qux")])));
-        expect(list("foo/BAZ/qux", caseSensitive: false),
-            completion(equals([p.join("foo", "baz", "qux")])));
+      test("lists literals case-insensitively", () async {
+        expect(await list("foo/baz/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
+        expect(await list("foo/BAZ/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
       });
 
-      test("lists ranges case-insensitively", () {
-        expect(list("foo/[bx][a-z]z/qux", caseSensitive: false),
-            completion(equals([p.join("foo", "baz", "qux")])));
-        expect(list("foo/[BX][A-Z]z/qux", caseSensitive: false),
-            completion(equals([p.join("foo", "baz", "qux")])));
+      test("lists ranges case-insensitively", () async {
+        expect(await list("foo/[bx][a-z]z/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
+        expect(await list("foo/[BX][A-Z]z/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
       });
 
-      test("options preserve case-insensitivity", () {
-        // expect(list("foo/{bar,baz}/qux", caseSensitive: false),
-        //     completion(equals([p.join("foo", "baz", "qux")])));
-        expect(list("foo/{BAR,BAZ}/qux", caseSensitive: false),
-            completion(equals([p.join("foo", "baz", "qux")])));
+      test("options preserve case-insensitivity", () async {
+        expect(await list("foo/{bar,baz}/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
+        expect(await list("foo/{BAR,BAZ}/qux", caseSensitive: false),
+            equals([p.join("foo", "baz", "qux")]));
       });
     });
   });
 }
 
-typedef Future<List<String>> ListFn(String glob,
+typedef FutureOr<List<String>> ListFn(String glob,
     {bool recursive, bool followLinks, bool caseSensitive});
 
 /// Runs [callback] in two groups with two values of [listFn]: one that uses
 /// [Glob.list], one that uses [Glob.listSync].
-void syncAndAsync(callback(ListFn listFn)) {
+void syncAndAsync(FutureOr callback(ListFn listFn)) {
   group("async", () {
     callback((pattern, {recursive: false, followLinks: true, caseSensitive}) {
-      return schedule(() {
-        var glob = new Glob(pattern,
-            recursive: recursive, caseSensitive: caseSensitive);
+      var glob =
+          new Glob(pattern, recursive: recursive, caseSensitive: caseSensitive);
 
-        // TODO(kevmoo) - need to get off scheduled_test to fix this
-        // https://github.com/dart-lang/glob/issues/14
-        // ignore: return_of_invalid_type
-        return glob
-            .list(root: sandbox, followLinks: followLinks)
-            .map((entity) => p.relative(entity.path, from: sandbox))
-            .toList();
-      }, 'listing $pattern');
+      return glob
+          .list(root: d.sandbox, followLinks: followLinks)
+          .map((entity) => p.relative(entity.path, from: d.sandbox))
+          .toList();
     });
   });
 
   group("sync", () {
     callback((pattern, {recursive: false, followLinks: true, caseSensitive}) {
-      return schedule(() {
-        var glob = new Glob(pattern,
-            recursive: recursive, caseSensitive: caseSensitive);
+      var glob =
+          new Glob(pattern, recursive: recursive, caseSensitive: caseSensitive);
 
-        return glob
-            .listSync(root: sandbox, followLinks: followLinks)
-            .map((entity) => p.relative(entity.path, from: sandbox))
-            .toList();
-      }, 'listing $pattern');
+      return glob
+          .listSync(root: d.sandbox, followLinks: followLinks)
+          .map((entity) => p.relative(entity.path, from: d.sandbox))
+          .toList();
     });
   });
 }
-
-void scheduleSandbox() {
-  schedule(() {
-    return Directory.systemTemp.createTemp('glob_').then((dir) {
-      sandbox = dir.path;
-      d.defaultRoot = sandbox;
-    });
-  }, 'creating sandbox');
-
-  currentSchedule.onComplete.schedule(() {
-    d.defaultRoot = null;
-    if (sandbox == null) return null;
-    var oldSandbox = sandbox;
-    sandbox = null;
-    return new Directory(oldSandbox).delete(recursive: true);
-  });
-}