summaryrefslogtreecommitdiffstats
path: root/webkit/fileapi/obfuscated_file_util_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/fileapi/obfuscated_file_util_unittest.cc')
-rw-r--r--webkit/fileapi/obfuscated_file_util_unittest.cc1445
1 files changed, 1445 insertions, 0 deletions
diff --git a/webkit/fileapi/obfuscated_file_util_unittest.cc b/webkit/fileapi/obfuscated_file_util_unittest.cc
new file mode 100644
index 0000000..ec40c67
--- /dev/null
+++ b/webkit/fileapi/obfuscated_file_util_unittest.cc
@@ -0,0 +1,1445 @@
+// Copyright (c) 2011 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 <algorithm>
+#include <set>
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_callback_factory.h"
+#include "base/message_loop.h"
+#include "base/platform_file.h"
+#include "base/scoped_temp_dir.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_path_manager.h"
+#include "webkit/fileapi/file_system_test_helper.h"
+#include "webkit/fileapi/file_system_usage_cache.h"
+#include "webkit/fileapi/obfuscated_file_util.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+#include "webkit/quota/quota_manager.h"
+#include "webkit/quota/quota_types.h"
+
+using namespace fileapi;
+
+namespace {
+
+FilePath UTF8ToFilePath(const std::string& str) {
+ FilePath::StringType result;
+#if defined(OS_POSIX)
+ result = str;
+#elif defined(OS_WIN)
+ result = base::SysUTF8ToWide(str);
+#endif
+ return FilePath(result);
+}
+
+bool FileExists(const FilePath& path) {
+ return file_util::PathExists(path) && !file_util::DirectoryExists(path);
+}
+
+int64 GetSize(const FilePath& path) {
+ int64 size;
+ EXPECT_TRUE(file_util::GetFileSize(path, &size));
+ return size;
+}
+
+// After a move, the dest exists and the source doesn't.
+// After a copy, both source and dest exist.
+struct CopyMoveTestCaseRecord {
+ bool is_copy_not_move;
+ const char source_path[64];
+ const char dest_path[64];
+ bool cause_overwrite;
+};
+
+const CopyMoveTestCaseRecord kCopyMoveTestCases[] = {
+ // This is the combinatoric set of:
+ // rename vs. same-name
+ // different directory vs. same directory
+ // overwrite vs. no-overwrite
+ // copy vs. move
+ // We can never be called with source and destination paths identical, so
+ // those cases are omitted.
+ {true, "dir0/file0", "dir0/file1", false},
+ {false, "dir0/file0", "dir0/file1", false},
+ {true, "dir0/file0", "dir0/file1", true},
+ {false, "dir0/file0", "dir0/file1", true},
+
+ {true, "dir0/file0", "dir1/file0", false},
+ {false, "dir0/file0", "dir1/file0", false},
+ {true, "dir0/file0", "dir1/file0", true},
+ {false, "dir0/file0", "dir1/file0", true},
+ {true, "dir0/file0", "dir1/file1", false},
+ {false, "dir0/file0", "dir1/file1", false},
+ {true, "dir0/file0", "dir1/file1", true},
+ {false, "dir0/file0", "dir1/file1", true},
+};
+
+struct MigrationTestCaseRecord {
+ bool is_directory;
+ const FilePath::CharType path[64];
+ int64 data_file_size;
+};
+
+const MigrationTestCaseRecord kMigrationTestCases[] = {
+ {true, FILE_PATH_LITERAL("dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir f"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g"), 0},
+ {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir h"), 0},
+ {true, FILE_PATH_LITERAL("dir b"), 0},
+ {true, FILE_PATH_LITERAL("dir b/dir a"), 0},
+ {true, FILE_PATH_LITERAL("dir c"), 0},
+ {false, FILE_PATH_LITERAL("file 0"), 38},
+ {false, FILE_PATH_LITERAL("file 2"), 60},
+ {false, FILE_PATH_LITERAL("file 3"), 0},
+ {false, FILE_PATH_LITERAL("dir a/file 0"), 39},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 0"), 40},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 1"), 41},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 2"), 42},
+ {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 3"), 50},
+};
+
+struct OriginEnumerationTestRecord {
+ std::string origin_url;
+ bool has_temporary;
+ bool has_persistent;
+};
+
+const OriginEnumerationTestRecord kOriginEnumerationTestRecords[] = {
+ {"http://example.com", false, true},
+ {"http://example1.com", true, false},
+ {"https://example1.com", true, true},
+ {"file://", false, true},
+ {"http://example.com:8000", false, true},
+};
+
+} // namespace (anonymous)
+
+// TODO(ericu): The vast majority of this and the other FSFU subclass tests
+// could theoretically be shared. It would basically be a FSFU interface
+// compliance test, and only the subclass-specific bits that look into the
+// implementation would need to be written per-subclass.
+class ObfuscatedFileUtilTest : public testing::Test {
+ public:
+ ObfuscatedFileUtilTest()
+ : origin_(GURL("http://www.example.com")),
+ type_(kFileSystemTypeTemporary),
+ callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ test_helper_(origin_, type_),
+ quota_status_(quota::kQuotaStatusUnknown),
+ usage_(-1) {
+ }
+
+ void SetUp() {
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+
+ quota_manager_ = new quota::QuotaManager(
+ false /* is_incognito */,
+ data_dir_.path(),
+ base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current(),
+ NULL /* special storage policy */);
+
+ // Every time we create a new helper, it creates another context, which
+ // creates another path manager, another sandbox_mount_point_provider, and
+ // another OFU. We need to pass in the context to skip all that.
+ file_system_context_ = new FileSystemContext(
+ base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current(),
+ new quota::MockSpecialStoragePolicy(),
+ quota_manager_->proxy(),
+ data_dir_.path(),
+ false /* incognito */,
+ true /* allow_file_access_from_files */,
+ false /* unlimited_quota */,
+ NULL /* path_manager */);
+
+ obfuscated_file_util_ = static_cast<ObfuscatedFileUtil*>(
+ file_system_context_->path_manager()->GetFileUtil(type_));
+
+ test_helper_.SetUp(file_system_context_.get(),
+ obfuscated_file_util_.get());
+ }
+
+ FileSystemOperationContext* NewContext(FileSystemTestOriginHelper* helper) {
+ FileSystemOperationContext* context;
+ if (helper)
+ context = helper->NewOperationContext();
+ else
+ context = test_helper_.NewOperationContext();
+ context->set_allowed_bytes_growth(1024 * 1024); // Big enough for all tests.
+ return context;
+ }
+
+ // This can only be used after SetUp has run and created file_system_context_
+ // and obfuscated_file_util_.
+ // Use this for tests which need to run in multiple origins; we need a test
+ // helper per origin.
+ FileSystemTestOriginHelper* NewHelper(
+ const GURL& origin, fileapi::FileSystemType type) {
+ FileSystemTestOriginHelper* helper =
+ new FileSystemTestOriginHelper(origin, type);
+
+ helper->SetUp(file_system_context_.get(),
+ obfuscated_file_util_.get());
+ return helper;
+ }
+
+ ObfuscatedFileUtil* ofu() {
+ return obfuscated_file_util_.get();
+ }
+
+ const FilePath& test_directory() const {
+ return data_dir_.path();
+ }
+
+ const GURL& origin() const {
+ return origin_;
+ }
+
+ fileapi::FileSystemType type() const {
+ return type_;
+ }
+
+ void GetUsageFromQuotaManager() {
+ quota_manager_->GetUsageAndQuota(
+ origin(), test_helper_.storage_type(),
+ callback_factory_.NewCallback(
+ &ObfuscatedFileUtilTest::OnGetUsage));
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(quota::kQuotaStatusOk, quota_status_);
+ }
+
+ void RevokeUsageCache() {
+ quota_manager_->ResetUsageTracker(test_helper_.storage_type());
+ ASSERT_TRUE(test_helper_.RevokeUsageCache());
+ }
+
+ int64 SizeInUsageFile() {
+ return test_helper_.GetCachedOriginUsage();
+ }
+
+ int64 usage() const { return usage_; }
+
+ void OnGetUsage(quota::QuotaStatusCode status, int64 usage, int64 unused) {
+ EXPECT_EQ(quota::kQuotaStatusOk, status);
+ quota_status_ = status;
+ usage_ = usage;
+ }
+
+ void CheckFileAndCloseHandle(
+ const FilePath& virtual_path, PlatformFile file_handle) {
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetLocalFilePath(
+ context.get(), virtual_path, &local_path));
+
+ base::PlatformFileInfo file_info0;
+ FilePath data_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), virtual_path, &file_info0, &data_path));
+ EXPECT_EQ(data_path, local_path);
+ EXPECT_TRUE(FileExists(data_path));
+ EXPECT_EQ(0, GetSize(data_path));
+
+ const char data[] = "test data";
+ const int length = arraysize(data) - 1;
+
+ if (base::kInvalidPlatformFileValue == file_handle) {
+ bool created = true;
+ PlatformFileError error;
+ file_handle = base::CreatePlatformFile(
+ data_path,
+ base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
+ &created,
+ &error);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error);
+ EXPECT_FALSE(created);
+ }
+ ASSERT_EQ(length, base::WritePlatformFile(file_handle, 0, data, length));
+ EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+
+ base::PlatformFileInfo file_info1;
+ EXPECT_EQ(length, GetSize(data_path));
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), virtual_path, &file_info1, &data_path));
+ EXPECT_EQ(data_path, local_path);
+
+ EXPECT_FALSE(file_info0.is_directory);
+ EXPECT_FALSE(file_info1.is_directory);
+ EXPECT_FALSE(file_info0.is_symbolic_link);
+ EXPECT_FALSE(file_info1.is_symbolic_link);
+ EXPECT_EQ(0, file_info0.size);
+ EXPECT_EQ(length, file_info1.size);
+ EXPECT_LE(file_info0.last_modified, file_info1.last_modified);
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
+ context.get(), virtual_path, length * 2));
+ EXPECT_EQ(length * 2, GetSize(data_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
+ context.get(), virtual_path, 0));
+ EXPECT_EQ(0, GetSize(data_path));
+ }
+
+ void ValidateTestDirectory(
+ const FilePath& root_path,
+ const std::set<FilePath::StringType>& files,
+ const std::set<FilePath::StringType>& directories) {
+ scoped_ptr<FileSystemOperationContext> context;
+ std::set<FilePath::StringType>::const_iterator iter;
+ for (iter = files.begin(); iter != files.end(); ++iter) {
+ bool created = true;
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(
+ context.get(), root_path.Append(*iter),
+ &created));
+ ASSERT_FALSE(created);
+ }
+ for (iter = directories.begin(); iter != directories.end(); ++iter) {
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(),
+ root_path.Append(*iter)));
+ }
+ }
+
+ void FillTestDirectory(
+ const FilePath& root_path,
+ std::set<FilePath::StringType>* files,
+ std::set<FilePath::StringType>* directories) {
+ scoped_ptr<FileSystemOperationContext> context;
+ context.reset(NewContext(NULL));
+ std::vector<base::FileUtilProxy::Entry> entries;
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->ReadDirectory(context.get(), root_path, &entries));
+ EXPECT_EQ(0UL, entries.size());
+
+ files->clear();
+ files->insert(FILE_PATH_LITERAL("first"));
+ files->insert(FILE_PATH_LITERAL("second"));
+ files->insert(FILE_PATH_LITERAL("third"));
+ directories->clear();
+ directories->insert(FILE_PATH_LITERAL("fourth"));
+ directories->insert(FILE_PATH_LITERAL("fifth"));
+ directories->insert(FILE_PATH_LITERAL("sixth"));
+ std::set<FilePath::StringType>::iterator iter;
+ for (iter = files->begin(); iter != files->end(); ++iter) {
+ bool created = false;
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(
+ context.get(), root_path.Append(*iter), &created));
+ ASSERT_TRUE(created);
+ }
+ for (iter = directories->begin(); iter != directories->end(); ++iter) {
+ bool exclusive = true;
+ bool recursive = false;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CreateDirectory(
+ context.get(), root_path.Append(*iter), exclusive, recursive));
+ }
+ ValidateTestDirectory(root_path, *files, *directories);
+ }
+
+ void TestReadDirectoryHelper(const FilePath& root_path) {
+ std::set<FilePath::StringType> files;
+ std::set<FilePath::StringType> directories;
+ FillTestDirectory(root_path, &files, &directories);
+
+ scoped_ptr<FileSystemOperationContext> context;
+ std::vector<base::FileUtilProxy::Entry> entries;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->ReadDirectory(context.get(), root_path, &entries));
+ std::vector<base::FileUtilProxy::Entry>::iterator entry_iter;
+ EXPECT_EQ(files.size() + directories.size(), entries.size());
+ for (entry_iter = entries.begin(); entry_iter != entries.end();
+ ++entry_iter) {
+ const base::FileUtilProxy::Entry& entry = *entry_iter;
+ std::set<FilePath::StringType>::iterator iter = files.find(entry.name);
+ if (iter != files.end()) {
+ EXPECT_FALSE(entry.is_directory);
+ files.erase(iter);
+ continue;
+ }
+ iter = directories.find(entry.name);
+ EXPECT_FALSE(directories.end() == iter);
+ EXPECT_TRUE(entry.is_directory);
+ directories.erase(iter);
+ }
+ }
+
+ void TestTouchHelper(const FilePath& path, bool is_file) {
+ base::Time last_access_time = base::Time::Now();
+ base::Time last_modified_time = base::Time::Now();
+
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Touch(
+ context.get(), path, last_access_time, last_modified_time));
+ FilePath local_path;
+ base::PlatformFileInfo file_info;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), path, &file_info, &local_path));
+ // 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(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
+
+ context.reset(NewContext(NULL));
+ last_modified_time += base::TimeDelta::FromHours(1);
+ last_access_time += base::TimeDelta::FromHours(14);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Touch(
+ context.get(), path, last_access_time, last_modified_time));
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), path, &file_info, &local_path));
+ EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
+ if (is_file) // Directories in OFU don't support atime.
+ EXPECT_EQ(file_info.last_accessed.ToTimeT(), last_access_time.ToTimeT());
+ }
+
+ void TestCopyInForeignFileHelper(bool overwrite) {
+ ScopedTempDir source_dir;
+ ASSERT_TRUE(source_dir.CreateUniqueTempDir());
+ FilePath root_path = source_dir.path();
+ FilePath src_path = root_path.AppendASCII("file_name");
+ FilePath dest_path(FILE_PATH_LITERAL("new file"));
+ int64 src_file_length = 87;
+
+ base::PlatformFileError error_code;
+ bool created = false;
+ int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE;
+ base::PlatformFile file_handle =
+ base::CreatePlatformFile(
+ src_path, file_flags, &created, &error_code);
+ EXPECT_TRUE(created);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error_code);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
+ ASSERT_TRUE(base::TruncatePlatformFile(file_handle, src_file_length));
+ EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+
+ scoped_ptr<FileSystemOperationContext> context;
+
+ if (overwrite) {
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), dest_path, &created));
+ EXPECT_TRUE(created);
+ }
+
+ const int64 path_cost =
+ ObfuscatedFileUtil::ComputeFilePathCost(dest_path);
+ if (!overwrite) {
+ // Verify that file creation requires sufficient quota for the path.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(path_cost + src_file_length - 1);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->CopyInForeignFile(context.get(), src_path, dest_path));
+ }
+
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(path_cost + src_file_length);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyInForeignFile(context.get(), src_path, dest_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), dest_path));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), dest_path));
+ context.reset(NewContext(NULL));
+ base::PlatformFileInfo file_info;
+ FilePath data_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), dest_path, &file_info, &data_path));
+ EXPECT_NE(data_path, src_path);
+ EXPECT_TRUE(FileExists(data_path));
+ EXPECT_EQ(src_file_length, GetSize(data_path));
+
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteFile(context.get(), dest_path));
+ }
+
+ private:
+ ScopedTempDir data_dir_;
+ scoped_refptr<ObfuscatedFileUtil> obfuscated_file_util_;
+ scoped_refptr<quota::QuotaManager> quota_manager_;
+ scoped_refptr<FileSystemContext> file_system_context_;
+ GURL origin_;
+ fileapi::FileSystemType type_;
+ base::ScopedCallbackFactory<ObfuscatedFileUtilTest>
+ callback_factory_;
+ FileSystemTestOriginHelper test_helper_;
+ quota::QuotaStatusCode quota_status_;
+ int64 usage_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
+};
+
+TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
+ base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
+ bool created;
+ FilePath path = UTF8ToFilePath("fake/file");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE;
+
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->CreateOrOpen(
+ context.get(), path, file_flags, &file_handle,
+ &created));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->DeleteFile(context.get(), path));
+
+ path = UTF8ToFilePath("test file");
+
+ // Verify that file creation requires sufficient quota for the path.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path) - 1);
+ ASSERT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->CreateOrOpen(
+ context.get(), path, file_flags, &file_handle, &created));
+
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CreateOrOpen(
+ context.get(), path, file_flags, &file_handle, &created));
+ ASSERT_TRUE(created);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file_handle);
+
+ CheckFileAndCloseHandle(path, file_handle);
+
+ context.reset(NewContext(NULL));
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetLocalFilePath(
+ context.get(), path, &local_path));
+ EXPECT_TRUE(file_util::PathExists(local_path));
+
+ // Verify that deleting a file isn't stopped by zero quota, and that it frees
+ // up quote from its path.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(0);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteFile(context.get(), path));
+ EXPECT_FALSE(file_util::PathExists(local_path));
+ EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(path),
+ context->allowed_bytes_growth());
+
+ context.reset(NewContext(NULL));
+ bool exclusive = true;
+ bool recursive = true;
+ FilePath directory_path = UTF8ToFilePath("series/of/directories");
+ path = directory_path.AppendASCII("file name");
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), directory_path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ file_handle = base::kInvalidPlatformFileValue;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CreateOrOpen(
+ context.get(), path, file_flags, &file_handle, &created));
+ ASSERT_TRUE(created);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file_handle);
+
+ CheckFileAndCloseHandle(path, file_handle);
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetLocalFilePath(
+ context.get(), path, &local_path));
+ EXPECT_TRUE(file_util::PathExists(local_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteFile(context.get(), path));
+ EXPECT_FALSE(file_util::PathExists(local_path));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
+ bool created = false;
+ FilePath path = UTF8ToFilePath("file");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->Truncate(context.get(), path, 4));
+
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+
+ context.reset(NewContext(NULL));
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetLocalFilePath(
+ context.get(), path, &local_path));
+ EXPECT_EQ(0, GetSize(local_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
+ context.get(), path, 10));
+ EXPECT_EQ(10, GetSize(local_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
+ context.get(), path, 1));
+ EXPECT_EQ(1, GetSize(local_path));
+
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), path));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
+ FilePath path = UTF8ToFilePath("fake/file");
+ bool created = false;
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->EnsureFileExists(
+ context.get(), path, &created));
+
+ // Verify that file creation requires sufficient quota for the path.
+ context.reset(NewContext(NULL));
+ path = UTF8ToFilePath("test file");
+ created = false;
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path) - 1);
+ ASSERT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_FALSE(created);
+
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+
+ CheckFileAndCloseHandle(path, base::kInvalidPlatformFileValue);
+
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_FALSE(created);
+
+ // Also test in a subdirectory.
+ path = UTF8ToFilePath("path/to/file.txt");
+ context.reset(NewContext(NULL));
+ bool exclusive = true;
+ bool recursive = true;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path.DirName(), exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), path));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ bool exclusive = false;
+ bool recursive = false;
+ FilePath path = UTF8ToFilePath("foo/bar");
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->DeleteSingleDirectory(context.get(), path));
+
+ FilePath root = UTF8ToFilePath("");
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->PathExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), root));
+
+ context.reset(NewContext(NULL));
+ exclusive = false;
+ recursive = true;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), root));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), path.DirName()));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), path.DirName()));
+
+ // Can't remove a non-empty directory.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY,
+ ofu()->DeleteSingleDirectory(context.get(), path.DirName()));
+
+ base::PlatformFileInfo file_info;
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), path, &file_info, &local_path));
+ EXPECT_TRUE(local_path.empty());
+ EXPECT_TRUE(file_info.is_directory);
+ EXPECT_FALSE(file_info.is_symbolic_link);
+
+ // Same create again should succeed, since exclusive is false.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ exclusive = true;
+ recursive = true;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ // Verify that deleting a directory isn't stopped by zero quota, and that it
+ // frees up quota from its path.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(0);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteSingleDirectory(context.get(), path));
+ EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(path),
+ context->allowed_bytes_growth());
+
+ path = UTF8ToFilePath("foo/bop");
+
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->PathExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), path));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofu()->GetFileInfo(
+ context.get(), path, &file_info, &local_path));
+
+ // Verify that file creation requires sufficient quota for the path.
+ exclusive = true;
+ recursive = false;
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path) - 1);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(path));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), path));
+
+ exclusive = true;
+ recursive = false;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ exclusive = true;
+ recursive = false;
+ path = UTF8ToFilePath("foo");
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ path = UTF8ToFilePath("blah");
+
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->PathExists(context.get(), path));
+
+ exclusive = true;
+ recursive = false;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->PathExists(context.get(), path));
+
+ exclusive = true;
+ recursive = false;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) {
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ bool exclusive = true;
+ bool recursive = true;
+ FilePath path = UTF8ToFilePath("directory/to/use");
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+ TestReadDirectoryHelper(path);
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestReadRootWithSlash) {
+ TestReadDirectoryHelper(UTF8ToFilePath(""));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) {
+ TestReadDirectoryHelper(UTF8ToFilePath("/"));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
+ FilePath path = UTF8ToFilePath("file");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+
+ context.reset(NewContext(NULL));
+ std::vector<base::FileUtilProxy::Entry> entries;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->ReadDirectory(context.get(), path, &entries));
+
+ EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), path));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestTouch) {
+ FilePath path = UTF8ToFilePath("file");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ base::Time last_access_time = base::Time::Now();
+ base::Time last_modified_time = base::Time::Now();
+
+ // It's not there yet.
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->Touch(
+ context.get(), path, last_access_time, last_modified_time));
+
+ // OK, now create it.
+ context.reset(NewContext(NULL));
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+ TestTouchHelper(path, true);
+
+ // Now test a directory:
+ context.reset(NewContext(NULL));
+ bool exclusive = true;
+ bool recursive = false;
+ path = UTF8ToFilePath("dir");
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(context.get(),
+ path, exclusive, recursive));
+ TestTouchHelper(path, false);
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) {
+ FilePath path = UTF8ToFilePath("fake/file");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ path = UTF8ToFilePath("file name");
+ context->set_allowed_bytes_growth(5);
+ bool created = false;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ EXPECT_FALSE(created);
+ context->set_allowed_bytes_growth(1024);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ EXPECT_TRUE(created);
+ int64 path_cost = ObfuscatedFileUtil::ComputeFilePathCost(path);
+ EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
+
+ context->set_allowed_bytes_growth(1024);
+ bool exclusive = true;
+ bool recursive = true;
+ path = UTF8ToFilePath("directory/to/use");
+ std::vector<FilePath::StringType> components;
+ path.GetComponents(&components);
+ path_cost = 0;
+ for (std::vector<FilePath::StringType>::iterator iter = components.begin();
+ iter != components.end(); ++iter) {
+ path_cost += ObfuscatedFileUtil::ComputeFilePathCost(
+ FilePath(*iter));
+ }
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(1024);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), path, exclusive, recursive));
+ EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
+ FilePath source_path = UTF8ToFilePath("path0.txt");
+ FilePath dest_path = UTF8ToFilePath("path1.txt");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ bool is_copy_not_move = false;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->CopyOrMoveFile(context.get(), source_path, dest_path,
+ is_copy_not_move));
+ context.reset(NewContext(NULL));
+ is_copy_not_move = true;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->CopyOrMoveFile(context.get(), source_path, dest_path,
+ is_copy_not_move));
+ source_path = UTF8ToFilePath("dir/dir/file");
+ bool exclusive = true;
+ bool recursive = true;
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), source_path.DirName(), exclusive, recursive));
+ is_copy_not_move = false;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->CopyOrMoveFile(context.get(), source_path, dest_path,
+ is_copy_not_move));
+ context.reset(NewContext(NULL));
+ is_copy_not_move = true;
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->CopyOrMoveFile(context.get(), source_path, dest_path,
+ is_copy_not_move));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
+ const int64 kSourceLength = 5;
+ const int64 kDestLength = 50;
+
+ for (size_t i = 0; i < arraysize(kCopyMoveTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "kCopyMoveTestCase " << i);
+ const CopyMoveTestCaseRecord& test_case = kCopyMoveTestCases[i];
+ SCOPED_TRACE(testing::Message() << "\t is_copy_not_move " <<
+ test_case.is_copy_not_move);
+ SCOPED_TRACE(testing::Message() << "\t source_path " <<
+ test_case.source_path);
+ SCOPED_TRACE(testing::Message() << "\t dest_path " <<
+ test_case.dest_path);
+ SCOPED_TRACE(testing::Message() << "\t cause_overwrite " <<
+ test_case.cause_overwrite);
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ bool exclusive = false;
+ bool recursive = true;
+ FilePath source_path = UTF8ToFilePath(test_case.source_path);
+ FilePath dest_path = UTF8ToFilePath(test_case.dest_path);
+
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), source_path.DirName(), exclusive, recursive));
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), dest_path.DirName(), exclusive, recursive));
+
+ bool created = false;
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), source_path, &created));
+ ASSERT_TRUE(created);
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Truncate(context.get(), source_path, kSourceLength));
+
+ if (test_case.cause_overwrite) {
+ context.reset(NewContext(NULL));
+ created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), dest_path, &created));
+ ASSERT_TRUE(created);
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Truncate(context.get(), dest_path, kDestLength));
+ }
+
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CopyOrMoveFile(context.get(),
+ source_path, dest_path, test_case.is_copy_not_move));
+ if (test_case.is_copy_not_move) {
+ base::PlatformFileInfo file_info;
+ FilePath local_path;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), source_path, &file_info, &local_path));
+ EXPECT_EQ(kSourceLength, file_info.size);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteFile(context.get(), source_path));
+ } else {
+ base::PlatformFileInfo file_info;
+ FilePath local_path;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofu()->GetFileInfo(
+ context.get(), source_path, &file_info, &local_path));
+ }
+ base::PlatformFileInfo file_info;
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
+ context.get(), dest_path, &file_info, &local_path));
+ EXPECT_EQ(kSourceLength, file_info.size);
+
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->DeleteFile(context.get(), dest_path));
+ }
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) {
+ FilePath src_path = UTF8ToFilePath("src path");
+ FilePath dest_path = UTF8ToFilePath("destination path");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->EnsureFileExists(
+ context.get(), src_path, &created));
+
+ bool is_copy = true;
+ // Copy, no overwrite.
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(dest_path) - 1);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(dest_path));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+
+ // Copy, with overwrite.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(0);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) {
+ FilePath src_path = UTF8ToFilePath("src path");
+ FilePath dest_path = UTF8ToFilePath("destination path");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->EnsureFileExists(
+ context.get(), src_path, &created));
+
+ bool is_copy = false;
+ // Move, rename, no overwrite.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(dest_path) -
+ ObfuscatedFileUtil::ComputeFilePathCost(src_path) - 1);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(
+ ObfuscatedFileUtil::ComputeFilePathCost(dest_path) -
+ ObfuscatedFileUtil::ComputeFilePathCost(src_path));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->EnsureFileExists(
+ context.get(), src_path, &created));
+
+ // Move, rename, with overwrite.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(0);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) {
+ FilePath src_path = UTF8ToFilePath("src path");
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->EnsureFileExists(
+ context.get(), src_path, &created));
+
+ bool exclusive = true;
+ bool recursive = false;
+ FilePath dir_path = UTF8ToFilePath("directory path");
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), dir_path, exclusive, recursive));
+
+ FilePath dest_path = dir_path.Append(src_path);
+
+ bool is_copy = false;
+ int64 allowed_bytes_growth = -1000; // Over quota, this should still work.
+ // Move, no rename, no overwrite.
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(allowed_bytes_growth);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+ EXPECT_EQ(allowed_bytes_growth, context->allowed_bytes_growth());
+
+ // Move, no rename, with overwrite.
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->EnsureFileExists(
+ context.get(), src_path, &created));
+ context.reset(NewContext(NULL));
+ context->set_allowed_bytes_growth(allowed_bytes_growth);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), src_path, dest_path, is_copy));
+ EXPECT_EQ(
+ allowed_bytes_growth +
+ ObfuscatedFileUtil::ComputeFilePathCost(src_path),
+ context->allowed_bytes_growth());
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestCopyInForeignFile) {
+ TestCopyInForeignFileHelper(false /* overwrite */);
+ TestCopyInForeignFileHelper(true /* overwrite */);
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestEnumerator) {
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ FilePath src_path = UTF8ToFilePath("source dir");
+ bool exclusive = true;
+ bool recursive = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
+ context.get(), src_path, exclusive, recursive));
+
+ std::set<FilePath::StringType> files;
+ std::set<FilePath::StringType> directories;
+ FillTestDirectory(src_path, &files, &directories);
+
+ FilePath dest_path = UTF8ToFilePath("destination dir");
+
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), dest_path));
+ context.reset(NewContext(NULL));
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Copy(context.get(), src_path, dest_path));
+
+ ValidateTestDirectory(dest_path, files, directories);
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), src_path));
+ context.reset(NewContext(NULL));
+ EXPECT_TRUE(ofu()->DirectoryExists(context.get(), dest_path));
+ context.reset(NewContext(NULL));
+ recursive = true;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Delete(context.get(), dest_path, recursive));
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->DirectoryExists(context.get(), dest_path));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestMigration) {
+ ScopedTempDir source_dir;
+ ASSERT_TRUE(source_dir.CreateUniqueTempDir());
+ FilePath root_path = source_dir.path().AppendASCII("chrome-pLmnMWXE7NzTFRsn");
+ ASSERT_TRUE(file_util::CreateDirectory(root_path));
+
+ for (size_t i = 0; i < arraysize(kMigrationTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Creating kMigrationTestPath " << i);
+ const MigrationTestCaseRecord& test_case = kMigrationTestCases[i];
+ FilePath local_src_path = root_path.Append(test_case.path);
+ if (test_case.is_directory) {
+ ASSERT_TRUE(
+ file_util::CreateDirectory(local_src_path));
+ } else {
+ base::PlatformFileError error_code;
+ bool created = false;
+ int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE;
+ base::PlatformFile file_handle =
+ base::CreatePlatformFile(
+ local_src_path, file_flags, &created, &error_code);
+ EXPECT_TRUE(created);
+ ASSERT_NE(base::kInvalidPlatformFileValue, file_handle);
+ ASSERT_EQ(base::PLATFORM_FILE_OK, error_code);
+ ASSERT_TRUE(
+ base::TruncatePlatformFile(file_handle, test_case.data_file_size));
+ EXPECT_TRUE(base::ClosePlatformFile(file_handle));
+ }
+ }
+
+ EXPECT_TRUE(ofu()->MigrateFromOldSandbox(origin(), type(), root_path));
+
+ FilePath new_root =
+ test_directory().AppendASCII("File System").AppendASCII("000").Append(
+ ofu()->GetDirectoryNameForType(type())).AppendASCII("Legacy");
+ for (size_t i = 0; i < arraysize(kMigrationTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Validating kMigrationTestPath " << i);
+ const MigrationTestCaseRecord& test_case = kMigrationTestCases[i];
+ FilePath local_data_path = new_root.Append(test_case.path);
+#if defined(OS_WIN)
+ local_data_path = local_data_path.NormalizeWindowsPathSeparators();
+#endif
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ base::PlatformFileInfo ofu_file_info;
+ FilePath data_path;
+ SCOPED_TRACE(testing::Message() << "Path is " << test_case.path);
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->GetFileInfo(context.get(), FilePath(test_case.path),
+ &ofu_file_info, &data_path));
+ if (test_case.is_directory) {
+ EXPECT_TRUE(ofu_file_info.is_directory);
+ } else {
+ base::PlatformFileInfo platform_file_info;
+ SCOPED_TRACE(testing::Message() << "local_data_path is " <<
+ local_data_path.value());
+ SCOPED_TRACE(testing::Message() << "data_path is " << data_path.value());
+ ASSERT_TRUE(file_util::GetFileInfo(local_data_path, &platform_file_info));
+ EXPECT_EQ(test_case.data_file_size, platform_file_info.size);
+ EXPECT_FALSE(platform_file_info.is_directory);
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+ EXPECT_EQ(local_data_path, data_path);
+ EXPECT_EQ(platform_file_info.size, ofu_file_info.size);
+ EXPECT_FALSE(ofu_file_info.is_directory);
+ }
+ }
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestOriginEnumerator) {
+ scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator>
+ enumerator(ofu()->CreateOriginEnumerator());
+ // The test helper starts out with a single filesystem.
+ EXPECT_TRUE(enumerator.get());
+ EXPECT_EQ(origin(), enumerator->Next());
+ ASSERT_TRUE(type() == kFileSystemTypeTemporary);
+ EXPECT_TRUE(enumerator->HasFileSystemType(kFileSystemTypeTemporary));
+ EXPECT_FALSE(enumerator->HasFileSystemType(kFileSystemTypePersistent));
+ EXPECT_EQ(GURL(), enumerator->Next());
+ EXPECT_FALSE(enumerator->HasFileSystemType(kFileSystemTypeTemporary));
+ EXPECT_FALSE(enumerator->HasFileSystemType(kFileSystemTypePersistent));
+
+ std::set<GURL> origins_expected;
+ origins_expected.insert(origin());
+
+ for (size_t i = 0; i < arraysize(kOriginEnumerationTestRecords); ++i) {
+ SCOPED_TRACE(testing::Message() <<
+ "Validating kOriginEnumerationTestRecords " << i);
+ const OriginEnumerationTestRecord& record =
+ kOriginEnumerationTestRecords[i];
+ GURL origin_url(record.origin_url);
+ origins_expected.insert(origin_url);
+ if (record.has_temporary) {
+ scoped_ptr<FileSystemTestOriginHelper> helper(
+ NewHelper(origin_url, kFileSystemTypeTemporary));
+ scoped_ptr<FileSystemOperationContext> context(NewContext(helper.get()));
+ context->set_src_origin_url(origin_url);
+ context->set_src_type(kFileSystemTypeTemporary);
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(),
+ FilePath().AppendASCII("file"), &created));
+ EXPECT_TRUE(created);
+ }
+ if (record.has_persistent) {
+ scoped_ptr<FileSystemTestOriginHelper> helper(
+ NewHelper(origin_url, kFileSystemTypePersistent));
+ scoped_ptr<FileSystemOperationContext> context(NewContext(helper.get()));
+ context->set_src_origin_url(origin_url);
+ context->set_src_type(kFileSystemTypePersistent);
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(),
+ FilePath().AppendASCII("file"), &created));
+ EXPECT_TRUE(created);
+ }
+ }
+ enumerator.reset(ofu()->CreateOriginEnumerator());
+ EXPECT_TRUE(enumerator.get());
+ std::set<GURL> origins_found;
+ GURL origin_url;
+ while (!(origin_url = enumerator->Next()).is_empty()) {
+ origins_found.insert(origin_url);
+ SCOPED_TRACE(testing::Message() << "Handling " << origin_url.spec());
+ bool found = false;
+ for (size_t i = 0; !found && i < arraysize(kOriginEnumerationTestRecords);
+ ++i) {
+ const OriginEnumerationTestRecord& record =
+ kOriginEnumerationTestRecords[i];
+ if (GURL(record.origin_url) != origin_url)
+ continue;
+ found = true;
+ EXPECT_EQ(record.has_temporary,
+ enumerator->HasFileSystemType(kFileSystemTypeTemporary));
+ EXPECT_EQ(record.has_persistent,
+ enumerator->HasFileSystemType(kFileSystemTypePersistent));
+ }
+ // Deal with the default filesystem created by the test helper.
+ if (!found && origin_url == origin()) {
+ ASSERT_TRUE(type() == kFileSystemTypeTemporary);
+ EXPECT_EQ(true,
+ enumerator->HasFileSystemType(kFileSystemTypeTemporary));
+ EXPECT_EQ(false,
+ enumerator->HasFileSystemType(kFileSystemTypePersistent));
+ found = true;
+ }
+ EXPECT_TRUE(found);
+ }
+
+ std::set<GURL> diff;
+ std::set_symmetric_difference(origins_expected.begin(),
+ origins_expected.end(), origins_found.begin(), origins_found.end(),
+ inserter(diff, diff.begin()));
+ EXPECT_TRUE(diff.empty());
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
+ scoped_ptr<FileSystemOperationContext> context(NewContext(NULL));
+
+ int64 expected_quota = 0;
+
+ for (size_t i = 0; i < arraysize(kMigrationTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "Creating kMigrationTestPath " << i);
+ const MigrationTestCaseRecord& test_case = kMigrationTestCases[i];
+ FilePath path(test_case.path);
+ expected_quota += ObfuscatedFileUtil::ComputeFilePathCost(path);
+ if (test_case.is_directory) {
+ bool exclusive = true;
+ bool recursive = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CreateDirectory(context.get(), path, exclusive, recursive));
+ } else {
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), path, &created));
+ ASSERT_TRUE(created);
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Truncate(context.get(), path,
+ test_case.data_file_size));
+ expected_quota += test_case.data_file_size;
+ }
+ }
+ EXPECT_EQ(expected_quota, SizeInUsageFile());
+ RevokeUsageCache();
+ EXPECT_EQ(-1, SizeInUsageFile());
+ GetUsageFromQuotaManager();
+ EXPECT_EQ(expected_quota, SizeInUsageFile());
+ EXPECT_EQ(expected_quota, usage());
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestInconsistency) {
+ const FilePath kPath1 = FilePath().AppendASCII("hoge");
+ const FilePath kPath2 = FilePath().AppendASCII("fuga");
+
+ scoped_ptr<FileSystemOperationContext> context;
+ base::PlatformFile file;
+ base::PlatformFileInfo file_info;
+ FilePath data_path;
+ bool created = false;
+
+ // Create a non-empty file.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), kPath1, &created));
+ EXPECT_TRUE(created);
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->Truncate(context.get(), kPath1, 10));
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->GetFileInfo(
+ context.get(), kPath1, &file_info, &data_path));
+ EXPECT_EQ(10, file_info.size);
+
+ // Destroy database to make inconsistency between database and filesystem.
+ ofu()->DestroyDirectoryDatabase(origin(), type());
+
+ // Try to get file info of broken file.
+ context.reset(NewContext(NULL));
+ EXPECT_FALSE(ofu()->PathExists(context.get(), kPath1));
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), kPath1, &created));
+ EXPECT_TRUE(created);
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->GetFileInfo(
+ context.get(), kPath1, &file_info, &data_path));
+ EXPECT_EQ(0, file_info.size);
+
+ // Make another broken file to |kPath2|.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), kPath2, &created));
+ EXPECT_TRUE(created);
+
+ // Destroy again.
+ ofu()->DestroyDirectoryDatabase(origin(), type());
+
+ // Repair broken |kPath1|.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ ofu()->Touch(context.get(), kPath1, base::Time::Now(),
+ base::Time::Now()));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), kPath1, &created));
+ EXPECT_TRUE(created);
+
+ // Copy from sound |kPath1| to broken |kPath2|.
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CopyOrMoveFile(context.get(), kPath1, kPath2,
+ true /* copy */));
+
+ ofu()->DestroyDirectoryDatabase(origin(), type());
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->CreateOrOpen(
+ context.get(), kPath1,
+ base::PLATFORM_FILE_READ | base::PLATFORM_FILE_CREATE,
+ &file, &created));
+ EXPECT_TRUE(created);
+ EXPECT_TRUE(base::GetPlatformFileInfo(file, &file_info));
+ EXPECT_EQ(0, file_info.size);
+ EXPECT_TRUE(base::ClosePlatformFile(file));
+}
+
+TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
+ const FilePath kPath[] = {
+ FilePath().AppendASCII("foo"),
+ FilePath().AppendASCII("bar"),
+ FilePath().AppendASCII("baz")
+ };
+ scoped_ptr<FileSystemOperationContext> context;
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kPath); ++i) {
+ bool created = false;
+ context.reset(NewContext(NULL));
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->EnsureFileExists(context.get(), kPath[i], &created));
+ EXPECT_TRUE(created);
+ }
+
+ context.reset(NewContext(NULL));
+ std::vector<base::FileUtilProxy::Entry> entries;
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->ReadDirectory(context.get(), FilePath(), &entries));
+ EXPECT_EQ(3u, entries.size());
+
+ context.reset(NewContext(NULL));
+ FilePath local_path;
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->GetLocalFilePath(context.get(), kPath[0], &local_path));
+ EXPECT_TRUE(file_util::Delete(local_path, false));
+
+ context.reset(NewContext(NULL));
+ entries.clear();
+ EXPECT_EQ(base::PLATFORM_FILE_OK,
+ ofu()->ReadDirectory(context.get(), FilePath(), &entries));
+ EXPECT_EQ(ARRAYSIZE_UNSAFE(kPath) - 1, entries.size());
+}