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