Bug 1173320 - patch 7/8 - Tests for FileList and Directories, r=smaug
☠☠ backed out by bd8284e36c7c ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Sat, 19 Mar 2016 14:34:57 +0100
changeset 289524 db971ba7c26de1d0849afb6640dd5232b8d9a80f
parent 289523 cd7e79d9a7507c6b33744428632dc684c2a82e10
child 289525 e5c224d964bcfe9f79be206aed262211348d4c57
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1173320
milestone48.0a1
Bug 1173320 - patch 7/8 - Tests for FileList and Directories, r=smaug
dom/base/test/script_postmessages_fileList.js
dom/base/test/test_postMessages.html
dom/filesystem/GetDirectoryListingTask.cpp
dom/filesystem/moz.build
dom/filesystem/tests/mochitest.ini
dom/filesystem/tests/moz.build
dom/filesystem/tests/script_fileList.js
dom/filesystem/tests/test_basic.html
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/webidl/HTMLInputElement.webidl
--- a/dom/base/test/script_postmessages_fileList.js
+++ b/dom/base/test/script_postmessages_fileList.js
@@ -1,15 +1,25 @@
 var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 Cu.importGlobalProperties(["File"]);
 
-var testFile = Cc["@mozilla.org/file/directory_service;1"]
-                 .getService(Ci.nsIDirectoryService)
-                 .QueryInterface(Ci.nsIProperties)
-                 .get("ProfD", Ci.nsIFile);
-testFile.append("prefs.js");
+addMessageListener("file.open", function () {
+  var testFile = Cc["@mozilla.org/file/directory_service;1"]
+                   .getService(Ci.nsIDirectoryService)
+                   .QueryInterface(Ci.nsIProperties)
+                   .get("ProfD", Ci.nsIFile);
+  testFile.append("prefs.js");
 
-addMessageListener("file.open", function () {
   sendAsyncMessage("file.opened", {
     file: new File(testFile)
   });
 });
 
+addMessageListener("dir.open", function () {
+  var testFile = Cc["@mozilla.org/file/directory_service;1"]
+                   .getService(Ci.nsIDirectoryService)
+                   .QueryInterface(Ci.nsIProperties)
+                   .get("ProfD", Ci.nsIFile);
+
+  sendAsyncMessage("dir.opened", {
+    dir: testFile.path
+  });
+});
--- a/dom/base/test/test_postMessages.html
+++ b/dom/base/test/test_postMessages.html
@@ -67,17 +67,17 @@ var clonableObjects = [
   { crossThreads: true, data: true },
   { crossThreads: true, data: new Date() },
   { crossThreads: true, data: [ 1, 'test', true, new Date() ] },
   { crossThreads: true, data: { a: true, b:  null, c: new Date(), d: [ true, false, {} ] } },
   { crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
   { crossThreads: true, data: new ImageData(2, 2) },
 ];
 
-function create_fileList() {
+function create_fileList_forFile() {
   var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
 
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
 
     // Just a simple test
@@ -88,16 +88,37 @@ function create_fileList() {
     script.destroy();
     next();
   }
 
   script.addMessageListener("file.opened", onOpened);
   script.sendAsyncMessage("file.open");
 }
 
+function create_fileList_forDir() {
+  var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
+  var script = SpecialPowers.loadChromeScript(url);
+
+  function onOpened(message) {
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
+
+    // Just a simple test
+    is(fileList.files.length, 1, "Filelist has 1 element");
+    ok(fileList.files[0] instanceof Directory, "We have a directory.");
+
+    clonableObjects.push({ crossThreads: false, data: fileList.files });
+    script.destroy();
+    next();
+  }
+
+  script.addMessageListener("dir.opened", onOpened);
+  script.sendAsyncMessage("dir.open");
+}
+
 function runTests(obj) {
   ok(('clonableObjects' in obj) &&
      ('transferableObjects' in obj) &&
      (obj.clonableObjects || obj.transferableObjects), "We must run some test!");
 
   // cloning tests
   new Promise(function(resolve, reject) {
     if (!obj.clonableObjects) {
@@ -508,17 +529,18 @@ function test_messagePort_inWorkers() {
         onmessage = null;
         next();
       }
     });
   }
 }
 
 var tests = [
-  create_fileList,
+  create_fileList_forFile,
+  create_fileList_forDir,
 
   test_windowToWindow,
   test_windowToIframe,
   test_windowToCrossOriginIframe,
 
   test_workers,
 
   test_broadcastChannel,
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -322,17 +322,17 @@ GetDirectoryListingTask::HandlerCallback
     return;
   }
 
   size_t count = mTargetData.Length();
 
   Sequence<OwningFileOrDirectory> listing;
 
   if (!listing.SetLength(count, mozilla::fallible_t())) {
-    mPromise->MaybeReject(NS_ERROR_FAILURE);
+    mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
     mPromise = nullptr;
     return;
   }
 
   for (unsigned i = 0; i < count; i++) {
     if (mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eDirectoryPath) {
       nsCOMPtr<nsIFile> directoryPath;
       NS_ConvertUTF16toUTF8 path(mTargetData[i].mDirectoryPath);
--- a/dom/filesystem/moz.build
+++ b/dom/filesystem/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+TEST_DIRS += ['tests']
+
 EXPORTS.mozilla.dom += [
     'DeviceStorageFileSystem.h',
     'Directory.h',
     'FileSystemBase.h',
     'FileSystemRequestParent.h',
     'FileSystemTaskBase.h',
     'FileSystemUtils.h',
     'OSFileSystem.h',
new file mode 100644
--- /dev/null
+++ b/dom/filesystem/tests/mochitest.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+support-files =
+  script_fileList.js
+
+[test_basic.html]
new file mode 100644
--- /dev/null
+++ b/dom/filesystem/tests/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += ['mochitest.ini']
new file mode 100644
--- /dev/null
+++ b/dom/filesystem/tests/script_fileList.js
@@ -0,0 +1,25 @@
+var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+Cu.importGlobalProperties(["File"]);
+
+addMessageListener("file.open", function () {
+  var testFile = Cc["@mozilla.org/file/directory_service;1"]
+                   .getService(Ci.nsIDirectoryService)
+                   .QueryInterface(Ci.nsIProperties)
+                   .get("ProfD", Ci.nsIFile);
+  testFile.append("prefs.js");
+
+  sendAsyncMessage("file.opened", {
+    file: new File(testFile)
+  });
+});
+
+addMessageListener("dir.open", function () {
+  var testFile = Cc["@mozilla.org/file/directory_service;1"]
+                   .getService(Ci.nsIDirectoryService)
+                   .QueryInterface(Ci.nsIProperties)
+                   .get("ProfD", Ci.nsIFile);
+
+  sendAsyncMessage("dir.opened", {
+    dir: testFile.path
+  });
+});
new file mode 100644
--- /dev/null
+++ b/dom/filesystem/tests/test_basic.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Directory API</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript;version=1.7">
+
+var directory;
+
+function create_fileList() {
+  var url = SimpleTest.getTestFileURL("script_fileList.js");
+  var script = SpecialPowers.loadChromeScript(url);
+
+  function onOpened(message) {
+    var fileList = document.getElementById('fileList');
+    SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
+
+    // Just a simple test
+    is(fileList.files.length, 1, "Filelist has 1 element");
+    ok(fileList.files[0] instanceof Directory, "We have a directory.");
+
+    directory = fileList.files[0];
+
+    script.destroy();
+    next();
+  }
+
+  script.addMessageListener("dir.opened", onOpened);
+  script.sendAsyncMessage("dir.open");
+}
+
+function test_basic() {
+  ok(directory, "Directory exists.");
+  ok(directory instanceof Directory, "We have a directory.");
+  is(directory.name, '/', "directory.name must be '/'");
+  is(directory.path, '/', "directory.path must be '/'");
+  next();
+}
+
+function checkSubDir(dir) {
+  dir.getFilesAndDirectories().then(
+    function(data) {
+      for (var i = 0; i < data.length; ++i) {
+        ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
+        if (data[i] instanceof Directory) {
+          isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
+          isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
+        }
+      }
+    }
+  );
+}
+
+function getFilesAndDirectories() {
+  directory.getFilesAndDirectories().then(
+    function(data) {
+      ok(data.length, "We should have some data.");
+      var promises = [];
+      for (var i = 0; i < data.length; ++i) {
+        ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
+        if (data[i] instanceof Directory) {
+          isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
+          isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
+          promises.push(checkSubDir(data[i]));
+        }
+      }
+
+      return Promise.all(promises);
+    },
+    function() {
+      ok(false, "Something when wrong");
+    }
+  ).then(next);
+}
+
+var tests = [
+  create_fileList,
+
+  test_basic,
+
+  getFilesAndDirectories,
+];
+
+function next() {
+  if (!tests.length) {
+    SimpleTest.finish();
+    return;
+  }
+
+  var test = tests.shift();
+  test();
+}
+
+SimpleTest.waitForExplicitFinish();
+next();
+</script>
+</body>
+</html>
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2279,16 +2279,44 @@ HTMLInputElement::MozSetFileNameArray(co
     names[i].Rebind(filename, nsCharTraits<char16_t>::length(filename));
   }
 
   ErrorResult rv;
   MozSetFileNameArray(list, rv);
   return rv.StealNSResult();
 }
 
+void
+HTMLInputElement::MozSetDirectory(const nsAString& aDirectoryPath,
+                                  ErrorResult& aRv)
+{
+  nsCOMPtr<nsIFile> file;
+  NS_ConvertUTF16toUTF8 path(aDirectoryPath);
+  aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
+  if (NS_WARN_IF(!window)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  RefPtr<Directory> directory = Directory::Create(window, file,
+                                                  Directory::eDOMRootDirectory);
+  MOZ_ASSERT(directory);
+
+  nsTArray<OwningFileOrDirectory> array;
+  OwningFileOrDirectory* element = array.AppendElement();
+  element->SetAsDirectory() = directory;
+
+  SetFilesOrDirectories(array, true);
+}
+
 bool
 HTMLInputElement::MozIsTextField(bool aExcludePassword)
 {
   // TODO: temporary until bug 773205 is fixed.
   if (IsExperimentalMobileType(mType)) {
     return false;
   }
 
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -719,16 +719,17 @@ public:
   nsIControllers* GetControllers(ErrorResult& aRv);
 
   int32_t GetTextLength(ErrorResult& aRv);
 
   void MozGetFileNameArray(nsTArray<nsString>& aFileNames, ErrorResult& aRv);
 
   void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv);
   void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
+  void MozSetDirectory(const nsAString& aDirectoryPath, ErrorResult& aRv);
 
   HTMLInputElement* GetOwnerNumberControl();
 
   void StartNumberControlSpinnerSpin();
   void StopNumberControlSpinnerSpin();
   void StepNumberControlForUserEvent(int32_t aDirection);
 
   /**
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -150,16 +150,20 @@ partial interface HTMLInputElement {
   sequence<DOMString> mozGetFileNameArray();
 
   [ChromeOnly, Throws]
   void mozSetFileNameArray(sequence<DOMString> fileNames);
 
   [ChromeOnly]
   void mozSetFileArray(sequence<File> files);
 
+  // This method is meant to use for testing only.
+  [ChromeOnly, Throws]
+  void mozSetDirectory(DOMString directoryPath);
+
   // Number controls (<input type=number>) have an anonymous text control
   // (<input type=text>) in the anonymous shadow tree that they contain. On
   // such an anonymous text control this property provides access to the
   // number control that owns the text control. This is useful, for example,
   // in code that looks at the currently focused element to make decisions
   // about which IME to bring up. Such code needs to be able to check for any
   // owning number control since it probably wants to bring up a number pad
   // instead of the standard keyboard, even when the anonymous text control has