• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • 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/file_util.h"
8 #include "base/files/file.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 
BaseFileTest()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 
SetUp()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 
TearDown()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 
ResetHash()84   void ResetHash() {
85     secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
86     memcpy(sha256_hash_, kEmptySha256Hash, crypto::kSHA256Length);
87   }
88 
UpdateHash(const char * data,size_t length)89   void UpdateHash(const char* data, size_t length) {
90     secure_hash_->Update(data, length);
91   }
92 
GetFinalHash()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 
MakeFileWithHash()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 
InitializeFile()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 
AppendDataToFile(const std::string & data)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 
set_expected_data(const std::string & data)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.
CreateTestFile()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.
CreateFileWithName(const base::FilePath & 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 
CurrentSpeedAtTime(base::TimeTicks current_time)184   int64 CurrentSpeedAtTime(base::TimeTicks current_time) {
185     EXPECT_TRUE(base_file_.get());
186     return base_file_->CurrentSpeedAtTime(current_time);
187   }
188 
StartTick()189   base::TimeTicks StartTick() {
190     EXPECT_TRUE(base_file_.get());
191     return base_file_->start_tick_;
192   }
193 
set_expected_error(DownloadInterruptReason err)194   void set_expected_error(DownloadInterruptReason err) {
195     expected_error_ = err;
196   }
197 
198  protected:
199   // BaseClass instance we are testing.
200   scoped_ptr<BaseFile> base_file_;
201 
202   // Temporary directory for renamed downloads.
203   base::ScopedTempDir temp_dir_;
204 
205   // Expect the file to survive deletion of the BaseFile instance.
206   bool expect_file_survives_;
207 
208   // Expect the file to be in progress.
209   bool expect_in_progress_;
210 
211   // Hash calculator.
212   scoped_ptr<crypto::SecureHash> secure_hash_;
213 
214   unsigned char sha256_hash_[crypto::kSHA256Length];
215 
216  private:
217   // Keep track of what data should be saved to the disk file.
218   std::string expected_data_;
219   DownloadInterruptReason expected_error_;
220 
221   // Mock file thread to satisfy debug checks in BaseFile.
222   base::MessageLoop message_loop_;
223   BrowserThreadImpl file_thread_;
224 };
225 
226 // This will initialize the entire array to zero.
227 const unsigned char BaseFileTest::kEmptySha256Hash[] = { 0 };
228 
229 // Test the most basic scenario: just create the object and do a sanity check
230 // on all its accessors. This is actually a case that rarely happens
231 // in production, where we would at least Initialize it.
TEST_F(BaseFileTest,CreateDestroy)232 TEST_F(BaseFileTest, CreateDestroy) {
233   EXPECT_EQ(base::FilePath().value(), base_file_->full_path().value());
234 }
235 
236 // Cancel the download explicitly.
TEST_F(BaseFileTest,Cancel)237 TEST_F(BaseFileTest, Cancel) {
238   ASSERT_TRUE(InitializeFile());
239   EXPECT_TRUE(base::PathExists(base_file_->full_path()));
240   base_file_->Cancel();
241   EXPECT_FALSE(base::PathExists(base_file_->full_path()));
242   EXPECT_NE(base::FilePath().value(), base_file_->full_path().value());
243 }
244 
245 // Write data to the file and detach it, so it doesn't get deleted
246 // automatically when base_file_ is destructed.
TEST_F(BaseFileTest,WriteAndDetach)247 TEST_F(BaseFileTest, WriteAndDetach) {
248   ASSERT_TRUE(InitializeFile());
249   ASSERT_TRUE(AppendDataToFile(kTestData1));
250   base_file_->Finish();
251   base_file_->Detach();
252   expect_file_survives_ = true;
253 }
254 
255 // Write data to the file and detach it, and calculate its sha256 hash.
TEST_F(BaseFileTest,WriteWithHashAndDetach)256 TEST_F(BaseFileTest, WriteWithHashAndDetach) {
257   // Calculate the final hash.
258   ResetHash();
259   UpdateHash(kTestData1, kTestDataLength1);
260   std::string expected_hash = GetFinalHash();
261   std::string expected_hash_hex =
262       base::HexEncode(expected_hash.data(), expected_hash.size());
263 
264   MakeFileWithHash();
265   ASSERT_TRUE(InitializeFile());
266   ASSERT_TRUE(AppendDataToFile(kTestData1));
267   base_file_->Finish();
268 
269   std::string hash;
270   base_file_->GetHash(&hash);
271   EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE",
272             expected_hash_hex);
273   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
274 
275   base_file_->Detach();
276   expect_file_survives_ = true;
277 }
278 
279 // Rename the file after writing to it, then detach.
TEST_F(BaseFileTest,WriteThenRenameAndDetach)280 TEST_F(BaseFileTest, WriteThenRenameAndDetach) {
281   ASSERT_TRUE(InitializeFile());
282 
283   base::FilePath initial_path(base_file_->full_path());
284   EXPECT_TRUE(base::PathExists(initial_path));
285   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
286   EXPECT_FALSE(base::PathExists(new_path));
287 
288   ASSERT_TRUE(AppendDataToFile(kTestData1));
289 
290   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
291   EXPECT_FALSE(base::PathExists(initial_path));
292   EXPECT_TRUE(base::PathExists(new_path));
293 
294   base_file_->Finish();
295   base_file_->Detach();
296   expect_file_survives_ = true;
297 }
298 
299 // Write data to the file once.
TEST_F(BaseFileTest,SingleWrite)300 TEST_F(BaseFileTest, SingleWrite) {
301   ASSERT_TRUE(InitializeFile());
302   ASSERT_TRUE(AppendDataToFile(kTestData1));
303   base_file_->Finish();
304 }
305 
306 // Write data to the file multiple times.
TEST_F(BaseFileTest,MultipleWrites)307 TEST_F(BaseFileTest, MultipleWrites) {
308   ASSERT_TRUE(InitializeFile());
309   ASSERT_TRUE(AppendDataToFile(kTestData1));
310   ASSERT_TRUE(AppendDataToFile(kTestData2));
311   ASSERT_TRUE(AppendDataToFile(kTestData3));
312   std::string hash;
313   EXPECT_FALSE(base_file_->GetHash(&hash));
314   base_file_->Finish();
315 }
316 
317 // Write data to the file once and calculate its sha256 hash.
TEST_F(BaseFileTest,SingleWriteWithHash)318 TEST_F(BaseFileTest, SingleWriteWithHash) {
319   // Calculate the final hash.
320   ResetHash();
321   UpdateHash(kTestData1, kTestDataLength1);
322   std::string expected_hash = GetFinalHash();
323   std::string expected_hash_hex =
324       base::HexEncode(expected_hash.data(), expected_hash.size());
325 
326   MakeFileWithHash();
327   ASSERT_TRUE(InitializeFile());
328   // Can get partial hash states before Finish() is called.
329   EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
330   ASSERT_TRUE(AppendDataToFile(kTestData1));
331   EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
332   base_file_->Finish();
333 
334   std::string hash;
335   base_file_->GetHash(&hash);
336   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
337 }
338 
339 // Write data to the file multiple times and calculate its sha256 hash.
TEST_F(BaseFileTest,MultipleWritesWithHash)340 TEST_F(BaseFileTest, MultipleWritesWithHash) {
341   // Calculate the final hash.
342   ResetHash();
343   UpdateHash(kTestData1, kTestDataLength1);
344   UpdateHash(kTestData2, kTestDataLength2);
345   UpdateHash(kTestData3, kTestDataLength3);
346   std::string expected_hash = GetFinalHash();
347   std::string expected_hash_hex =
348       base::HexEncode(expected_hash.data(), expected_hash.size());
349 
350   std::string hash;
351   MakeFileWithHash();
352   ASSERT_TRUE(InitializeFile());
353   ASSERT_TRUE(AppendDataToFile(kTestData1));
354   ASSERT_TRUE(AppendDataToFile(kTestData2));
355   ASSERT_TRUE(AppendDataToFile(kTestData3));
356   // No hash before Finish() is called.
357   EXPECT_FALSE(base_file_->GetHash(&hash));
358   base_file_->Finish();
359 
360   EXPECT_TRUE(base_file_->GetHash(&hash));
361   EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8",
362             expected_hash_hex);
363   EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
364 }
365 
366 // Write data to the file multiple times, interrupt it, and continue using
367 // another file.  Calculate the resulting combined sha256 hash.
TEST_F(BaseFileTest,MultipleWritesInterruptedWithHash)368 TEST_F(BaseFileTest, MultipleWritesInterruptedWithHash) {
369   // Calculate the final hash.
370   ResetHash();
371   UpdateHash(kTestData1, kTestDataLength1);
372   UpdateHash(kTestData2, kTestDataLength2);
373   UpdateHash(kTestData3, kTestDataLength3);
374   std::string expected_hash = GetFinalHash();
375   std::string expected_hash_hex =
376       base::HexEncode(expected_hash.data(), expected_hash.size());
377 
378   MakeFileWithHash();
379   ASSERT_TRUE(InitializeFile());
380   // Write some data
381   ASSERT_TRUE(AppendDataToFile(kTestData1));
382   ASSERT_TRUE(AppendDataToFile(kTestData2));
383   // Get the hash state and file name.
384   std::string hash_state;
385   hash_state = base_file_->GetHashState();
386   // Finish the file.
387   base_file_->Finish();
388 
389   base::FilePath new_file_path(temp_dir_.path().Append(
390       base::FilePath(FILE_PATH_LITERAL("second_file"))));
391 
392   ASSERT_TRUE(base::CopyFile(base_file_->full_path(), new_file_path));
393 
394   // Create another file
395   BaseFile second_file(new_file_path,
396                        GURL(),
397                        GURL(),
398                        base_file_->bytes_so_far(),
399                        true,
400                        hash_state,
401                        base::File(),
402                        net::BoundNetLog());
403   ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
404             second_file.Initialize(base::FilePath()));
405   std::string data(kTestData3);
406   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
407             second_file.AppendDataToFile(data.data(), data.size()));
408   second_file.Finish();
409 
410   std::string hash;
411   EXPECT_TRUE(second_file.GetHash(&hash));
412   // This will fail until getting the hash state is supported in SecureHash.
413   EXPECT_STREQ(expected_hash_hex.c_str(),
414                base::HexEncode(hash.data(), hash.size()).c_str());
415 }
416 
417 // Rename the file after all writes to it.
TEST_F(BaseFileTest,WriteThenRename)418 TEST_F(BaseFileTest, WriteThenRename) {
419   ASSERT_TRUE(InitializeFile());
420 
421   base::FilePath initial_path(base_file_->full_path());
422   EXPECT_TRUE(base::PathExists(initial_path));
423   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
424   EXPECT_FALSE(base::PathExists(new_path));
425 
426   ASSERT_TRUE(AppendDataToFile(kTestData1));
427 
428   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
429             base_file_->Rename(new_path));
430   EXPECT_FALSE(base::PathExists(initial_path));
431   EXPECT_TRUE(base::PathExists(new_path));
432 
433   base_file_->Finish();
434 }
435 
436 // Rename the file while the download is still in progress.
TEST_F(BaseFileTest,RenameWhileInProgress)437 TEST_F(BaseFileTest, RenameWhileInProgress) {
438   ASSERT_TRUE(InitializeFile());
439 
440   base::FilePath initial_path(base_file_->full_path());
441   EXPECT_TRUE(base::PathExists(initial_path));
442   base::FilePath new_path(temp_dir_.path().AppendASCII("NewFile"));
443   EXPECT_FALSE(base::PathExists(new_path));
444 
445   ASSERT_TRUE(AppendDataToFile(kTestData1));
446 
447   EXPECT_TRUE(base_file_->in_progress());
448   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
449   EXPECT_FALSE(base::PathExists(initial_path));
450   EXPECT_TRUE(base::PathExists(new_path));
451 
452   ASSERT_TRUE(AppendDataToFile(kTestData2));
453 
454   base_file_->Finish();
455 }
456 
457 // Test that a failed rename reports the correct error.
TEST_F(BaseFileTest,RenameWithError)458 TEST_F(BaseFileTest, RenameWithError) {
459   ASSERT_TRUE(InitializeFile());
460 
461   // TestDir is a subdirectory in |temp_dir_| that we will make read-only so
462   // that the rename will fail.
463   base::FilePath test_dir(temp_dir_.path().AppendASCII("TestDir"));
464   ASSERT_TRUE(base::CreateDirectory(test_dir));
465 
466   base::FilePath new_path(test_dir.AppendASCII("TestFile"));
467   EXPECT_FALSE(base::PathExists(new_path));
468 
469   {
470     file_util::PermissionRestorer restore_permissions_for(test_dir);
471     ASSERT_TRUE(file_util::MakeFileUnwritable(test_dir));
472     EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
473               base_file_->Rename(new_path));
474   }
475 
476   base_file_->Finish();
477 }
478 
479 // Test that a failed write reports an error.
TEST_F(BaseFileTest,WriteWithError)480 TEST_F(BaseFileTest, WriteWithError) {
481   base::FilePath path;
482   ASSERT_TRUE(base::CreateTemporaryFile(&path));
483 
484   // Pass a file handle which was opened without the WRITE flag.
485   // This should result in an error when writing.
486   base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
487   base_file_.reset(new BaseFile(path,
488                                 GURL(),
489                                 GURL(),
490                                 0,
491                                 false,
492                                 std::string(),
493                                 file.Pass(),
494                                 net::BoundNetLog()));
495   ASSERT_TRUE(InitializeFile());
496 #if defined(OS_WIN)
497   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
498 #elif defined (OS_POSIX)
499   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
500 #endif
501   ASSERT_FALSE(AppendDataToFile(kTestData1));
502   base_file_->Finish();
503 }
504 
505 // Try to write to uninitialized file.
TEST_F(BaseFileTest,UninitializedFile)506 TEST_F(BaseFileTest, UninitializedFile) {
507   expect_in_progress_ = false;
508   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
509   EXPECT_FALSE(AppendDataToFile(kTestData1));
510 }
511 
512 // Create two |BaseFile|s with the same file, and attempt to write to both.
513 // Overwrite base_file_ with another file with the same name and
514 // non-zero contents, and make sure the last file to close 'wins'.
TEST_F(BaseFileTest,DuplicateBaseFile)515 TEST_F(BaseFileTest, DuplicateBaseFile) {
516   ASSERT_TRUE(InitializeFile());
517 
518   // Create another |BaseFile| referring to the file that |base_file_| owns.
519   CreateFileWithName(base_file_->full_path());
520 
521   ASSERT_TRUE(AppendDataToFile(kTestData1));
522   base_file_->Finish();
523 }
524 
525 // Create a file and append to it.
TEST_F(BaseFileTest,AppendToBaseFile)526 TEST_F(BaseFileTest, AppendToBaseFile) {
527   // Create a new file.
528   base::FilePath existing_file_name = CreateTestFile();
529 
530   set_expected_data(kTestData4);
531 
532   // Use the file we've just created.
533   base_file_.reset(new BaseFile(existing_file_name,
534                                 GURL(),
535                                 GURL(),
536                                 kTestDataLength4,
537                                 false,
538                                 std::string(),
539                                 base::File(),
540                                 net::BoundNetLog()));
541 
542   ASSERT_TRUE(InitializeFile());
543 
544   const base::FilePath file_name = base_file_->full_path();
545   EXPECT_NE(base::FilePath::StringType(), file_name.value());
546 
547   // Write into the file.
548   EXPECT_TRUE(AppendDataToFile(kTestData1));
549 
550   base_file_->Finish();
551   base_file_->Detach();
552   expect_file_survives_ = true;
553 }
554 
555 // Create a read-only file and attempt to write to it.
TEST_F(BaseFileTest,ReadonlyBaseFile)556 TEST_F(BaseFileTest, ReadonlyBaseFile) {
557   // Create a new file.
558   base::FilePath readonly_file_name = CreateTestFile();
559 
560   // Restore permissions to the file when we are done with this test.
561   file_util::PermissionRestorer restore_permissions(readonly_file_name);
562 
563   // Make it read-only.
564   EXPECT_TRUE(file_util::MakeFileUnwritable(readonly_file_name));
565 
566   // Try to overwrite it.
567   base_file_.reset(new BaseFile(readonly_file_name,
568                                 GURL(),
569                                 GURL(),
570                                 0,
571                                 false,
572                                 std::string(),
573                                 base::File(),
574                                 net::BoundNetLog()));
575 
576   expect_in_progress_ = false;
577   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
578   EXPECT_FALSE(InitializeFile());
579 
580   const base::FilePath file_name = base_file_->full_path();
581   EXPECT_NE(base::FilePath::StringType(), file_name.value());
582 
583   // Write into the file.
584   set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
585   EXPECT_FALSE(AppendDataToFile(kTestData1));
586 
587   base_file_->Finish();
588   base_file_->Detach();
589   expect_file_survives_ = true;
590 }
591 
TEST_F(BaseFileTest,IsEmptyHash)592 TEST_F(BaseFileTest, IsEmptyHash) {
593   std::string empty(crypto::kSHA256Length, '\x00');
594   EXPECT_TRUE(BaseFile::IsEmptyHash(empty));
595   std::string not_empty(crypto::kSHA256Length, '\x01');
596   EXPECT_FALSE(BaseFile::IsEmptyHash(not_empty));
597   EXPECT_FALSE(BaseFile::IsEmptyHash(std::string()));
598 
599   std::string also_not_empty = empty;
600   also_not_empty[crypto::kSHA256Length - 1] = '\x01';
601   EXPECT_FALSE(BaseFile::IsEmptyHash(also_not_empty));
602 }
603 
604 // Test that a temporary file is created in the default download directory.
TEST_F(BaseFileTest,CreatedInDefaultDirectory)605 TEST_F(BaseFileTest, CreatedInDefaultDirectory) {
606   ASSERT_TRUE(base_file_->full_path().empty());
607   ASSERT_TRUE(InitializeFile());
608   EXPECT_FALSE(base_file_->full_path().empty());
609 
610   // On Windows, CreateTemporaryFileInDir() will cause a path with short names
611   // to be expanded into a path with long names. Thus temp_dir.path() might not
612   // be a string-wise match to base_file_->full_path().DirName() even though
613   // they are in the same directory.
614   base::FilePath temp_file;
615   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
616   ASSERT_FALSE(temp_file.empty());
617   EXPECT_STREQ(temp_file.DirName().value().c_str(),
618                base_file_->full_path().DirName().value().c_str());
619   base_file_->Finish();
620 }
621 
TEST_F(BaseFileTest,NoDoubleDeleteAfterCancel)622 TEST_F(BaseFileTest, NoDoubleDeleteAfterCancel) {
623   ASSERT_TRUE(InitializeFile());
624   base::FilePath full_path = base_file_->full_path();
625   ASSERT_FALSE(full_path.empty());
626   ASSERT_TRUE(base::PathExists(full_path));
627 
628   base_file_->Cancel();
629   ASSERT_FALSE(base::PathExists(full_path));
630 
631   const char kData[] = "hello";
632   const int kDataLength = static_cast<int>(arraysize(kData) - 1);
633   ASSERT_EQ(kDataLength, base::WriteFile(full_path, kData, kDataLength));
634   // The file that we created here should stick around when the BaseFile is
635   // destroyed during TearDown.
636   expect_file_survives_ = true;
637 }
638 
639 }  // namespace content
640