Home | History | Annotate | Download | only in download
      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 "content/browser/download/base_file.h"
      6 
      7 #include "base/files/file.h"
      8 #include "base/files/file_util.h"
      9 #include "base/files/scoped_temp_dir.h"
     10 #include "base/logging.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/test/test_file_util.h"
     14 #include "content/browser/browser_thread_impl.h"
     15 #include "content/public/browser/download_interrupt_reasons.h"
     16 #include "crypto/secure_hash.h"
     17 #include "crypto/sha2.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 namespace content {
     21 namespace {
     22 
     23 const char kTestData1[] = "Let's write some data to the file!\n";
     24 const char kTestData2[] = "Writing more data.\n";
     25 const char kTestData3[] = "Final line.";
     26 const char kTestData4[] = "supercalifragilisticexpialidocious";
     27 const int kTestDataLength1 = arraysize(kTestData1) - 1;
     28 const int kTestDataLength2 = arraysize(kTestData2) - 1;
     29 const int kTestDataLength3 = arraysize(kTestData3) - 1;
     30 const int kTestDataLength4 = arraysize(kTestData4) - 1;
     31 const int kElapsedTimeSeconds = 5;
     32 const base::TimeDelta kElapsedTimeDelta = base::TimeDelta::FromSeconds(
     33     kElapsedTimeSeconds);
     34 
     35 }  // namespace
     36 
     37 class BaseFileTest : public testing::Test {
     38  public:
     39   static const unsigned char kEmptySha256Hash[crypto::kSHA256Length];
     40 
     41   BaseFileTest()
     42       : expect_file_survives_(false),
     43         expect_in_progress_(true),
     44         expected_error_(DOWNLOAD_INTERRUPT_REASON_NONE),
     45         file_thread_(BrowserThread::FILE, &message_loop_) {
     46   }
     47 
     48   virtual void SetUp() {
     49     ResetHash();
     50     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     51     base_file_.reset(new BaseFile(base::FilePath(),
     52                                   GURL(),
     53                                   GURL(),
     54                                   0,
     55                                   false,
     56                                   std::string(),
     57                                   base::File(),
     58                                   net::BoundNetLog()));
     59   }
     60 
     61   virtual void TearDown() {
     62     EXPECT_FALSE(base_file_->in_progress());
     63     if (!expected_error_) {
     64       EXPECT_EQ(static_cast<int64>(expected_data_.size()),
     65                 base_file_->bytes_so_far());
     66     }
     67 
     68     base::FilePath full_path = base_file_->full_path();
     69 
     70     if (!expected_data_.empty() && !expected_error_) {
     71       // Make sure the data has been properly written to disk.
     72       std::string disk_data;
     73       EXPECT_TRUE(base::ReadFileToString(full_path, &disk_data));
     74       EXPECT_EQ(expected_data_, disk_data);
     75     }
     76 
     77     // Make sure the mock BrowserThread outlives the BaseFile to satisfy
     78     // thread checks inside it.
     79     base_file_.reset();
     80 
     81     EXPECT_EQ(expect_file_survives_, base::PathExists(full_path));
     82   }
     83 
     84   void ResetHash() {
     85     secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
     86     memcpy(sha256_hash_, kEmptySha256Hash, crypto::kSHA256Length);
     87   }
     88 
     89   void UpdateHash(const char* data, size_t length) {
     90     secure_hash_->Update(data, length);
     91   }
     92 
     93   std::string GetFinalHash() {
     94     std::string hash;
     95     secure_hash_->Finish(sha256_hash_, crypto::kSHA256Length);
     96     hash.assign(reinterpret_cast<const char*>(sha256_hash_),
     97                 sizeof(sha256_hash_));
     98     return hash;
     99   }
    100 
    101   void MakeFileWithHash() {
    102     base_file_.reset(new BaseFile(base::FilePath(),
    103                                   GURL(),
    104                                   GURL(),
    105                                   0,
    106                                   true,
    107                                   std::string(),
    108                                   base::File(),
    109                                   net::BoundNetLog()));
    110   }
    111 
    112   bool InitializeFile() {
    113     DownloadInterruptReason result = base_file_->Initialize(temp_dir_.path());
    114     EXPECT_EQ(expected_error_, result);
    115     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
    116   }
    117 
    118   bool AppendDataToFile(const std::string& data) {
    119     EXPECT_EQ(expect_in_progress_, base_file_->in_progress());
    120     DownloadInterruptReason result =
    121         base_file_->AppendDataToFile(data.data(), data.size());
    122     if (result == DOWNLOAD_INTERRUPT_REASON_NONE)
    123       EXPECT_TRUE(expect_in_progress_) << " result = " << result;
    124 
    125     EXPECT_EQ(expected_error_, result);
    126     if (base_file_->in_progress()) {
    127       expected_data_ += data;
    128       if (expected_error_ == DOWNLOAD_INTERRUPT_REASON_NONE) {
    129         EXPECT_EQ(static_cast<int64>(expected_data_.size()),
    130                   base_file_->bytes_so_far());
    131       }
    132     }
    133     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
    134   }
    135 
    136   void set_expected_data(const std::string& data) { expected_data_ = data; }
    137 
    138   // Helper functions.
    139   // Create a file.  Returns the complete file path.
    140   base::FilePath CreateTestFile() {
    141     base::FilePath file_name;
    142     BaseFile file(base::FilePath(),
    143                   GURL(),
    144                   GURL(),
    145                   0,
    146                   false,
    147                   std::string(),
    148                   base::File(),
    149                   net::BoundNetLog());
    150 
    151     EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    152               file.Initialize(temp_dir_.path()));
    153     file_name = file.full_path();
    154     EXPECT_NE(base::FilePath::StringType(), file_name.value());
    155 
    156     EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    157               file.AppendDataToFile(kTestData4, kTestDataLength4));
    158 
    159     // Keep the file from getting deleted when existing_file_name is deleted.
    160     file.Detach();
    161 
    162     return file_name;
    163   }
    164 
    165   // Create a file with the specified file name.
    166   void CreateFileWithName(const base::FilePath& file_name) {
    167     EXPECT_NE(base::FilePath::StringType(), file_name.value());
    168     BaseFile duplicate_file(file_name,
    169                             GURL(),
    170                             GURL(),
    171                             0,
    172                             false,
    173                             std::string(),
    174                             base::File(),
    175                             net::BoundNetLog());
    176     EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    177               duplicate_file.Initialize(temp_dir_.path()));
    178     // Write something into it.
    179     duplicate_file.AppendDataToFile(kTestData4, kTestDataLength4);
    180     // Detach the file so it isn't deleted on destruction of |duplicate_file|.
    181     duplicate_file.Detach();
    182   }
    183 
    184   int64 CurrentSpeedAtTime(base::TimeTicks current_time) {
    185     EXPECT_TRUE(base_file_.get());
    186     return base_file_->CurrentSpeedAtTime(current_time);
    187   }
    188 
    189   base::TimeTicks StartTick() {
    190     EXPECT_TRUE(base_file_.get());
    191     return base_file_->start_tick_;
    192   }
    193 
    194   void set_expected_error(DownloadInterruptReason err) {
    195     expected_error_ = err;
    196   }
    197 
    198   void ExpectPermissionError(DownloadInterruptReason err) {
    199     EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR ||
    200                 err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED)
    201         << "Interrupt reason = " << err;
    202   }
    203 
    204  protected:
    205   // BaseClass instance we are testing.
    206   scoped_ptr<BaseFile> base_file_;
    207 
    208   // Temporary directory for renamed downloads.
    209   base::ScopedTempDir temp_dir_;
    210 
    211   // Expect the file to survive deletion of the BaseFile instance.
    212   bool expect_file_survives_;
    213 
    214   // Expect the file to be in progress.
    215   bool expect_in_progress_;
    216 
    217   // Hash calculator.
    218   scoped_ptr<crypto::SecureHash> secure_hash_;
    219 
    220   unsigned char sha256_hash_[crypto::kSHA256Length];
    221 
    222  private:
    223   // Keep track of what data should be saved to the disk file.
    224   std::string expected_data_;
    225   DownloadInterruptReason expected_error_;
    226 
    227   // Mock file thread to satisfy debug checks in BaseFile.
    228   base::MessageLoop message_loop_;
    229   BrowserThreadImpl file_thread_;
    230 };
    231 
    232 // This will initialize the entire array to zero.
    233 const unsigned char BaseFileTest::kEmptySha256Hash[] = { 0 };
    234 
    235 // Test the most basic scenario: just create the object and do a sanity check
    236 // on all its accessors. This is actually a case that rarely happens
    237 // in production, where we would at least Initialize it.
    238 TEST_F(BaseFileTest, CreateDestroy) {
    239   EXPECT_EQ(base::FilePath().value(), base_file_->full_path().value());
    240 }
    241 
    242 // Cancel the download explicitly.
    243 TEST_F(BaseFileTest, Cancel) {
    244   ASSERT_TRUE(InitializeFile());
    245   EXPECT_TRUE(base::PathExists(base_file_->full_path()));
    246   base_file_->Cancel();
    247   EXPECT_FALSE(base::PathExists(base_file_->full_path()));
    248   EXPECT_NE(base::FilePath().value(), base_file_->full_path().value());
    249 }
    250 
    251 // Write data to the file and detach it, so it doesn't get deleted
    252 // automatically when base_file_ is destructed.
    253 TEST_F(BaseFileTest, WriteAndDetach) {
    254   ASSERT_TRUE(InitializeFile());
    255   ASSERT_TRUE(AppendDataToFile(kTestData1));
    256   base_file_->Finish();
    257   base_file_->Detach();
    258   expect_file_survives_ = true;
    259 }
    260 
    261 // Write data to the file and detach it, and calculate its sha256 hash.
    262 TEST_F(BaseFileTest, WriteWithHashAndDetach) {
    263   // Calculate the final hash.
    264   ResetHash();
    265   UpdateHash(kTestData1, kTestDataLength1);
    266   std::string expected_hash = GetFinalHash();
    267   std::string expected_hash_hex =
    268       base::HexEncode(expected_hash.data(), expected_hash.size());
    269 
    270   MakeFileWithHash();
    271   ASSERT_TRUE(InitializeFile());
    272   ASSERT_TRUE(AppendDataToFile(kTestData1));
    273   base_file_->Finish();
    274 
    275   std::string hash;
    276   base_file_->GetHash(&hash);
    277   EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE",
    278             expected_hash_hex);
    279   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
    280 
    281   base_file_->Detach();
    282   expect_file_survives_ = true;
    283 }
    284 
    285 // Rename the file after writing to it, then detach.
    286 TEST_F(BaseFileTest, WriteThenRenameAndDetach) {
    287   ASSERT_TRUE(InitializeFile());
    288 
    289   base::FilePath initial_path(base_file_->full_path());
    290   EXPECT_TRUE(base::PathExists(initial_path));
    291   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
    292   EXPECT_FALSE(base::PathExists(new_path));
    293 
    294   ASSERT_TRUE(AppendDataToFile(kTestData1));
    295 
    296   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
    297   EXPECT_FALSE(base::PathExists(initial_path));
    298   EXPECT_TRUE(base::PathExists(new_path));
    299 
    300   base_file_->Finish();
    301   base_file_->Detach();
    302   expect_file_survives_ = true;
    303 }
    304 
    305 // Write data to the file once.
    306 TEST_F(BaseFileTest, SingleWrite) {
    307   ASSERT_TRUE(InitializeFile());
    308   ASSERT_TRUE(AppendDataToFile(kTestData1));
    309   base_file_->Finish();
    310 }
    311 
    312 // Write data to the file multiple times.
    313 TEST_F(BaseFileTest, MultipleWrites) {
    314   ASSERT_TRUE(InitializeFile());
    315   ASSERT_TRUE(AppendDataToFile(kTestData1));
    316   ASSERT_TRUE(AppendDataToFile(kTestData2));
    317   ASSERT_TRUE(AppendDataToFile(kTestData3));
    318   std::string hash;
    319   EXPECT_FALSE(base_file_->GetHash(&hash));
    320   base_file_->Finish();
    321 }
    322 
    323 // Write data to the file once and calculate its sha256 hash.
    324 TEST_F(BaseFileTest, SingleWriteWithHash) {
    325   // Calculate the final hash.
    326   ResetHash();
    327   UpdateHash(kTestData1, kTestDataLength1);
    328   std::string expected_hash = GetFinalHash();
    329   std::string expected_hash_hex =
    330       base::HexEncode(expected_hash.data(), expected_hash.size());
    331 
    332   MakeFileWithHash();
    333   ASSERT_TRUE(InitializeFile());
    334   // Can get partial hash states before Finish() is called.
    335   EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
    336   ASSERT_TRUE(AppendDataToFile(kTestData1));
    337   EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
    338   base_file_->Finish();
    339 
    340   std::string hash;
    341   base_file_->GetHash(&hash);
    342   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
    343 }
    344 
    345 // Write data to the file multiple times and calculate its sha256 hash.
    346 TEST_F(BaseFileTest, MultipleWritesWithHash) {
    347   // Calculate the final hash.
    348   ResetHash();
    349   UpdateHash(kTestData1, kTestDataLength1);
    350   UpdateHash(kTestData2, kTestDataLength2);
    351   UpdateHash(kTestData3, kTestDataLength3);
    352   std::string expected_hash = GetFinalHash();
    353   std::string expected_hash_hex =
    354       base::HexEncode(expected_hash.data(), expected_hash.size());
    355 
    356   std::string hash;
    357   MakeFileWithHash();
    358   ASSERT_TRUE(InitializeFile());
    359   ASSERT_TRUE(AppendDataToFile(kTestData1));
    360   ASSERT_TRUE(AppendDataToFile(kTestData2));
    361   ASSERT_TRUE(AppendDataToFile(kTestData3));
    362   // No hash before Finish() is called.
    363   EXPECT_FALSE(base_file_->GetHash(&hash));
    364   base_file_->Finish();
    365 
    366   EXPECT_TRUE(base_file_->GetHash(&hash));
    367   EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8",
    368             expected_hash_hex);
    369   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
    370 }
    371 
    372 // Write data to the file multiple times, interrupt it, and continue using
    373 // another file.  Calculate the resulting combined sha256 hash.
    374 TEST_F(BaseFileTest, MultipleWritesInterruptedWithHash) {
    375   // Calculate the final hash.
    376   ResetHash();
    377   UpdateHash(kTestData1, kTestDataLength1);
    378   UpdateHash(kTestData2, kTestDataLength2);
    379   UpdateHash(kTestData3, kTestDataLength3);
    380   std::string expected_hash = GetFinalHash();
    381   std::string expected_hash_hex =
    382       base::HexEncode(expected_hash.data(), expected_hash.size());
    383 
    384   MakeFileWithHash();
    385   ASSERT_TRUE(InitializeFile());
    386   // Write some data
    387   ASSERT_TRUE(AppendDataToFile(kTestData1));
    388   ASSERT_TRUE(AppendDataToFile(kTestData2));
    389   // Get the hash state and file name.
    390   std::string hash_state;
    391   hash_state = base_file_->GetHashState();
    392   // Finish the file.
    393   base_file_->Finish();
    394 
    395   base::FilePath new_file_path(temp_dir_.path().Append(
    396       base::FilePath(FILE_PATH_LITERAL("second_file"))));
    397 
    398   ASSERT_TRUE(base::CopyFile(base_file_->full_path(), new_file_path));
    399 
    400   // Create another file
    401   BaseFile second_file(new_file_path,
    402                        GURL(),
    403                        GURL(),
    404                        base_file_->bytes_so_far(),
    405                        true,
    406                        hash_state,
    407                        base::File(),
    408                        net::BoundNetLog());
    409   ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    410             second_file.Initialize(base::FilePath()));
    411   std::string data(kTestData3);
    412   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    413             second_file.AppendDataToFile(data.data(), data.size()));
    414   second_file.Finish();
    415 
    416   std::string hash;
    417   EXPECT_TRUE(second_file.GetHash(&hash));
    418   // This will fail until getting the hash state is supported in SecureHash.
    419   EXPECT_STREQ(expected_hash_hex.c_str(),
    420                base::HexEncode(hash.data(), hash.size()).c_str());
    421 }
    422 
    423 // Rename the file after all writes to it.
    424 TEST_F(BaseFileTest, WriteThenRename) {
    425   ASSERT_TRUE(InitializeFile());
    426 
    427   base::FilePath initial_path(base_file_->full_path());
    428   EXPECT_TRUE(base::PathExists(initial_path));
    429   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
    430   EXPECT_FALSE(base::PathExists(new_path));
    431 
    432   ASSERT_TRUE(AppendDataToFile(kTestData1));
    433 
    434   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
    435             base_file_->Rename(new_path));
    436   EXPECT_FALSE(base::PathExists(initial_path));
    437   EXPECT_TRUE(base::PathExists(new_path));
    438 
    439   base_file_->Finish();
    440 }
    441 
    442 // Rename the file while the download is still in progress.
    443 TEST_F(BaseFileTest, RenameWhileInProgress) {
    444   ASSERT_TRUE(InitializeFile());
    445 
    446   base::FilePath initial_path(base_file_->full_path());
    447   EXPECT_TRUE(base::PathExists(initial_path));
    448   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
    449   EXPECT_FALSE(base::PathExists(new_path));
    450 
    451   ASSERT_TRUE(AppendDataToFile(kTestData1));
    452 
    453   EXPECT_TRUE(base_file_->in_progress());
    454   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
    455   EXPECT_FALSE(base::PathExists(initial_path));
    456   EXPECT_TRUE(base::PathExists(new_path));
    457 
    458   ASSERT_TRUE(AppendDataToFile(kTestData2));
    459 
    460   base_file_->Finish();
    461 }
    462 
    463 // Test that a failed rename reports the correct error.
    464 TEST_F(BaseFileTest, RenameWithError) {
    465   ASSERT_TRUE(InitializeFile());
    466 
    467   // TestDir is a subdirectory in |temp_dir_| that we will make read-only so
    468   // that the rename will fail.
    469   base::FilePath test_dir(temp_dir_.path().AppendASCII("TestDir"));
    470   ASSERT_TRUE(base::CreateDirectory(test_dir));
    471 
    472   base::FilePath new_path(test_dir.AppendASCII("TestFile"));
    473   EXPECT_FALSE(base::PathExists(new_path));
    474 
    475   {
    476     base::FilePermissionRestorer restore_permissions_for(test_dir);
    477     ASSERT_TRUE(base::MakeFileUnwritable(test_dir));
    478     ExpectPermissionError(base_file_->Rename(new_path));
    479   }
    480 
    481   base_file_->Finish();
    482 }
    483 
    484 // Test that if a rename fails for an in-progress BaseFile, it remains writeable
    485 // and renameable.
    486 TEST_F(BaseFileTest, RenameWithErrorInProgress) {
    487   ASSERT_TRUE(InitializeFile());
    488 
    489   base::FilePath test_dir(temp_dir_.path().AppendASCII("TestDir"));
    490   ASSERT_TRUE(base::CreateDirectory(test_dir));
    491 
    492   base::FilePath new_path(test_dir.AppendASCII("TestFile"));
    493   EXPECT_FALSE(base::PathExists(new_path));
    494 
    495   // Write some data to start with.
    496   ASSERT_TRUE(AppendDataToFile(kTestData1));
    497   ASSERT_TRUE(base_file_->in_progress());
    498 
    499   base::FilePath old_path = base_file_->full_path();
    500 
    501   {
    502     base::FilePermissionRestorer restore_permissions_for(test_dir);
    503     ASSERT_TRUE(base::MakeFileUnwritable(test_dir));
    504     ExpectPermissionError(base_file_->Rename(new_path));
    505 
    506     // The file should still be open and we should be able to continue writing
    507     // to it.
    508     ASSERT_TRUE(base_file_->in_progress());
    509     ASSERT_TRUE(AppendDataToFile(kTestData2));
    510     ASSERT_EQ(old_path.value(), base_file_->full_path().value());
    511 
    512     // Try to rename again, just for kicks. It should still fail.
    513     ExpectPermissionError(base_file_->Rename(new_path));
    514   }
    515 
    516   // Now that TestDir is writeable again, we should be able to successfully
    517   // rename the file.
    518   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
    519   ASSERT_EQ(new_path.value(), base_file_->full_path().value());
    520   ASSERT_TRUE(AppendDataToFile(kTestData3));
    521 
    522   base_file_->Finish();
    523 
    524   // The contents of the file should be intact.
    525   std::string file_contents;
    526   std::string expected_contents(kTestData1);
    527   expected_contents += kTestData2;
    528   expected_contents += kTestData3;
    529   ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
    530   EXPECT_EQ(expected_contents, file_contents);
    531 }
    532 
    533 // Test that a failed write reports an error.
    534 TEST_F(BaseFileTest, WriteWithError) {
    535   base::FilePath path;
    536   ASSERT_TRUE(base::CreateTemporaryFile(&path));
    537 
    538   // Pass a file handle which was opened without the WRITE flag.
    539   // This should result in an error when writing.
    540   base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
    541   base_file_.reset(new BaseFile(path,
    542                                 GURL(),
    543                                 GURL(),
    544                                 0,
    545                                 false,
    546                                 std::string(),
    547                                 file.Pass(),
    548                                 net::BoundNetLog()));
    549   ASSERT_TRUE(InitializeFile());
    550 #if defined(OS_WIN)
    551   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
    552 #elif defined (OS_POSIX)
    553   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    554 #endif
    555   ASSERT_FALSE(AppendDataToFile(kTestData1));
    556   base_file_->Finish();
    557 }
    558 
    559 // Try to write to uninitialized file.
    560 TEST_F(BaseFileTest, UninitializedFile) {
    561   expect_in_progress_ = false;
    562   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    563   EXPECT_FALSE(AppendDataToFile(kTestData1));
    564 }
    565 
    566 // Create two |BaseFile|s with the same file, and attempt to write to both.
    567 // Overwrite base_file_ with another file with the same name and
    568 // non-zero contents, and make sure the last file to close 'wins'.
    569 TEST_F(BaseFileTest, DuplicateBaseFile) {
    570   ASSERT_TRUE(InitializeFile());
    571 
    572   // Create another |BaseFile| referring to the file that |base_file_| owns.
    573   CreateFileWithName(base_file_->full_path());
    574 
    575   ASSERT_TRUE(AppendDataToFile(kTestData1));
    576   base_file_->Finish();
    577 }
    578 
    579 // Create a file and append to it.
    580 TEST_F(BaseFileTest, AppendToBaseFile) {
    581   // Create a new file.
    582   base::FilePath existing_file_name = CreateTestFile();
    583 
    584   set_expected_data(kTestData4);
    585 
    586   // Use the file we've just created.
    587   base_file_.reset(new BaseFile(existing_file_name,
    588                                 GURL(),
    589                                 GURL(),
    590                                 kTestDataLength4,
    591                                 false,
    592                                 std::string(),
    593                                 base::File(),
    594                                 net::BoundNetLog()));
    595 
    596   ASSERT_TRUE(InitializeFile());
    597 
    598   const base::FilePath file_name = base_file_->full_path();
    599   EXPECT_NE(base::FilePath::StringType(), file_name.value());
    600 
    601   // Write into the file.
    602   EXPECT_TRUE(AppendDataToFile(kTestData1));
    603 
    604   base_file_->Finish();
    605   base_file_->Detach();
    606   expect_file_survives_ = true;
    607 }
    608 
    609 // Create a read-only file and attempt to write to it.
    610 TEST_F(BaseFileTest, ReadonlyBaseFile) {
    611   // Create a new file.
    612   base::FilePath readonly_file_name = CreateTestFile();
    613 
    614   // Restore permissions to the file when we are done with this test.
    615   base::FilePermissionRestorer restore_permissions(readonly_file_name);
    616 
    617   // Make it read-only.
    618   EXPECT_TRUE(base::MakeFileUnwritable(readonly_file_name));
    619 
    620   // Try to overwrite it.
    621   base_file_.reset(new BaseFile(readonly_file_name,
    622                                 GURL(),
    623                                 GURL(),
    624                                 0,
    625                                 false,
    626                                 std::string(),
    627                                 base::File(),
    628                                 net::BoundNetLog()));
    629 
    630   expect_in_progress_ = false;
    631   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
    632   EXPECT_FALSE(InitializeFile());
    633 
    634   const base::FilePath file_name = base_file_->full_path();
    635   EXPECT_NE(base::FilePath::StringType(), file_name.value());
    636 
    637   // Write into the file.
    638   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
    639   EXPECT_FALSE(AppendDataToFile(kTestData1));
    640 
    641   base_file_->Finish();
    642   base_file_->Detach();
    643   expect_file_survives_ = true;
    644 }
    645 
    646 TEST_F(BaseFileTest, IsEmptyHash) {
    647   std::string empty(crypto::kSHA256Length, '\x00');
    648   EXPECT_TRUE(BaseFile::IsEmptyHash(empty));
    649   std::string not_empty(crypto::kSHA256Length, '\x01');
    650   EXPECT_FALSE(BaseFile::IsEmptyHash(not_empty));
    651   EXPECT_FALSE(BaseFile::IsEmptyHash(std::string()));
    652 
    653   std::string also_not_empty = empty;
    654   also_not_empty[crypto::kSHA256Length - 1] = '\x01';
    655   EXPECT_FALSE(BaseFile::IsEmptyHash(also_not_empty));
    656 }
    657 
    658 // Test that a temporary file is created in the default download directory.
    659 TEST_F(BaseFileTest, CreatedInDefaultDirectory) {
    660   ASSERT_TRUE(base_file_->full_path().empty());
    661   ASSERT_TRUE(InitializeFile());
    662   EXPECT_FALSE(base_file_->full_path().empty());
    663 
    664   // On Windows, CreateTemporaryFileInDir() will cause a path with short names
    665   // to be expanded into a path with long names. Thus temp_dir.path() might not
    666   // be a string-wise match to base_file_->full_path().DirName() even though
    667   // they are in the same directory.
    668   base::FilePath temp_file;
    669   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
    670   ASSERT_FALSE(temp_file.empty());
    671   EXPECT_STREQ(temp_file.DirName().value().c_str(),
    672                base_file_->full_path().DirName().value().c_str());
    673   base_file_->Finish();
    674 }
    675 
    676 TEST_F(BaseFileTest, NoDoubleDeleteAfterCancel) {
    677   ASSERT_TRUE(InitializeFile());
    678   base::FilePath full_path = base_file_->full_path();
    679   ASSERT_FALSE(full_path.empty());
    680   ASSERT_TRUE(base::PathExists(full_path));
    681 
    682   base_file_->Cancel();
    683   ASSERT_FALSE(base::PathExists(full_path));
    684 
    685   const char kData[] = "hello";
    686   const int kDataLength = static_cast<int>(arraysize(kData) - 1);
    687   ASSERT_EQ(kDataLength, base::WriteFile(full_path, kData, kDataLength));
    688   // The file that we created here should stick around when the BaseFile is
    689   // destroyed during TearDown.
    690   expect_file_survives_ = true;
    691 }
    692 
    693 }  // namespace content
    694