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