Bug 1400098 - test_fileapi.html rewritten using Promises, r=qdot
☠☠ backed out by 933be59f89bd ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 13 Oct 2017 08:47:41 +0200
changeset 386122 6f968efadcdc0e14007e84b1b36d08351c6ccc9e
parent 386121 322dbb6b6736339695b8be2f8043ba4c7ee9e140
child 386123 a7b1484b2367547280e18559dc25205479d23a23
push id32676
push userarchaeopteryx@coole-files.de
push dateFri, 13 Oct 2017 21:38:18 +0000
treeherdermozilla-central@a31334a65a1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1400098
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1400098 - test_fileapi.html rewritten using Promises, r=qdot
dom/file/tests/common_fileReader.js
dom/file/tests/mochitest.ini
dom/file/tests/test_fileapi.html
new file mode 100644
--- /dev/null
+++ b/dom/file/tests/common_fileReader.js
@@ -0,0 +1,495 @@
+function runTests(asciiFile, binaryFile, nonExistingFile, utf8TextFile,
+                  utf16TextFile, emptyFile, dataUrlFile0, dataUrlFile1,
+                  dataUrlFile2, testTextData) {
+  return test_basic()
+    .then(() => {
+      return test_readAsText(asciiFile, testASCIIData);
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(asciiFile, testASCIIData,
+                                         testASCIIData.length, "");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(asciiFile, testASCIIData,
+                                         testASCIIData.length, "iso8859-1");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(utf8TextFile, testTextData,
+                                         convertToUTF8(testTextData).length,
+                                         "utf8");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(utf16TextFile, testTextData,
+                                         convertToUTF16(testTextData).length,
+                                         "utf-16");
+    })
+    .then(() => {
+      return test_readAsBinaryString(binaryFile, testBinaryData);
+    })
+    .then(() => {
+      return test_readAsArrayBuffer(binaryFile, testBinaryData);
+    })
+    .then(() => {
+      return test_onlyResult()
+    })
+    .then(() => {
+      return test_readAsText(emptyFile, "");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(emptyFile, "", 0, "");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(emptyFile, "", 0, "utf8");
+    })
+    .then(() => {
+      return test_readAsTextWithEncoding(emptyFile, "", 0, "utf-16");
+    })
+    .then(() => {
+      return test_readAsBinaryString(emptyFile, "");
+    })
+    .then(() => {
+      return test_readAsArrayBuffer(emptyFile, "");
+    })
+    .then(() => {
+      return test_readAsDataURL(emptyFile, convertToDataURL(""), 0);
+    })
+    .then(() => {
+      return test_readAsTextTwice(asciiFile, testASCIIData);
+    })
+    .then(() => {
+      return test_readAsBinaryStringTwice(binaryFile, testBinaryData);
+    })
+    .then(() => {
+      return test_readAsDataURLTwice(binaryFile, convertToDataURL(testBinaryData),
+                                     testBinaryData.length);
+    })
+    .then(() => {
+      return test_readAsArrayBufferTwice(binaryFile, testBinaryData);
+    })
+    .then(() => {
+      return test_readAsArrayBufferTwice2(binaryFile, testBinaryData);
+    })
+    .then(() => {
+      return test_readAsDataURL_customLength(dataUrlFile0, convertToDataURL(dataurldata0),
+                                             dataurldata0.length, 0);
+    })
+    .then(() => {
+      return test_readAsDataURL_customLength(dataUrlFile1, convertToDataURL(dataurldata1),
+                                             dataurldata1.length, 1);
+    })
+    .then(() => {
+      return test_readAsDataURL_customLength(dataUrlFile2, convertToDataURL(dataurldata2),
+                                             dataurldata2.length, 2);
+    })
+    .then(() => {
+      return test_abort(asciiFile);
+    })
+    .then(() => {
+      return test_abort_readAsX(asciiFile, testASCIIData);
+    })
+    .then(() => {
+      return test_nonExisting(nonExistingFile);
+    });
+}
+
+function convertToUTF16(s) {
+  let res = "";
+  for (let i = 0; i < s.length; ++i) {
+    c = s.charCodeAt(i);
+    res += String.fromCharCode(c & 255, c >>> 8);
+  }
+  return res;
+}
+
+function convertToUTF8(s) {
+  return unescape(encodeURIComponent(s));
+}
+
+function convertToDataURL(s) {
+  return "data:application/octet-stream;base64," + btoa(s);
+}
+
+function loadEventHandler_string(event, resolve, reader, data, dataLength, testName) {
+  is(event.target, reader, "Correct target.");
+  is(event.target.readyState, FileReader.DONE, "readyState in test " + testName);
+  is(event.target.error, null, "no error in test " + testName);
+  is(event.target.result, data, "result in test " + testName);
+  is(event.lengthComputable, true, "lengthComputable in test " + testName);
+  is(event.loaded, dataLength, "loaded in test " + testName);
+  is(event.total, dataLength, "total in test " + testName);
+  resolve();
+}
+
+function loadEventHandler_arrayBuffer(event, resolve, reader, data, testName) {
+  is(event.target.readyState, FileReader.DONE, "readyState in test " + testName);
+  is(event.target.error, null, "no error in test " +  testName);
+  is(event.lengthComputable, true, "lengthComputable in test " + testName);
+  is(event.loaded, data.length, "loaded in test " + testName);
+  is(event.total, data.length, "total in test " + testName);
+  is(event.target.result.byteLength, data.length, "array buffer size in test " + testName);
+
+  let u8v = new Uint8Array(event.target.result);
+  is(String.fromCharCode.apply(String, u8v), data,
+     "array buffer contents in test " + testName);
+  u8v = null;
+
+  SpecialPowers.gc();
+
+  is(event.target.result.byteLength, data.length,
+     "array buffer size after gc in test " + testName);
+  u8v = new Uint8Array(event.target.result);
+  is(String.fromCharCode.apply(String, u8v), data,
+     "array buffer contents after gc in test " + testName);
+
+  resolve();
+}
+
+function test_basic() {
+  return new Promise(resolve => {
+    is(FileReader.EMPTY, 0, "correct EMPTY value");
+    is(FileReader.LOADING, 1, "correct LOADING value");
+    is(FileReader.DONE, 2, "correct DONE value");
+    resolve();
+  });
+}
+
+function test_readAsText(blob, text) {
+  return new Promise(resolve => {
+    let onloadHasRun = false;
+    let onloadStartHasRun = false;
+
+    let r = new FileReader();
+    is(r.readyState, FileReader.EMPTY, "correct initial text readyState");
+
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, text.length, "readAsText");
+    }
+
+    r.addEventListener("load", () => { onloadHasRun = true });
+    r.addEventListener("loadstart", () => { onloadStartHasRun = true });
+
+    r.readAsText(blob);
+
+    is(r.readyState, FileReader.LOADING, "correct loading text readyState");
+    is(onloadHasRun, false, "text loading must be async");
+    is(onloadStartHasRun, true, "text loadstart should fire sync");
+  });
+}
+
+function test_readAsBinaryString(blob, text) {
+  return new Promise(resolve => {
+    let onloadHasRun = false;
+    let onloadStartHasRun = false;
+
+    let r = new FileReader();
+    is(r.readyState, FileReader.EMPTY, "correct initial binary readyState");
+
+    r.addEventListener("load", function() { onloadHasRun = true });
+    r.addEventListener("loadstart", function() { onloadStartHasRun = true });
+
+    r.readAsBinaryString(blob);
+
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, text.length, "readAsBinaryString");
+    }
+
+    is(r.readyState, FileReader.LOADING, "correct loading binary readyState");
+    is(onloadHasRun, false, "binary loading must be async");
+    is(onloadStartHasRun, true, "binary loadstart should fire sync");
+  });
+}
+
+function test_readAsArrayBuffer(blob, text) {
+  return new Promise(resolve => {
+    let onloadHasRun = false;
+    let onloadStartHasRun = false;
+
+    r = new FileReader();
+    is(r.readyState, FileReader.EMPTY, "correct initial arrayBuffer readyState");
+
+    r.addEventListener("load", function() { onloadHasRun = true });
+    r.addEventListener("loadstart", function() { onloadStartHasRun = true });
+
+    r.readAsArrayBuffer(blob);
+
+    r.onload = event => {
+      loadEventHandler_arrayBuffer(event, resolve, r, text, "readAsArrayBuffer");
+    }
+
+    is(r.readyState, FileReader.LOADING, "correct loading arrayBuffer readyState");
+    is(onloadHasRun, false, "arrayBuffer loading must be async");
+    is(onloadStartHasRun, true, "arrayBuffer loadstart should fire sync");
+  });
+}
+
+// Test a variety of encodings, and make sure they work properly
+function test_readAsTextWithEncoding(blob, text, length, charset) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, length, "readAsText-" + charset);
+    }
+    r.readAsText(blob, charset);
+  });
+}
+
+// Test get result without reading
+function test_onlyResult() {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    is(r.readyState, FileReader.EMPTY, "readyState in test reader get result without reading");
+    is(r.error, null, "no error in test reader get result without reading");
+    is(r.result, null, "result in test reader get result without reading");
+    resolve();
+  });
+}
+
+function test_readAsDataURL(blob, text, length) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, length, "readAsDataURL");
+    }
+    r.readAsDataURL(blob);
+  });
+}
+
+// Test reusing a FileReader to read multiple times
+function test_readAsTextTwice(blob, text) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, () => {}, r, text, text.length, "readAsText-reused-once");
+    }
+
+    let anotherListener = event => {
+      let r = event.target;
+      r.removeEventListener("load", anotherListener);
+      r.onload = event => {
+        loadEventHandler_string(event, resolve, r, text, text.length, "readAsText-reused-twice");
+      }
+      r.readAsText(blob);
+    };
+
+    r.addEventListener("load", anotherListener);
+    r.readAsText(blob);
+  });
+}
+
+// Test reusing a FileReader to read multiple times
+function test_readAsBinaryStringTwice(blob, text) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, () => {}, r, text, text.length, "readAsBinaryString-reused-once");
+    }
+
+    let anotherListener = event => {
+      let r = event.target;
+      r.removeEventListener("load", anotherListener);
+      r.onload = event => {
+        loadEventHandler_string(event, resolve, r, text, text.length, "readAsBinaryString-reused-twice");
+      }
+      r.readAsBinaryString(blob);
+    };
+
+    r.addEventListener("load", anotherListener);
+    r.readAsBinaryString(blob);
+  });
+}
+
+function test_readAsDataURLTwice(blob, text, length) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, () => {}, r, text, length, "readAsDataURL-reused-once");
+    }
+
+    let anotherListener = event => {
+      let r = event.target;
+      r.removeEventListener("load", anotherListener);
+      r.onload = event => {
+        loadEventHandler_string(event, resolve, r, text, length, "readAsDataURL-reused-twice");
+      }
+      r.readAsDataURL(blob);
+    };
+
+    r.addEventListener("load", anotherListener);
+    r.readAsDataURL(blob);
+  });
+}
+
+function test_readAsArrayBufferTwice(blob, text) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_arrayBuffer(event, () => {}, r, text, "readAsArrayBuffer-reused-once");
+    }
+
+    let anotherListener = event => {
+      let r = event.target;
+      r.removeEventListener("load", anotherListener);
+      r.onload = event => {
+        loadEventHandler_arrayBuffer(event, resolve, r, text, "readAsArrayBuffer-reused-twice");
+      }
+      r.readAsArrayBuffer(blob);
+    };
+
+    r.addEventListener("load", anotherListener);
+    r.readAsArrayBuffer(blob);
+  });
+}
+
+// Test first reading as ArrayBuffer then read as something else (BinaryString)
+// and doesn't crash
+function test_readAsArrayBufferTwice2(blob, text) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_arrayBuffer(event, () => {}, r, text, "readAsArrayBuffer-reused-once2");
+    }
+
+    let anotherListener = event => {
+      let r = event.target;
+      r.removeEventListener("load", anotherListener);
+      r.onload = event => {
+        loadEventHandler_string(event, resolve, r, text, text.length, "readAsArrayBuffer-reused-twice2");
+      }
+      r.readAsBinaryString(blob);
+    };
+
+    r.addEventListener("load", anotherListener);
+    r.readAsArrayBuffer(blob);
+  });
+}
+
+function test_readAsDataURL_customLength(blob, text, length, numb) {
+  return new Promise(resolve => {
+    is(length % 3, numb, "Want to test data with length %3 == " + numb);
+    let r = new FileReader();
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, length, "dataurl reading, %3 = " + numb);
+    }
+    r.readAsDataURL(blob);
+  });
+}
+
+// Test abort()
+function test_abort(blob) {
+  return new Promise(resolve => {
+    let abortHasRun = false;
+    let loadEndHasRun = false;
+
+    let r = new FileReader();
+
+    r.onabort = function (event) {
+      is(abortHasRun, false, "abort should only fire once");
+      is(loadEndHasRun, false, "loadend shouldn't have fired yet");
+      abortHasRun = true;
+      is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
+      is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
+      is(event.target.result, null, "file data should be null on aborted reads");
+    }
+
+    r.onloadend = function (event) {
+      is(abortHasRun, true, "abort should fire before loadend");
+      is(loadEndHasRun, false, "loadend should only fire once");
+      loadEndHasRun = true;
+      is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
+      is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
+      is(event.target.result, null, "file data should be null on aborted reads");
+    }
+
+    r.onload = function() { ok(false, "load should not fire for aborted reads") };
+    r.onerror = function() { ok(false, "error should not fire for aborted reads") };
+    r.onprogress = function() { ok(false, "progress should not fire for aborted reads") };
+
+    let abortThrew = false;
+    try {
+      r.abort();
+    } catch(e) {
+      abortThrew = true;
+    }
+
+    is(abortThrew, false, "abort() doesn't throw");
+    is(abortHasRun, false, "abort() is a no-op unless loading");
+
+    r.readAsText(blob);
+    r.abort();
+
+    is(abortHasRun, true, "abort should fire sync");
+    is(loadEndHasRun, true, "loadend should fire sync");
+
+    resolve();
+  });
+}
+
+// Test calling readAsX to cause abort()
+function test_abort_readAsX(blob, text) {
+  return new Promise(resolve => {
+    let reuseAbortHasRun = false;
+
+    letr = new FileReader();
+    r.onabort = function (event) {
+      is(reuseAbortHasRun, false, "abort should only fire once");
+      reuseAbortHasRun = true;
+      is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
+      is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
+      is(event.target.result, null, "file data should be null on aborted reads");
+    }
+    r.onload = function() { ok(false, "load should fire for nested reads"); };
+
+    let abortThrew = false;
+    try {
+      r.abort();
+    } catch(e) {
+      abortThrew = true;
+    }
+
+    is(abortThrew, false, "abort() should not throw");
+    is(reuseAbortHasRun, false, "abort() is a no-op unless loading");
+    r.readAsText(blob);
+
+    let readThrew = false;
+    try {
+      r.readAsText(blob);
+    } catch(e) {
+      readThrew = true;
+    }
+
+    is(readThrew, true, "readAsText() must throw if loading");
+    is(reuseAbortHasRun, false, "abort should not fire");
+
+    r.onload = event => {
+      loadEventHandler_string(event, resolve, r, text, text.length, "reuse-as-abort reading");
+    }
+  });
+}
+
+// Test reading from nonexistent files
+function test_nonExisting(blob) {
+  return new Promise(resolve => {
+    let r = new FileReader();
+
+    r.onerror = function (event) {
+      is(event.target.readyState, FileReader.DONE, "should be DONE while firing onerror");
+      is(event.target.error.name, "NotFoundError", "error set to NotFoundError for nonexistent files");
+      is(event.target.result, null, "file data should be null on aborted reads");
+      resolve();
+    };
+    r.onload = function (event) {
+      is(false, "nonexistent file shouldn't load! (FIXME: bug 1122788)");
+    };
+
+    let didThrow = false;
+    try {
+      r.readAsDataURL(blob);
+    } catch(ex) {
+      didThrow = true;
+    }
+
+    // Once this test passes, we should test that onerror gets called and
+    // that the FileReader object is in the right state during that call.
+    is(didThrow, false, "shouldn't throw when opening nonexistent file, should fire error instead");
+  });
+}
--- a/dom/file/tests/mochitest.ini
+++ b/dom/file/tests/mochitest.ini
@@ -17,12 +17,13 @@ support-files =
 [test_blobconstructor.html]
 [test_blobURL_expiring.html]
 [test_file_from_blob.html]
 [test_ipc_messagemanager_blob.html]
 support-files = file_ipc_messagemanager_blob.html
 [test_nonascii_blob_url.html]
 [test_file_negative_date.html]
 [test_fileapi.html]
+support-files = common_fileReader.js
 [test_fileapi_slice.html]
 skip-if = (toolkit == 'android') # Android: Bug 775227
 [test_mozfiledataurl.html]
 skip-if = toolkit == 'android' #TIMED_OUT
--- a/dom/file/tests/test_fileapi.html
+++ b/dom/file/tests/test_fileapi.html
@@ -1,47 +1,23 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=414796
--->
-  <title>Test for Bug 414796</title>
+  <title>Test for FileReader API</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="common_fileReader.js"></script>
 </head>
 
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=414796">Mozilla Bug 414796</a>
-<p id="display">
-</p>
-<div id="content" style="display: none">
-</div>
-
-<pre id="test">
 <script class="testbody" type="text/javascript">
 
-// File constructors should not work from non-chrome code
-try {
-  var file = File("/etc/passwd");
-  ok(false, "Did not throw on unprivileged attempt to construct a File");
-} catch (e) {
-  ok(true, "Threw on an unprivileged attempt to construct a File");
-}
-
 const minFileSize = 20000;
-var testRanCounter = 0;
-var expectedTestCount = 0;
-var testSetupFinished = false;
 SimpleTest.waitForExplicitFinish();
 
-is(FileReader.EMPTY, 0, "correct EMPTY value");
-is(FileReader.LOADING, 1, "correct LOADING value");
-is(FileReader.DONE, 2, "correct DONE value");
-
 // Create strings containing data we'll test with. We'll want long
 // strings to ensure they span multiple buffers while loading
 var testTextData = "asd b\tlah\u1234w\u00a0r";
 while (testTextData.length < minFileSize) {
   testTextData = testTextData + testTextData;
 }
 
 var testASCIIData = "abcdef 123456\n";
@@ -89,399 +65,16 @@ function onFilesOpened(message) {
     utf8TextFile,
     utf16TextFile,
     emptyFile,
     dataUrlFile0,
     dataUrlFile1,
     dataUrlFile2,
   ] = message;
 
-  // Test that plain reading works and fires events as expected, both
-  // for text and binary reading
-
-  var onloadHasRunText = false;
-  var onloadStartHasRunText = false;
-  r = new FileReader();
-  is(r.readyState, FileReader.EMPTY, "correct initial text readyState");
-  r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "plain reading");
-  r.addEventListener("load", function() { onloadHasRunText = true });
-  r.addEventListener("loadstart", function() { onloadStartHasRunText = true });
-  r.readAsText(asciiFile);
-  is(r.readyState, FileReader.LOADING, "correct loading text readyState");
-  is(onloadHasRunText, false, "text loading must be async");
-  is(onloadStartHasRunText, true, "text loadstart should fire sync");
-  expectedTestCount++;
-
-  var onloadHasRunBinary = false;
-  var onloadStartHasRunBinary = false;
-  r = new FileReader();
-  is(r.readyState, FileReader.EMPTY, "correct initial binary readyState");
-  r.addEventListener("load", function() { onloadHasRunBinary = true });
-  r.addEventListener("loadstart", function() { onloadStartHasRunBinary = true });
-  r.readAsBinaryString(binaryFile);
-  r.onload = getLoadHandler(testBinaryData, testBinaryData.length, "binary reading");
-  is(r.readyState, FileReader.LOADING, "correct loading binary readyState");
-  is(onloadHasRunBinary, false, "binary loading must be async");
-  is(onloadStartHasRunBinary, true, "binary loadstart should fire sync");
-  expectedTestCount++;
-
-  var onloadHasRunArrayBuffer = false;
-  var onloadStartHasRunArrayBuffer = false;
-  r = new FileReader();
-  is(r.readyState, FileReader.EMPTY, "correct initial arrayBuffer readyState");
-  r.addEventListener("load", function() { onloadHasRunArrayBuffer = true });
-  r.addEventListener("loadstart", function() { onloadStartHasRunArrayBuffer = true });
-  r.readAsArrayBuffer(binaryFile);
-  r.onload = getLoadHandlerForArrayBuffer(testBinaryData, testBinaryData.length, "array buffer reading");
-  is(r.readyState, FileReader.LOADING, "correct loading arrayBuffer readyState");
-  is(onloadHasRunArrayBuffer, false, "arrayBuffer loading must be async");
-  is(onloadStartHasRunArrayBuffer, true, "arrayBuffer loadstart should fire sync");
-  expectedTestCount++;
-
-  // Test a variety of encodings, and make sure they work properly
-  r = new FileReader();
-  r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "no encoding reading");
-  r.readAsText(asciiFile, "");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "iso8859 reading");
-  r.readAsText(asciiFile, "iso-8859-1");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler(testTextData,
-                            convertToUTF8(testTextData).length,
-                            "utf8 reading");
-  r.readAsText(utf8TextFile, "utf8");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.readAsText(utf16TextFile, "utf-16");
-  r.onload = getLoadHandler(testTextData,
-                            convertToUTF16(testTextData).length,
-                            "utf16 reading");
-  expectedTestCount++;
-
-  // Test get result without reading
-  r = new FileReader();
-  is(r.readyState, FileReader.EMPTY,
-     "readyState in test reader get result without reading");
-  is(r.error, null,
-     "no error in test reader get result without reading");
-  is(r.result, null,
-     "result in test reader get result without reading");
-
-  // Test loading an empty file works (and doesn't crash!)
-  r = new FileReader();
-  r.onload = getLoadHandler("", 0, "empty no encoding reading");
-  r.readAsText(emptyFile, "");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler("", 0, "empty utf8 reading");
-  r.readAsText(emptyFile, "utf8");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler("", 0, "empty utf16 reading");
-  r.readAsText(emptyFile, "utf-16");
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler("", 0, "empty binary string reading");
-  r.readAsBinaryString(emptyFile);
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandlerForArrayBuffer("", 0, "empty array buffer reading");
-  r.readAsArrayBuffer(emptyFile);
-  expectedTestCount++;
-
-  r = new FileReader();
-  r.onload = getLoadHandler(convertToDataURL(""), 0, "empt binary string reading");
-  r.readAsDataURL(emptyFile);
-  expectedTestCount++;
-
-  // Test reusing a FileReader to read multiple times
-  r = new FileReader();
-  r.onload = getLoadHandler(testASCIIData,
-                            testASCIIData.length,
-                            "to-be-reused reading text")
-  var makeAnotherReadListener = function(event) {
-    r = event.target;
-    r.removeEventListener("load", makeAnotherReadListener);
-    r.onload = getLoadHandler(testASCIIData,
-                              testASCIIData.length,
-                              "reused reading text");
-    r.readAsText(asciiFile);
-  };
-  r.addEventListener("load", makeAnotherReadListener);
-  r.readAsText(asciiFile);
-  expectedTestCount += 2;
-
-  r = new FileReader();
-  r.onload = getLoadHandler(testBinaryData,
-                            testBinaryData.length,
-                            "to-be-reused reading binary")
-  var makeAnotherReadListener2 = function(event) {
-    r = event.target;
-    r.removeEventListener("load", makeAnotherReadListener2);
-    r.onload = getLoadHandler(testBinaryData,
-                              testBinaryData.length,
-                              "reused reading binary");
-    r.readAsBinaryString(binaryFile);
-  };
-  r.addEventListener("load", makeAnotherReadListener2);
-  r.readAsBinaryString(binaryFile);
-  expectedTestCount += 2;
-
-  r = new FileReader();
-  r.onload = getLoadHandler(convertToDataURL(testBinaryData),
-                            testBinaryData.length,
-                            "to-be-reused reading data url")
-  var makeAnotherReadListener3 = function(event) {
-    r = event.target;
-    r.removeEventListener("load", makeAnotherReadListener3);
-    r.onload = getLoadHandler(convertToDataURL(testBinaryData),
-                              testBinaryData.length,
-                              "reused reading data url");
-    r.readAsDataURL(binaryFile);
-  };
-  r.addEventListener("load", makeAnotherReadListener3);
-  r.readAsDataURL(binaryFile);
-  expectedTestCount += 2;
-
-  r = new FileReader();
-  r.onload = getLoadHandlerForArrayBuffer(testBinaryData,
-                                          testBinaryData.length,
-                                          "to-be-reused reading arrayBuffer")
-  var makeAnotherReadListener4 = function(event) {
-    r = event.target;
-    r.removeEventListener("load", makeAnotherReadListener4);
-    r.onload = getLoadHandlerForArrayBuffer(testBinaryData,
-                                            testBinaryData.length,
-                                            "reused reading arrayBuffer");
-    r.readAsArrayBuffer(binaryFile);
-  };
-  r.addEventListener("load", makeAnotherReadListener4);
-  r.readAsArrayBuffer(binaryFile);
-  expectedTestCount += 2;
-
-  // Test first reading as ArrayBuffer then read as something else
-  // (BinaryString) and doesn't crash
-  r = new FileReader();
-  r.onload = getLoadHandlerForArrayBuffer(testBinaryData,
-                                          testBinaryData.length,
-                                          "to-be-reused reading arrayBuffer")
-  var makeAnotherReadListener5 = function(event) {
-    r = event.target;
-    r.removeEventListener("load", makeAnotherReadListener5);
-    r.onload = getLoadHandler(testBinaryData,
-                              testBinaryData.length,
-                              "reused reading binary string");
-    r.readAsBinaryString(binaryFile);
-  };
-  r.addEventListener("load", makeAnotherReadListener5);
-  r.readAsArrayBuffer(binaryFile);
-  expectedTestCount += 2;
-
-  //Test data-URI encoding on differing file sizes
-  is(dataurldata0.length % 3, 0, "Want to test data with length % 3 == 0");
-  r = new FileReader();
-  r.onload = getLoadHandler(convertToDataURL(dataurldata0),
-                            dataurldata0.length,
-                            "dataurl reading, %3 = 0");
-  r.readAsDataURL(dataUrlFile0);
-  expectedTestCount++;
-
-  is(dataurldata1.length % 3, 1, "Want to test data with length % 3 == 1");
-  r = new FileReader();
-  r.onload = getLoadHandler(convertToDataURL(dataurldata1),
-                            dataurldata1.length,
-                            "dataurl reading, %3 = 1");
-  r.readAsDataURL(dataUrlFile1);
-  expectedTestCount++;
-
-  is(dataurldata2.length % 3, 2, "Want to test data with length % 3 == 2");
-  r = new FileReader();
-  r.onload = getLoadHandler(convertToDataURL(dataurldata2),
-                            dataurldata2.length,
-                            "dataurl reading, %3 = 2");
-  r.readAsDataURL(dataUrlFile2),
-  expectedTestCount++;
-
-
-  // Test abort()
-  var abortHasRun = false;
-  var loadEndHasRun = false;
-  r = new FileReader();
-  r.onabort = function (event) {
-    is(abortHasRun, false, "abort should only fire once");
-    is(loadEndHasRun, false, "loadend shouldn't have fired yet");
-    abortHasRun = true;
-    is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
-    is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
-    is(event.target.result, null, "file data should be null on aborted reads");
-  }
-  r.onloadend = function (event) {
-    is(abortHasRun, true, "abort should fire before loadend");
-    is(loadEndHasRun, false, "loadend should only fire once");
-    loadEndHasRun = true;
-    is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
-    is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
-    is(event.target.result, null, "file data should be null on aborted reads");
-  }
-  r.onload = function() { ok(false, "load should not fire for aborted reads") };
-  r.onerror = function() { ok(false, "error should not fire for aborted reads") };
-  r.onprogress = function() { ok(false, "progress should not fire for aborted reads") };
-  var abortThrew = false;
-  try {
-    r.abort();
-  } catch(e) {
-    abortThrew = true;
-  }
-  is(abortThrew, false, "abort() doesn't throw");
-  is(abortHasRun, false, "abort() is a no-op unless loading");
-  r.readAsText(asciiFile);
-  r.abort();
-  is(abortHasRun, true, "abort should fire sync");
-  is(loadEndHasRun, true, "loadend should fire sync");
-
-  // Test calling readAsX to cause abort()
-  var reuseAbortHasRun = false;
-  r = new FileReader();
-  r.onabort = function (event) {
-    is(reuseAbortHasRun, false, "abort should only fire once");
-    reuseAbortHasRun = true;
-    is(event.target.readyState, FileReader.DONE, "should be DONE while firing onabort");
-    is(event.target.error.name, "AbortError", "error set to AbortError for aborted reads");
-    is(event.target.result, null, "file data should be null on aborted reads");
-  }
-  r.onload = function() { ok(false, "load should fire for nested reads"); };
-
-  var abortThrew = false;
-  try {
-    r.abort();
-  } catch(e) {
-    abortThrew = true;
-  }
-  is(abortThrew, false, "abort() should not throw");
-  is(reuseAbortHasRun, false, "abort() is a no-op unless loading");
-  r.readAsText(asciiFile);
-
-  var readThrew = false;
-  try {
-    r.readAsText(asciiFile);
-  } catch(e) {
-    readThrew = true;
-  }
-  is(readThrew, true, "readAsText() must throw if loading");
-  is(reuseAbortHasRun, false, "abort should not fire");
-  r.onload = getLoadHandler(testASCIIData, testASCIIData.length, "reuse-as-abort reading");
-  expectedTestCount++;
-
-
-  // Test reading from nonexistent files
-  r = new FileReader();
-  var didThrow = false;
-  r.onerror = function (event) {
-    is(event.target.readyState, FileReader.DONE, "should be DONE while firing onerror");
-    is(event.target.error.name, "NotFoundError", "error set to NotFoundError for nonexistent files");
-    is(event.target.result, null, "file data should be null on aborted reads");
-    testHasRun();
-  };
-  r.onload = function (event) {
-    is(false, "nonexistent file shouldn't load! (FIXME: bug 1122788)");
-    testHasRun();
-  };
-  try {
-    r.readAsDataURL(nonExistingFile);
-    expectedTestCount++;
-  } catch(ex) {
-    didThrow = true;
-  }
-  // Once this test passes, we should test that onerror gets called and
-  // that the FileReader object is in the right state during that call.
-  is(didThrow, false, "shouldn't throw when opening nonexistent file, should fire error instead");
-
-
-  function getLoadHandler(expectedResult, expectedLength, testName) {
-    return function (event) {
-      is(event.target.readyState, FileReader.DONE,
-         "readyState in test " + testName);
-      is(event.target.error, null,
-         "no error in test " + testName);
-      is(event.target.result, expectedResult,
-         "result in test " + testName);
-      is(event.lengthComputable, true,
-         "lengthComputable in test " + testName);
-      is(event.loaded, expectedLength,
-         "loaded in test " + testName);
-      is(event.total, expectedLength,
-         "total in test " + testName);
-      testHasRun();
-    }
-  }
-
-  function getLoadHandlerForArrayBuffer(expectedResult, expectedLength, testName) {
-    return function (event) {
-      is(event.target.readyState, FileReader.DONE,
-         "readyState in test " + testName);
-      is(event.target.error, null,
-         "no error in test " +  testName);
-      is(event.lengthComputable, true,
-         "lengthComputable in test " + testName);
-      is(event.loaded, expectedLength,
-         "loaded in test " + testName);
-      is(event.total, expectedLength,
-         "total in test " + testName);
-      is(event.target.result.byteLength, expectedLength,
-         "array buffer size in test " + testName);
-      var u8v = new Uint8Array(event.target.result);
-      is(String.fromCharCode.apply(String, u8v), expectedResult,
-         "array buffer contents in test " + testName);
-      u8v = null;
-      SpecialPowers.gc();
-      is(event.target.result.byteLength, expectedLength,
-         "array buffer size after gc in test " + testName);
-      u8v = new Uint8Array(event.target.result);
-      is(String.fromCharCode.apply(String, u8v), expectedResult,
-         "array buffer contents after gc in test " + testName);
-      testHasRun();
-    }
-  }
-
-  function testHasRun() {
-    //alert(testRanCounter);
-    ++testRanCounter;
-    if (testRanCounter == expectedTestCount) {
-      is(testSetupFinished, true, "test setup should have finished; check for exceptions");
-      is(onloadHasRunText, true, "onload text should have fired by now");
-      is(onloadHasRunBinary, true, "onload binary should have fired by now");
-      opener.destroy();
-      SimpleTest.finish();
-    }
-  }
-
-  testSetupFinished = true;
-}
-
-function convertToUTF16(s) {
-  res = "";
-  for (var i = 0; i < s.length; ++i) {
-    c = s.charCodeAt(i);
-    res += String.fromCharCode(c & 255, c >>> 8);
-  }
-  return res;
-}
-
-function convertToUTF8(s) {
-  return unescape(encodeURIComponent(s));
-}
-
-function convertToDataURL(s) {
-  return "data:application/octet-stream;base64," + btoa(s);
+  runTests(asciiFile, binaryFile, nonExistingFile, utf8TextFile, utf16TextFile,
+           emptyFile, dataUrlFile0, dataUrlFile1, dataUrlFile2, testTextData)
+  .then(SimpleTest.finish);
 }
 
 </script>
-</pre>
-</body> </html>
+</body>
+</html>