Home | History | Annotate | Download | only in files
      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 "base/files/file_util_proxy.h"
      6 
      7 #include <map>
      8 
      9 #include "base/bind.h"
     10 #include "base/file_util.h"
     11 #include "base/files/scoped_temp_dir.h"
     12 #include "base/logging.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/platform_file.h"
     16 #include "base/threading/thread.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace base {
     20 
     21 class FileUtilProxyTest : public testing::Test {
     22  public:
     23   FileUtilProxyTest()
     24       : message_loop_(MessageLoop::TYPE_IO),
     25         file_thread_("FileUtilProxyTestFileThread"),
     26         error_(PLATFORM_FILE_OK),
     27         created_(false),
     28         file_(kInvalidPlatformFileValue),
     29         bytes_written_(-1),
     30         weak_factory_(this) {}
     31 
     32   virtual void SetUp() OVERRIDE {
     33     ASSERT_TRUE(dir_.CreateUniqueTempDir());
     34     ASSERT_TRUE(file_thread_.Start());
     35   }
     36 
     37   virtual void TearDown() OVERRIDE {
     38     if (file_ != kInvalidPlatformFileValue)
     39       ClosePlatformFile(file_);
     40   }
     41 
     42   void DidFinish(PlatformFileError error) {
     43     error_ = error;
     44     MessageLoop::current()->QuitWhenIdle();
     45   }
     46 
     47   void DidCreateOrOpen(PlatformFileError error,
     48                        PassPlatformFile file,
     49                        bool created) {
     50     error_ = error;
     51     file_ = file.ReleaseValue();
     52     created_ = created;
     53     MessageLoop::current()->QuitWhenIdle();
     54   }
     55 
     56   void DidCreateTemporary(PlatformFileError error,
     57                           PassPlatformFile file,
     58                           const FilePath& path) {
     59     error_ = error;
     60     file_ = file.ReleaseValue();
     61     path_ = path;
     62     MessageLoop::current()->QuitWhenIdle();
     63   }
     64 
     65   void DidGetFileInfo(PlatformFileError error,
     66                       const PlatformFileInfo& file_info) {
     67     error_ = error;
     68     file_info_ = file_info;
     69     MessageLoop::current()->QuitWhenIdle();
     70   }
     71 
     72   void DidRead(PlatformFileError error,
     73                const char* data,
     74                int bytes_read) {
     75     error_ = error;
     76     buffer_.resize(bytes_read);
     77     memcpy(&buffer_[0], data, bytes_read);
     78     MessageLoop::current()->QuitWhenIdle();
     79   }
     80 
     81   void DidWrite(PlatformFileError error,
     82                 int bytes_written) {
     83     error_ = error;
     84     bytes_written_ = bytes_written;
     85     MessageLoop::current()->QuitWhenIdle();
     86   }
     87 
     88  protected:
     89   PlatformFile GetTestPlatformFile(int flags) {
     90     if (file_ != kInvalidPlatformFileValue)
     91       return file_;
     92     bool created;
     93     PlatformFileError error;
     94     file_ = CreatePlatformFile(test_path(), flags, &created, &error);
     95     EXPECT_EQ(PLATFORM_FILE_OK, error);
     96     EXPECT_NE(kInvalidPlatformFileValue, file_);
     97     return file_;
     98   }
     99 
    100   TaskRunner* file_task_runner() const {
    101     return file_thread_.message_loop_proxy().get();
    102   }
    103   const FilePath& test_dir_path() const { return dir_.path(); }
    104   const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
    105 
    106   MessageLoop message_loop_;
    107   Thread file_thread_;
    108 
    109   ScopedTempDir dir_;
    110   PlatformFileError error_;
    111   bool created_;
    112   PlatformFile file_;
    113   FilePath path_;
    114   PlatformFileInfo file_info_;
    115   std::vector<char> buffer_;
    116   int bytes_written_;
    117   WeakPtrFactory<FileUtilProxyTest> weak_factory_;
    118 };
    119 
    120 TEST_F(FileUtilProxyTest, CreateOrOpen_Create) {
    121   FileUtilProxy::CreateOrOpen(
    122       file_task_runner(),
    123       test_path(),
    124       PLATFORM_FILE_CREATE | PLATFORM_FILE_READ,
    125       Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
    126   MessageLoop::current()->Run();
    127 
    128   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    129   EXPECT_TRUE(created_);
    130   EXPECT_NE(kInvalidPlatformFileValue, file_);
    131   EXPECT_TRUE(PathExists(test_path()));
    132 }
    133 
    134 TEST_F(FileUtilProxyTest, CreateOrOpen_Open) {
    135   // Creates a file.
    136   file_util::WriteFile(test_path(), NULL, 0);
    137   ASSERT_TRUE(PathExists(test_path()));
    138 
    139   // Opens the created file.
    140   FileUtilProxy::CreateOrOpen(
    141       file_task_runner(),
    142       test_path(),
    143       PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
    144       Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
    145   MessageLoop::current()->Run();
    146 
    147   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    148   EXPECT_FALSE(created_);
    149   EXPECT_NE(kInvalidPlatformFileValue, file_);
    150 }
    151 
    152 TEST_F(FileUtilProxyTest, CreateOrOpen_OpenNonExistent) {
    153   FileUtilProxy::CreateOrOpen(
    154       file_task_runner(),
    155       test_path(),
    156       PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
    157       Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
    158   MessageLoop::current()->Run();
    159   EXPECT_EQ(PLATFORM_FILE_ERROR_NOT_FOUND, error_);
    160   EXPECT_FALSE(created_);
    161   EXPECT_EQ(kInvalidPlatformFileValue, file_);
    162   EXPECT_FALSE(PathExists(test_path()));
    163 }
    164 
    165 TEST_F(FileUtilProxyTest, Close) {
    166   // Creates a file.
    167   PlatformFile file = GetTestPlatformFile(
    168       PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
    169 
    170 #if defined(OS_WIN)
    171   // This fails on Windows if the file is not closed.
    172   EXPECT_FALSE(base::Move(test_path(),
    173                                test_dir_path().AppendASCII("new")));
    174 #endif
    175 
    176   FileUtilProxy::Close(
    177       file_task_runner(),
    178       file,
    179       Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
    180   MessageLoop::current()->Run();
    181   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    182 
    183   // Now it should pass on all platforms.
    184   EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
    185 }
    186 
    187 TEST_F(FileUtilProxyTest, CreateTemporary) {
    188   FileUtilProxy::CreateTemporary(
    189       file_task_runner(), 0 /* additional_file_flags */,
    190       Bind(&FileUtilProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
    191   MessageLoop::current()->Run();
    192   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    193   EXPECT_TRUE(PathExists(path_));
    194   EXPECT_NE(kInvalidPlatformFileValue, file_);
    195 
    196   // The file should be writable.
    197 #if defined(OS_WIN)
    198   HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    199   OVERLAPPED overlapped = {0};
    200   overlapped.hEvent = hEvent;
    201   DWORD bytes_written;
    202   if (!::WriteFile(file_, "test", 4, &bytes_written, &overlapped)) {
    203     // Temporary file is created with ASYNC flag, so WriteFile may return 0
    204     // with ERROR_IO_PENDING.
    205     EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
    206     GetOverlappedResult(file_, &overlapped, &bytes_written, TRUE);
    207   }
    208   EXPECT_EQ(4, bytes_written);
    209 #else
    210   // On POSIX ASYNC flag does not affect synchronous read/write behavior.
    211   EXPECT_EQ(4, WritePlatformFile(file_, 0, "test", 4));
    212 #endif
    213   EXPECT_TRUE(ClosePlatformFile(file_));
    214   file_ = kInvalidPlatformFileValue;
    215 
    216   // Make sure the written data can be read from the returned path.
    217   std::string data;
    218   EXPECT_TRUE(file_util::ReadFileToString(path_, &data));
    219   EXPECT_EQ("test", data);
    220 
    221   // Make sure we can & do delete the created file to prevent leaks on the bots.
    222   EXPECT_TRUE(base::DeleteFile(path_, false));
    223 }
    224 
    225 TEST_F(FileUtilProxyTest, GetFileInfo_File) {
    226   // Setup.
    227   ASSERT_EQ(4, file_util::WriteFile(test_path(), "test", 4));
    228   PlatformFileInfo expected_info;
    229   file_util::GetFileInfo(test_path(), &expected_info);
    230 
    231   // Run.
    232   FileUtilProxy::GetFileInfo(
    233       file_task_runner(),
    234       test_path(),
    235       Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
    236   MessageLoop::current()->Run();
    237 
    238   // Verify.
    239   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    240   EXPECT_EQ(expected_info.size, file_info_.size);
    241   EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
    242   EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
    243   EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
    244   EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
    245   EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
    246 }
    247 
    248 TEST_F(FileUtilProxyTest, GetFileInfo_Directory) {
    249   // Setup.
    250   ASSERT_TRUE(file_util::CreateDirectory(test_path()));
    251   PlatformFileInfo expected_info;
    252   file_util::GetFileInfo(test_path(), &expected_info);
    253 
    254   // Run.
    255   FileUtilProxy::GetFileInfo(
    256       file_task_runner(),
    257       test_path(),
    258       Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
    259   MessageLoop::current()->Run();
    260 
    261   // Verify.
    262   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    263   EXPECT_EQ(expected_info.size, file_info_.size);
    264   EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
    265   EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
    266   EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
    267   EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
    268   EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
    269 }
    270 
    271 TEST_F(FileUtilProxyTest, Read) {
    272   // Setup.
    273   const char expected_data[] = "bleh";
    274   int expected_bytes = arraysize(expected_data);
    275   ASSERT_EQ(expected_bytes,
    276             file_util::WriteFile(test_path(), expected_data, expected_bytes));
    277 
    278   // Run.
    279   FileUtilProxy::Read(
    280       file_task_runner(),
    281       GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_READ),
    282       0,  // offset
    283       128,
    284       Bind(&FileUtilProxyTest::DidRead, weak_factory_.GetWeakPtr()));
    285   MessageLoop::current()->Run();
    286 
    287   // Verify.
    288   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    289   EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
    290   for (size_t i = 0; i < buffer_.size(); ++i) {
    291     EXPECT_EQ(expected_data[i], buffer_[i]);
    292   }
    293 }
    294 
    295 TEST_F(FileUtilProxyTest, WriteAndFlush) {
    296   const char data[] = "foo!";
    297   int data_bytes = ARRAYSIZE_UNSAFE(data);
    298   PlatformFile file = GetTestPlatformFile(
    299       PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
    300 
    301   FileUtilProxy::Write(
    302       file_task_runner(),
    303       file,
    304       0,  // offset
    305       data,
    306       data_bytes,
    307       Bind(&FileUtilProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
    308   MessageLoop::current()->Run();
    309   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    310   EXPECT_EQ(data_bytes, bytes_written_);
    311 
    312   // Flush the written data.  (So that the following read should always
    313   // succeed.  On some platforms it may work with or without this flush.)
    314   FileUtilProxy::Flush(
    315       file_task_runner(),
    316       file,
    317       Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
    318   MessageLoop::current()->Run();
    319   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    320 
    321   // Verify the written data.
    322   char buffer[10];
    323   EXPECT_EQ(data_bytes, file_util::ReadFile(test_path(), buffer, data_bytes));
    324   for (int i = 0; i < data_bytes; ++i) {
    325     EXPECT_EQ(data[i], buffer[i]);
    326   }
    327 }
    328 
    329 TEST_F(FileUtilProxyTest, Touch) {
    330   Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
    331   Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
    332 
    333   FileUtilProxy::Touch(
    334       file_task_runner(),
    335       GetTestPlatformFile(PLATFORM_FILE_CREATE |
    336                           PLATFORM_FILE_WRITE |
    337                           PLATFORM_FILE_WRITE_ATTRIBUTES),
    338       last_accessed_time,
    339       last_modified_time,
    340       Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
    341   MessageLoop::current()->Run();
    342   EXPECT_EQ(PLATFORM_FILE_OK, error_);
    343 
    344   PlatformFileInfo info;
    345   file_util::GetFileInfo(test_path(), &info);
    346 
    347   // The returned values may only have the seconds precision, so we cast
    348   // the double values to int here.
    349   EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
    350             static_cast<int>(info.last_modified.ToDoubleT()));
    351   EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
    352             static_cast<int>(info.last_accessed.ToDoubleT()));
    353 }
    354 
    355 TEST_F(FileUtilProxyTest, Truncate_Shrink) {
    356   // Setup.
    357   const char kTestData[] = "0123456789";
    358   ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
    359   PlatformFileInfo info;
    360   file_util::GetFileInfo(test_path(), &info);
    361   ASSERT_EQ(10, info.size);
    362 
    363   // Run.
    364   FileUtilProxy::Truncate(
    365       file_task_runner(),
    366       GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
    367       7,
    368       Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
    369   MessageLoop::current()->Run();
    370 
    371   // Verify.
    372   file_util::GetFileInfo(test_path(), &info);
    373   ASSERT_EQ(7, info.size);
    374 
    375   char buffer[7];
    376   EXPECT_EQ(7, file_util::ReadFile(test_path(), buffer, 7));
    377   int i = 0;
    378   for (; i < 7; ++i)
    379     EXPECT_EQ(kTestData[i], buffer[i]);
    380 }
    381 
    382 TEST_F(FileUtilProxyTest, Truncate_Expand) {
    383   // Setup.
    384   const char kTestData[] = "9876543210";
    385   ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
    386   PlatformFileInfo info;
    387   file_util::GetFileInfo(test_path(), &info);
    388   ASSERT_EQ(10, info.size);
    389 
    390   // Run.
    391   FileUtilProxy::Truncate(
    392       file_task_runner(),
    393       GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
    394       53,
    395       Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
    396   MessageLoop::current()->Run();
    397 
    398   // Verify.
    399   file_util::GetFileInfo(test_path(), &info);
    400   ASSERT_EQ(53, info.size);
    401 
    402   char buffer[53];
    403   EXPECT_EQ(53, file_util::ReadFile(test_path(), buffer, 53));
    404   int i = 0;
    405   for (; i < 10; ++i)
    406     EXPECT_EQ(kTestData[i], buffer[i]);
    407   for (; i < 53; ++i)
    408     EXPECT_EQ(0, buffer[i]);
    409 }
    410 
    411 }  // namespace base
    412