1// Copyright (c) 2011 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/file_util.h" 6#include "base/memory/scoped_temp_dir.h" 7#include "base/message_loop.h" 8#include "base/string_number_conversions.h" 9#include "chrome/browser/download/base_file.h" 10#include "content/browser/browser_thread.h" 11#include "net/base/file_stream.h" 12#include "testing/gtest/include/gtest/gtest.h" 13 14namespace { 15 16const char kTestData1[] = "Let's write some data to the file!\n"; 17const char kTestData2[] = "Writing more data.\n"; 18const char kTestData3[] = "Final line."; 19 20class BaseFileTest : public testing::Test { 21 public: 22 BaseFileTest() 23 : expect_file_survives_(false), 24 file_thread_(BrowserThread::FILE, &message_loop_) { 25 } 26 27 virtual void SetUp() { 28 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 29 base_file_.reset( 30 new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_)); 31 } 32 33 virtual void TearDown() { 34 EXPECT_FALSE(base_file_->in_progress()); 35 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 36 base_file_->bytes_so_far()); 37 38 FilePath full_path = base_file_->full_path(); 39 40 if (!expected_data_.empty()) { 41 // Make sure the data has been properly written to disk. 42 std::string disk_data; 43 EXPECT_TRUE(file_util::ReadFileToString(full_path, &disk_data)); 44 EXPECT_EQ(expected_data_, disk_data); 45 } 46 47 // Make sure the mock BrowserThread outlives the BaseFile to satisfy 48 // thread checks inside it. 49 base_file_.reset(); 50 51 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); 52 } 53 54 void AppendDataToFile(const std::string& data) { 55 ASSERT_TRUE(base_file_->in_progress()); 56 base_file_->AppendDataToFile(data.data(), data.size()); 57 expected_data_ += data; 58 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 59 base_file_->bytes_so_far()); 60 } 61 62 protected: 63 linked_ptr<net::FileStream> file_stream_; 64 65 // BaseClass instance we are testing. 66 scoped_ptr<BaseFile> base_file_; 67 68 // Temporary directory for renamed downloads. 69 ScopedTempDir temp_dir_; 70 71 // Expect the file to survive deletion of the BaseFile instance. 72 bool expect_file_survives_; 73 74 private: 75 // Keep track of what data should be saved to the disk file. 76 std::string expected_data_; 77 78 // Mock file thread to satisfy debug checks in BaseFile. 79 MessageLoop message_loop_; 80 BrowserThread file_thread_; 81}; 82 83// Test the most basic scenario: just create the object and do a sanity check 84// on all its accessors. This is actually a case that rarely happens 85// in production, where we would at least Initialize it. 86TEST_F(BaseFileTest, CreateDestroy) { 87 EXPECT_EQ(FilePath().value(), base_file_->full_path().value()); 88} 89 90// Cancel the download explicitly. 91TEST_F(BaseFileTest, Cancel) { 92 ASSERT_TRUE(base_file_->Initialize(false)); 93 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); 94 base_file_->Cancel(); 95 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); 96 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); 97} 98 99// Write data to the file and detach it, so it doesn't get deleted 100// automatically when base_file_ is destructed. 101TEST_F(BaseFileTest, WriteAndDetach) { 102 ASSERT_TRUE(base_file_->Initialize(false)); 103 AppendDataToFile(kTestData1); 104 base_file_->Finish(); 105 base_file_->Detach(); 106 expect_file_survives_ = true; 107} 108 109// Write data to the file and detach it, and calculate its sha256 hash. 110TEST_F(BaseFileTest, WriteWithHashAndDetach) { 111 ASSERT_TRUE(base_file_->Initialize(true)); 112 AppendDataToFile(kTestData1); 113 base_file_->Finish(); 114 115 std::string hash; 116 base_file_->GetSha256Hash(&hash); 117 EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", 118 base::HexEncode(hash.data(), hash.size())); 119 120 base_file_->Detach(); 121 expect_file_survives_ = true; 122} 123 124// Rename the file after writing to it, then detach. 125TEST_F(BaseFileTest, WriteThenRenameAndDetach) { 126 ASSERT_TRUE(base_file_->Initialize(false)); 127 128 FilePath initial_path(base_file_->full_path()); 129 EXPECT_TRUE(file_util::PathExists(initial_path)); 130 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 131 EXPECT_FALSE(file_util::PathExists(new_path)); 132 133 AppendDataToFile(kTestData1); 134 135 EXPECT_TRUE(base_file_->Rename(new_path)); 136 EXPECT_FALSE(file_util::PathExists(initial_path)); 137 EXPECT_TRUE(file_util::PathExists(new_path)); 138 139 base_file_->Finish(); 140 base_file_->Detach(); 141 expect_file_survives_ = true; 142} 143 144// Write data to the file once. 145TEST_F(BaseFileTest, SingleWrite) { 146 ASSERT_TRUE(base_file_->Initialize(false)); 147 AppendDataToFile(kTestData1); 148 base_file_->Finish(); 149} 150 151// Write data to the file multiple times. 152TEST_F(BaseFileTest, MultipleWrites) { 153 ASSERT_TRUE(base_file_->Initialize(false)); 154 AppendDataToFile(kTestData1); 155 AppendDataToFile(kTestData2); 156 AppendDataToFile(kTestData3); 157 std::string hash; 158 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); 159 base_file_->Finish(); 160} 161 162// Write data to the file once and calculate its sha256 hash. 163TEST_F(BaseFileTest, SingleWriteWithHash) { 164 ASSERT_TRUE(base_file_->Initialize(true)); 165 AppendDataToFile(kTestData1); 166 base_file_->Finish(); 167 168 std::string hash; 169 base_file_->GetSha256Hash(&hash); 170 EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", 171 base::HexEncode(hash.data(), hash.size())); 172} 173 174// Write data to the file multiple times and calculate its sha256 hash. 175TEST_F(BaseFileTest, MultipleWritesWithHash) { 176 std::string hash; 177 178 ASSERT_TRUE(base_file_->Initialize(true)); 179 AppendDataToFile(kTestData1); 180 AppendDataToFile(kTestData2); 181 AppendDataToFile(kTestData3); 182 // no hash before Finish() is called either. 183 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); 184 base_file_->Finish(); 185 186 EXPECT_TRUE(base_file_->GetSha256Hash(&hash)); 187 EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8", 188 base::HexEncode(hash.data(), hash.size())); 189} 190 191// Rename the file after all writes to it. 192TEST_F(BaseFileTest, WriteThenRename) { 193 ASSERT_TRUE(base_file_->Initialize(false)); 194 195 FilePath initial_path(base_file_->full_path()); 196 EXPECT_TRUE(file_util::PathExists(initial_path)); 197 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 198 EXPECT_FALSE(file_util::PathExists(new_path)); 199 200 AppendDataToFile(kTestData1); 201 202 EXPECT_TRUE(base_file_->Rename(new_path)); 203 EXPECT_FALSE(file_util::PathExists(initial_path)); 204 EXPECT_TRUE(file_util::PathExists(new_path)); 205 206 base_file_->Finish(); 207} 208 209// Rename the file while the download is still in progress. 210TEST_F(BaseFileTest, RenameWhileInProgress) { 211 ASSERT_TRUE(base_file_->Initialize(false)); 212 213 FilePath initial_path(base_file_->full_path()); 214 EXPECT_TRUE(file_util::PathExists(initial_path)); 215 FilePath new_path(temp_dir_.path().AppendASCII("NewFile")); 216 EXPECT_FALSE(file_util::PathExists(new_path)); 217 218 AppendDataToFile(kTestData1); 219 220 EXPECT_TRUE(base_file_->in_progress()); 221 EXPECT_TRUE(base_file_->Rename(new_path)); 222 EXPECT_FALSE(file_util::PathExists(initial_path)); 223 EXPECT_TRUE(file_util::PathExists(new_path)); 224 225 AppendDataToFile(kTestData2); 226 227 base_file_->Finish(); 228} 229 230} // namespace 231