// 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 "webkit/fileapi/file_system_directory_database.h" #include #include "base/memory/scoped_ptr.h" #include "base/scoped_temp_dir.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace fileapi { class FileSystemDirectoryDatabaseTest : public testing::Test { public: typedef FileSystemDirectoryDatabase::FileId FileId; typedef FileSystemDirectoryDatabase::FileInfo FileInfo; FileSystemDirectoryDatabaseTest() { EXPECT_TRUE(base_.CreateUniqueTempDir()); InitDatabase(); } FileSystemDirectoryDatabase* db() { return db_.get(); } void InitDatabase() { db_.reset(); FilePath path = base_.path().AppendASCII("db"); db_.reset(new FileSystemDirectoryDatabase(path)); } bool AddFileInfo(FileId parent_id, const FilePath::StringType& name) { FileId file_id; FileInfo info; info.parent_id = parent_id; info.name = name; return db_->AddFileInfo(info, &file_id); } protected: // Common temp base for nondestructive uses. ScopedTempDir base_; scoped_ptr db_; DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabaseTest); }; TEST_F(FileSystemDirectoryDatabaseTest, TestMissingFileGetInfo) { FileId file_id = 888; FileInfo info; EXPECT_FALSE(db()->GetFileInfo(file_id, &info)); } TEST_F(FileSystemDirectoryDatabaseTest, TestGetRootFileInfoBeforeCreate) { FileId file_id = 0; FileInfo info; EXPECT_TRUE(db()->GetFileInfo(file_id, &info)); EXPECT_EQ(0, info.parent_id); EXPECT_TRUE(info.name.empty()); EXPECT_TRUE(info.data_path.empty()); } TEST_F(FileSystemDirectoryDatabaseTest, TestMissingParentAddFileInfo) { FileId parent_id = 7; EXPECT_FALSE(AddFileInfo(parent_id, FILE_PATH_LITERAL("foo"))); } TEST_F(FileSystemDirectoryDatabaseTest, TestAddNameClash) { FileInfo info; FileId file_id; info.parent_id = 0; info.name = FILE_PATH_LITERAL("dir 0"); EXPECT_TRUE(db()->AddFileInfo(info, &file_id)); // Check for name clash in the root directory. FilePath::StringType name = info.name; EXPECT_FALSE(AddFileInfo(0, name)); name = FILE_PATH_LITERAL("dir 1"); EXPECT_TRUE(AddFileInfo(0, name)); name = FILE_PATH_LITERAL("subdir 0"); EXPECT_TRUE(AddFileInfo(file_id, name)); // Check for name clash in a subdirectory. EXPECT_FALSE(AddFileInfo(file_id, name)); name = FILE_PATH_LITERAL("subdir 1"); EXPECT_TRUE(AddFileInfo(file_id, name)); } TEST_F(FileSystemDirectoryDatabaseTest, TestRenameNoMoveNameClash) { FileInfo info; FileId file_id0; FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); info.parent_id = 0; info.name = name0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); EXPECT_TRUE(AddFileInfo(0, name1)); info.name = name1; EXPECT_FALSE(db()->UpdateFileInfo(file_id0, info)); info.name = name2; EXPECT_TRUE(db()->UpdateFileInfo(file_id0, info)); } TEST_F(FileSystemDirectoryDatabaseTest, TestMoveSameNameNameClash) { FileInfo info; FileId file_id0; FileId file_id1; FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); info.parent_id = 0; info.name = name0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); info.parent_id = 0; EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); info.name = name1; EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); } TEST_F(FileSystemDirectoryDatabaseTest, TestMoveRenameNameClash) { FileInfo info; FileId file_id0; FileId file_id1; FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); info.parent_id = 0; info.name = name0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); info.parent_id = 0; info.name = name0; EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); info.name = name1; EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); // Also test a successful move+rename. info.parent_id = file_id0; info.name = name2; EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); } TEST_F(FileSystemDirectoryDatabaseTest, TestRemoveWithChildren) { FileInfo info; FileId file_id0; FileId file_id1; info.parent_id = 0; info.name = FILE_PATH_LITERAL("foo"); EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); EXPECT_FALSE(db()->RemoveFileInfo(file_id0)); EXPECT_TRUE(db()->RemoveFileInfo(file_id1)); EXPECT_TRUE(db()->RemoveFileInfo(file_id0)); } TEST_F(FileSystemDirectoryDatabaseTest, TestGetChildWithName) { FileInfo info; FileId file_id0; FileId file_id1; FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); info.parent_id = 0; info.name = name0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); EXPECT_NE(file_id0, file_id1); FileId check_file_id; EXPECT_FALSE(db()->GetChildWithName(0, name1, &check_file_id)); EXPECT_TRUE(db()->GetChildWithName(0, name0, &check_file_id)); EXPECT_EQ(file_id0, check_file_id); EXPECT_FALSE(db()->GetChildWithName(file_id0, name0, &check_file_id)); EXPECT_TRUE(db()->GetChildWithName(file_id0, name1, &check_file_id)); EXPECT_EQ(file_id1, check_file_id); } TEST_F(FileSystemDirectoryDatabaseTest, TestGetFileWithPath) { FileInfo info; FileId file_id0; FileId file_id1; FileId file_id2; FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); FilePath::StringType name2 = FILE_PATH_LITERAL("dog"); info.parent_id = 0; info.name = name0; EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); EXPECT_NE(file_id0, file_id1); info.parent_id = file_id1; info.name = name2; EXPECT_TRUE(db()->AddFileInfo(info, &file_id2)); EXPECT_NE(file_id0, file_id2); EXPECT_NE(file_id1, file_id2); FileId check_file_id; FilePath path = FilePath(name0); EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); EXPECT_EQ(file_id0, check_file_id); path = path.Append(name1); EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); EXPECT_EQ(file_id1, check_file_id); path = path.Append(name2); EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); EXPECT_EQ(file_id2, check_file_id); } TEST_F(FileSystemDirectoryDatabaseTest, TestListChildren) { // No children in the root. std::vector children; EXPECT_TRUE(db()->ListChildren(0, &children)); EXPECT_TRUE(children.empty()); // One child in the root. FileId file_id0; FileInfo info; info.parent_id = 0; info.name = FILE_PATH_LITERAL("foo"); EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); EXPECT_TRUE(db()->ListChildren(0, &children)); EXPECT_EQ(children.size(), 1UL); EXPECT_EQ(children[0], file_id0); // Two children in the root. FileId file_id1; info.name = FILE_PATH_LITERAL("bar"); EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); EXPECT_TRUE(db()->ListChildren(0, &children)); EXPECT_EQ(2UL, children.size()); if (children[0] == file_id0) { EXPECT_EQ(children[1], file_id1); } else { EXPECT_EQ(children[1], file_id0); EXPECT_EQ(children[0], file_id1); } // No children in a subdirectory. EXPECT_TRUE(db()->ListChildren(file_id0, &children)); EXPECT_TRUE(children.empty()); // One child in a subdirectory. info.parent_id = file_id0; info.name = FILE_PATH_LITERAL("foo"); FileId file_id2; FileId file_id3; EXPECT_TRUE(db()->AddFileInfo(info, &file_id2)); EXPECT_TRUE(db()->ListChildren(file_id0, &children)); EXPECT_EQ(1UL, children.size()); EXPECT_EQ(children[0], file_id2); // Two children in a subdirectory. info.name = FILE_PATH_LITERAL("bar"); EXPECT_TRUE(db()->AddFileInfo(info, &file_id3)); EXPECT_TRUE(db()->ListChildren(file_id0, &children)); EXPECT_EQ(2UL, children.size()); if (children[0] == file_id2) { EXPECT_EQ(children[1], file_id3); } else { EXPECT_EQ(children[1], file_id2); EXPECT_EQ(children[0], file_id3); } } TEST_F(FileSystemDirectoryDatabaseTest, TestUpdateModificationTime) { FileInfo info0; FileId file_id; info0.parent_id = 0; info0.name = FILE_PATH_LITERAL("name"); info0.data_path = FilePath(FILE_PATH_LITERAL("fake path")); info0.modification_time = base::Time::Now(); EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); FileInfo info1; EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); EXPECT_EQ(info0.name, info1.name); EXPECT_EQ(info0.parent_id, info1.parent_id); EXPECT_EQ(info0.data_path, info1.data_path); EXPECT_EQ( floor(info0.modification_time.ToDoubleT()), info1.modification_time.ToDoubleT()); EXPECT_TRUE(db()->UpdateModificationTime(file_id, base::Time::UnixEpoch())); EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); EXPECT_EQ(info0.name, info1.name); EXPECT_EQ(info0.parent_id, info1.parent_id); EXPECT_EQ(info0.data_path, info1.data_path); EXPECT_NE(info0.modification_time, info1.modification_time); EXPECT_EQ( info1.modification_time.ToDoubleT(), floor(base::Time::UnixEpoch().ToDoubleT())); EXPECT_FALSE(db()->UpdateModificationTime(999, base::Time::UnixEpoch())); } TEST_F(FileSystemDirectoryDatabaseTest, TestSimpleFileOperations) { FileId file_id = 888; FileInfo info0; EXPECT_FALSE(db()->GetFileInfo(file_id, &info0)); info0.parent_id = 0; info0.data_path = FilePath(FILE_PATH_LITERAL("foo")); info0.name = FILE_PATH_LITERAL("file name"); info0.modification_time = base::Time::Now(); EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); FileInfo info1; EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); EXPECT_EQ(info0.parent_id, info1.parent_id); EXPECT_EQ(info0.data_path, info1.data_path); EXPECT_EQ(info0.name, info1.name); EXPECT_EQ( floor(info0.modification_time.ToDoubleT()), info1.modification_time.ToDoubleT()); } TEST_F(FileSystemDirectoryDatabaseTest, TestOverwritingMoveFileSrcDirectory) { FileId directory_id; FileInfo info0; info0.parent_id = 0; info0.name = FILE_PATH_LITERAL("directory"); info0.modification_time = base::Time::Now(); EXPECT_TRUE(db()->AddFileInfo(info0, &directory_id)); FileId file_id; FileInfo info1; info1.parent_id = 0; info1.data_path = FilePath(FILE_PATH_LITERAL("bar")); info1.name = FILE_PATH_LITERAL("file"); info1.modification_time = base::Time::UnixEpoch(); EXPECT_TRUE(db()->AddFileInfo(info1, &file_id)); EXPECT_FALSE(db()->OverwritingMoveFile(directory_id, file_id)); } TEST_F(FileSystemDirectoryDatabaseTest, TestOverwritingMoveFileDestDirectory) { FileId file_id; FileInfo info0; info0.parent_id = 0; info0.name = FILE_PATH_LITERAL("file"); info0.data_path = FilePath(FILE_PATH_LITERAL("bar")); info0.modification_time = base::Time::Now(); EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); FileId directory_id; FileInfo info1; info1.parent_id = 0; info1.name = FILE_PATH_LITERAL("directory"); info1.modification_time = base::Time::UnixEpoch(); EXPECT_TRUE(db()->AddFileInfo(info1, &directory_id)); EXPECT_FALSE(db()->OverwritingMoveFile(file_id, directory_id)); } TEST_F(FileSystemDirectoryDatabaseTest, TestOverwritingMoveFileSuccess) { FileId file_id0; FileInfo info0; info0.parent_id = 0; info0.data_path = FilePath(FILE_PATH_LITERAL("foo")); info0.name = FILE_PATH_LITERAL("file name 0"); info0.modification_time = base::Time::Now(); EXPECT_TRUE(db()->AddFileInfo(info0, &file_id0)); FileInfo dir_info; FileId dir_id; dir_info.parent_id = 0; dir_info.name = FILE_PATH_LITERAL("directory name"); EXPECT_TRUE(db()->AddFileInfo(dir_info, &dir_id)); FileId file_id1; FileInfo info1; info1.parent_id = dir_id; info1.data_path = FilePath(FILE_PATH_LITERAL("bar")); info1.name = FILE_PATH_LITERAL("file name 1"); info1.modification_time = base::Time::UnixEpoch(); EXPECT_TRUE(db()->AddFileInfo(info1, &file_id1)); EXPECT_TRUE(db()->OverwritingMoveFile(file_id0, file_id1)); FileInfo check_info; FileId check_id; EXPECT_FALSE(db()->GetFileWithPath(FilePath(info0.name), &check_id)); EXPECT_TRUE(db()->GetFileWithPath( FilePath(dir_info.name).Append(info1.name), &check_id)); EXPECT_TRUE(db()->GetFileInfo(check_id, &check_info)); EXPECT_EQ(info0.data_path, check_info.data_path); } TEST_F(FileSystemDirectoryDatabaseTest, TestGetNextInteger) { int64 next; EXPECT_TRUE(db()->GetNextInteger(&next)); EXPECT_EQ(0, next); EXPECT_TRUE(db()->GetNextInteger(&next)); EXPECT_EQ(1, next); InitDatabase(); EXPECT_TRUE(db()->GetNextInteger(&next)); EXPECT_EQ(2, next); EXPECT_TRUE(db()->GetNextInteger(&next)); EXPECT_EQ(3, next); InitDatabase(); EXPECT_TRUE(db()->GetNextInteger(&next)); EXPECT_EQ(4, next); } } // namespace fileapi