|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "storage/browser/fileapi/file_system_operation_impl.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "content/browser/fileapi/mock_file_change_observer.h" | 
|  | #include "content/browser/fileapi/mock_file_update_observer.h" | 
|  | #include "content/browser/quota/mock_quota_manager.h" | 
|  | #include "content/browser/quota/mock_quota_manager_proxy.h" | 
|  | #include "content/public/test/sandbox_file_system_test_helper.h" | 
|  | #include "storage/browser/blob/shareable_file_reference.h" | 
|  | #include "storage/browser/fileapi/file_system_context.h" | 
|  | #include "storage/browser/fileapi/file_system_file_util.h" | 
|  | #include "storage/browser/fileapi/file_system_operation_context.h" | 
|  | #include "storage/browser/fileapi/file_system_operation_runner.h" | 
|  | #include "storage/browser/fileapi/sandbox_file_system_backend.h" | 
|  | #include "storage/browser/quota/quota_manager.h" | 
|  | #include "storage/browser/quota/quota_manager_proxy.h" | 
|  | #include "storage/browser/test/async_file_test_helper.h" | 
|  | #include "storage/common/fileapi/file_system_util.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | using content::AsyncFileTestHelper; | 
|  | using storage::FileSystemOperation; | 
|  | using storage::FileSystemOperationContext; | 
|  | using storage::FileSystemOperationRunner; | 
|  | using storage::FileSystemURL; | 
|  | using storage::QuotaManager; | 
|  | using storage::QuotaManagerProxy; | 
|  | using storage::ShareableFileReference; | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | // Test class for FileSystemOperationImpl. | 
|  | class FileSystemOperationImplTest | 
|  | : public testing::Test { | 
|  | public: | 
|  | FileSystemOperationImplTest() : weak_factory_(this) {} | 
|  |  | 
|  | protected: | 
|  | void SetUp() override { | 
|  | EXPECT_TRUE(base_.CreateUniqueTempDir()); | 
|  | change_observers_ = | 
|  | storage::MockFileChangeObserver::CreateList(&change_observer_); | 
|  | update_observers_ = | 
|  | storage::MockFileUpdateObserver::CreateList(&update_observer_); | 
|  |  | 
|  | base::FilePath base_dir = base_.GetPath().AppendASCII("filesystem"); | 
|  | quota_manager_ = | 
|  | new MockQuotaManager(false /* is_incognito */, base_dir, | 
|  | base::ThreadTaskRunnerHandle::Get().get(), | 
|  | base::ThreadTaskRunnerHandle::Get().get(), | 
|  | NULL /* special storage policy */); | 
|  | quota_manager_proxy_ = new MockQuotaManagerProxy( | 
|  | quota_manager(), base::ThreadTaskRunnerHandle::Get().get()); | 
|  | sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get()); | 
|  | sandbox_file_system_.AddFileChangeObserver(&change_observer_); | 
|  | sandbox_file_system_.AddFileUpdateObserver(&update_observer_); | 
|  | update_observer_.Disable(); | 
|  | } | 
|  |  | 
|  | void TearDown() override { | 
|  | // Let the client go away before dropping a ref of the quota manager proxy. | 
|  | quota_manager_proxy()->SimulateQuotaManagerDestroyed(); | 
|  | quota_manager_ = NULL; | 
|  | quota_manager_proxy_ = NULL; | 
|  | sandbox_file_system_.TearDown(); | 
|  | } | 
|  |  | 
|  | FileSystemOperationRunner* operation_runner() { | 
|  | return sandbox_file_system_.operation_runner(); | 
|  | } | 
|  |  | 
|  | const base::File::Info& info() const { return info_; } | 
|  | const base::FilePath& path() const { return path_; } | 
|  | const std::vector<storage::DirectoryEntry>& entries() const { | 
|  | return entries_; | 
|  | } | 
|  |  | 
|  | const ShareableFileReference* shareable_file_ref() const { | 
|  | return shareable_file_ref_.get(); | 
|  | } | 
|  |  | 
|  | MockQuotaManager* quota_manager() { | 
|  | return static_cast<MockQuotaManager*>(quota_manager_.get()); | 
|  | } | 
|  |  | 
|  | MockQuotaManagerProxy* quota_manager_proxy() { | 
|  | return static_cast<MockQuotaManagerProxy*>( | 
|  | quota_manager_proxy_.get()); | 
|  | } | 
|  |  | 
|  | storage::FileSystemFileUtil* file_util() { | 
|  | return sandbox_file_system_.file_util(); | 
|  | } | 
|  |  | 
|  | storage::MockFileChangeObserver* change_observer() { | 
|  | return &change_observer_; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> NewContext() { | 
|  | FileSystemOperationContext* context = | 
|  | sandbox_file_system_.NewOperationContext(); | 
|  | // Grant enough quota for all test cases. | 
|  | context->set_allowed_bytes_growth(1000000); | 
|  | return base::WrapUnique(context); | 
|  | } | 
|  |  | 
|  | FileSystemURL URLForPath(const std::string& path) const { | 
|  | return sandbox_file_system_.CreateURLFromUTF8(path); | 
|  | } | 
|  |  | 
|  | base::FilePath PlatformPath(const std::string& path) { | 
|  | return sandbox_file_system_.GetLocalPath( | 
|  | base::FilePath::FromUTF8Unsafe(path)); | 
|  | } | 
|  |  | 
|  | bool FileExists(const std::string& path) { | 
|  | return AsyncFileTestHelper::FileExists( | 
|  | sandbox_file_system_.file_system_context(), URLForPath(path), | 
|  | AsyncFileTestHelper::kDontCheckSize); | 
|  | } | 
|  |  | 
|  | bool DirectoryExists(const std::string& path) { | 
|  | return AsyncFileTestHelper::DirectoryExists( | 
|  | sandbox_file_system_.file_system_context(), URLForPath(path)); | 
|  | } | 
|  |  | 
|  | FileSystemURL CreateFile(const std::string& path) { | 
|  | FileSystemURL url = URLForPath(path); | 
|  | bool created = false; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | file_util()->EnsureFileExists(NewContext().get(), | 
|  | url, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | return url; | 
|  | } | 
|  |  | 
|  | FileSystemURL CreateDirectory(const std::string& path) { | 
|  | FileSystemURL url = URLForPath(path); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | file_util()->CreateDirectory(NewContext().get(), url, | 
|  | false /* exclusive */, true)); | 
|  | return url; | 
|  | } | 
|  |  | 
|  | int64_t GetFileSize(const std::string& path) { | 
|  | base::File::Info info; | 
|  | EXPECT_TRUE(base::GetFileInfo(PlatformPath(path), &info)); | 
|  | return info.size; | 
|  | } | 
|  |  | 
|  | // Callbacks for recording test results. | 
|  | FileSystemOperation::StatusCallback RecordStatusCallback( | 
|  | const base::Closure& closure, | 
|  | base::File::Error* status) { | 
|  | return base::Bind(&FileSystemOperationImplTest::DidFinish, | 
|  | weak_factory_.GetWeakPtr(), | 
|  | closure, | 
|  | status); | 
|  | } | 
|  |  | 
|  | FileSystemOperation::ReadDirectoryCallback RecordReadDirectoryCallback( | 
|  | const base::Closure& closure, | 
|  | base::File::Error* status) { | 
|  | return base::Bind(&FileSystemOperationImplTest::DidReadDirectory, | 
|  | weak_factory_.GetWeakPtr(), | 
|  | closure, | 
|  | status); | 
|  | } | 
|  |  | 
|  | FileSystemOperation::GetMetadataCallback RecordMetadataCallback( | 
|  | const base::Closure& closure, | 
|  | base::File::Error* status) { | 
|  | return base::Bind(&FileSystemOperationImplTest::DidGetMetadata, | 
|  | weak_factory_.GetWeakPtr(), | 
|  | closure, | 
|  | status); | 
|  | } | 
|  |  | 
|  | FileSystemOperation::SnapshotFileCallback RecordSnapshotFileCallback( | 
|  | const base::Closure& closure, | 
|  | base::File::Error* status) { | 
|  | return base::Bind(&FileSystemOperationImplTest::DidCreateSnapshotFile, | 
|  | weak_factory_.GetWeakPtr(), | 
|  | closure, | 
|  | status); | 
|  | } | 
|  |  | 
|  | void DidFinish(const base::Closure& closure, | 
|  | base::File::Error* status, | 
|  | base::File::Error actual) { | 
|  | *status = actual; | 
|  | closure.Run(); | 
|  | } | 
|  |  | 
|  | void DidReadDirectory(const base::Closure& closure, | 
|  | base::File::Error* status, | 
|  | base::File::Error actual, | 
|  | const std::vector<storage::DirectoryEntry>& entries, | 
|  | bool /* has_more */) { | 
|  | entries_ = entries; | 
|  | *status = actual; | 
|  | closure.Run(); | 
|  | } | 
|  |  | 
|  | void DidGetMetadata(const base::Closure& closure, | 
|  | base::File::Error* status, | 
|  | base::File::Error actual, | 
|  | const base::File::Info& info) { | 
|  | info_ = info; | 
|  | *status = actual; | 
|  | closure.Run(); | 
|  | } | 
|  |  | 
|  | void DidCreateSnapshotFile( | 
|  | const base::Closure& closure, | 
|  | base::File::Error* status, | 
|  | base::File::Error actual, | 
|  | const base::File::Info& info, | 
|  | const base::FilePath& platform_path, | 
|  | const scoped_refptr<ShareableFileReference>& shareable_file_ref) { | 
|  | info_ = info; | 
|  | path_ = platform_path; | 
|  | *status = actual; | 
|  | shareable_file_ref_ = shareable_file_ref; | 
|  | closure.Run(); | 
|  | } | 
|  |  | 
|  | int64_t GetDataSizeOnDisk() { | 
|  | return sandbox_file_system_.ComputeCurrentOriginUsage() - | 
|  | sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage(); | 
|  | } | 
|  |  | 
|  | void GetUsageAndQuota(int64_t* usage, int64_t* quota) { | 
|  | storage::QuotaStatusCode status = | 
|  | AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(), | 
|  | sandbox_file_system_.origin(), | 
|  | sandbox_file_system_.type(), | 
|  | usage, | 
|  | quota); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | ASSERT_EQ(storage::kQuotaStatusOk, status); | 
|  | } | 
|  |  | 
|  | int64_t ComputePathCost(const FileSystemURL& url) { | 
|  | int64_t base_usage; | 
|  | GetUsageAndQuota(&base_usage, NULL); | 
|  |  | 
|  | AsyncFileTestHelper::CreateFile( | 
|  | sandbox_file_system_.file_system_context(), url); | 
|  | EXPECT_EQ(base::File::FILE_OK, Remove(url, false /* recursive */)); | 
|  |  | 
|  | change_observer()->ResetCount(); | 
|  |  | 
|  | int64_t total_usage; | 
|  | GetUsageAndQuota(&total_usage, NULL); | 
|  | return total_usage - base_usage; | 
|  | } | 
|  |  | 
|  | void GrantQuotaForCurrentUsage() { | 
|  | int64_t usage; | 
|  | GetUsageAndQuota(&usage, NULL); | 
|  | quota_manager()->SetQuota(sandbox_file_system_.origin(), | 
|  | sandbox_file_system_.storage_type(), | 
|  | usage); | 
|  | } | 
|  |  | 
|  | int64_t GetUsage() { | 
|  | int64_t usage = 0; | 
|  | GetUsageAndQuota(&usage, NULL); | 
|  | return usage; | 
|  | } | 
|  |  | 
|  | void AddQuota(int64_t quota_delta) { | 
|  | int64_t quota; | 
|  | GetUsageAndQuota(NULL, "a); | 
|  | quota_manager()->SetQuota(sandbox_file_system_.origin(), | 
|  | sandbox_file_system_.storage_type(), | 
|  | quota + quota_delta); | 
|  | } | 
|  |  | 
|  | base::File::Error Move( | 
|  | const FileSystemURL& src, | 
|  | const FileSystemURL& dest, | 
|  | storage::FileSystemOperation::CopyOrMoveOption option) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->Move( | 
|  | src, | 
|  | dest, | 
|  | option, | 
|  | RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error Copy( | 
|  | const FileSystemURL& src, | 
|  | const FileSystemURL& dest, | 
|  | storage::FileSystemOperation::CopyOrMoveOption option) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->Copy( | 
|  | src, dest, option, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT, | 
|  | FileSystemOperationRunner::CopyProgressCallback(), | 
|  | RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error CopyInForeignFile(const base::FilePath& src, | 
|  | const FileSystemURL& dest) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->CopyInForeignFile( | 
|  | src, dest, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error Truncate(const FileSystemURL& url, int size) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->Truncate( | 
|  | url, size, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error CreateFile(const FileSystemURL& url, bool exclusive) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->CreateFile( | 
|  | url, exclusive, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error Remove(const FileSystemURL& url, bool recursive) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->Remove( | 
|  | url, recursive, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error CreateDirectory(const FileSystemURL& url, | 
|  | bool exclusive, | 
|  | bool recursive) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->CreateDirectory( | 
|  | url, | 
|  | exclusive, | 
|  | recursive, | 
|  | RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error GetMetadata(const FileSystemURL& url, int fields) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->GetMetadata( | 
|  | url, fields, RecordMetadataCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error ReadDirectory(const FileSystemURL& url) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->ReadDirectory( | 
|  | url, RecordReadDirectoryCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error CreateSnapshotFile(const FileSystemURL& url) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->CreateSnapshotFile( | 
|  | url, RecordSnapshotFileCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error FileExists(const FileSystemURL& url) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->FileExists( | 
|  | url, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error DirectoryExists(const FileSystemURL& url) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->DirectoryExists( | 
|  | url, RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | base::File::Error TouchFile(const FileSystemURL& url, | 
|  | const base::Time& last_access_time, | 
|  | const base::Time& last_modified_time) { | 
|  | base::File::Error status; | 
|  | base::RunLoop run_loop; | 
|  | update_observer_.Enable(); | 
|  | operation_runner()->TouchFile( | 
|  | url, | 
|  | last_access_time, | 
|  | last_modified_time, | 
|  | RecordStatusCallback(run_loop.QuitClosure(), &status)); | 
|  | run_loop.Run(); | 
|  | update_observer_.Disable(); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | private: | 
|  | base::MessageLoopForIO message_loop_; | 
|  | scoped_refptr<QuotaManager> quota_manager_; | 
|  | scoped_refptr<QuotaManagerProxy> quota_manager_proxy_; | 
|  |  | 
|  | // Common temp base for nondestructive uses. | 
|  | base::ScopedTempDir base_; | 
|  |  | 
|  | SandboxFileSystemTestHelper sandbox_file_system_; | 
|  |  | 
|  | // For post-operation status. | 
|  | base::File::Info info_; | 
|  | base::FilePath path_; | 
|  | std::vector<storage::DirectoryEntry> entries_; | 
|  | scoped_refptr<ShareableFileReference> shareable_file_ref_; | 
|  |  | 
|  | storage::MockFileChangeObserver change_observer_; | 
|  | storage::ChangeObserverList change_observers_; | 
|  | storage::MockFileUpdateObserver update_observer_; | 
|  | storage::UpdateObserverList update_observers_; | 
|  |  | 
|  | base::WeakPtrFactory<FileSystemOperationImplTest> weak_factory_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(FileSystemOperationImplTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDoesntExist) { | 
|  | change_observer()->ResetCount(); | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_ERROR_NOT_FOUND, | 
|  | Move(URLForPath("a"), URLForPath("b"), FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveFailureContainsPath) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("src/dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDirExistsDestFile) { | 
|  | // Src exists and is dir. Dest is a file. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  | FileSystemURL dest_file(CreateFile("dest/file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Move(src_dir, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestMoveFailureSrcFileExistsDestNonEmptyDir) { | 
|  | // Src exists and is a directory. Dest is a non-empty directory. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  | FileSystemURL dest_file(CreateFile("dest/file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, | 
|  | Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcFileExistsDestDir) { | 
|  | // Src exists and is a file. Dest is a directory. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL src_file(CreateFile("src/file")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Move(src_file, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveFailureDestParentDoesntExist) { | 
|  | // Dest. parent path does not exist. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | Move(src_dir, | 
|  | URLForPath("nonexistent/deset"), | 
|  | FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndOverwrite) { | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  | FileSystemURL dest_file(CreateFile("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Move(src_file, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(FileExists("dest")); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndNew) { | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | Move(src_file, URLForPath("new"), FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(FileExists("new")); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndOverwrite) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_FALSE(DirectoryExists("src")); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Make sure we've overwritten but not moved the source under the |dest_dir|. | 
|  | EXPECT_TRUE(DirectoryExists("dest")); | 
|  | EXPECT_FALSE(DirectoryExists("dest/src")); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndNew) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | Move(src_dir, URLForPath("dest/new"), FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_FALSE(DirectoryExists("src")); | 
|  | EXPECT_TRUE(DirectoryExists("dest/new")); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirRecursive) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | CreateDirectory("src/dir"); | 
|  | CreateFile("src/dir/sub"); | 
|  |  | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(DirectoryExists("dest/dir")); | 
|  | EXPECT_TRUE(FileExists("dest/dir/sub")); | 
|  |  | 
|  | EXPECT_EQ(3, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestMoveSuccessSamePath) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | CreateDirectory("src/dir"); | 
|  | CreateFile("src/dir/sub"); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Move(src_dir, src_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(DirectoryExists("src/dir")); | 
|  | EXPECT_TRUE(FileExists("src/dir/sub")); | 
|  |  | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_create_file_from_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDoesntExist) { | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_ERROR_NOT_FOUND, | 
|  | Copy(URLForPath("a"), URLForPath("b"), FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureContainsPath) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("src/dir")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDirExistsDestFile) { | 
|  | // Src exists and is dir. Dest is a file. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  | FileSystemURL dest_file(CreateFile("dest/file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Copy(src_dir, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestCopyFailureSrcFileExistsDestNonEmptyDir) { | 
|  | // Src exists and is a directory. Dest is a non-empty directory. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  | FileSystemURL dest_file(CreateFile("dest/file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, | 
|  | Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcFileExistsDestDir) { | 
|  | // Src exists and is a file. Dest is a directory. | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, | 
|  | Copy(src_file, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureDestParentDoesntExist) { | 
|  | // Dest. parent path does not exist. | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | Copy(src_dir, | 
|  | URLForPath("nonexistent/dest"), | 
|  | FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL src_file(CreateFile("src/file")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(src_file, 6)); | 
|  | EXPECT_EQ(6, GetFileSize("src/file")); | 
|  |  | 
|  | FileSystemURL dest_file(URLForPath("dest/file")); | 
|  | int64_t dest_path_cost = ComputePathCost(dest_file); | 
|  | GrantQuotaForCurrentUsage(); | 
|  | AddQuota(6 + dest_path_cost - 1); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_FALSE(FileExists("dest/file")); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndOverwrite) { | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  | FileSystemURL dest_file(CreateFile("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | EXPECT_TRUE(FileExists("dest")); | 
|  | EXPECT_EQ(4, quota_manager_proxy()->notify_storage_accessed_count()); | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_modify_file_count()); | 
|  |  | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndNew) { | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | Copy(src_file, URLForPath("new"), FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(FileExists("new")); | 
|  | EXPECT_EQ(4, quota_manager_proxy()->notify_storage_accessed_count()); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndOverwrite) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | // Make sure we've overwritten but not copied the source under the |dest_dir|. | 
|  | EXPECT_TRUE(DirectoryExists("dest")); | 
|  | EXPECT_FALSE(DirectoryExists("dest/src")); | 
|  | EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 3); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndNew) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | FileSystemURL dest_dir_new(URLForPath("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_dir, dest_dir_new, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_TRUE(DirectoryExists("dest")); | 
|  | EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 2); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirRecursive) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | CreateDirectory("src/dir"); | 
|  | CreateFile("src/dir/sub"); | 
|  |  | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | EXPECT_TRUE(DirectoryExists("dest/dir")); | 
|  | EXPECT_TRUE(FileExists("dest/dir/sub")); | 
|  |  | 
|  | // For recursive copy we may record multiple read access. | 
|  | EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 1); | 
|  |  | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopySuccessSamePath) { | 
|  | FileSystemURL src_dir(CreateDirectory("src")); | 
|  | CreateDirectory("src/dir"); | 
|  | CreateFile("src/dir/sub"); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_dir, src_dir, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | EXPECT_TRUE(DirectoryExists("src/dir")); | 
|  | EXPECT_TRUE(FileExists("src/dir/sub")); | 
|  |  | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_EQ(0, change_observer()->get_and_reset_create_file_from_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) { | 
|  | base::FilePath src_local_disk_file_path; | 
|  | base::CreateTemporaryFile(&src_local_disk_file_path); | 
|  | const char test_data[] = "foo"; | 
|  | int data_size = arraysize(test_data); | 
|  | base::WriteFile(src_local_disk_file_path, test_data, data_size); | 
|  |  | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | int64_t before_usage; | 
|  | GetUsageAndQuota(&before_usage, NULL); | 
|  |  | 
|  | // Check that the file copied and corresponding usage increased. | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file"))); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->create_file_count()); | 
|  | EXPECT_TRUE(FileExists("dest/file")); | 
|  | int64_t after_usage; | 
|  | GetUsageAndQuota(&after_usage, NULL); | 
|  | EXPECT_GT(after_usage, before_usage); | 
|  |  | 
|  | // Compare contents of src and copied file. | 
|  | char buffer[100]; | 
|  | EXPECT_EQ(data_size, base::ReadFile(PlatformPath("dest/file"), | 
|  | buffer, data_size)); | 
|  | for (int i = 0; i < data_size; ++i) | 
|  | EXPECT_EQ(test_data[i], buffer[i]); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileFailureByQuota) { | 
|  | base::FilePath src_local_disk_file_path; | 
|  | base::CreateTemporaryFile(&src_local_disk_file_path); | 
|  | const char test_data[] = "foo"; | 
|  | base::WriteFile(src_local_disk_file_path, test_data, arraysize(test_data)); | 
|  |  | 
|  | FileSystemURL dest_dir(CreateDirectory("dest")); | 
|  |  | 
|  | GrantQuotaForCurrentUsage(); | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_ERROR_NO_SPACE, | 
|  | CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file"))); | 
|  |  | 
|  | EXPECT_FALSE(FileExists("dest/file")); | 
|  | EXPECT_EQ(0, change_observer()->create_file_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateFileFailure) { | 
|  | // Already existing file and exclusive true. | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateFile(file, true)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileExists) { | 
|  | // Already existing file and exclusive false. | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | EXPECT_EQ(base::File::FILE_OK, CreateFile(file, false)); | 
|  | EXPECT_TRUE(FileExists("file")); | 
|  |  | 
|  | // The file was already there; did nothing. | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessExclusive) { | 
|  | // File doesn't exist but exclusive is true. | 
|  | EXPECT_EQ(base::File::FILE_OK, CreateFile(URLForPath("new"), true)); | 
|  | EXPECT_TRUE(FileExists("new")); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileDoesntExist) { | 
|  | // Non existing file. | 
|  | EXPECT_EQ(base::File::FILE_OK, CreateFile(URLForPath("nonexistent"), false)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestCreateDirFailureDestParentDoesntExist) { | 
|  | // Dest. parent path does not exist. | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | CreateDirectory(URLForPath("nonexistent/dir"), false, false)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateDirFailureDirExists) { | 
|  | // Exclusive and dir existing at path. | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateDirectory(dir, true, false)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateDirFailureFileExists) { | 
|  | // Exclusive true and file existing at path. | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateDirectory(file, true, false)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateDirSuccess) { | 
|  | // Dir exists and exclusive is false. | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  | EXPECT_EQ(base::File::FILE_OK, CreateDirectory(dir, false, false)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Dir doesn't exist. | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | CreateDirectory(URLForPath("new"), false, false)); | 
|  | EXPECT_TRUE(DirectoryExists("new")); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateDirSuccessExclusive) { | 
|  | // Dir doesn't exist. | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | CreateDirectory(URLForPath("new"), true, false)); | 
|  | EXPECT_TRUE(DirectoryExists("new")); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataFailure) { | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | GetMetadata(URLForPath("nonexistent"), | 
|  | storage::FileSystemOperation::GET_METADATA_FIELD_NONE)); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | FileExists(URLForPath("nonexistent"))); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | DirectoryExists(URLForPath("nonexistent"))); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) { | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  | FileSystemURL file(CreateFile("dir/file")); | 
|  | int read_access = 0; | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, DirectoryExists(dir)); | 
|  | ++read_access; | 
|  |  | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | GetMetadata( | 
|  | dir, storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY)); | 
|  | EXPECT_TRUE(info().is_directory); | 
|  | ++read_access; | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, FileExists(file)); | 
|  | ++read_access; | 
|  |  | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | GetMetadata( | 
|  | file, storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY)); | 
|  | EXPECT_FALSE(info().is_directory); | 
|  | ++read_access; | 
|  |  | 
|  | EXPECT_EQ(read_access, | 
|  | quota_manager_proxy()->notify_storage_accessed_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestTypeMismatchErrors) { | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE, FileExists(dir)); | 
|  |  | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, DirectoryExists(file)); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestReadDirFailure) { | 
|  | // Path doesn't exist | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ReadDirectory(URLForPath("nonexistent"))); | 
|  |  | 
|  | // File exists. | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, ReadDirectory(file)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestReadDirSuccess) { | 
|  | //      parent_dir | 
|  | //       |       | | 
|  | //  child_dir  child_file | 
|  | // Verify reading parent_dir. | 
|  | FileSystemURL parent_dir(CreateDirectory("dir")); | 
|  | FileSystemURL child_dir(CreateDirectory("dir/child_dir")); | 
|  | FileSystemURL child_file(CreateFile("dir/child_file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, ReadDirectory(parent_dir)); | 
|  | EXPECT_EQ(2u, entries().size()); | 
|  |  | 
|  | for (size_t i = 0; i < entries().size(); ++i) { | 
|  | if (entries()[i].is_directory) | 
|  | EXPECT_EQ(FILE_PATH_LITERAL("child_dir"), entries()[i].name); | 
|  | else | 
|  | EXPECT_EQ(FILE_PATH_LITERAL("child_file"), entries()[i].name); | 
|  | } | 
|  | EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestRemoveFailure) { | 
|  | // Path doesn't exist. | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | Remove(URLForPath("nonexistent"), false /* recursive */)); | 
|  |  | 
|  | // It's an error to try to remove a non-empty directory if recursive flag | 
|  | // is false. | 
|  | //      parent_dir | 
|  | //       |       | | 
|  | //  child_dir  child_file | 
|  | // Verify deleting parent_dir. | 
|  | FileSystemURL parent_dir(CreateDirectory("dir")); | 
|  | FileSystemURL child_dir(CreateDirectory("dir/child_dir")); | 
|  | FileSystemURL child_file(CreateFile("dir/child_file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, | 
|  | Remove(parent_dir, false /* recursive */)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestRemoveSuccess) { | 
|  | FileSystemURL empty_dir(CreateDirectory("empty_dir")); | 
|  | EXPECT_TRUE(DirectoryExists("empty_dir")); | 
|  | EXPECT_EQ(base::File::FILE_OK, Remove(empty_dir, false /* recursive */)); | 
|  | EXPECT_FALSE(DirectoryExists("empty_dir")); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestRemoveSuccessRecursive) { | 
|  | // Removing a non-empty directory with recursive flag == true should be ok. | 
|  | //      parent_dir | 
|  | //       |       | | 
|  | //  child_dir  child_files | 
|  | //       | | 
|  | //  child_files | 
|  | // | 
|  | // Verify deleting parent_dir. | 
|  | FileSystemURL parent_dir(CreateDirectory("dir")); | 
|  | for (int i = 0; i < 8; ++i) | 
|  | CreateFile(base::StringPrintf("dir/file-%d", i)); | 
|  | FileSystemURL child_dir(CreateDirectory("dir/child_dir")); | 
|  | for (int i = 0; i < 8; ++i) | 
|  | CreateFile(base::StringPrintf("dir/child_dir/file-%d", i)); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, Remove(parent_dir, true /* recursive */)); | 
|  | EXPECT_FALSE(DirectoryExists("parent_dir")); | 
|  |  | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(16, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestTruncate) { | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | base::FilePath platform_path = PlatformPath("file"); | 
|  |  | 
|  | char test_data[] = "test data"; | 
|  | int data_size = static_cast<int>(sizeof(test_data)); | 
|  | EXPECT_EQ(data_size, | 
|  | base::WriteFile(platform_path, test_data, data_size)); | 
|  |  | 
|  | // Check that its length is the size of the data written. | 
|  | EXPECT_EQ( | 
|  | base::File::FILE_OK, | 
|  | GetMetadata( | 
|  | file, storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY | | 
|  | storage::FileSystemOperation::GET_METADATA_FIELD_SIZE)); | 
|  | EXPECT_FALSE(info().is_directory); | 
|  | EXPECT_EQ(data_size, info().size); | 
|  |  | 
|  | // Extend the file by truncating it. | 
|  | int length = 17; | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(file, length)); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Check that its length is now 17 and that it's all zeroes after the test | 
|  | // data. | 
|  | EXPECT_EQ(length, GetFileSize("file")); | 
|  | char data[100]; | 
|  | EXPECT_EQ(length, base::ReadFile(platform_path, data, length)); | 
|  | for (int i = 0; i < length; ++i) { | 
|  | if (i < static_cast<int>(sizeof(test_data))) | 
|  | EXPECT_EQ(test_data[i], data[i]); | 
|  | else | 
|  | EXPECT_EQ(0, data[i]); | 
|  | } | 
|  |  | 
|  | // Shorten the file by truncating it. | 
|  | length = 3; | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(file, length)); | 
|  |  | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Check that its length is now 3 and that it contains only bits of test data. | 
|  | EXPECT_EQ(length, GetFileSize("file")); | 
|  | EXPECT_EQ(length, base::ReadFile(platform_path, data, length)); | 
|  | for (int i = 0; i < length; ++i) | 
|  | EXPECT_EQ(test_data[i], data[i]); | 
|  |  | 
|  | // Truncate is not a 'read' access.  (Here expected access count is 1 | 
|  | // since we made 1 read access for GetMetadata.) | 
|  | EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestTruncateFailureByQuota) { | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  | FileSystemURL file(CreateFile("dir/file")); | 
|  |  | 
|  | GrantQuotaForCurrentUsage(); | 
|  | AddQuota(10); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(file, 10)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | EXPECT_EQ(10, GetFileSize("dir/file")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, Truncate(file, 11)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | EXPECT_EQ(10, GetFileSize("dir/file")); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestTouchFile) { | 
|  | FileSystemURL file(CreateFile("file")); | 
|  | base::FilePath platform_path = PlatformPath("file"); | 
|  |  | 
|  | base::File::Info info; | 
|  | EXPECT_TRUE(base::GetFileInfo(platform_path, &info)); | 
|  | EXPECT_FALSE(info.is_directory); | 
|  | EXPECT_EQ(0, info.size); | 
|  | const base::Time last_modified = info.last_modified; | 
|  | const base::Time last_accessed = info.last_accessed; | 
|  |  | 
|  | const base::Time new_modified_time = base::Time::UnixEpoch(); | 
|  | const base::Time new_accessed_time = new_modified_time + | 
|  | base::TimeDelta::FromHours(77); | 
|  | ASSERT_NE(last_modified, new_modified_time); | 
|  | ASSERT_NE(last_accessed, new_accessed_time); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | TouchFile(file, new_accessed_time, new_modified_time)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | EXPECT_TRUE(base::GetFileInfo(platform_path, &info)); | 
|  | // We compare as time_t here to lower our resolution, to avoid false | 
|  | // negatives caused by conversion to the local filesystem's native | 
|  | // representation and back. | 
|  | EXPECT_EQ(new_modified_time.ToTimeT(), info.last_modified.ToTimeT()); | 
|  | EXPECT_EQ(new_accessed_time.ToTimeT(), info.last_accessed.ToTimeT()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, TestCreateSnapshotFile) { | 
|  | FileSystemURL dir(CreateDirectory("dir")); | 
|  |  | 
|  | // Create a file for the testing. | 
|  | EXPECT_EQ(base::File::FILE_OK, DirectoryExists(dir)); | 
|  | FileSystemURL file(CreateFile("dir/file")); | 
|  | EXPECT_EQ(base::File::FILE_OK, FileExists(file)); | 
|  |  | 
|  | // See if we can get a 'snapshot' file info for the file. | 
|  | // Since FileSystemOperationImpl assumes the file exists in the local | 
|  | // directory it should just returns the same metadata and platform_path | 
|  | // as the file itself. | 
|  | EXPECT_EQ(base::File::FILE_OK, CreateSnapshotFile(file)); | 
|  | EXPECT_FALSE(info().is_directory); | 
|  | EXPECT_EQ(PlatformPath("dir/file"), path()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // The FileSystemOpration implementation does not create a | 
|  | // shareable file reference. | 
|  | EXPECT_EQ(NULL, shareable_file_ref()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestMoveSuccessSrcDirRecursiveWithQuota) { | 
|  | FileSystemURL src(CreateDirectory("src")); | 
|  | int src_path_cost = GetUsage(); | 
|  |  | 
|  | FileSystemURL dest(CreateDirectory("dest")); | 
|  | FileSystemURL child_file1(CreateFile("src/file1")); | 
|  | FileSystemURL child_file2(CreateFile("src/file2")); | 
|  | FileSystemURL child_dir(CreateDirectory("src/dir")); | 
|  | FileSystemURL grandchild_file1(CreateFile("src/dir/file1")); | 
|  | FileSystemURL grandchild_file2(CreateFile("src/dir/file2")); | 
|  |  | 
|  | int total_path_cost = GetUsage(); | 
|  | EXPECT_EQ(0, GetDataSizeOnDisk()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(child_file1, 5000)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(child_file2, 400)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file1, 30)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file2, 2)); | 
|  |  | 
|  | const int64_t all_file_size = 5000 + 400 + 30 + 2; | 
|  | EXPECT_EQ(all_file_size, GetDataSizeOnDisk()); | 
|  | EXPECT_EQ(all_file_size + total_path_cost, GetUsage()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Move(src, dest, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | EXPECT_FALSE(DirectoryExists("src/dir")); | 
|  | EXPECT_FALSE(FileExists("src/dir/file2")); | 
|  | EXPECT_TRUE(DirectoryExists("dest/dir")); | 
|  | EXPECT_TRUE(FileExists("dest/dir/file2")); | 
|  |  | 
|  | EXPECT_EQ(all_file_size, GetDataSizeOnDisk()); | 
|  | EXPECT_EQ(all_file_size + total_path_cost - src_path_cost, | 
|  | GetUsage()); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestCopySuccessSrcDirRecursiveWithQuota) { | 
|  | FileSystemURL src(CreateDirectory("src")); | 
|  | FileSystemURL dest1(CreateDirectory("dest1")); | 
|  | FileSystemURL dest2(CreateDirectory("dest2")); | 
|  |  | 
|  | int64_t usage = GetUsage(); | 
|  | FileSystemURL child_file1(CreateFile("src/file1")); | 
|  | FileSystemURL child_file2(CreateFile("src/file2")); | 
|  | FileSystemURL child_dir(CreateDirectory("src/dir")); | 
|  | int64_t child_path_cost = GetUsage() - usage; | 
|  | usage += child_path_cost; | 
|  |  | 
|  | FileSystemURL grandchild_file1(CreateFile("src/dir/file1")); | 
|  | FileSystemURL grandchild_file2(CreateFile("src/dir/file2")); | 
|  | int64_t total_path_cost = GetUsage(); | 
|  | int64_t grandchild_path_cost = total_path_cost - usage; | 
|  |  | 
|  | EXPECT_EQ(0, GetDataSizeOnDisk()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(child_file1, 8000)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(child_file2, 700)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file1, 60)); | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file2, 5)); | 
|  |  | 
|  | const int64_t child_file_size = 8000 + 700; | 
|  | const int64_t grandchild_file_size = 60 + 5; | 
|  | const int64_t all_file_size = child_file_size + grandchild_file_size; | 
|  | int64_t expected_usage = all_file_size + total_path_cost; | 
|  |  | 
|  | usage = GetUsage(); | 
|  | EXPECT_EQ(all_file_size, GetDataSizeOnDisk()); | 
|  | EXPECT_EQ(expected_usage, usage); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src, dest1, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | expected_usage += all_file_size + child_path_cost + grandchild_path_cost; | 
|  | EXPECT_TRUE(DirectoryExists("src/dir")); | 
|  | EXPECT_TRUE(FileExists("src/dir/file2")); | 
|  | EXPECT_TRUE(DirectoryExists("dest1/dir")); | 
|  | EXPECT_TRUE(FileExists("dest1/dir/file2")); | 
|  |  | 
|  | EXPECT_EQ(2 * all_file_size, GetDataSizeOnDisk()); | 
|  | EXPECT_EQ(expected_usage, GetUsage()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(child_dir, dest2, FileSystemOperation::OPTION_NONE)); | 
|  |  | 
|  | expected_usage += grandchild_file_size + grandchild_path_cost; | 
|  | usage = GetUsage(); | 
|  | EXPECT_EQ(2 * child_file_size + 3 * grandchild_file_size, | 
|  | GetDataSizeOnDisk()); | 
|  | EXPECT_EQ(expected_usage, usage); | 
|  | } | 
|  |  | 
|  | TEST_F(FileSystemOperationImplTest, | 
|  | TestCopySuccessSrcFileWithDifferentFileSize) { | 
|  | FileSystemURL src_file(CreateFile("src")); | 
|  | FileSystemURL dest_file(CreateFile("dest")); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, Truncate(dest_file, 6)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE)); | 
|  | EXPECT_EQ(0, GetFileSize("dest")); | 
|  | } | 
|  |  | 
|  | }  // namespace content |