Bug 1284987 - Entries API - part 3 - FileSystemEntry.getParent recursion, r=smaug

This commit is contained in:
Andrea Marchesini 2016-11-03 07:55:51 +01:00
parent 3a9551a834
commit d7a6ec8806
4 changed files with 89 additions and 20 deletions

View File

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CallbackRunnables.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/File.h"
@ -75,17 +76,23 @@ EmptyEntriesCallbackRunnable::Run()
}
GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
Directory* aDirectory,
nsTArray<nsString>& aParts,
FileSystem* aFileSystem,
FileSystemEntryCallback* aSuccessCallback,
ErrorCallback* aErrorCallback,
FileSystemDirectoryEntry::GetInternalType aType)
: mParentEntry(aParentEntry)
, mDirectory(aDirectory)
, mParts(aParts)
, mFileSystem(aFileSystem)
, mSuccessCallback(aSuccessCallback)
, mErrorCallback(aErrorCallback)
, mType(aType)
{
MOZ_ASSERT(aParentEntry);
MOZ_ASSERT(aDirectory);
MOZ_ASSERT(!aParts.IsEmpty());
MOZ_ASSERT(aFileSystem);
MOZ_ASSERT(aSuccessCallback || aErrorCallback);
}
@ -93,6 +100,23 @@ GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
GetEntryHelper::~GetEntryHelper()
{}
void
GetEntryHelper::Run()
{
MOZ_ASSERT(!mParts.IsEmpty());
ErrorResult rv;
RefPtr<Promise> promise = mDirectory->Get(mParts[0], rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
Error(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mParts.RemoveElementAt(0);
promise->AppendNativeHandler(this);
}
void
GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
@ -102,9 +126,23 @@ GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
// This is not the last part of the path.
if (!mParts.IsEmpty()) {
ContinueRunning(obj);
return;
}
CompleteOperation(obj);
}
void
GetEntryHelper::CompleteOperation(JSObject* aObj)
{
MOZ_ASSERT(mParts.IsEmpty());
if (mType == FileSystemDirectoryEntry::eGetFile) {
RefPtr<File> file;
if (NS_FAILED(UNWRAP_OBJECT(File, obj, file))) {
if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) {
Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
return;
}
@ -119,7 +157,7 @@ GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory);
RefPtr<Directory> directory;
if (NS_FAILED(UNWRAP_OBJECT(Directory, obj, directory))) {
if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
return;
}
@ -130,6 +168,28 @@ GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
mSuccessCallback->HandleEvent(*entry);
}
void
GetEntryHelper::ContinueRunning(JSObject* aObj)
{
MOZ_ASSERT(!mParts.IsEmpty());
RefPtr<Directory> directory;
if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
return;
}
RefPtr<FileSystemDirectoryEntry> entry =
new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
mParentEntry, mFileSystem);
// Update the internal values.
mParentEntry = entry;
mDirectory = directory;
Run();
}
void
GetEntryHelper::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{

View File

@ -66,11 +66,16 @@ public:
NS_DECL_ISUPPORTS
GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
Directory* aDirectory,
nsTArray<nsString>& aParts,
FileSystem* aFileSystem,
FileSystemEntryCallback* aSuccessCallback,
ErrorCallback* aErrorCallback,
FileSystemDirectoryEntry::GetInternalType aType);
void
Run();
virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
@ -83,10 +88,20 @@ private:
void
Error(nsresult aError);
void
ContinueRunning(JSObject* aObj);
void
CompleteOperation(JSObject* aObj);
RefPtr<FileSystemDirectoryEntry> mParentEntry;
RefPtr<Directory> mDirectory;
nsTArray<nsString> mParts;
RefPtr<FileSystem> mFileSystem;
RefPtr<FileSystemEntryCallback> mSuccessCallback;
RefPtr<ErrorCallback> mErrorCallback;
FileSystemDirectoryEntry::GetInternalType mType;
};

View File

@ -93,22 +93,14 @@ FileSystemDirectoryEntry::GetInternal(const nsAString& aPath,
return;
}
ErrorResult error;
RefPtr<Promise> promise = mDirectory->Get(aPath, error);
if (NS_WARN_IF(error.Failed())) {
ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
error.StealNSResult());
return;
}
RefPtr<GetEntryHelper> handler =
new GetEntryHelper(this, Filesystem(),
RefPtr<GetEntryHelper> helper =
new GetEntryHelper(this, mDirectory, parts, Filesystem(),
aSuccessCallback.WasPassed()
? &aSuccessCallback.Value() : nullptr,
aErrorCallback.WasPassed()
? &aErrorCallback.Value() : nullptr,
aType);
promise->AppendNativeHandler(handler);
helper->Run();
}
void

View File

@ -177,7 +177,7 @@ function test_directoryEntry_getFile_simple() {
directoryEntry.getFile("foo.txt", {},
function(e) {
is(e.name, "foo.txt", "We have the right FileEntry.");
test_getParent(e, directoryEntry);
test_getParent(e, directoryEntry, /* nested */ false);
}, function(e) {
ok(false, "This should not happen.");
});
@ -187,7 +187,7 @@ function test_directoryEntry_getFile_deep() {
directoryEntry.getFile("subdir/bar.txt", {},
function(e) {
is(e.name, "bar.txt", "We have the right FileEntry.");
test_getParent(e, null);
test_getParent(e, directoryEntry, /* nested */ true);
}, function(e) {
ok(false, "This should not happen.");
});
@ -237,7 +237,7 @@ function test_directoryEntry_getDirectory_simple() {
directoryEntry.getDirectory("subdir", {},
function(e) {
is(e.name, "subdir", "We have the right DirectoryEntry.");
test_getParent(e, directoryEntry);
test_getParent(e, directoryEntry, /* nested */ false);
}, function(e) {
ok(false, "This should not happen.");
});
@ -247,7 +247,7 @@ function test_directoryEntry_getDirectory_deep() {
directoryEntry.getDirectory("subdir/subsubdir", {},
function(e) {
is(e.name, "subsubdir", "We have the right DirectoryEntry.");
test_getParent(e, directoryEntry);
test_getParent(e, directoryEntry, /* nested */ true);
}, function(e) {
ok(false, "This should not happen.");
});
@ -403,13 +403,15 @@ function cleanUpTestingFiles() {
script.sendAsyncMessage("entries.delete");
}
function test_getParent(entry, parentEntry) {
function test_getParent(entry, parentEntry, nested) {
entry.getParent(function(e) {
ok(e, "We have a parent Entry.");
if (parentEntry) {
if (!nested) {
is (e, parentEntry, "Parent entry matches");
next();
} else {
test_getParent(e, parentEntry, false);
}
next();
}, function(e) {
ok(false, "This should not happen.");
});