// 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/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_test_helper.h" #include "webkit/fileapi/obfuscated_file_system_file_util.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 ObfuscatedFileSystemFileUtilTest : public testing::Test { public: ObfuscatedFileSystemFileUtilTest() : origin_(GURL("http://www.example.com")), type_(kFileSystemTypeTemporary), test_helper_(origin_, type_) { } void SetUp() { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); obfuscated_file_system_file_util_ = new ObfuscatedFileSystemFileUtil(data_dir_.path()); test_helper_.SetUp(data_dir_.path(), false, // incognito false, // unlimited quota NULL, // quota::QuotaManagerProxy obfuscated_file_system_file_util_.get()); } FileSystemOperationContext* NewContext() { FileSystemOperationContext* context = test_helper_.NewOperationContext(); context->set_allowed_bytes_growth(1024 * 1024); return context; } ObfuscatedFileSystemFileUtil* ofsfu() { return obfuscated_file_system_file_util_.get(); } const FilePath& test_directory() const { return data_dir_.path(); } const GURL& origin_url() const { return origin_; } fileapi::FileSystemType type() const { return type_; } void CheckFileAndCloseHandle( const FilePath& virtual_path, PlatformFile file_handle) { scoped_ptr<FileSystemOperationContext> context(NewContext()); FilePath local_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetLocalFilePath( context.get(), virtual_path, &local_path)); base::PlatformFileInfo file_info0; FilePath data_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate( context.get(), virtual_path, length * 2)); EXPECT_EQ(length * 2, GetSize(data_path)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate( context.get(), virtual_path, 1)); EXPECT_EQ(1, 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()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists( context.get(), root_path.Append(*iter), &created)); ASSERT_FALSE(created); } for (iter = directories.begin(); iter != directories.end(); ++iter) { context.reset(NewContext()); EXPECT_TRUE(ofsfu()->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()); std::vector<base::FileUtilProxy::Entry> entries; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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) { base::Time last_access_time = base::Time::Now(); // Ignored, so not tested. base::Time last_modified_time = base::Time::Now(); scoped_ptr<FileSystemOperationContext> context(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Touch( context.get(), path, last_access_time, last_modified_time)); FilePath local_path; base::PlatformFileInfo file_info; context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); last_modified_time += base::TimeDelta::FromHours(1); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Touch( context.get(), path, last_access_time, last_modified_time)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetFileInfo( context.get(), path, &file_info, &local_path)); EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), dest_path, &created)); EXPECT_TRUE(created); } context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CopyInForeignFile(context.get(), src_path, dest_path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), dest_path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), dest_path)); context.reset(NewContext()); base::PlatformFileInfo file_info; FilePath data_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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, ofsfu()->DeleteFile(context.get(), dest_path)); } private: ScopedTempDir data_dir_; scoped_refptr<ObfuscatedFileSystemFileUtil> obfuscated_file_system_file_util_; GURL origin_; fileapi::FileSystemType type_; FileSystemTestOriginHelper test_helper_; DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileSystemFileUtilTest); }; TEST_F(ObfuscatedFileSystemFileUtilTest, TestCreateAndDeleteFile) { base::PlatformFile file_handle = base::kInvalidPlatformFileValue; bool created; FilePath path = UTF8ToFilePath("fake/file"); scoped_ptr<FileSystemOperationContext> context(NewContext()); int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->CreateOrOpen( context.get(), path, file_flags, &file_handle, &created)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->DeleteFile(context.get(), path)); path = UTF8ToFilePath("test file"); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); FilePath local_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetLocalFilePath( context.get(), path, &local_path)); EXPECT_TRUE(file_util::PathExists(local_path)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->DeleteFile(context.get(), path)); EXPECT_FALSE(file_util::PathExists(local_path)); context.reset(NewContext()); 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, ofsfu()->CreateDirectory( context.get(), directory_path, exclusive, recursive)); context.reset(NewContext()); file_handle = base::kInvalidPlatformFileValue; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetLocalFilePath( context.get(), path, &local_path)); EXPECT_TRUE(file_util::PathExists(local_path)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->DeleteFile(context.get(), path)); EXPECT_FALSE(file_util::PathExists(local_path)); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestTruncate) { bool created = false; FilePath path = UTF8ToFilePath("file"); scoped_ptr<FileSystemOperationContext> context(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->Truncate(context.get(), path, 4)); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), path, &created)); ASSERT_TRUE(created); context.reset(NewContext()); FilePath local_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetLocalFilePath( context.get(), path, &local_path)); EXPECT_EQ(0, GetSize(local_path)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate( context.get(), path, 10)); EXPECT_EQ(10, GetSize(local_path)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate( context.get(), path, 1)); EXPECT_EQ(1, GetSize(local_path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), path)); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestEnsureFileExists) { FilePath path = UTF8ToFilePath("fake/file"); bool created = false; scoped_ptr<FileSystemOperationContext> context(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->EnsureFileExists( context.get(), path, &created)); context.reset(NewContext()); path = UTF8ToFilePath("test file"); created = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), path, &created)); ASSERT_TRUE(created); CheckFileAndCloseHandle(path, base::kInvalidPlatformFileValue); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), path, &created)); ASSERT_FALSE(created); // Also test in a subdirectory. path = UTF8ToFilePath("path/to/file.txt"); context.reset(NewContext()); bool exclusive = true; bool recursive = true; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path.DirName(), exclusive, recursive)); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), path, &created)); ASSERT_TRUE(created); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), path)); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestDirectoryOps) { scoped_ptr<FileSystemOperationContext> context(NewContext()); bool exclusive = false; bool recursive = false; FilePath path = UTF8ToFilePath("foo/bar"); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->DeleteSingleDirectory(context.get(), path)); FilePath root = UTF8ToFilePath(""); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->PathExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->IsDirectoryEmpty(context.get(), root)); context.reset(NewContext()); exclusive = false; recursive = true; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->IsDirectoryEmpty(context.get(), root)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), path.DirName())); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->IsDirectoryEmpty(context.get(), path.DirName())); // Can't remove a non-empty directory. context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, ofsfu()->DeleteSingleDirectory(context.get(), path.DirName())); base::PlatformFileInfo file_info; FilePath local_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); exclusive = true; recursive = true; context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->DeleteSingleDirectory(context.get(), path)); path = UTF8ToFilePath("foo/bop"); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->PathExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->IsDirectoryEmpty(context.get(), path)); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->GetFileInfo( context.get(), path, &file_info, &local_path)); exclusive = true; recursive = false; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), path)); exclusive = true; recursive = false; EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); exclusive = true; recursive = false; path = UTF8ToFilePath("foo"); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); path = UTF8ToFilePath("blah"); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->PathExists(context.get(), path)); exclusive = true; recursive = false; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->PathExists(context.get(), path)); exclusive = true; recursive = false; EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestReadDirectory) { scoped_ptr<FileSystemOperationContext> context(NewContext()); bool exclusive = true; bool recursive = true; FilePath path = UTF8ToFilePath("directory/to/use"); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); TestReadDirectoryHelper(path); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestReadRootWithSlash) { TestReadDirectoryHelper(UTF8ToFilePath("")); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestReadRootWithEmptyString) { TestReadDirectoryHelper(UTF8ToFilePath("/")); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestReadDirectoryOnFile) { FilePath path = UTF8ToFilePath("file"); scoped_ptr<FileSystemOperationContext> context(NewContext()); bool created = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), path, &created)); ASSERT_TRUE(created); context.reset(NewContext()); std::vector<base::FileUtilProxy::Entry> entries; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->ReadDirectory(context.get(), path, &entries)); EXPECT_TRUE(ofsfu()->IsDirectoryEmpty(context.get(), path)); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestTouch) { FilePath path = UTF8ToFilePath("fake/file"); base::Time last_access_time = base::Time::Now(); // Ignored, so not tested. base::Time last_modified_time = base::Time::Now(); scoped_ptr<FileSystemOperationContext> context(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->Touch( context.get(), path, last_access_time, last_modified_time)); // Touch will create a file if it's not there but its parent is. path = UTF8ToFilePath("file name"); TestTouchHelper(path); bool exclusive = true; bool recursive = true; path = UTF8ToFilePath("directory/to/use"); context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), path, exclusive, recursive)); TestTouchHelper(path); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestCopyOrMoveFileNotFound) { FilePath source_path = UTF8ToFilePath("path0.txt"); FilePath dest_path = UTF8ToFilePath("path1.txt"); scoped_ptr<FileSystemOperationContext> context(NewContext()); bool is_copy_not_move = false; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->CopyOrMoveFile(context.get(), source_path, dest_path, is_copy_not_move)); context.reset(NewContext()); is_copy_not_move = true; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->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()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), source_path.DirName(), exclusive, recursive)); is_copy_not_move = false; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->CopyOrMoveFile(context.get(), source_path, dest_path, is_copy_not_move)); context.reset(NewContext()); is_copy_not_move = true; EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->CopyOrMoveFile(context.get(), source_path, dest_path, is_copy_not_move)); } TEST_F(ObfuscatedFileSystemFileUtilTest, 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()); 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()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), source_path.DirName(), exclusive, recursive)); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->CreateDirectory( context.get(), dest_path.DirName(), exclusive, recursive)); bool created = false; context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), source_path, &created)); ASSERT_TRUE(created); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate(context.get(), source_path, kSourceLength)); if (test_case.cause_overwrite) { context.reset(NewContext()); created = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), dest_path, &created)); ASSERT_TRUE(created); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Truncate(context.get(), dest_path, kDestLength)); } context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetFileInfo( context.get(), source_path, &file_info, &local_path)); EXPECT_EQ(kSourceLength, file_info.size); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->DeleteFile(context.get(), source_path)); } else { base::PlatformFileInfo file_info; FilePath local_path; context.reset(NewContext()); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, ofsfu()->GetFileInfo( context.get(), source_path, &file_info, &local_path)); } base::PlatformFileInfo file_info; FilePath local_path; EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetFileInfo( context.get(), dest_path, &file_info, &local_path)); EXPECT_EQ(kSourceLength, file_info.size); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->DeleteFile(context.get(), dest_path)); } } TEST_F(ObfuscatedFileSystemFileUtilTest, TestCopyInForeignFile) { TestCopyInForeignFileHelper(false /* overwrite */); TestCopyInForeignFileHelper(true /* overwrite */); } TEST_F(ObfuscatedFileSystemFileUtilTest, TestEnumerator) { scoped_ptr<FileSystemOperationContext> context(NewContext()); FilePath src_path = UTF8ToFilePath("source dir"); bool exclusive = true; bool recursive = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->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()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), dest_path)); context.reset(NewContext()); ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Copy(context.get(), src_path, dest_path)); ValidateTestDirectory(dest_path, files, directories); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), src_path)); context.reset(NewContext()); EXPECT_TRUE(ofsfu()->DirectoryExists(context.get(), dest_path)); context.reset(NewContext()); recursive = true; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->Delete(context.get(), dest_path, recursive)); context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), dest_path)); } TEST_F(ObfuscatedFileSystemFileUtilTest, 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(ofsfu()->MigrateFromOldSandbox(origin_url(), type(), root_path)); FilePath new_root = test_directory().AppendASCII("000").Append( ofsfu()->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()); base::PlatformFileInfo ofsfu_file_info; FilePath data_path; SCOPED_TRACE(testing::Message() << "Path is " << test_case.path); EXPECT_EQ(base::PLATFORM_FILE_OK, ofsfu()->GetFileInfo(context.get(), FilePath(test_case.path), &ofsfu_file_info, &data_path)); if (test_case.is_directory) { EXPECT_TRUE(ofsfu_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()); EXPECT_EQ(local_data_path, data_path); EXPECT_EQ(platform_file_info.size, ofsfu_file_info.size); EXPECT_FALSE(ofsfu_file_info.is_directory); } } } TEST_F(ObfuscatedFileSystemFileUtilTest, TestOriginEnumerator) { scoped_ptr<ObfuscatedFileSystemFileUtil::AbstractOriginEnumerator> enumerator(ofsfu()->CreateOriginEnumerator()); EXPECT_TRUE(enumerator.get()); EXPECT_EQ(GURL(), enumerator->Next()); EXPECT_FALSE(enumerator->HasFileSystemType(kFileSystemTypeTemporary)); EXPECT_FALSE(enumerator->HasFileSystemType(kFileSystemTypePersistent)); std::set<GURL> origins_expected; 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<FileSystemOperationContext> context(NewContext()); context->set_src_origin_url(origin_url); context->set_src_type(kFileSystemTypeTemporary); bool created = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), FilePath().AppendASCII("file"), &created)); EXPECT_TRUE(created); } if (record.has_persistent) { scoped_ptr<FileSystemOperationContext> context(NewContext()); context->set_src_origin_url(origin_url); context->set_src_type(kFileSystemTypePersistent); bool created = false; ASSERT_EQ(base::PLATFORM_FILE_OK, ofsfu()->EnsureFileExists(context.get(), FilePath().AppendASCII("file"), &created)); EXPECT_TRUE(created); } } enumerator.reset(ofsfu()->CreateOriginEnumerator()); EXPECT_TRUE(enumerator.get()); std::set<GURL> origins_found; GURL origin; while (!(origin = enumerator->Next()).is_empty()) { origins_found.insert(origin); SCOPED_TRACE(testing::Message() << "Handling " << origin.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) continue; found = true; EXPECT_EQ(record.has_temporary, enumerator->HasFileSystemType(kFileSystemTypeTemporary)); EXPECT_EQ(record.has_persistent, enumerator->HasFileSystemType(kFileSystemTypePersistent)); } 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()); }