1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 7 #include "base/file_util.h" 8 #include "base/files/file_path.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/platform_file.h" 13 #include "base/strings/sys_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "webkit/browser/fileapi/async_file_test_helper.h" 17 #include "webkit/browser/fileapi/file_system_context.h" 18 #include "webkit/browser/fileapi/file_system_file_util.h" 19 #include "webkit/browser/fileapi/file_system_operation_context.h" 20 #include "webkit/browser/fileapi/local_file_util.h" 21 #include "webkit/browser/fileapi/mock_file_system_context.h" 22 #include "webkit/browser/fileapi/native_file_util.h" 23 #include "webkit/common/fileapi/file_system_types.h" 24 25 namespace fileapi { 26 27 namespace { 28 29 const GURL kOrigin("http://foo/"); 30 const FileSystemType kFileSystemType = kFileSystemTypeTest; 31 32 } // namespace 33 34 class LocalFileUtilTest : public testing::Test { 35 public: 36 LocalFileUtilTest() {} 37 38 virtual void SetUp() { 39 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 40 file_system_context_ = CreateFileSystemContextForTesting( 41 NULL, data_dir_.path()); 42 } 43 44 virtual void TearDown() { 45 file_system_context_ = NULL; 46 base::MessageLoop::current()->RunUntilIdle(); 47 } 48 49 protected: 50 FileSystemOperationContext* NewContext() { 51 FileSystemOperationContext* context = 52 new FileSystemOperationContext(file_system_context_.get()); 53 context->set_update_observers( 54 *file_system_context_->GetUpdateObservers(kFileSystemType)); 55 context->set_root_path(data_dir_.path()); 56 return context; 57 } 58 59 LocalFileUtil* file_util() { 60 return static_cast<LocalFileUtil*>( 61 file_system_context_->GetFileUtil(kFileSystemType)); 62 } 63 64 FileSystemURL CreateURL(const std::string& file_name) { 65 return file_system_context_->CreateCrackedFileSystemURL( 66 kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name)); 67 } 68 69 base::FilePath LocalPath(const char *file_name) { 70 base::FilePath path; 71 scoped_ptr<FileSystemOperationContext> context(NewContext()); 72 file_util()->GetLocalFilePath(context.get(), CreateURL(file_name), &path); 73 return path; 74 } 75 76 bool FileExists(const char *file_name) { 77 return base::PathExists(LocalPath(file_name)) && 78 !base::DirectoryExists(LocalPath(file_name)); 79 } 80 81 bool DirectoryExists(const char *file_name) { 82 return base::DirectoryExists(LocalPath(file_name)); 83 } 84 85 int64 GetSize(const char *file_name) { 86 base::PlatformFileInfo info; 87 file_util::GetFileInfo(LocalPath(file_name), &info); 88 return info.size; 89 } 90 91 base::PlatformFileError CreateFile(const char* file_name, 92 base::PlatformFile* file_handle, 93 bool* created) { 94 int file_flags = base::PLATFORM_FILE_CREATE | 95 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC; 96 97 scoped_ptr<FileSystemOperationContext> context(NewContext()); 98 return file_util()->CreateOrOpen( 99 context.get(), 100 CreateURL(file_name), 101 file_flags, file_handle, created); 102 } 103 104 base::PlatformFileError EnsureFileExists(const char* file_name, 105 bool* created) { 106 scoped_ptr<FileSystemOperationContext> context(NewContext()); 107 return file_util()->EnsureFileExists( 108 context.get(), 109 CreateURL(file_name), created); 110 } 111 112 FileSystemContext* file_system_context() { 113 return file_system_context_.get(); 114 } 115 116 private: 117 base::MessageLoop message_loop_; 118 scoped_refptr<FileSystemContext> file_system_context_; 119 base::ScopedTempDir data_dir_; 120 121 DISALLOW_COPY_AND_ASSIGN(LocalFileUtilTest); 122 }; 123 124 TEST_F(LocalFileUtilTest, CreateAndClose) { 125 const char *file_name = "test_file"; 126 base::PlatformFile file_handle; 127 bool created; 128 ASSERT_EQ(base::PLATFORM_FILE_OK, 129 CreateFile(file_name, &file_handle, &created)); 130 ASSERT_TRUE(created); 131 132 EXPECT_TRUE(FileExists(file_name)); 133 EXPECT_EQ(0, GetSize(file_name)); 134 135 scoped_ptr<FileSystemOperationContext> context(NewContext()); 136 EXPECT_EQ(base::PLATFORM_FILE_OK, 137 file_util()->Close(context.get(), file_handle)); 138 } 139 140 // file_util::CreateSymbolicLink is only supported on POSIX. 141 #if defined(OS_POSIX) 142 TEST_F(LocalFileUtilTest, CreateFailForSymlink) { 143 // Create symlink target file. 144 const char *target_name = "symlink_target"; 145 base::PlatformFile target_handle; 146 bool symlink_target_created = false; 147 ASSERT_EQ(base::PLATFORM_FILE_OK, 148 CreateFile(target_name, &target_handle, &symlink_target_created)); 149 ASSERT_TRUE(symlink_target_created); 150 base::FilePath target_path = LocalPath(target_name); 151 152 // Create symlink where target must be real file. 153 const char *symlink_name = "symlink_file"; 154 base::FilePath symlink_path = LocalPath(symlink_name); 155 ASSERT_TRUE(file_util::CreateSymbolicLink(target_path, symlink_path)); 156 ASSERT_TRUE(FileExists(symlink_name)); 157 158 // Try to open the symlink file which should fail. 159 scoped_ptr<FileSystemOperationContext> context(NewContext()); 160 FileSystemURL url = CreateURL(symlink_name); 161 int file_flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; 162 base::PlatformFile file_handle; 163 bool created = false; 164 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_util()->CreateOrOpen( 165 context.get(), url, file_flags, &file_handle, &created)); 166 EXPECT_FALSE(created); 167 } 168 #endif 169 170 TEST_F(LocalFileUtilTest, EnsureFileExists) { 171 const char *file_name = "foobar"; 172 bool created; 173 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(file_name, &created)); 174 ASSERT_TRUE(created); 175 176 EXPECT_TRUE(FileExists(file_name)); 177 EXPECT_EQ(0, GetSize(file_name)); 178 179 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(file_name, &created)); 180 EXPECT_FALSE(created); 181 } 182 183 TEST_F(LocalFileUtilTest, TouchFile) { 184 const char *file_name = "test_file"; 185 base::PlatformFile file_handle; 186 bool created; 187 ASSERT_EQ(base::PLATFORM_FILE_OK, 188 CreateFile(file_name, &file_handle, &created)); 189 ASSERT_TRUE(created); 190 191 scoped_ptr<FileSystemOperationContext> context(NewContext()); 192 193 base::PlatformFileInfo info; 194 ASSERT_TRUE(file_util::GetFileInfo(LocalPath(file_name), &info)); 195 const base::Time new_accessed = 196 info.last_accessed + base::TimeDelta::FromHours(10); 197 const base::Time new_modified = 198 info.last_modified + base::TimeDelta::FromHours(5); 199 200 EXPECT_EQ(base::PLATFORM_FILE_OK, 201 file_util()->Touch(context.get(), CreateURL(file_name), 202 new_accessed, new_modified)); 203 204 ASSERT_TRUE(file_util::GetFileInfo(LocalPath(file_name), &info)); 205 EXPECT_EQ(new_accessed, info.last_accessed); 206 EXPECT_EQ(new_modified, info.last_modified); 207 208 EXPECT_EQ(base::PLATFORM_FILE_OK, 209 file_util()->Close(context.get(), file_handle)); 210 } 211 212 TEST_F(LocalFileUtilTest, TouchDirectory) { 213 const char *dir_name = "test_dir"; 214 scoped_ptr<FileSystemOperationContext> context(NewContext()); 215 ASSERT_EQ(base::PLATFORM_FILE_OK, 216 file_util()->CreateDirectory(context.get(), 217 CreateURL(dir_name), 218 false /* exclusive */, 219 false /* recursive */)); 220 221 base::PlatformFileInfo info; 222 ASSERT_TRUE(file_util::GetFileInfo(LocalPath(dir_name), &info)); 223 const base::Time new_accessed = 224 info.last_accessed + base::TimeDelta::FromHours(10); 225 const base::Time new_modified = 226 info.last_modified + base::TimeDelta::FromHours(5); 227 228 EXPECT_EQ(base::PLATFORM_FILE_OK, 229 file_util()->Touch(context.get(), CreateURL(dir_name), 230 new_accessed, new_modified)); 231 232 ASSERT_TRUE(file_util::GetFileInfo(LocalPath(dir_name), &info)); 233 EXPECT_EQ(new_accessed, info.last_accessed); 234 EXPECT_EQ(new_modified, info.last_modified); 235 } 236 237 TEST_F(LocalFileUtilTest, Truncate) { 238 const char *file_name = "truncated"; 239 bool created; 240 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(file_name, &created)); 241 ASSERT_TRUE(created); 242 243 scoped_ptr<FileSystemOperationContext> context; 244 245 context.reset(NewContext()); 246 ASSERT_EQ(base::PLATFORM_FILE_OK, 247 file_util()->Truncate(context.get(), CreateURL(file_name), 1020)); 248 249 EXPECT_TRUE(FileExists(file_name)); 250 EXPECT_EQ(1020, GetSize(file_name)); 251 } 252 253 TEST_F(LocalFileUtilTest, CopyFile) { 254 const char *from_file = "fromfile"; 255 const char *to_file1 = "tofile1"; 256 const char *to_file2 = "tofile2"; 257 bool created; 258 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(from_file, &created)); 259 ASSERT_TRUE(created); 260 261 scoped_ptr<FileSystemOperationContext> context; 262 context.reset(NewContext()); 263 ASSERT_EQ(base::PLATFORM_FILE_OK, 264 file_util()->Truncate(context.get(), CreateURL(from_file), 1020)); 265 266 EXPECT_TRUE(FileExists(from_file)); 267 EXPECT_EQ(1020, GetSize(from_file)); 268 269 ASSERT_EQ(base::PLATFORM_FILE_OK, 270 AsyncFileTestHelper::Copy(file_system_context(), 271 CreateURL(from_file), 272 CreateURL(to_file1))); 273 274 context.reset(NewContext()); 275 ASSERT_EQ(base::PLATFORM_FILE_OK, 276 AsyncFileTestHelper::Copy(file_system_context(), 277 CreateURL(from_file), 278 CreateURL(to_file2))); 279 280 EXPECT_TRUE(FileExists(from_file)); 281 EXPECT_EQ(1020, GetSize(from_file)); 282 EXPECT_TRUE(FileExists(to_file1)); 283 EXPECT_EQ(1020, GetSize(to_file1)); 284 EXPECT_TRUE(FileExists(to_file2)); 285 EXPECT_EQ(1020, GetSize(to_file2)); 286 } 287 288 TEST_F(LocalFileUtilTest, CopyDirectory) { 289 const char *from_dir = "fromdir"; 290 const char *from_file = "fromdir/fromfile"; 291 const char *to_dir = "todir"; 292 const char *to_file = "todir/fromfile"; 293 bool created; 294 scoped_ptr<FileSystemOperationContext> context; 295 296 context.reset(NewContext()); 297 ASSERT_EQ(base::PLATFORM_FILE_OK, 298 file_util()->CreateDirectory(context.get(), CreateURL(from_dir), 299 false, false)); 300 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(from_file, &created)); 301 ASSERT_TRUE(created); 302 303 context.reset(NewContext()); 304 ASSERT_EQ(base::PLATFORM_FILE_OK, 305 file_util()->Truncate(context.get(), CreateURL(from_file), 1020)); 306 307 EXPECT_TRUE(DirectoryExists(from_dir)); 308 EXPECT_TRUE(FileExists(from_file)); 309 EXPECT_EQ(1020, GetSize(from_file)); 310 EXPECT_FALSE(DirectoryExists(to_dir)); 311 312 context.reset(NewContext()); 313 ASSERT_EQ(base::PLATFORM_FILE_OK, 314 AsyncFileTestHelper::Copy(file_system_context(), 315 CreateURL(from_dir), CreateURL(to_dir))); 316 317 EXPECT_TRUE(DirectoryExists(from_dir)); 318 EXPECT_TRUE(FileExists(from_file)); 319 EXPECT_EQ(1020, GetSize(from_file)); 320 EXPECT_TRUE(DirectoryExists(to_dir)); 321 EXPECT_TRUE(FileExists(to_file)); 322 EXPECT_EQ(1020, GetSize(to_file)); 323 } 324 325 TEST_F(LocalFileUtilTest, MoveFile) { 326 const char *from_file = "fromfile"; 327 const char *to_file = "tofile"; 328 bool created; 329 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(from_file, &created)); 330 ASSERT_TRUE(created); 331 scoped_ptr<FileSystemOperationContext> context; 332 333 context.reset(NewContext()); 334 ASSERT_EQ(base::PLATFORM_FILE_OK, 335 file_util()->Truncate(context.get(), CreateURL(from_file), 1020)); 336 337 EXPECT_TRUE(FileExists(from_file)); 338 EXPECT_EQ(1020, GetSize(from_file)); 339 340 context.reset(NewContext()); 341 ASSERT_EQ(base::PLATFORM_FILE_OK, 342 AsyncFileTestHelper::Move(file_system_context(), 343 CreateURL(from_file), 344 CreateURL(to_file))); 345 346 EXPECT_FALSE(FileExists(from_file)); 347 EXPECT_TRUE(FileExists(to_file)); 348 EXPECT_EQ(1020, GetSize(to_file)); 349 } 350 351 TEST_F(LocalFileUtilTest, MoveDirectory) { 352 const char *from_dir = "fromdir"; 353 const char *from_file = "fromdir/fromfile"; 354 const char *to_dir = "todir"; 355 const char *to_file = "todir/fromfile"; 356 bool created; 357 scoped_ptr<FileSystemOperationContext> context; 358 359 context.reset(NewContext()); 360 ASSERT_EQ(base::PLATFORM_FILE_OK, 361 file_util()->CreateDirectory(context.get(), CreateURL(from_dir), 362 false, false)); 363 ASSERT_EQ(base::PLATFORM_FILE_OK, EnsureFileExists(from_file, &created)); 364 ASSERT_TRUE(created); 365 366 context.reset(NewContext()); 367 ASSERT_EQ(base::PLATFORM_FILE_OK, 368 file_util()->Truncate(context.get(), CreateURL(from_file), 1020)); 369 370 EXPECT_TRUE(DirectoryExists(from_dir)); 371 EXPECT_TRUE(FileExists(from_file)); 372 EXPECT_EQ(1020, GetSize(from_file)); 373 EXPECT_FALSE(DirectoryExists(to_dir)); 374 375 context.reset(NewContext()); 376 ASSERT_EQ(base::PLATFORM_FILE_OK, 377 AsyncFileTestHelper::Move(file_system_context(), 378 CreateURL(from_dir), 379 CreateURL(to_dir))); 380 381 EXPECT_FALSE(DirectoryExists(from_dir)); 382 EXPECT_TRUE(DirectoryExists(to_dir)); 383 EXPECT_TRUE(FileExists(to_file)); 384 EXPECT_EQ(1020, GetSize(to_file)); 385 } 386 387 } // namespace fileapi 388