Home | History | Annotate | Download | only in fileapi
      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