Remove scheduled test (#44)

diff --git a/.travis.yml b/.travis.yml
index deb901b..4c8c5ff 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,20 +1,10 @@
 language: dart
-dart:
-  - dev
-  - stable
+dart: dev
 
 dart_task:
-  - test
-
-matrix:
-  include:
-    - dart: dev
-      dart_task: dartfmt
-    # Only care about being analyzer clean for dev and stable
-    - dart: dev
-      dart_task: dartanalyzer
-    - dart: stable
-      dart_task: dartanalyzer
+ - test
+ - dartfmt
+ - dartanalyzer
 
 # Only building master means that we don't run two builds for each pull request.
 branches:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4ca0ba..5e6c3d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.9.7+6
+
+* Internal changes only, namely removing dep on scheduled test. 
+
 # 0.9.7+5
 
 * Fix an analysis warning.
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index ef39eef..18b53c9 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -71,18 +71,6 @@
 /// under the covers.
 Future newFuture(callback()) => new Future.value().then((_) => callback());
 
-/// Returns a [Future] that completes after pumping the event queue [times]
-/// times. By default, this should pump the event queue enough times to allow
-/// any code to run, as long as it's not waiting on some external event.
-Future pumpEventQueue([int times = 20]) {
-  if (times == 0) return new Future.value();
-  // We use a delayed future to allow microtask events to finish. The
-  // Future.value or Future() constructors use scheduleMicrotask themselves and
-  // would therefore not wait for microtask callbacks that are scheduled after
-  // invoking this method.
-  return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1));
-}
-
 /// A stream transformer that batches all events that are sent at the same time.
 ///
 /// When multiple events are synchronously added to a stream controller, the
diff --git a/pubspec.yaml b/pubspec.yaml
index d1260d5..62abc69 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: watcher
-version: 0.9.7+6.dev
+version: 0.9.7+6
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/watcher
 description: >
@@ -12,5 +12,5 @@
   path: '>=0.9.0 <2.0.0'
 dev_dependencies:
   benchmark_harness: '^1.0.4'
-  scheduled_test: '^0.12.0'
-  test: '^0.12.18+1'
+  test: '^0.12.29'
+  test_descriptor: '^1.0.0'
diff --git a/test/directory_watcher/linux_test.dart b/test/directory_watcher/linux_test.dart
index 34e6896..25c5504 100644
--- a/test/directory_watcher/linux_test.dart
+++ b/test/directory_watcher/linux_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('linux')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/linux.dart';
 import 'package:watcher/watcher.dart';
 
@@ -14,8 +14,6 @@
 void main() {
   watcherFactory = (dir) => new LinuxDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 
   test('DirectoryWatcher creates a LinuxDirectoryWatcher on Linux', () {
@@ -24,15 +22,15 @@
   });
 
   test('emits events for many nested files moved out then immediately back in',
-      () {
+      () async {
     withPermutations(
         (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
 
     renameDir("dir/sub", "sub");
     renameDir("sub", "dir/sub");
 
-    allowEither(() {
+    await allowEither(() {
       inAnyOrder(withPermutations(
           (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
 
diff --git a/test/directory_watcher/mac_os_test.dart b/test/directory_watcher/mac_os_test.dart
index 46b7ca2..8fa76fd 100644
--- a/test/directory_watcher/mac_os_test.dart
+++ b/test/directory_watcher/mac_os_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('mac-os')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/mac_os.dart';
 import 'package:watcher/watcher.dart';
 
@@ -14,8 +14,6 @@
 void main() {
   watcherFactory = (dir) => new MacOSDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 
   test('DirectoryWatcher creates a MacOSDirectoryWatcher on Mac OS', () {
@@ -25,28 +23,28 @@
 
   test(
       'does not notify about the watched directory being deleted and '
-      'recreated immediately before watching', () {
+      'recreated immediately before watching', () async {
     createDir("dir");
     writeFile("dir/old.txt");
     deleteDir("dir");
     createDir("dir");
 
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
     writeFile("dir/newer.txt");
-    expectAddEvent("dir/newer.txt");
+    await expectAddEvent("dir/newer.txt");
   });
 
   test('emits events for many nested files moved out then immediately back in',
-      () {
+      () async {
     withPermutations(
         (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
 
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
 
     renameDir("dir/sub", "sub");
     renameDir("sub", "dir/sub");
 
-    allowEither(() {
+    await allowEither(() {
       inAnyOrder(withPermutations(
           (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
 
diff --git a/test/directory_watcher/polling_test.dart b/test/directory_watcher/polling_test.dart
index 0192b25..39bbbef 100644
--- a/test/directory_watcher/polling_test.dart
+++ b/test/directory_watcher/polling_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/watcher.dart';
 
 import 'shared.dart';
@@ -13,16 +13,14 @@
   watcherFactory = (dir) => new PollingDirectoryWatcher(dir,
       pollingDelay: new Duration(milliseconds: 100));
 
-  setUp(createSandbox);
-
   sharedTests();
 
-  test('does not notify if the modification time did not change', () {
+  test('does not notify if the modification time did not change', () async {
     writeFile("a.txt", contents: "before");
     writeFile("b.txt", contents: "before");
-    startWatcher();
+    await startWatcher();
     writeFile("a.txt", contents: "after", updateModified: false);
     writeFile("b.txt", contents: "after");
-    expectModifyEvent("b.txt");
+    await expectModifyEvent("b.txt");
   });
 }
diff --git a/test/directory_watcher/shared.dart b/test/directory_watcher/shared.dart
index 2bdc077..2c0f441 100644
--- a/test/directory_watcher/shared.dart
+++ b/test/directory_watcher/shared.dart
@@ -2,136 +2,138 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/utils.dart';
 
 import '../utils.dart';
 
 void sharedTests() {
-  test('does not notify for files that already exist when started', () {
+  test('does not notify for files that already exist when started', () async {
     // Make some pre-existing files.
     writeFile("a.txt");
     writeFile("b.txt");
 
-    startWatcher();
+    await startWatcher();
 
     // Change one after the watcher is running.
     writeFile("b.txt", contents: "modified");
 
     // We should get a modify event for the changed file, but no add events
     // for them before this.
-    expectModifyEvent("b.txt");
+    await expectModifyEvent("b.txt");
   });
 
-  test('notifies when a file is added', () {
-    startWatcher();
+  test('notifies when a file is added', () async {
+    await startWatcher();
     writeFile("file.txt");
-    expectAddEvent("file.txt");
+    await expectAddEvent("file.txt");
   });
 
-  test('notifies when a file is modified', () {
+  test('notifies when a file is modified', () async {
     writeFile("file.txt");
-    startWatcher();
+    await startWatcher();
     writeFile("file.txt", contents: "modified");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
-  test('notifies when a file is removed', () {
+  test('notifies when a file is removed', () async {
     writeFile("file.txt");
-    startWatcher();
+    await startWatcher();
     deleteFile("file.txt");
-    expectRemoveEvent("file.txt");
+    await expectRemoveEvent("file.txt");
   });
 
-  test('notifies when a file is modified multiple times', () {
+  test('notifies when a file is modified multiple times', () async {
     writeFile("file.txt");
-    startWatcher();
+    await startWatcher();
     writeFile("file.txt", contents: "modified");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
     writeFile("file.txt", contents: "modified again");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
-  test('notifies even if the file contents are unchanged', () {
+  test('notifies even if the file contents are unchanged', () async {
     writeFile("a.txt", contents: "same");
     writeFile("b.txt", contents: "before");
-    startWatcher();
+    await startWatcher();
 
     writeFile("a.txt", contents: "same");
     writeFile("b.txt", contents: "after");
-    inAnyOrder([isModifyEvent("a.txt"), isModifyEvent("b.txt")]);
+    await inAnyOrder([isModifyEvent("a.txt"), isModifyEvent("b.txt")]);
   });
 
-  test('when the watched directory is deleted, removes all files', () {
+  test('when the watched directory is deleted, removes all files', () async {
     writeFile("dir/a.txt");
     writeFile("dir/b.txt");
 
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
 
     deleteDir("dir");
-    inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
   });
 
-  test('when the watched directory is moved, removes all files', () {
+  test('when the watched directory is moved, removes all files', () async {
     writeFile("dir/a.txt");
     writeFile("dir/b.txt");
 
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
 
     renameDir("dir", "moved_dir");
     createDir("dir");
-    inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
   });
 
   // Regression test for b/30768513.
   test(
       "doesn't crash when the directory is moved immediately after a subdir "
-      "is added", () {
+      "is added", () async {
     writeFile("dir/a.txt");
     writeFile("dir/b.txt");
 
-    startWatcher(path: "dir");
+    await startWatcher(path: "dir");
 
     createDir("dir/subdir");
     renameDir("dir", "moved_dir");
     createDir("dir");
-    inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
+    await inAnyOrder([isRemoveEvent("dir/a.txt"), isRemoveEvent("dir/b.txt")]);
   });
 
   group("moves", () {
-    test('notifies when a file is moved within the watched directory', () {
+    test('notifies when a file is moved within the watched directory',
+        () async {
       writeFile("old.txt");
-      startWatcher();
+      await startWatcher();
       renameFile("old.txt", "new.txt");
 
-      inAnyOrder([isAddEvent("new.txt"), isRemoveEvent("old.txt")]);
+      await inAnyOrder([isAddEvent("new.txt"), isRemoveEvent("old.txt")]);
     });
 
     test('notifies when a file is moved from outside the watched directory',
-        () {
+        () async {
       writeFile("old.txt");
       createDir("dir");
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
 
       renameFile("old.txt", "dir/new.txt");
       expectAddEvent("dir/new.txt");
     });
 
-    test('notifies when a file is moved outside the watched directory', () {
+    test('notifies when a file is moved outside the watched directory',
+        () async {
       writeFile("dir/old.txt");
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
 
       renameFile("dir/old.txt", "new.txt");
       expectRemoveEvent("dir/old.txt");
     });
 
-    test('notifies when a file is moved onto an existing one', () {
+    test('notifies when a file is moved onto an existing one', () async {
       writeFile("from.txt");
       writeFile("to.txt");
-      startWatcher();
+      await startWatcher();
 
       renameFile("from.txt", "to.txt");
-      inAnyOrder([isRemoveEvent("from.txt"), isModifyEvent("to.txt")]);
+      await inAnyOrder([isRemoveEvent("from.txt"), isModifyEvent("to.txt")]);
     });
   });
 
@@ -144,14 +146,15 @@
   // that as well.
   group("clustered changes", () {
     test("doesn't notify when a file is created and then immediately removed",
-        () {
-      startWatcher();
+        () async {
+      writeFile("test.txt");
+      await startWatcher();
       writeFile("file.txt");
       deleteFile("file.txt");
 
       // Backup case.
       startClosingEventStream();
-      allowEvents(() {
+      await allowEvents(() {
         expectAddEvent("file.txt");
         expectRemoveEvent("file.txt");
       });
@@ -159,14 +162,14 @@
 
     test(
         "reports a modification when a file is deleted and then immediately "
-        "recreated", () {
+        "recreated", () async {
       writeFile("file.txt");
-      startWatcher();
+      await startWatcher();
 
       deleteFile("file.txt");
       writeFile("file.txt", contents: "re-created");
 
-      allowEither(() {
+      await allowEither(() {
         expectModifyEvent("file.txt");
       }, () {
         // Backup case.
@@ -177,14 +180,14 @@
 
     test(
         "reports a modification when a file is moved and then immediately "
-        "recreated", () {
+        "recreated", () async {
       writeFile("old.txt");
-      startWatcher();
+      await startWatcher();
 
       renameFile("old.txt", "new.txt");
       writeFile("old.txt", contents: "re-created");
 
-      allowEither(() {
+      await allowEither(() {
         inAnyOrder([isModifyEvent("old.txt"), isAddEvent("new.txt")]);
       }, () {
         // Backup case.
@@ -196,76 +199,77 @@
 
     test(
         "reports a removal when a file is modified and then immediately "
-        "removed", () {
+        "removed", () async {
       writeFile("file.txt");
-      startWatcher();
+      await startWatcher();
 
       writeFile("file.txt", contents: "modified");
       deleteFile("file.txt");
 
       // Backup case.
-      allowModifyEvent("file.txt");
+      await allowModifyEvent("file.txt");
 
-      expectRemoveEvent("file.txt");
+      await expectRemoveEvent("file.txt");
     });
 
     test("reports an add when a file is added and then immediately modified",
-        () {
-      startWatcher();
+        () async {
+      await startWatcher();
 
       writeFile("file.txt");
       writeFile("file.txt", contents: "modified");
 
-      expectAddEvent("file.txt");
+      await expectAddEvent("file.txt");
 
       // Backup case.
       startClosingEventStream();
-      allowModifyEvent("file.txt");
+      await allowModifyEvent("file.txt");
     });
   });
 
   group("subdirectories", () {
-    test('watches files in subdirectories', () {
-      startWatcher();
+    test('watches files in subdirectories', () async {
+      await startWatcher();
       writeFile("a/b/c/d/file.txt");
       expectAddEvent("a/b/c/d/file.txt");
     });
 
     test(
         'notifies when a subdirectory is moved within the watched directory '
-        'and then its contents are modified', () {
+        'and then its contents are modified', () async {
       writeFile("old/file.txt");
-      startWatcher();
+      await startWatcher();
 
       renameDir("old", "new");
-      inAnyOrder([isRemoveEvent("old/file.txt"), isAddEvent("new/file.txt")]);
+      await inAnyOrder(
+          [isRemoveEvent("old/file.txt"), isAddEvent("new/file.txt")]);
 
       writeFile("new/file.txt", contents: "modified");
-      expectModifyEvent("new/file.txt");
+      await expectModifyEvent("new/file.txt");
     });
 
-    test('notifies when a file is replaced by a subdirectory', () {
+    test('notifies when a file is replaced by a subdirectory', () async {
       writeFile("new");
       writeFile("old/file.txt");
-      startWatcher();
+      await startWatcher();
 
       deleteFile("new");
       renameDir("old", "new");
-      inAnyOrder([
+      await inAnyOrder([
         isRemoveEvent("new"),
         isRemoveEvent("old/file.txt"),
         isAddEvent("new/file.txt")
       ]);
     });
 
-    test('notifies when a subdirectory is replaced by a file', () {
+    test('notifies when a subdirectory is replaced by a file', () async {
       writeFile("old");
       writeFile("new/file.txt");
-      startWatcher();
+      await startWatcher();
 
       renameDir("new", "newer");
       renameFile("old", "new");
-      inAnyOrder([
+      await inAnyOrder([
         isRemoveEvent("new/file.txt"),
         isAddEvent("newer/file.txt"),
         isRemoveEvent("old"),
@@ -275,23 +279,23 @@
       "mac-os": new Skip("https://github.com/dart-lang/watcher/issues/21")
     });
 
-    test('emits events for many nested files added at once', () {
+    test('emits events for many nested files added at once', () async {
       withPermutations((i, j, k) => writeFile("sub/sub-$i/sub-$j/file-$k.txt"));
 
       createDir("dir");
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
       renameDir("sub", "dir/sub");
 
-      inAnyOrder(withPermutations(
+      await inAnyOrder(withPermutations(
           (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
     });
 
-    test('emits events for many nested files removed at once', () {
+    test('emits events for many nested files removed at once', () async {
       withPermutations(
           (i, j, k) => writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
 
       createDir("dir");
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
 
       // Rename the directory rather than deleting it because native watchers
       // report a rename as a single DELETE event for the directory, whereas
@@ -299,19 +303,19 @@
       // directory.
       renameDir("dir/sub", "sub");
 
-      inAnyOrder(withPermutations(
+      await inAnyOrder(withPermutations(
           (i, j, k) => isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")));
     });
 
-    test('emits events for many nested files moved at once', () {
+    test('emits events for many nested files moved at once', () async {
       withPermutations(
           (i, j, k) => writeFile("dir/old/sub-$i/sub-$j/file-$k.txt"));
 
       createDir("dir");
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
       renameDir("dir/old", "dir/new");
 
-      inAnyOrder(unionAll(withPermutations((i, j, k) {
+      await inAnyOrder(unionAll(withPermutations((i, j, k) {
         return new Set.from([
           isRemoveEvent("dir/old/sub-$i/sub-$j/file-$k.txt"),
           isAddEvent("dir/new/sub-$i/sub-$j/file-$k.txt")
@@ -321,10 +325,10 @@
 
     test(
         "emits events for many files added at once in a subdirectory with the "
-        "same name as a removed file", () {
+        "same name as a removed file", () async {
       writeFile("dir/sub");
       withPermutations((i, j, k) => writeFile("old/sub-$i/sub-$j/file-$k.txt"));
-      startWatcher(path: "dir");
+      await startWatcher(path: "dir");
 
       deleteFile("dir/sub");
       renameDir("old", "dir/sub");
@@ -332,7 +336,7 @@
       var events = withPermutations(
           (i, j, k) => isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt"));
       events.add(isRemoveEvent("dir/sub"));
-      inAnyOrder(events);
+      await inAnyOrder(events);
     });
   });
 }
diff --git a/test/directory_watcher/windows_test.dart b/test/directory_watcher/windows_test.dart
index 176fe2d..3696f9c 100644
--- a/test/directory_watcher/windows_test.dart
+++ b/test/directory_watcher/windows_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('windows')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/windows.dart';
 import 'package:watcher/watcher.dart';
 
@@ -14,9 +14,11 @@
 void main() {
   watcherFactory = (dir) => new WindowsDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
-  sharedTests();
+  // TODO(grouma) - renable when https://github.com/dart-lang/sdk/issues/31760
+  // is resolved.
+  group("Shared Tests:", () {
+    sharedTests();
+  }, skip: "SDK issue see - https://github.com/dart-lang/sdk/issues/31760");
 
   test('DirectoryWatcher creates a WindowsDirectoryWatcher on Windows', () {
     expect(
diff --git a/test/file_watcher/native_test.dart b/test/file_watcher/native_test.dart
index cbf11b6..b6ed901 100644
--- a/test/file_watcher/native_test.dart
+++ b/test/file_watcher/native_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('linux || mac-os')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/file_watcher/native.dart';
 
 import 'shared.dart';
@@ -14,7 +14,6 @@
   watcherFactory = (file) => new NativeFileWatcher(file);
 
   setUp(() {
-    createSandbox();
     writeFile("file.txt");
   });
 
diff --git a/test/file_watcher/polling_test.dart b/test/file_watcher/polling_test.dart
index e502544..01d579a 100644
--- a/test/file_watcher/polling_test.dart
+++ b/test/file_watcher/polling_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('linux || mac-os')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/watcher.dart';
 
 import 'shared.dart';
@@ -15,7 +15,6 @@
       pollingDelay: new Duration(milliseconds: 100));
 
   setUp(() {
-    createSandbox();
     writeFile("file.txt");
   });
 
diff --git a/test/file_watcher/shared.dart b/test/file_watcher/shared.dart
index 50f7aeb..286a042 100644
--- a/test/file_watcher/shared.dart
+++ b/test/file_watcher/shared.dart
@@ -4,73 +4,67 @@
 
 import 'dart:async';
 
-import 'package:scheduled_test/scheduled_test.dart';
-import 'package:watcher/src/utils.dart';
+import 'package:test/test.dart';
 
 import '../utils.dart';
 
 void sharedTests() {
-  test("doesn't notify if the file isn't modified", () {
-    startWatcher(path: "file.txt");
-    // Give the watcher time to fire events if it's going to.
-    schedule(() => pumpEventQueue());
+  test("doesn't notify if the file isn't modified", () async {
+    await startWatcher(path: "file.txt");
+    await pumpEventQueue();
     deleteFile("file.txt");
-    expectRemoveEvent("file.txt");
+    await expectRemoveEvent("file.txt");
   });
 
-  test("notifies when a file is modified", () {
-    startWatcher(path: "file.txt");
+  test("notifies when a file is modified", () async {
+    await startWatcher(path: "file.txt");
     writeFile("file.txt", contents: "modified");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
-  test("notifies when a file is removed", () {
-    startWatcher(path: "file.txt");
+  test("notifies when a file is removed", () async {
+    await startWatcher(path: "file.txt");
     deleteFile("file.txt");
-    expectRemoveEvent("file.txt");
+    await expectRemoveEvent("file.txt");
   });
 
-  test("notifies when a file is modified multiple times", () {
-    startWatcher(path: "file.txt");
+  test("notifies when a file is modified multiple times", () async {
+    await startWatcher(path: "file.txt");
     writeFile("file.txt", contents: "modified");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
     writeFile("file.txt", contents: "modified again");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
-  test("notifies even if the file contents are unchanged", () {
-    startWatcher(path: "file.txt");
+  test("notifies even if the file contents are unchanged", () async {
+    await startWatcher(path: "file.txt");
     writeFile("file.txt");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
-  test("emits a remove event when the watched file is moved away", () {
-    startWatcher(path: "file.txt");
+  test("emits a remove event when the watched file is moved away", () async {
+    await startWatcher(path: "file.txt");
     renameFile("file.txt", "new.txt");
-    expectRemoveEvent("file.txt");
+    await expectRemoveEvent("file.txt");
   });
 
   test(
       "emits a modify event when another file is moved on top of the watched "
-      "file", () {
+      "file", () async {
     writeFile("old.txt");
-    startWatcher(path: "file.txt");
+    await startWatcher(path: "file.txt");
     renameFile("old.txt", "file.txt");
-    expectModifyEvent("file.txt");
+    await expectModifyEvent("file.txt");
   });
 
   // Regression test for a race condition.
-  test("closes the watcher immediately after deleting the file", () {
+  test("closes the watcher immediately after deleting the file", () async {
     writeFile("old.txt");
-    var watcher = createWatcher(path: "file.txt", waitForReady: false);
-    var sub = schedule(() => watcher.events.listen(null));
+    var watcher = createWatcher(path: "file.txt");
+    var sub = watcher.events.listen(null);
 
     deleteFile("file.txt");
-    schedule(() async {
-      // Reproducing the race condition will always be flaky, but this sleep
-      // helped it reproduce more consistently on my machine.
-      await new Future.delayed(new Duration(milliseconds: 10));
-      (await sub).cancel();
-    });
+    await new Future.delayed(new Duration(milliseconds: 10));
+    await sub.cancel();
   });
 }
diff --git a/test/no_subscription/linux_test.dart b/test/no_subscription/linux_test.dart
index c8e8ae9..e9bfd69 100644
--- a/test/no_subscription/linux_test.dart
+++ b/test/no_subscription/linux_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('linux')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/linux.dart';
 
 import 'shared.dart';
@@ -13,7 +13,5 @@
 void main() {
   watcherFactory = (dir) => new LinuxDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/no_subscription/mac_os_test.dart b/test/no_subscription/mac_os_test.dart
index 499aff3..fc14ebf 100644
--- a/test/no_subscription/mac_os_test.dart
+++ b/test/no_subscription/mac_os_test.dart
@@ -5,7 +5,7 @@
 @TestOn('mac-os')
 @Skip("Flaky due to sdk#23877")
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/mac_os.dart';
 
 import 'shared.dart';
@@ -14,7 +14,5 @@
 void main() {
   watcherFactory = (dir) => new MacOSDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/no_subscription/polling_test.dart b/test/no_subscription/polling_test.dart
index 5c99bc0..75fa3a7 100644
--- a/test/no_subscription/polling_test.dart
+++ b/test/no_subscription/polling_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:scheduled_test/scheduled_test.dart';
 import 'package:watcher/watcher.dart';
 
 import 'shared.dart';
@@ -11,7 +10,5 @@
 void main() {
   watcherFactory = (dir) => new PollingDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/no_subscription/shared.dart b/test/no_subscription/shared.dart
index 5858656..c7e0501 100644
--- a/test/no_subscription/shared.dart
+++ b/test/no_subscription/shared.dart
@@ -4,60 +4,51 @@
 
 import 'dart:async';
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:async/async.dart';
+import 'package:test/test.dart';
 import 'package:watcher/watcher.dart';
 
 import '../utils.dart';
 
 void sharedTests() {
-  test('does not notify for changes when there are no subscribers', () {
+  test('does not notify for changes when there are no subscribers', () async {
     // Note that this test doesn't rely as heavily on the test functions in
     // utils.dart because it needs to be very explicit about when the event
     // stream is and is not subscribed.
     var watcher = createWatcher();
+    var queue = new StreamQueue(watcher.events);
+    queue.hasNext;
 
-    // Subscribe to the events.
-    var completer = new Completer();
-    var subscription = watcher.events.listen(expectAsync1((event) {
-      expect(event, isWatchEvent(ChangeType.ADD, "file.txt"));
-      completer.complete();
-    }));
+    var future =
+        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, "file.txt")));
+    expect(queue, neverEmits(anything));
 
-    writeFile("file.txt");
+    await watcher.ready;
 
-    // Then wait until we get an event for it.
-    schedule(() => completer.future);
+    writeFile('file.txt');
+
+    await future;
 
     // Unsubscribe.
-    schedule(() {
-      subscription.cancel();
-    });
+    await queue.cancel(immediate: true);
 
     // Now write a file while we aren't listening.
     writeFile("unwatched.txt");
 
-    // Then start listening again.
-    schedule(() {
-      completer = new Completer();
-      subscription = watcher.events.listen(expectAsync1((event) {
-        // We should get an event for the third file, not the one added while
-        // we weren't subscribed.
-        expect(event, isWatchEvent(ChangeType.ADD, "added.txt"));
-        completer.complete();
-      }));
+    queue = new StreamQueue(watcher.events);
+    future =
+        expectLater(queue, emits(isWatchEvent(ChangeType.ADD, "added.txt")));
+    expect(queue, neverEmits(isWatchEvent(ChangeType.ADD, "unwatched.txt")));
 
-      // Wait until the watcher is ready to dispatch events again.
-      return watcher.ready;
-    });
+    // Wait until the watcher is ready to dispatch events again.
+    await watcher.ready;
 
     // And add a third file.
     writeFile("added.txt");
 
     // Wait until we get an event for the third file.
-    schedule(() => completer.future);
+    await future;
 
-    schedule(() {
-      subscription.cancel();
-    });
+    await queue.cancel(immediate: true);
   });
 }
diff --git a/test/ready/linux_test.dart b/test/ready/linux_test.dart
index c8e8ae9..e9bfd69 100644
--- a/test/ready/linux_test.dart
+++ b/test/ready/linux_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('linux')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/linux.dart';
 
 import 'shared.dart';
@@ -13,7 +13,5 @@
 void main() {
   watcherFactory = (dir) => new LinuxDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/ready/mac_os_test.dart b/test/ready/mac_os_test.dart
index d5b1c8e..9533cc8 100644
--- a/test/ready/mac_os_test.dart
+++ b/test/ready/mac_os_test.dart
@@ -4,7 +4,7 @@
 
 @TestOn('mac-os')
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 import 'package:watcher/src/directory_watcher/mac_os.dart';
 
 import 'shared.dart';
@@ -13,7 +13,5 @@
 void main() {
   watcherFactory = (dir) => new MacOSDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/ready/polling_test.dart b/test/ready/polling_test.dart
index 5c99bc0..75fa3a7 100644
--- a/test/ready/polling_test.dart
+++ b/test/ready/polling_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:scheduled_test/scheduled_test.dart';
 import 'package:watcher/watcher.dart';
 
 import 'shared.dart';
@@ -11,7 +10,5 @@
 void main() {
   watcherFactory = (dir) => new PollingDirectoryWatcher(dir);
 
-  setUp(createSandbox);
-
   sharedTests();
 }
diff --git a/test/ready/shared.dart b/test/ready/shared.dart
index 7be4833..730d579 100644
--- a/test/ready/shared.dart
+++ b/test/ready/shared.dart
@@ -2,97 +2,61 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:scheduled_test/scheduled_test.dart';
+import 'package:test/test.dart';
 
 import '../utils.dart';
 
 void sharedTests() {
-  test('ready does not complete until after subscription', () {
-    var watcher = createWatcher(waitForReady: false);
+  test('ready does not complete until after subscription', () async {
+    var watcher = createWatcher();
 
     var ready = false;
     watcher.ready.then((_) {
       ready = true;
     });
+    await pumpEventQueue();
 
-    // Should not be ready yet.
-    schedule(() {
-      expect(ready, isFalse);
-    });
+    expect(ready, isFalse);
 
     // Subscribe to the events.
-    schedule(() {
-      var subscription = watcher.events.listen((event) {});
+    watcher.events.listen((event) {});
 
-      currentSchedule.onComplete.schedule(() {
-        subscription.cancel();
-      });
-    });
+    await watcher.ready;
 
     // Should eventually be ready.
-    schedule(() => watcher.ready);
-
-    schedule(() {
-      expect(ready, isTrue);
-    });
+    expect(watcher.isReady, isTrue);
   });
 
-  test('ready completes immediately when already ready', () {
-    var watcher = createWatcher(waitForReady: false);
+  test('ready completes immediately when already ready', () async {
+    var watcher = createWatcher();
 
     // Subscribe to the events.
-    schedule(() {
-      var subscription = watcher.events.listen((event) {});
+    watcher.events.listen((event) {});
 
-      currentSchedule.onComplete.schedule(() {
-        subscription.cancel();
-      });
-    });
+    // Allow watcher to become ready
+    await watcher.ready;
 
-    // Should eventually be ready.
-    schedule(() => watcher.ready);
-
-    // Now ready should be a future that immediately completes.
-    var ready = false;
-    schedule(() {
-      watcher.ready.then((_) {
-        ready = true;
-      });
-    });
-
-    schedule(() {
-      expect(ready, isTrue);
-    });
+    // Ensure ready completes immediately
+    expect(
+        watcher.ready.timeout(new Duration(milliseconds: 0),
+            onTimeout: () => throw 'Does not complete immedately'),
+        completes);
   });
 
-  test('ready returns a future that does not complete after unsubscribing', () {
-    var watcher = createWatcher(waitForReady: false);
+  test('ready returns a future that does not complete after unsubscribing',
+      () async {
+    var watcher = createWatcher();
 
     // Subscribe to the events.
-    var subscription;
-    schedule(() {
-      subscription = watcher.events.listen((event) {});
-    });
-
-    var ready = false;
+    var subscription = watcher.events.listen((event) {});
 
     // Wait until ready.
-    schedule(() => watcher.ready);
+    await watcher.ready;
 
     // Now unsubscribe.
-    schedule(() {
-      subscription.cancel();
-
-      // Track when it's ready again.
-      ready = false;
-      watcher.ready.then((_) {
-        ready = true;
-      });
-    });
+    await subscription.cancel();
 
     // Should be back to not ready.
-    schedule(() {
-      expect(ready, isFalse);
-    });
+    expect(watcher.ready, doesNotComplete);
   });
 }
diff --git a/test/utils.dart b/test/utils.dart
index 6700500..637eacf 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -2,21 +2,23 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:io';
 
+import 'package:async/async.dart';
 import 'package:path/path.dart' as p;
-import 'package:scheduled_test/scheduled_stream.dart';
-import 'package:scheduled_test/scheduled_test.dart';
-import 'package:watcher/watcher.dart';
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
+
 import 'package:watcher/src/stat.dart';
-import 'package:watcher/src/utils.dart';
+import 'package:watcher/watcher.dart';
 
-/// The path to the temporary sandbox created for each test. All file
-/// operations are implicitly relative to this directory.
-String _sandboxDir;
+typedef Watcher WatcherFactory(String directory);
 
-/// The [Watcher] being used for the current scheduled test.
-Watcher _watcher;
+/// Sets the function used to create the watcher.
+set watcherFactory(WatcherFactory factory) {
+  _watcherFactory = factory;
+}
 
 /// The mock modification times (in milliseconds since epoch) for each file.
 ///
@@ -27,53 +29,10 @@
 ///
 /// Instead, we'll just mock that out. Each time a file is written, we manually
 /// increment the mod time for that file instantly.
-Map<String, int> _mockFileModificationTimes;
-
-typedef Watcher WatcherFactory(String directory);
-
-/// Sets the function used to create the watcher.
-set watcherFactory(WatcherFactory factory) {
-  _watcherFactory = factory;
-}
+final _mockFileModificationTimes = <String, int>{};
 
 WatcherFactory _watcherFactory;
 
-/// Creates the sandbox directory the other functions in this library use and
-/// ensures it's deleted when the test ends.
-///
-/// This should usually be called by [setUp].
-void createSandbox() {
-  var dir = Directory.systemTemp.createTempSync('watcher_test_');
-  _sandboxDir = dir.path;
-
-  _mockFileModificationTimes = new Map<String, int>();
-  mockGetModificationTime((path) {
-    path = p.normalize(p.relative(path, from: _sandboxDir));
-
-    // Make sure we got a path in the sandbox.
-    assert(p.isRelative(path) && !path.startsWith(".."));
-
-    var mtime = _mockFileModificationTimes[path];
-    return new DateTime.fromMillisecondsSinceEpoch(mtime == null ? 0 : mtime);
-  });
-
-  // Delete the sandbox when done.
-  currentSchedule.onComplete.schedule(() {
-    if (_sandboxDir != null) {
-      // TODO(rnystrom): Issue 19155. The watcher should already be closed when
-      // we clean up the sandbox.
-      if (_watcherEvents != null) {
-        _watcherEvents.close();
-      }
-      new Directory(_sandboxDir).deleteSync(recursive: true);
-      _sandboxDir = null;
-    }
-
-    _mockFileModificationTimes = null;
-    mockGetModificationTime(null);
-  }, "delete sandbox");
-}
-
 /// Creates a new [Watcher] that watches a temporary file or directory.
 ///
 /// Normally, this will pause the schedule until the watcher is done scanning
@@ -81,62 +40,43 @@
 /// not schedule this delay.
 ///
 /// If [path] is provided, watches a subdirectory in the sandbox with that name.
-Watcher createWatcher({String path, bool waitForReady}) {
+Watcher createWatcher({String path}) {
   if (path == null) {
-    path = _sandboxDir;
+    path = d.sandbox;
   } else {
-    path = p.join(_sandboxDir, path);
+    path = p.join(d.sandbox, path);
   }
 
-  var watcher = _watcherFactory(path);
-
-  // Wait until the scan is finished so that we don't miss changes to files
-  // that could occur before the scan completes.
-  if (waitForReady != false) {
-    schedule(() => watcher.ready, "wait for watcher to be ready");
-  }
-
-  return watcher;
+  return _watcherFactory(path);
 }
 
 /// The stream of events from the watcher started with [startWatcher].
-ScheduledStream<WatchEvent> _watcherEvents;
+StreamQueue<WatchEvent> _watcherEvents;
 
 /// Creates a new [Watcher] that watches a temporary file or directory and
 /// starts monitoring it for events.
 ///
 /// If [path] is provided, watches a path in the sandbox with that name.
-void startWatcher({String path}) {
+Future<Null> startWatcher({String path}) async {
+  mockGetModificationTime((path) {
+    path = p.normalize(p.relative(path, from: d.sandbox));
+
+    // Make sure we got a path in the sandbox.
+    assert(p.isRelative(path) && !path.startsWith(".."));
+
+    var mtime = _mockFileModificationTimes[path];
+    return new DateTime.fromMillisecondsSinceEpoch(mtime ?? 0);
+  });
+
   // We want to wait until we're ready *after* we subscribe to the watcher's
   // events.
-  _watcher = createWatcher(path: path, waitForReady: false);
-
-  // Schedule [_watcher.events.listen] so that the watcher doesn't start
-  // watching [path] before it exists. Expose [_watcherEvents] immediately so
-  // that it can be accessed synchronously after this.
-  _watcherEvents = new ScheduledStream(futureStream(
-      schedule(() {
-        currentSchedule.onComplete.schedule(() {
-          _watcher = null;
-          if (!_closePending) _watcherEvents.close();
-
-          // If there are already errors, don't add this to the output and make
-          // people think it might be the root cause.
-          if (currentSchedule.errors.isEmpty) {
-            _watcherEvents.expect(isDone);
-          }
-        }, "reset watcher");
-
-        return _watcher.events;
-      }, "create watcher"),
-      broadcast: true));
-
-  schedule(() => _watcher.ready, "wait for watcher to be ready");
+  var watcher = createWatcher(path: path);
+  _watcherEvents = new StreamQueue(watcher.events);
+  // Forces a subscription to the underlying stream.
+  _watcherEvents.hasNext;
+  await watcher.ready;
 }
 
-/// Whether an event to close [_watcherEvents] has been scheduled.
-bool _closePending = false;
-
 /// Schedule closing the watcher stream after the event queue has been pumped.
 ///
 /// This is necessary when events are allowed to occur, but don't have to occur,
@@ -144,12 +84,7 @@
 /// indefinitely because they might in the future and because the watcher is
 /// normally only closed after the test completes.
 void startClosingEventStream() {
-  schedule(() {
-    _closePending = true;
-    pumpEventQueue().then((_) => _watcherEvents.close()).whenComplete(() {
-      _closePending = false;
-    });
-  }, 'start closing event stream');
+  pumpEventQueue().then((_) => _watcherEvents.cancel(immediate: true));
 }
 
 /// A list of [StreamMatcher]s that have been collected using
@@ -165,7 +100,7 @@
   _collectedStreamMatchers = new List<StreamMatcher>();
   try {
     block();
-    return inOrder(_collectedStreamMatchers);
+    return emitsInOrder(_collectedStreamMatchers);
   } finally {
     _collectedStreamMatchers = oldStreamMatchers;
   }
@@ -175,47 +110,45 @@
 /// it with [_collectStreamMatcher].
 ///
 /// [streamMatcher] can be a [StreamMatcher], a [Matcher], or a value.
-void _expectOrCollect(streamMatcher) {
+Future _expectOrCollect(streamMatcher) {
   if (_collectedStreamMatchers != null) {
-    _collectedStreamMatchers.add(new StreamMatcher.wrap(streamMatcher));
+    _collectedStreamMatchers.add(emits(streamMatcher));
+    return null;
   } else {
-    _watcherEvents.expect(streamMatcher);
+    return expectLater(_watcherEvents, emits(streamMatcher));
   }
 }
 
 /// Expects that [matchers] will match emitted events in any order.
 ///
 /// [matchers] may be [Matcher]s or values, but not [StreamMatcher]s.
-void inAnyOrder(Iterable matchers) {
+Future inAnyOrder(Iterable matchers) {
   matchers = matchers.toSet();
-  _expectOrCollect(nextValues(matchers.length, unorderedMatches(matchers)));
+  return _expectOrCollect(emitsInAnyOrder(matchers));
 }
 
 /// Expects that the expectations established in either [block1] or [block2]
 /// will match the emitted events.
 ///
 /// If both blocks match, the one that consumed more events will be used.
-void allowEither(block1(), block2()) {
-  _expectOrCollect(
-      either(_collectStreamMatcher(block1), _collectStreamMatcher(block2)));
-}
+Future allowEither(block1(), block2()) => _expectOrCollect(
+    emitsAnyOf([_collectStreamMatcher(block1), _collectStreamMatcher(block2)]));
 
 /// Allows the expectations established in [block] to match the emitted events.
 ///
 /// If the expectations in [block] don't match, no error will be raised and no
 /// events will be consumed. If this is used at the end of a test,
 /// [startClosingEventStream] should be called before it.
-void allowEvents(block()) {
-  _expectOrCollect(allow(_collectStreamMatcher(block)));
-}
+Future allowEvents(block()) =>
+    _expectOrCollect(mayEmit(_collectStreamMatcher(block)));
 
-/// Returns a matcher that matches a [WatchEvent] with the given [type] and
-/// [path].
+/// Returns a StreamMatcher that matches a [WatchEvent] with the given [type]
+/// and [path].
 Matcher isWatchEvent(ChangeType type, String path) {
   return predicate((e) {
     return e is WatchEvent &&
         e.type == type &&
-        e.path == p.join(_sandboxDir, p.normalize(path));
+        e.path == p.join(d.sandbox, p.normalize(path));
   }, "is $type $path");
 }
 
@@ -231,16 +164,16 @@
 Matcher isRemoveEvent(String path) => isWatchEvent(ChangeType.REMOVE, path);
 
 /// Expects that the next event emitted will be for an add event for [path].
-void expectAddEvent(String path) =>
+Future expectAddEvent(String path) =>
     _expectOrCollect(isWatchEvent(ChangeType.ADD, path));
 
 /// Expects that the next event emitted will be for a modification event for
 /// [path].
-void expectModifyEvent(String path) =>
+Future expectModifyEvent(String path) =>
     _expectOrCollect(isWatchEvent(ChangeType.MODIFY, path));
 
 /// Expects that the next event emitted will be for a removal event for [path].
-void expectRemoveEvent(String path) =>
+Future expectRemoveEvent(String path) =>
     _expectOrCollect(isWatchEvent(ChangeType.REMOVE, path));
 
 /// Consumes an add event for [path] if one is emitted at this point in the
@@ -248,24 +181,24 @@
 ///
 /// If this is used at the end of a test, [startClosingEventStream] should be
 /// called before it.
-void allowAddEvent(String path) =>
-    _expectOrCollect(allow(isWatchEvent(ChangeType.ADD, path)));
+Future allowAddEvent(String path) =>
+    _expectOrCollect(mayEmit(isWatchEvent(ChangeType.ADD, path)));
 
 /// Consumes a modification event for [path] if one is emitted at this point in
 /// the schedule, but doesn't throw an error if it isn't.
 ///
 /// If this is used at the end of a test, [startClosingEventStream] should be
 /// called before it.
-void allowModifyEvent(String path) =>
-    _expectOrCollect(allow(isWatchEvent(ChangeType.MODIFY, path)));
+Future allowModifyEvent(String path) =>
+    _expectOrCollect(mayEmit(isWatchEvent(ChangeType.MODIFY, path)));
 
 /// Consumes a removal event for [path] if one is emitted at this point in the
 /// schedule, but doesn't throw an error if it isn't.
 ///
 /// If this is used at the end of a test, [startClosingEventStream] should be
 /// called before it.
-void allowRemoveEvent(String path) =>
-    _expectOrCollect(allow(isWatchEvent(ChangeType.REMOVE, path)));
+Future allowRemoveEvent(String path) =>
+    _expectOrCollect(mayEmit(isWatchEvent(ChangeType.REMOVE, path)));
 
 /// Schedules writing a file in the sandbox at [path] with [contents].
 ///
@@ -275,71 +208,55 @@
   if (contents == null) contents = "";
   if (updateModified == null) updateModified = true;
 
-  schedule(() {
-    var fullPath = p.join(_sandboxDir, path);
+  var fullPath = p.join(d.sandbox, path);
 
-    // Create any needed subdirectories.
-    var dir = new Directory(p.dirname(fullPath));
-    if (!dir.existsSync()) {
-      dir.createSync(recursive: true);
-    }
+  // Create any needed subdirectories.
+  var dir = new Directory(p.dirname(fullPath));
+  if (!dir.existsSync()) {
+    dir.createSync(recursive: true);
+  }
 
-    new File(fullPath).writeAsStringSync(contents);
+  new File(fullPath).writeAsStringSync(contents);
 
-    // Manually update the mock modification time for the file.
-    if (updateModified) {
-      // Make sure we always use the same separator on Windows.
-      path = p.normalize(path);
+  if (updateModified) {
+    path = p.normalize(path);
 
-      _mockFileModificationTimes.putIfAbsent(path, () => 0);
-      _mockFileModificationTimes[path]++;
-    }
-  }, "write file $path");
+    _mockFileModificationTimes.putIfAbsent(path, () => 0);
+    _mockFileModificationTimes[path]++;
+  }
 }
 
 /// Schedules deleting a file in the sandbox at [path].
 void deleteFile(String path) {
-  schedule(() {
-    new File(p.join(_sandboxDir, path)).deleteSync();
-  }, "delete file $path");
+  new File(p.join(d.sandbox, path)).deleteSync();
 }
 
 /// Schedules renaming a file in the sandbox from [from] to [to].
 ///
 /// If [contents] is omitted, creates an empty file.
 void renameFile(String from, String to) {
-  schedule(() {
-    new File(p.join(_sandboxDir, from)).renameSync(p.join(_sandboxDir, to));
+  new File(p.join(d.sandbox, from)).renameSync(p.join(d.sandbox, to));
 
-    // Make sure we always use the same separator on Windows.
-    to = p.normalize(to);
+  // Make sure we always use the same separator on Windows.
+  to = p.normalize(to);
 
-    // Manually update the mock modification time for the file.
-    _mockFileModificationTimes.putIfAbsent(to, () => 0);
-    _mockFileModificationTimes[to]++;
-  }, "rename file $from to $to");
+  _mockFileModificationTimes.putIfAbsent(to, () => 0);
+  _mockFileModificationTimes[to]++;
 }
 
 /// Schedules creating a directory in the sandbox at [path].
 void createDir(String path) {
-  schedule(() {
-    new Directory(p.join(_sandboxDir, path)).createSync();
-  }, "create directory $path");
+  new Directory(p.join(d.sandbox, path)).createSync();
 }
 
 /// Schedules renaming a directory in the sandbox from [from] to [to].
 void renameDir(String from, String to) {
-  schedule(() {
-    new Directory(p.join(_sandboxDir, from))
-        .renameSync(p.join(_sandboxDir, to));
-  }, "rename directory $from to $to");
+  new Directory(p.join(d.sandbox, from)).renameSync(p.join(d.sandbox, to));
 }
 
 /// Schedules deleting a directory in the sandbox at [path].
 void deleteDir(String path) {
-  schedule(() {
-    new Directory(p.join(_sandboxDir, path)).deleteSync(recursive: true);
-  }, "delete directory $path");
+  new Directory(p.join(d.sandbox, path)).deleteSync(recursive: true);
 }
 
 /// Runs [callback] with every permutation of non-negative [i], [j], and [k]