Bug 800697 - [OS.File] Convert async testsuite to use Task.js. r=Yoric
authorAndres Hernandez <andres@appcoast.com>
Tue, 23 Oct 2012 11:48:52 -0600
changeset 111346 0d2953f1459789258bf0409f5ff2bc0381aa4f5e
parent 111345 3593d9ccfec22d065ee4fa6065dca29be4990439
child 111347 d9c1eb0c7b8d75dd403e4eba950b013737384150
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersYoric
bugs800697
milestone19.0a1
Bug 800697 - [OS.File] Convert async testsuite to use Task.js. r=Yoric
toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
--- a/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
+++ b/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
@@ -1,62 +1,29 @@
 "use strict";
 
 Components.utils.import("resource://gre/modules/osfile.jsm");
 Components.utils.import("resource://gre/modules/commonjs/promise/core.js");
+Components.utils.import("resource://gre/modules/Task.jsm");
 
 // The following are used to compare against a well-tested reference
 // implementation of file I/O.
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 let myok = ok;
 let myis = is;
 let myinfo = info;
 let myisnot = isnot;
 
 let isPromise = function ispromise(value) {
   return value != null && typeof value == "object" && "then" in value;
 };
 
-/**
- * Execute a function once a promise is resolved or rejected,
- * regardless of whether it has been resolved or rejected, and
- * propagate the previous resolution/rejection.
- *
- * Typically used for cleanup. Think of this as the promise
- * version of |finally|.
- */
-let always = function always(promise, fun) {
-  let p2 = Promise.defer();
-  let onsuccess = function(resolution) {
-    fun();
-    p2.resolve(resolution);
-  };
-  let onreject = function(rejection) {
-    fun();
-    p2.reject(rejection);
-  };
-  promise.then(onsuccess, onreject);
-  return p2.promise;
-};
-
-let ensureSuccess = function ensureSuccess(promise, test) {
-  let p2 = Promise.defer();
-  promise.then(function onSuccess(x) {
-    p2.resolve(x);
-  }, function onFailure(err) {
-    test.fail("Uncaught error " + err + "\n" + err.stack);
-    p2.reject(err);
-  });
-
-  return p2.promise;
-};
-
 let maketest = function(prefix, test) {
   let utils = {
     ok: function ok(t, m) {
       myok(t, prefix + ": " + m);
     },
     is: function is(l, r, m) {
       myis(l, r, prefix + ": " + m);
     },
@@ -147,841 +114,472 @@ let reference_fetch_file = function refe
  *
  * @param {string} a The _absolute_ path to the first file.
  * @param {string} b The _absolute_ path to the second file.
  *
  * @resolves {null}
  */
 let reference_compare_files = function reference_compare_files(a, b, test) {
   test.info("Comparing files " + a + " and " + b);
-  let promise = reference_fetch_file(a, test);
-
-  let a_contents, b_contents;
-  promise = promise.then(function got_a(contents) {
-    a_contents = contents;
-    return reference_fetch_file(b, test);
-  });
-  promise = promise.then(function got_b(contents) {
-    b_contents = contents;
-    is(a_contents, b_contents, "Contents of files " + a + " and " + b + " match");
-  });
-  return promise;
+  let a_contents = yield reference_fetch_file(a, test);
+  let b_contents = yield reference_fetch_file(b, test);
+  is(a_contents, b_contents, "Contents of files " + a + " and " + b + " match");
 };
 
-let test = maketest("Main",
-  function main(test) {
+let test = maketest("Main", function main(test) {
+  return Task.spawn(function() {
     SimpleTest.waitForExplicitFinish();
-    let tests = [test_constants, test_path, test_open, test_stat,
-                 test_read_write, test_read_write_all,
-                 test_position, test_copy,
-                 test_iter, test_exists];
-    let current = 0;
-    let aux = function aux() {
-      if (current >= tests.length) {
-        info("Test is over");
-        SimpleTest.finish();
-        return null;
-      }
-      let test = tests[current++];
-      let result = test();
-      if (isPromise(result)) {
-        // The test has returned a promise
-        return result.then(aux, aux);
-      } else {
-        return aux();
-      }
-    };
-    return aux();
-  }
-);
+    yield test_constants();
+    yield test_path();
+    yield test_open();
+    yield test_stat();
+    yield test_read_write();
+    yield test_read_write_all();
+    yield test_position();
+    yield test_copy();
+    yield test_mkdir();
+    yield test_iter();
+    yield test_exists();
+    info("Test is over");
+    SimpleTest.finish();
+  });
+});
 
 /**
  * A file that we know exists and that can be used for reading.
  */
 let EXISTING_FILE = OS.Path.join("chrome", "toolkit", "components",
   "osfile", "tests", "mochi", "main_test_osfile_async.js");
 
 /**
  * Test that OS.Constants is defined correctly.
  */
-let test_constants = maketest("constants",
-  function constants(test) {
+let test_constants = maketest("constants", function constants(test) {
+  return Task.spawn(function() {
     test.isnot(OS.Constants, null, "OS.Constants exists");
     test.ok(OS.Constants.Win || OS.Constants.libc, "OS.Constants.Win exists or OS.Constants.Unix exists");
     test.isnot(OS.Constants.Path, null, "OS.Constants.Path exists");
     test.isnot(OS.Constants.Sys, null, "OS.Constants.Sys exists");
-    return Promise.resolve(true);
+  });
 });
 
 /**
  * Test that OS.Constants.Path paths are consistent.
  */
-let test_path = maketest("path",
-  function path(test) {
+let test_path = maketest("path",  function path(test) {
+  return Task.spawn(function() {
     test.ok(OS.Path, "OS.Path exists");
     test.ok(OS.Constants.Path, "OS.Constants.Path exists");
     test.is(OS.Constants.Path.tmpDir, Services.dirsvc.get("TmpD", Components.interfaces.nsIFile).path, "OS.Constants.Path.tmpDir is correct");
     test.is(OS.Constants.Path.profileDir, Services.dirsvc.get("ProfD", Components.interfaces.nsIFile).path, "OS.Constants.Path.profileDir is correct");
-    return Promise.resolve(true);
+  });
 });
 
 /**
  * Test OS.File.open for reading:
  * - with an existing file (should succeed);
  * - with a non-existing file (should fail);
  * - with inconsistent arguments (should fail).
  */
-let test_open = maketest("open",
-  function open(test) {
-    let promise;
-
-    // Attempt to open a file that does not exist, ensure that it
-    // yields the appropriate error
-    promise = OS.File.open(OS.Path.join(".", "This file does not exist")).
-      then(function onSuccess(fd) {
-        test.ok(false, "File opening 1 succeeded (it should fail)" + fd);
-      }, function onFailure(err) {
-        test.ok(true, "File opening 1 failed " + err);
-        test.ok(err instanceof OS.File.Error, "File opening 1 returned a file error");
-        test.ok(err.becauseNoSuchFile, "File opening 1 informed that the file does not exist");
-      });
+let test_open = maketest("open",  function open(test) {
+  return Task.spawn(function() {
+    // Attempt to open a file that does not exist, ensure that it yields the
+    // appropriate error.
+    try {
+      let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
+      test.ok(false, "File opening 1 succeeded (it should fail)" + fd);
+    } catch (err) {
+      test.ok(true, "File opening 1 failed " + err);
+      test.ok(err instanceof OS.File.Error, "File opening 1 returned a file error");
+      test.ok(err.becauseNoSuchFile, "File opening 1 informed that the file does not exist");
+    }
 
-    // Attempt to open a file with the wrong args, so that it fails
-    // before serialization, ensure that it yields the appropriate error
-    promise = promise.then(function open_with_wrong_args() {
-      test.info("Attempting to open a file with wrong arguments");
-      return OS.File.open(1, 2, 3);
-    });
-    promise = promise.then(
-      function onSuccess(fd) {
-        test.ok(false, "File opening 2 succeeded (it should fail)" + fd);
-      }, function onFailure(err) {
-        test.ok(true, "File opening 2 failed " + err);
-        test.ok(!(err instanceof OS.File.Error), "File opening 2 returned something that is not a file error");
-        test.ok(err.constructor.name == "TypeError", "File opening 2 returned a TypeError");
-      }
-    );
+    // Attempt to open a file with the wrong args, so that it fails before
+    // serialization, ensure that it yields the appropriate error.
+    test.info("Attempting to open a file with wrong arguments");
+    try {
+      let fd = yield OS.File.open(1, 2, 3);
+      test.ok(false, "File opening 2 succeeded (it should fail)" + fd);
+    } catch (err) {
+      test.ok(true, "File opening 2 failed " + err);
+      test.ok(!(err instanceof OS.File.Error), "File opening 2 returned something that is not a file error");
+      test.ok(err.constructor.name == "TypeError", "File opening 2 returned a TypeError");
+    }
 
     // Attempt to open a file correctly
-    promise = promise.then(function open_should_work() {
-      test.info("Attempting to open a file correctly");
-      return OS.File.open(EXISTING_FILE);
-    });
-    let openedFile;
-    promise = promise.then(function open_has_worked(file) {
-      test.ok(true, "File opened correctly");
-      openedFile = file;
-    });
+    test.info("Attempting to open a file correctly");
+    let openedFile = yield OS.File.open(EXISTING_FILE);
+    test.ok(true, "File opened correctly");
 
-    // Attempting to close file
-    promise = promise.then(function close_1() {
-      test.info("Attempting to close a file correctly");
-      return openedFile.close();
-    });
+    test.info("Attempting to close a file correctly");
+    yield openedFile.close();
 
-    // Attempt to close that file a second time
-    promise = promise.then(function close_2() {
-      test.info("Attempting to close a file again");
-      return openedFile.close();
-    });
-
-    // Do not forget to return the promise.
-    return promise;
+    test.info("Attempting to close a file again");
+    yield openedFile.close();
+  });
 });
 
 /**
  * Test OS.File.stat and OS.File.prototype.stat
  */
-let test_stat = maketest("stat",
-  function stat(test) {
-    let promise;
-    let file;
-    let stat;
-
+let test_stat = maketest("stat", function stat(test) {
+  return Task.spawn(function() {
     // Open a file and stat it
-    promise = OS.File.open(EXISTING_FILE);
-    promise = promise.then(function open_has_worked(aFile) {
-      file = aFile;
-      test.info("Stating file");
-      return file.stat();
-    });
+    let file = yield OS.File.open(EXISTING_FILE);
+    let stat1;
 
-    promise = promise.then(
-      function stat_has_worked(aStat) {
-        test.ok(true, "stat has worked " + aStat);
-        test.ok(aStat, "stat is not empty");
-        stat = aStat;
-      }
-    );
-
-    promise = always(promise,
-      function close() {
-        if (file) {
-          file.close();
-        }
-      }
-    );
+    try {
+      test.info("Stating file");
+      stat1 = yield file.stat();
+      test.ok(true, "stat has worked " + stat1);
+      test.ok(stat1, "stat is not empty");
+    } finally {
+      yield file.close();
+    }
 
     // Stat the same file without opening it
-    promise = promise.then(
-      function stat_without_opening() {
-        test.info("Stating a file without opening it");
-        return OS.File.stat(EXISTING_FILE);
-      }
-    );
-
-    // Check that both stats are identical
-    promise = promise.then(
-      function stat_has_worked_2(aStat) {
-        test.ok(true, "stat 2 has worked " + aStat);
-        test.ok(aStat, "stat 2 is not empty");
-        for (let key in aStat) {
-          test.is("" + stat[key], "" + aStat[key], "Stat field " + key + "is the same");
-        }
-      }
-    );
-
-    // Do not forget to return the promise.
-    return promise;
+    test.info("Stating a file without opening it");
+    let stat2 = yield OS.File.stat(EXISTING_FILE);
+    test.ok(true, "stat 2 has worked " + stat2);
+    test.ok(stat2, "stat 2 is not empty");
+    for (let key in stat2) {
+      test.is("" + stat1[key], "" + stat2[key], "Stat field " + key + "is the same");
+    }
+  });
 });
 
 /**
  * Test OS.File.prototype.{read, readTo, write}
  */
-let test_read_write = maketest("read_write",
-  function read_write(test) {
-    let promise;
-    let array;
-    let fileSource, fileDest;
-    let pathSource;
-    let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
-       "osfile async test.tmp");
-
+let test_read_write = maketest("read_write", function read_write(test) {
+  return Task.spawn(function() {
     // Test readTo/write
-
-    promise = OS.File.getCurrentDirectory();
-    promise = promise.then(
-      function obtained_current_directory(path) {
-        test.ok(path, "Obtained current directory");
-        pathSource = OS.Path.join(path, EXISTING_FILE);
-        return OS.File.open(pathSource);
-      }
-    );
+    let currentDir = yield OS.File.getCurrentDirectory();
+    let pathSource = OS.Path.join(currentDir, EXISTING_FILE);
+    let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
+      "osfile async test.tmp");
 
-    promise = promise.then(
-      function input_file_opened(file) {
-        test.info("Input file opened");
-        fileSource = file;
-        test.info("OS.Constants.Path is " + OS.Constants.Path.toSource());
-        return OS.File.open(pathDest,
-          { truncate: true, read: true, write: true} );
-      });
-
-    promise = promise.then (
-      function output_file_opened(file) {
-        test.info("Output file opened");
-        fileDest = file;
-        return fileSource.stat();
-      }
-    );
+    let fileSource = yield OS.File.open(pathSource);
+    test.info("Input file opened");
+    let fileDest = yield OS.File.open(pathDest,
+      { truncate: true, read: true, write: true});
+    test.info("Output file opened");
 
-    let size;
-    promise = promise.then(
-      function input_stat_worked(stat) {
-        test.info("Input stat worked");
-        size = stat.size;
-        array = new Uint8Array(size);
-        test.info("Now calling readTo");
-        return fileSource.readTo(array);
-      }
-    );
-
-    promise = promise.then(
-      function read_worked(length) {
-        test.info("ReadTo worked");
-        test.is(length, size, "ReadTo got all bytes");
-        return fileDest.write(array);
-      }
-    );
+    let stat = yield fileSource.stat();
+    test.info("Input stat worked");
+    let size = stat.size;
+    let array = new Uint8Array(size);
 
-    promise = promise.then(
-      function write_worked(length) {
-        test.info("Write worked");
-        test.is(length, size, "Write wrote all bytes");
-        return;
-      }
-    );
-
-    // Test read
-    promise = promise.then(
-      function prepare_readall() {
-        return fileSource.setPosition(0);
-      }
-    );
-    promise = promise.then(
-      function setposition_worked() {
-        return fileSource.read();
-      }
-    );
-    promise = promise.then(
-      function readall_worked(result) {
-        test.info("ReadAll worked");
-        test.is(result.length, size, "ReadAll read all bytes");
-        test.is(Array.prototype.join.call(result),
-                Array.prototype.join.call(array),
-                "ReadAll result is correct");
-      }
-    );
+    try {
+      test.info("Now calling readTo");
+      let readLength = yield fileSource.readTo(array);
+      test.info("ReadTo worked");
+      test.is(readLength, size, "ReadTo got all bytes");
+      let writeLength = yield fileDest.write(array);
+      test.info("Write worked");
+      test.is(writeLength, size, "Write wrote all bytes");
 
-
-    // Close stuff
-
-    promise = always(promise,
-      function close_all() {
-        return fileSource.close().then(fileDest.close);
-      }
-    );
+      // Test read
+      yield fileSource.setPosition(0);
+      let readAllResult = yield fileSource.read();
+      test.info("ReadAll worked");
+      test.is(readAllResult.length, size, "ReadAll read all bytes");
+      test.is(Array.prototype.join.call(readAllResult),
+              Array.prototype.join.call(array),
+              "ReadAll result is correct");
+    } finally {
+      // Close stuff
+      yield fileSource.close();
+      yield fileDest.close();
+      test.info("Files are closed");
+    }
 
-    promise = promise.then(
-      function files_closed() {
-        test.info("Files are closed");
-        return OS.File.stat(pathDest);
-      }
-    );
-
-    promise = promise.then(
-      function comparing_sizes(stat) {
-        test.is(stat.size, size, "Both files have the same size");
-      }
-    );
-
-    promise = promise.then(
-      function compare_contents() {
-        return reference_compare_files(pathSource, pathDest, test);
-      }
-    );
-    return promise;
+    stat = yield OS.File.stat(pathDest);
+    test.is(stat.size, size, "Both files have the same size");
+    yield reference_compare_files(pathSource, pathDest, test);
+  });
 });
 
-let test_read_write_all = maketest(
-  "read_write_all",
-  function read_write_all(test) {
-    let pathSource;
+/**
+ * Test OS.File.prototype.{writeAtomic}
+ */
+let test_read_write_all = maketest("read_write_all", function read_write_all(test) {
+  return Task.spawn(function() {
     let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
-       "osfile async test read writeAtomic.tmp");
+      "osfile async test read writeAtomic.tmp");
     let tmpPath = pathDest + ".tmp";
 
-    let options, optionsBackup;
-
-// Check that read + writeAtomic performs a correct copy
-
-    let promise = OS.File.getCurrentDirectory();
-    promise = promise.then(
-      function obtained_current_directory(path) {
-        test.ok(path, "Obtained current directory");
-        pathSource = OS.Path.join(path, EXISTING_FILE);
-        return OS.File.read(pathSource);
-      }
-    );
-    promise = ensureSuccess(promise, test);
+    // Check that read + writeAtomic performs a correct copy
+    let currentDir = yield OS.File.getCurrentDirectory();
+    let pathSource = OS.Path.join(currentDir, EXISTING_FILE);
+    let contents = yield OS.File.read(pathSource);
+    test.ok(contents, "Obtained contents");
+    let options = {tmpPath: tmpPath};
+    let optionsBackup = {tmpPath: tmpPath};
+    let bytesWritten = yield OS.File.writeAtomic(pathDest, contents, options);
+    test.is(contents.byteLength, bytesWritten, "Wrote the correct number of bytes");
 
-    let contents;
-    promise = promise.then(
-      function read_complete(result) {
-        test.ok(result, "Obtained contents");
-        contents = result;
-        options = {tmpPath: tmpPath};
-        optionsBackup = {tmpPath: tmpPath};
-        return OS.File.writeAtomic(pathDest, contents, options);
-      }
-    );
-    promise = ensureSuccess(promise, test);
-
-// Check that options are not altered
-
-    promise = promise.then(
-      function atomicWrite_complete(bytesWritten) {
-        test.is(contents.byteLength, bytesWritten, "Wrote the correct number of bytes");
-        test.is(Object.keys(options).length, Object.keys(optionsBackup).length,
-                "The number of options was not changed");
-        for (let k in options) {
-          test.is(options[k], optionsBackup[k], "Option was not changed");
-        }
-        return reference_compare_files(pathSource, pathDest, test);
-      }
-    );
-    promise = ensureSuccess(promise, test);
+    // Check that options are not altered
+    test.is(Object.keys(options).length, Object.keys(optionsBackup).length,
+            "The number of options was not changed");
+    for (let k in options) {
+      test.is(options[k], optionsBackup[k], "Option was not changed");
+    }
+    yield reference_compare_files(pathSource, pathDest, test);
 
-// Check that temporary file was removed
-
-    promise = promise.then(
-      function compare_complete() {
-        test.info("Compare complete");
-        test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed");
-      }
-    );
-    promise = ensureSuccess(promise, test);
-
-// Check that writeAtomic fails if noOverwrite is true and the destination file already exists!
-
-    promise = promise.then(
-      function check_with_noOverwrite() {
-        let view = new Uint8Array(contents.buffer, 10, 200);
-        options = {tmpPath: tmpPath, noOverwrite: true};
-        return OS.File.writeAtomic(pathDest, view, options);
-      }
-    );
+    // Check that temporary file was removed
+    test.info("Compare complete");
+    test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed");
 
-    promise = promise.then(
-      function onSuccess() {
-        test.fail("With noOverwrite, writeAtomic should have refused to overwrite file");
-      },
-      function onFailure(err) {
-        test.info("With noOverwrite, writeAtomic correctly failed");
-        test.ok(err instanceof OS.File.Error, "writeAtomic correctly failed with a file error");
-        test.ok(err.becauseExists, "writeAtomic file error confirmed that the file already exists");
-        return reference_compare_files(pathSource, pathDest, test);
-      }
-    );
+    // Check that writeAtomic fails if noOverwrite is true and the destination
+    // file already exists!
+    let view = new Uint8Array(contents.buffer, 10, 200);
+    try {
+      options = {tmpPath: tmpPath, noOverwrite: true};
+      yield OS.File.writeAtomic(pathDest, view, options);
+      test.fail("With noOverwrite, writeAtomic should have refused to overwrite file");
+    } catch (err) {
+      test.info("With noOverwrite, writeAtomic correctly failed");
+      test.ok(err instanceof OS.File.Error, "writeAtomic correctly failed with a file error");
+      test.ok(err.becauseExists, "writeAtomic file error confirmed that the file already exists");
+    }
+    yield reference_compare_files(pathSource, pathDest, test);
+    test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed");
 
-    promise = promise.then(
-      function compare_complete() {
-        test.info("With noOverwrite, writeAtomic correctly did not overwrite destination file");
-        test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed");
-      }
-    );
-    promise = ensureSuccess(promise, test);
-
-// Now write a subset
-
+    // Now write a subset
     let START = 10;
     let LENGTH = 100;
-    promise = promise.then(
-      function() {
-        let view = new Uint8Array(contents.buffer, START, LENGTH);
-        return OS.File.writeAtomic(pathDest, view, {tmpPath: tmpPath});
-      }
-    );
-
-    promise = promise.then(
-      function partial_write_complete(bytesWritten) {
-        test.is(bytesWritten, LENGTH, "Partial write wrote the correct number of bytes");
-        return OS.File.read(pathDest);
+    view = new Uint8Array(contents.buffer, START, LENGTH);
+    bytesWritten = yield OS.File.writeAtomic(pathDest, view, {tmpPath: tmpPath});
+    test.is(bytesWritten, LENGTH, "Partial write wrote the correct number of bytes");
+    let array2 = yield OS.File.read(pathDest);
+    let view1 = new Uint8Array(contents.buffer, START, LENGTH);
+    test.is(view1.length, array2.length, "Re-read partial write with the correct number of bytes");
+    for (let i = 0; i < LENGTH; ++i) {
+      if (view1[i] != array2[i]) {
+        test.is(view1[i], array2[i], "Offset " + i + " is correct");
       }
-    );
+      test.ok(true, "Compared re-read of partial write");
+    }
+
+    // Check that writeAtomic fails if there is no tmpPath.
+    // FIXME: Remove this as part of bug 793660
+    try {
+      yield OS.File.writeAtomic(pathDest, contents, {});
+      test.fail("Without a tmpPath, writeAtomic should have failed");
+    } catch (err) {
+      test.ok(true, "Without a tmpPath, writeAtomic has failed as expected");
+    }
+  });
+});
+
+/**
+ * Test file.{getPosition, setPosition}
+ */
+let test_position = maketest("position", function position(test) {
+  return Task.spawn(function() {
+    let file = yield OS.File.open(EXISTING_FILE);
 
-    promise = promise.then(
-      function read_partial_write_complete(array2) {
-        let view1 = new Uint8Array(contents.buffer, START, LENGTH);
-        test.is(view1.length, array2.length, "Re-read partial write with the correct number of bytes");
-        for (let i = 0; i < LENGTH; ++i) {
-          if (view1[i] != array2[i]) {
-            test.is(view1[i], array2[i], "Offset " + i + " is correct");
-          }
-          test.ok(true, "Compared re-read of partial write");
+    try {
+      let stat = yield file.stat();
+      test.info("Obtained file length");
+
+      let view = new Uint8Array(stat.size);
+      yield file.readTo(view);
+      test.info("First batch of content read");
+
+      let CHUNK_SIZE = 178;// An arbitrary number of bytes to read from the file
+      let pos = yield file.getPosition();
+      test.info("Obtained position");
+      test.is(pos, view.byteLength, "getPosition returned the end of the file");
+      pos = yield file.setPosition(-CHUNK_SIZE, OS.File.POS_END);
+      test.info("Changed position");
+      test.is(pos, view.byteLength - CHUNK_SIZE, "setPosition returned the correct position");
+
+      let view2 = new Uint8Array(CHUNK_SIZE);
+      yield file.readTo(view2);
+      test.info("Read the end of the file");
+      for (let i = 0; i < CHUNK_SIZE; ++i) {
+        if (view2[i] != view[i + view.byteLength - CHUNK_SIZE]) {
+          test.is(view2[i], view[i], "setPosition put us in the right position");
         }
       }
-    );
-    promise = ensureSuccess(promise, test);
-
-// Check that writeAtomic fails if there is no tmpPath
-// FIXME: Remove this as part of bug 793660
-
-    promise = promise.then(
-      function check_without_tmpPath() {
-        return OS.File.writeAtomic(pathDest, contents, {});
-      },
-      function onFailure() {
-        test.info("Resetting failure");
-      }
-    );
-
-    promise = promise.then(
-      function onSuccess() {
-        test.fail("Without a tmpPath, writeAtomic should have failed");
-      },
-      function onFailure() {
-        test.ok("Without a tmpPath, writeAtomic has failed as expected");
-      }
-    );
-
-    return promise;
-  }
-);
-
-let test_position = maketest(
-  "position",
-  function position(test){
-
-    let promise = OS.File.open(EXISTING_FILE);
-
-    let file;
-
-    promise = promise.then(
-      function input_file_opened(aFile) {
-        file = aFile;
-        return file.stat();
-      }
-    );
-
-    let view;
-    promise = promise.then(
-      function obtained_stat(stat) {
-        test.info("Obtained file length");
-        view = new Uint8Array(stat.size);
-        return file.readTo(view);
-      });
-
-    promise = promise.then(
-      function input_file_read() {
-        test.info("First batch of content read");
-        return file.getPosition();
-      }
-    );
-
-    let pos;
-    let CHUNK_SIZE = 178;// An arbitrary number of bytes to read from the file
+    } finally {
+      yield file.close();
+    }
+  });
+});
 
-    promise = promise.then(
-      function obtained_position(aPos) {
-        test.info("Obtained position");
-        test.is(aPos, view.byteLength, "getPosition returned the end of the file");
-        return file.setPosition(-CHUNK_SIZE, OS.File.POS_END);
-      }
-    );
-
-    let view2;
-    promise = promise.then(
-      function changed_position(aPos) {
-        test.info("Changed position");
-        test.is(aPos, view.byteLength - CHUNK_SIZE, "setPosition returned the correct position");
-        view2 = new Uint8Array(CHUNK_SIZE);
-        return file.readTo(view2);
-      }
-    );
-
-    promise = promise.then(
-      function input_file_reread() {
-        test.info("Read the end of the file");
-        for (let i = 0; i < CHUNK_SIZE; ++i) {
-          if (view2[i] != view[i + view.byteLength - CHUNK_SIZE]) {
-            test.is(view2[i], view[i], "setPosition put us in the right position");
-          }
-        }
-      }
-    );
-
-    promise = always(promise,
-      function () {
-        if (file) {
-          file.close();
-        }
-      });
-
-    return promise;
-  });
-
-let test_copy = maketest("copy",
-  function copy(test) {
-    let promise;
-
-    let pathSource;
+/**
+ * Test OS.File.prototype.{copy, move}
+ */
+let test_copy = maketest("copy", function copy(test) {
+  return Task.spawn(function() {
+    let currentDir = yield OS.File.getCurrentDirectory();
+    let pathSource = OS.Path.join(currentDir, EXISTING_FILE);
     let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
-       "osfile async test 2.tmp");
-
-    promise = OS.File.getCurrentDirectory();
-    promise = promise.then(
-      function obtained_current_directory(path) {
-        test.ok(path, "Obtained current directory");
-        pathSource = OS.Path.join(path, EXISTING_FILE);
-        return OS.File.copy(pathSource, pathDest);
-      }
-    );
-
-    promise = promise.then(
-      function copy_complete() {
-        test.info("Copy complete");
-        return reference_compare_files(pathSource, pathDest, test);
-      }
-    );
+      "osfile async test 2.tmp");
+    yield OS.File.copy(pathSource, pathDest);
+    test.info("Copy complete");
+    yield reference_compare_files(pathSource, pathDest, test);
+    test.info("First compare complete");
 
     let pathDest2 = OS.Path.join(OS.Constants.Path.tmpDir,
-       "osfile async test 3.tmp");
-
-    promise = promise.then(
-      function compare_complete_1() {
-        test.info("First compare complete");
-        return OS.File.move(pathDest, pathDest2);
-      }
-    );
-
-    promise = promise.then(
-      function move_complete() {
-        test.info("Move complete");
-        return reference_compare_files(pathSource, pathDest2, test);
-      }
-    );
+      "osfile async test 3.tmp");
+    yield OS.File.move(pathDest, pathDest2);
+    test.info("Move complete");
+    yield reference_compare_files(pathSource, pathDest2, test);
+    test.info("Second compare complete");
 
-    promise = promise.then(
-      function compare_complete_2() {
-        test.info("Second compare complete");
-        return OS.File.open(pathDest);
-      }
-    );
+    try {
+      let field = yield OS.File.open(pathDest);
+      test.fail("I should not have been able to open " + pathDest);
+      file.close();
+    } catch (err) {
+      test.ok(err, "Could not open a file after it has been moved away " + err);
+      test.ok(err instanceof OS.File.Error, "Error is an OS.File.Error");
+      test.ok(err.becauseNoSuchFile, "Error mentions that the file does not exist");
+    }
+  });
+});
 
-    promise = promise.then(
-      function open_should_not_have_succeeded(file) {
-        test.fail("I should not have been able to open " + pathDest);
-        file.close();
-      },
-      function open_did_not_succeed(reason) {
-        test.ok(reason, "Could not open a file after it has been moved away " + reason);
-        test.ok(reason instanceof OS.File.Error, "Error is an OS.File.Error");
-        test.ok(reason.becauseNoSuchFile, "Error mentions that the file does not exist");
-      }
-    );
-
-    return promise;
-  });
-
-let test_mkdir = maketest("mkdir",
-  function mkdir(test) {
+/**
+ * Test OS.File.prototype.{removeEmptyDir, makeDir}
+ */
+let test_mkdir = maketest("mkdir", function mkdir(test) {
+  return Task.spawn(function() {
     const DIRNAME = "test_dir.tmp";
 
     // Cleanup
-    let promise = OS.File.removeEmptyDir(DIRNAME, {ignoreAbsent: true});
-
+    yield OS.File.removeEmptyDir(DIRNAME, {ignoreAbsent: true});
 
     // Remove an absent directory with ignoreAbsent
-    promise = promise.then(
-      function() {
-        return OS.File.removeEmptyDir(DIRNAME, {ignoreAbent: true});
-    });
-
-    promise = test.okpromise(promise, "Check that removing an absent directory with ignoreAbsent succeeds");
+    yield OS.File.removeEmptyDir(DIRNAME, {ignoreAbsent: true});
+    test.ok(true, "Removing an absent directory with ignoreAbsent succeeds");
 
     // Remove an absent directory without ignoreAbsent
-    promise = promise.then(
-      function() {
-        return OS.File.removeEmptyDir(DIRNAME);
-      }
-    );
-    promise = promise.then(
-      function shouldNotHaveSucceeded() {
-        test.fail("Check that removing an absent directory without ignoreAbsent fails");
-      },
-      function(result) {
-        test.ok(result.rejected instanceof OS.File.Error && result.rejected.becauseNoSuchFile, "Check that removing an absent directory without ignoreAbsent throws the right error");
-      }
-    );
+    try {
+      yield OS.File.removeEmptyDir(DIRNAME);
+      test.fail("Removing an absent directory without ignoreAbsent should have failed");
+    } catch (err) {
+      test.ok(err, "Removing an absent directory without ignoreAbsent throws the right error");
+      test.ok(err instanceof OS.File.Error, "Error is an OS.File.Error");
+      test.ok(err.becauseNoSuchFile, "Error mentions that the file does not exist");
+    }
 
     // Creating a directory (should succeed)
-    promise = promise.then(
-      function() {
-        return OS.File.makeDir(DIRNAME);
-      }
-    );
-    test.okpromise(promise, "Creating a directory");
-    promise = promise.then(
-      function() {
-        return OS.File.stat(DIRNAME);
-      }
-    );
-    promise = promise.then(
-      function(stat) {
-        test.ok(stat.isDir, "I have effectively created a directory");
-      }
-    );
+    test.ok(true, "Creating a directory");
+    yield OS.File.makeDir(DIRNAME);
+    let stat = yield OS.File.stat(DIRNAME);
+    test.ok(stat.isDir, "I have effectively created a directory");
 
     // Creating a directory (should fail)
-    promise = promise.then(
-      function() {
-        return OS.File.makeDir(DIRNAME);
-      }
-    );
-    promise = promise.then(
-      function shouldNotHaveSucceeded() {
-        test.fail("Check that creating over an existing directory fails");
-      },
-      function(result) {
-        test.ok(result.rejected instanceof OS.File.Error && result.rejected.becauseExists, "Check that creating over an existing directory throws the right error");
-      }
-    );
+    try {
+      yield OS.File.makeDir(DIRNAME);
+      test.fail("Creating over an existing directory should have failed");
+    } catch (err) {
+      test.ok(err, "Creating over an existing directory throws the right error");
+      test.ok(err instanceof OS.File.Error, "Error is an OS.File.Error");
+      test.ok(err.becauseExists, "Error mentions that the file already exists");
+    }
 
     // Remove a directory and check the result
-    promise = promise.then(
-      function() {
-        return OS.File.removeEmptyDir(DIRNAME);
-      }
-    );
-    promise = okpromise(promise, "Removing empty directory suceeded");
+    yield OS.File.removeEmptyDir(DIRNAME);
+    test.ok(true, "Removing empty directory suceeded");
+    try {
+      yield OS.File.stat(DIRNAME);
+      test.fail("Removing directory should have failed");
+    } catch (err) {
+      test.ok(err, "Directory was effectively removed");
+      test.ok(err instanceof OS.File.Error, "Error is an OS.File.Error");
+      test.ok(err.becauseNoSuchFile, "Error mentions that the file does not exist");
+    }
+  });
+});
 
-    promise = promise.then(
-      function() {
-        return OS.File.stat(DIRNAME);
-      }
-    );
-    promise = promise.then(
-      function shouldNotHaveSucceeded() {
-        test.fail("Check that directory was effectively removed");
-      },
-      function(error) {
-        ok(error instanceof OS.File.Error && error.becauseNoSuchFile,
-           "Directory was effectively removed");
-      }
-    );
-
-    return promise;
-  });
-
-let test_iter = maketest("iter",
-  function iter(test) {
-    let path;
-    let promise = OS.File.getCurrentDirectory();
-    let temporary_file_name;
-    let iterator;
+/**
+ * Test OS.File.prototype.{DirectoryIterator}
+ */
+let test_iter = maketest("iter", function iter(test) {
+  return Task.spawn(function() {
+    let currentDir = yield OS.File.getCurrentDirectory();
 
     // Trivial walks through the directory
-    promise = promise.then(
-      function obtained_current_directory(aPath) {
-        test.info("Preparing iteration");
-        path = aPath;
-        iterator = new OS.File.DirectoryIterator(aPath);
-        temporary_file_name = OS.Path.join(path, "empty-temporary-file.tmp");
-        return OS.File.remove(temporary_file_name);
-      }
-    );
-
-    // Ignore errors removing file
-    promise = promise.then(null, function() {});
-
-    promise = promise.then(
-      function removed_temporary_file() {
-        return iterator.nextBatch();
-      }
-    );
+    test.info("Preparing iteration");
+    let iterator = new OS.File.DirectoryIterator(currentDir);
+    let temporary_file_name = OS.Path.join(currentDir, "empty-temporary-file.tmp");
+    try {
+      yield OS.File.remove(temporary_file_name);
+    } catch (err) {
+      // Ignore errors removing file
+    }
+    let allFiles1 = yield iterator.nextBatch();
+    test.info("Obtained all files through nextBatch");
+    test.isnot(allFiles1.length, 0, "There is at least one file");
+    test.isnot(allFiles1[0].path, null, "Files have a path");
+    yield iterator.close();
+    test.info("Closed iterator");
 
-    let allfiles1;
-    promise = promise.then(
-      function obtained_allfiles1(aAllFiles) {
-        test.info("Obtained all files through nextBatch");
-        allfiles1 = aAllFiles;
-        test.isnot(allfiles1.length, 0, "There is at least one file");
-        test.isnot(allfiles1[0].path, null, "Files have a path");
-        return iterator.close();
-      });
-
-    let allfiles2 = [];
+    let allFiles2 = [];
     let i = 0;
-    promise = promise.then(
-      function closed_iterator() {
-        test.info("Closed iterator");
-        iterator = new OS.File.DirectoryIterator(path);
-        return iterator.forEach(function(entry, index) {
-          is(i++, index, "Getting the correct index");
-          allfiles2.push(entry);
-        });
+    iterator = new OS.File.DirectoryIterator(currentDir);
+    yield iterator.forEach(function(entry, index) {
+      test.is(i++, index, "Getting the correct index");
+      allFiles2.push(entry);
+    });
+    test.info("Obtained all files through forEach");
+    is(allFiles1.length, allFiles2.length, "Both runs returned the same number of files");
+    for (let i = 0; i < allFiles1.length; ++i) {
+      if (allFiles1[i].path != allFiles2[i].path) {
+        test.is(allFiles1[i].path, allFiles2[i].path, "Both runs return the same files");
+        break;
       }
-    );
-
-    promise = promise.then(
-      function obtained_allfiles2() {
-        test.info("Obtained all files through forEach");
-        is(allfiles1.length, allfiles2.length, "Both runs returned the same number of files");
-        for (let i = 0; i < allfiles1.length; ++i) {
-          if (allfiles1[i].path != allfiles2[i].path) {
-            test.is(allfiles1[i].path, allfiles2[i].path, "Both runs return the same files");
-            break;
-          }
-        }
-      }
-    );
+    }
 
     // Testing batch iteration + whether an iteration can be stopped early
     let BATCH_LENGTH = 10;
-    promise = promise.then(
-      function compared_allfiles() {
-        test.info("Getting some files through nextBatch");
-        iterator.close();
-        iterator = new OS.File.DirectoryIterator(path);
-        return iterator.nextBatch(BATCH_LENGTH);
-      }
-    );
-    let somefiles1;
-    promise = promise.then(
-      function obtained_somefiles1(aFiles) {
-        somefiles1 = aFiles;
-        return iterator.nextBatch(BATCH_LENGTH);
+    test.info("Getting some files through nextBatch");
+    yield iterator.close();
+
+    iterator = new OS.File.DirectoryIterator(currentDir);
+    let someFiles1 = yield iterator.nextBatch(BATCH_LENGTH);
+    let someFiles2 = yield iterator.nextBatch(BATCH_LENGTH);
+    yield iterator.close();
+
+    iterator = new OS.File.DirectoryIterator(currentDir);
+    yield iterator.forEach(function cb(entry, index, iterator) {
+      if (index < BATCH_LENGTH) {
+        test.is(entry.path, someFiles1[index].path, "Both runs return the same files (part 1)");
+      } else if (index < 2*BATCH_LENGTH) {
+        test.is(entry.path, someFiles2[index - BATCH_LENGTH].path, "Both runs return the same files (part 2)");
+      } else if (index == 2 * BATCH_LENGTH) {
+        test.info("Attempting to stop asynchronous forEach");
+        return iterator.close();
+      } else {
+        test.fail("Can we stop an asynchronous forEach? " + index);
       }
-    );
-    let somefiles2;
-    promise = promise.then(
-      function obtained_somefiles2(aFiles) {
-        somefiles2 = aFiles;
-        iterator.close();
-        iterator = new OS.File.DirectoryIterator(path);
-        return iterator.forEach(
-          function cb(entry, index, iterator) {
-            if (index < BATCH_LENGTH) {
-              test.is(entry.path, somefiles1[index].path, "Both runs return the same files (part 1)");
-            } else if (index < 2*BATCH_LENGTH) {
-              test.is(entry.path, somefiles2[index - BATCH_LENGTH].path, "Both runs return the same files (part 2)");
-            } else if (index == 2 * BATCH_LENGTH) {
-              test.info("Attempting to stop asynchronous forEach");
-              return iterator.close();
-            } else {
-              test.fail("Can we stop an asynchronous forEach? " + index);
-            }
-            return null;
-          });
-      }
-    );
+      return null;
+    });
 
     // Ensuring that we find new files if they appear
-    promise = promise.then(
-      function create_temporary_file() {
-        return OS.File.open(temporary_file_name, { write: true } );
-      }
-    );
-    promise = promise.then(
-      function with_temporary_file(file) {
-        file.close();
-        iterator = new OS.File.DirectoryIterator(path);
-        return iterator.nextBatch();
-      }
-    );
-    promise = promise.then(
-      function with_new_list(aFiles) {
-        is(aFiles.length, allfiles1.length + 1, "The directory iterator has noticed the new file");
-      }
-    );
-
-    promise = always(promise,
-      function cleanup() {
-        if (iterator) {
-          iterator.close();
-        }
-      }
-    );
-
-    return promise;
+    let file = yield OS.File.open(temporary_file_name, { write: true } );
+    file.close();
+    iterator = new OS.File.DirectoryIterator(currentDir);
+    try {
+      let files = yield iterator.nextBatch();
+      is(files.length, allFiles1.length + 1, "The directory iterator has noticed the new file");
+    } finally {
+      yield iterator.close();
+    }
+  });
 });
 
 /**
  * Test OS.File.prototype.{exists}
  */
-let test_exists = maketest("exists",
-  function exists(test) {
-    let promise;
-
-    promise = OS.File.exists(EXISTING_FILE);
-    promise = promise.then(function exists_worked(aExists) {
-      test.ok(aExists, "file exists");
-      return OS.File.exists(EXISTING_FILE + ".tmp");
-    });
-
-    promise = promise.then(function exists_on_absent_file_worked(aExists) {
-      test.ok(!aExists, "file does not exists");
-    });
-
-    // Do not forget to return the promise.
-    return promise;
+let test_exists = maketest("exists", function exists(test) {
+  return Task.spawn(function() {
+    let fileExists = yield OS.File.exists(EXISTING_FILE);
+    test.ok(fileExists, "file exists");
+    fileExists = yield OS.File.exists(EXISTING_FILE + ".tmp");
+    test.ok(!fileExists, "file does not exists");
+  });
 });