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