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
20namespace content {
21namespace {
22
23const char kTestData1[] = "Let's write some data to the file!\n";
24const char kTestData2[] = "Writing more data.\n";
25const char kTestData3[] = "Final line.";
26const char kTestData4[] = "supercalifragilisticexpialidocious";
27const int kTestDataLength1 = arraysize(kTestData1) - 1;
28const int kTestDataLength2 = arraysize(kTestData2) - 1;
29const int kTestDataLength3 = arraysize(kTestData3) - 1;
30const int kTestDataLength4 = arraysize(kTestData4) - 1;
31const int kElapsedTimeSeconds = 5;
32const base::TimeDelta kElapsedTimeDelta = base::TimeDelta::FromSeconds(
33    kElapsedTimeSeconds);
34
35}  // namespace
36
37class 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.
233const 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.
238TEST_F(BaseFileTest, CreateDestroy) {
239  EXPECT_EQ(base::FilePath().value(), base_file_->full_path().value());
240}
241
242// Cancel the download explicitly.
243TEST_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.
253TEST_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.
262TEST_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.
286TEST_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.
306TEST_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.
313TEST_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.
324TEST_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.
346TEST_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.
374TEST_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.
424TEST_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.
443TEST_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.
464TEST_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.
486TEST_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.
534TEST_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.
560TEST_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'.
569TEST_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.
580TEST_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.
610TEST_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
646TEST_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.
659TEST_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
676TEST_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