OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
6 #include "base/message_loop.h" | 6 #include "base/message_loop.h" |
7 #include "base/scoped_temp_dir.h" | 7 #include "base/scoped_temp_dir.h" |
8 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
9 #include "chrome/browser/download/download_util.h" | |
9 #include "content/browser/browser_thread.h" | 10 #include "content/browser/browser_thread.h" |
10 #include "content/browser/download/base_file.h" | 11 #include "content/browser/download/base_file.h" |
11 #include "net/base/file_stream.h" | 12 #include "net/base/file_stream.h" |
13 #include "net/base/net_errors.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
13 | 15 |
14 namespace { | 16 namespace { |
15 | 17 |
18 class MockFileStream : public net::FileStream { | |
19 public: | |
20 MockFileStream() : forced_error_(0) {} | |
21 MockFileStream(base::PlatformFile file, int flags) | |
22 : net::FileStream(file, flags), forced_error_(0) {} | |
23 | |
24 void set_forced_error(int error) { forced_error_ = error; } | |
25 void clear_forced_error() { forced_error_ = 0; } | |
wtc
2011/08/23 00:18:35
Nit: it may be better to use net::OK instead of 0
cbentzel
2011/08/23 01:34:01
+1
ahendrickson
2011/08/25 21:55:15
Done.
| |
26 | |
27 int Open(const FilePath& path, int open_flags) { | |
28 path_ = path; | |
29 return get_error(net::FileStream::Open(path, open_flags)); | |
30 } | |
31 | |
32 int64 Seek(net::Whence whence, int64 offset) { | |
33 return get_error64(net::FileStream::Seek(whence, offset)); | |
34 } | |
35 | |
36 int64 Available() { | |
37 return get_error64(net::FileStream::Available()); | |
38 } | |
39 | |
40 int Read(char* buf, int buf_len, net::CompletionCallback* callback) { | |
41 return get_error(net::FileStream::Read(buf, buf_len, callback)); | |
42 } | |
43 | |
44 int ReadUntilComplete(char *buf, int buf_len) { | |
45 return get_error(net::FileStream::ReadUntilComplete(buf, buf_len)); | |
46 } | |
47 | |
48 int Write(const char* buf, int buf_len, net::CompletionCallback* callback) { | |
49 return get_error(net::FileStream::Write(buf, buf_len, callback)); | |
50 } | |
wtc
2011/08/23 00:18:35
Nit: add a blank line after this line.
ahendrickson
2011/08/25 21:55:15
Done.
| |
51 int64 Truncate(int64 bytes) { | |
52 return get_error64(net::FileStream::Truncate(bytes)); | |
53 } | |
54 | |
55 int Flush() { | |
56 return get_error(net::FileStream::Flush()); | |
57 } | |
wtc
2011/08/23 00:18:35
All the net::FileStream virtual methods that you o
ahendrickson
2011/08/25 21:55:15
Done.
| |
58 | |
59 const FilePath& get_path() const { return path_; } | |
60 | |
61 private: | |
62 int get_error(int function_error) { | |
cbentzel
2011/08/23 01:34:01
Perhaps GetError or even ReturnError() since this
ahendrickson
2011/08/25 21:55:15
Done.
| |
63 if (forced_error_ != 0) { | |
64 int ret = forced_error_; | |
65 clear_forced_error(); | |
66 return ret; | |
67 } | |
68 | |
69 return function_error; | |
70 } | |
71 | |
72 int64 get_error64(int64 function_error) { | |
73 if (forced_error_ != 0) { | |
74 int64 ret = forced_error_; | |
75 clear_forced_error(); | |
76 return ret; | |
77 } | |
78 | |
79 return function_error; | |
80 } | |
81 | |
82 int forced_error_; | |
83 FilePath path_; | |
84 }; | |
85 | |
16 const char kTestData1[] = "Let's write some data to the file!\n"; | 86 const char kTestData1[] = "Let's write some data to the file!\n"; |
17 const char kTestData2[] = "Writing more data.\n"; | 87 const char kTestData2[] = "Writing more data.\n"; |
18 const char kTestData3[] = "Final line."; | 88 const char kTestData3[] = "Final line."; |
19 | 89 |
90 } // namespace | |
91 | |
20 class BaseFileTest : public testing::Test { | 92 class BaseFileTest : public testing::Test { |
21 public: | 93 public: |
22 BaseFileTest() | 94 BaseFileTest() |
23 : expect_file_survives_(false), | 95 : expect_file_survives_(false), |
24 file_thread_(BrowserThread::FILE, &message_loop_) { | 96 file_thread_(BrowserThread::FILE, &message_loop_) { |
25 } | 97 } |
26 | 98 |
27 virtual void SetUp() { | 99 virtual void SetUp() { |
28 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 100 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
29 base_file_.reset( | 101 base_file_.reset( |
(...skipping 14 matching lines...) Expand all Loading... | |
44 EXPECT_EQ(expected_data_, disk_data); | 116 EXPECT_EQ(expected_data_, disk_data); |
45 } | 117 } |
46 | 118 |
47 // Make sure the mock BrowserThread outlives the BaseFile to satisfy | 119 // Make sure the mock BrowserThread outlives the BaseFile to satisfy |
48 // thread checks inside it. | 120 // thread checks inside it. |
49 base_file_.reset(); | 121 base_file_.reset(); |
50 | 122 |
51 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); | 123 EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); |
52 } | 124 } |
53 | 125 |
54 void AppendDataToFile(const std::string& data) { | 126 bool OpenMockFileStream() { |
55 ASSERT_TRUE(base_file_->in_progress()); | 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
56 base_file_->AppendDataToFile(data.data(), data.size()); | 128 |
129 FilePath path; | |
130 if (!download_util::CreateTemporaryFileForDownload(&path)) | |
131 return false; | |
132 | |
133 // Create a new file stream if it is not provided. | |
cbentzel
2011/08/23 01:34:01
What does the "if it is not provided" mean? When
ahendrickson
2011/08/25 21:55:15
Removed.
| |
134 mock_file_stream_.reset(new MockFileStream); | |
135 if (mock_file_stream_->Open( | |
136 path, | |
137 base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE) != 0) { | |
138 mock_file_stream_.reset(); | |
139 return false; | |
140 } | |
141 | |
142 // We may be re-opening the file after rename. Always make sure we're | |
143 // writing at the end of the file. | |
144 if (mock_file_stream_->Seek(net::FROM_END, 0) < 0) { | |
145 mock_file_stream_.reset(); | |
146 return false; | |
147 } | |
148 | |
149 return true; | |
150 } | |
151 | |
152 void ForceError(net::Error error) { | |
153 mock_file_stream_->set_forced_error(error); | |
154 } | |
155 | |
156 bool AppendDataToFile(const std::string& data) { | |
157 EXPECT_TRUE(base_file_->in_progress()); | |
158 bool appended = base_file_->AppendDataToFile(data.data(), data.size()); | |
57 expected_data_ += data; | 159 expected_data_ += data; |
58 EXPECT_EQ(static_cast<int64>(expected_data_.size()), | 160 EXPECT_EQ(static_cast<int64>(expected_data_.size()), |
59 base_file_->bytes_so_far()); | 161 base_file_->bytes_so_far()); |
162 return appended; | |
60 } | 163 } |
61 | 164 |
62 protected: | 165 protected: |
63 linked_ptr<net::FileStream> file_stream_; | 166 linked_ptr<net::FileStream> file_stream_; |
167 linked_ptr<MockFileStream> mock_file_stream_; | |
64 | 168 |
65 // BaseClass instance we are testing. | 169 // BaseClass instance we are testing. |
66 scoped_ptr<BaseFile> base_file_; | 170 scoped_ptr<BaseFile> base_file_; |
67 | 171 |
68 // Temporary directory for renamed downloads. | 172 // Temporary directory for renamed downloads. |
69 ScopedTempDir temp_dir_; | 173 ScopedTempDir temp_dir_; |
70 | 174 |
71 // Expect the file to survive deletion of the BaseFile instance. | 175 // Expect the file to survive deletion of the BaseFile instance. |
72 bool expect_file_survives_; | 176 bool expect_file_survives_; |
73 | 177 |
(...skipping 19 matching lines...) Expand all Loading... | |
93 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); | 197 EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); |
94 base_file_->Cancel(); | 198 base_file_->Cancel(); |
95 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); | 199 EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); |
96 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); | 200 EXPECT_NE(FilePath().value(), base_file_->full_path().value()); |
97 } | 201 } |
98 | 202 |
99 // Write data to the file and detach it, so it doesn't get deleted | 203 // Write data to the file and detach it, so it doesn't get deleted |
100 // automatically when base_file_ is destructed. | 204 // automatically when base_file_ is destructed. |
101 TEST_F(BaseFileTest, WriteAndDetach) { | 205 TEST_F(BaseFileTest, WriteAndDetach) { |
102 ASSERT_TRUE(base_file_->Initialize(false)); | 206 ASSERT_TRUE(base_file_->Initialize(false)); |
103 AppendDataToFile(kTestData1); | 207 AppendDataToFile(kTestData1); |
cbentzel
2011/08/23 01:34:01
All calls to AppendDataToFile should be wrapped in
ahendrickson
2011/08/25 21:55:15
Done.
| |
104 base_file_->Finish(); | 208 base_file_->Finish(); |
105 base_file_->Detach(); | 209 base_file_->Detach(); |
106 expect_file_survives_ = true; | 210 expect_file_survives_ = true; |
107 } | 211 } |
108 | 212 |
109 // Write data to the file and detach it, and calculate its sha256 hash. | 213 // Write data to the file and detach it, and calculate its sha256 hash. |
110 TEST_F(BaseFileTest, WriteWithHashAndDetach) { | 214 TEST_F(BaseFileTest, WriteWithHashAndDetach) { |
111 ASSERT_TRUE(base_file_->Initialize(true)); | 215 ASSERT_TRUE(base_file_->Initialize(true)); |
112 AppendDataToFile(kTestData1); | 216 AppendDataToFile(kTestData1); |
113 base_file_->Finish(); | 217 base_file_->Finish(); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 EXPECT_TRUE(base_file_->in_progress()); | 324 EXPECT_TRUE(base_file_->in_progress()); |
221 EXPECT_TRUE(base_file_->Rename(new_path)); | 325 EXPECT_TRUE(base_file_->Rename(new_path)); |
222 EXPECT_FALSE(file_util::PathExists(initial_path)); | 326 EXPECT_FALSE(file_util::PathExists(initial_path)); |
223 EXPECT_TRUE(file_util::PathExists(new_path)); | 327 EXPECT_TRUE(file_util::PathExists(new_path)); |
224 | 328 |
225 AppendDataToFile(kTestData2); | 329 AppendDataToFile(kTestData2); |
226 | 330 |
227 base_file_->Finish(); | 331 base_file_->Finish(); |
228 } | 332 } |
229 | 333 |
230 } // namespace | 334 // Write data to the file multiple times. |
335 TEST_F(BaseFileTest, MultipleWritesWithError) { | |
336 ASSERT_TRUE(OpenMockFileStream()); | |
337 base_file_.reset(new BaseFile(mock_file_stream_->get_path(), | |
338 GURL(), GURL(), 0, mock_file_stream_)); | |
339 ASSERT_TRUE(base_file_->Initialize(false)); | |
340 ASSERT_TRUE(AppendDataToFile(kTestData1)); | |
341 ASSERT_TRUE(AppendDataToFile(kTestData2)); | |
342 ForceError(net::ERR_FAILED); | |
cbentzel
2011/08/23 01:34:01
Should you use one of the more likely ERR's here?
ahendrickson
2011/08/25 21:55:15
Yes, they will.
| |
343 ASSERT_FALSE(AppendDataToFile(kTestData3)); | |
344 std::string hash; | |
345 EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); | |
346 base_file_->Finish(); | |
347 } | |
OLD | NEW |