blob: b5e100297d9af0d3c6e218b4d2f53d79808b67c1 [file] [log] [blame]
rvargas@chromium.orgc40e3b12014-03-15 14:19:31 +09001// Copyright 2014 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/files/file_proxy.h"
6
7#include <map>
8
9#include "base/bind.h"
10#include "base/file_util.h"
11#include "base/files/file.h"
12#include "base/files/scoped_temp_dir.h"
13#include "base/logging.h"
14#include "base/memory/weak_ptr.h"
15#include "base/message_loop/message_loop.h"
16#include "base/threading/thread.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace base {
20
21class FileProxyTest : public testing::Test {
22 public:
23 FileProxyTest()
24 : file_thread_("FileProxyTestFileThread"),
25 error_(File::FILE_OK),
26 bytes_written_(-1),
27 weak_factory_(this) {}
28
29 virtual void SetUp() OVERRIDE {
30 ASSERT_TRUE(dir_.CreateUniqueTempDir());
31 ASSERT_TRUE(file_thread_.Start());
32 }
33
34 void DidFinish(File::Error error) {
35 error_ = error;
36 MessageLoop::current()->QuitWhenIdle();
37 }
38
39 void DidCreateOrOpen(File::Error error) {
40 error_ = error;
41 MessageLoop::current()->QuitWhenIdle();
42 }
43
44 void DidCreateTemporary(File::Error error,
45 const FilePath& path) {
46 error_ = error;
47 path_ = path;
48 MessageLoop::current()->QuitWhenIdle();
49 }
50
51 void DidGetFileInfo(File::Error error,
52 const File::Info& file_info) {
53 error_ = error;
54 file_info_ = file_info;
55 MessageLoop::current()->QuitWhenIdle();
56 }
57
58 void DidRead(File::Error error,
59 const char* data,
60 int bytes_read) {
61 error_ = error;
62 buffer_.resize(bytes_read);
63 memcpy(&buffer_[0], data, bytes_read);
64 MessageLoop::current()->QuitWhenIdle();
65 }
66
67 void DidWrite(File::Error error,
68 int bytes_written) {
69 error_ = error;
70 bytes_written_ = bytes_written;
71 MessageLoop::current()->QuitWhenIdle();
72 }
73
74 protected:
75 void CreateProxy(uint32 flags, FileProxy* proxy) {
76 proxy->CreateOrOpen(
77 test_path(), flags,
78 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
79 MessageLoop::current()->Run();
80 EXPECT_TRUE(proxy->IsValid());
81 }
82
83 TaskRunner* file_task_runner() const {
84 return file_thread_.message_loop_proxy().get();
85 }
86 const FilePath& test_dir_path() const { return dir_.path(); }
87 const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
88
89 MessageLoopForIO message_loop_;
90 Thread file_thread_;
91
92 ScopedTempDir dir_;
93 File::Error error_;
94 FilePath path_;
95 File::Info file_info_;
96 std::vector<char> buffer_;
97 int bytes_written_;
98 WeakPtrFactory<FileProxyTest> weak_factory_;
99};
100
101TEST_F(FileProxyTest, CreateOrOpen_Create) {
102 FileProxy proxy(file_task_runner());
103 proxy.CreateOrOpen(
104 test_path(),
105 File::FLAG_CREATE | File::FLAG_READ,
106 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
107 MessageLoop::current()->Run();
108
109 EXPECT_EQ(File::FILE_OK, error_);
110 EXPECT_TRUE(proxy.IsValid());
111 EXPECT_TRUE(proxy.created());
112 EXPECT_TRUE(PathExists(test_path()));
113}
114
115TEST_F(FileProxyTest, CreateOrOpen_Open) {
116 // Creates a file.
117 base::WriteFile(test_path(), NULL, 0);
118 ASSERT_TRUE(PathExists(test_path()));
119
120 // Opens the created file.
121 FileProxy proxy(file_task_runner());
122 proxy.CreateOrOpen(
123 test_path(),
124 File::FLAG_OPEN | File::FLAG_READ,
125 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
126 MessageLoop::current()->Run();
127
128 EXPECT_EQ(File::FILE_OK, error_);
129 EXPECT_TRUE(proxy.IsValid());
130 EXPECT_FALSE(proxy.created());
131}
132
133TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) {
134 FileProxy proxy(file_task_runner());
135 proxy.CreateOrOpen(
136 test_path(),
137 File::FLAG_OPEN | File::FLAG_READ,
138 Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
139 MessageLoop::current()->Run();
140 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_);
141 EXPECT_FALSE(proxy.IsValid());
142 EXPECT_FALSE(proxy.created());
143 EXPECT_FALSE(PathExists(test_path()));
144}
145
146TEST_F(FileProxyTest, Close) {
147 // Creates a file.
148 FileProxy proxy(file_task_runner());
149 CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
150
151#if defined(OS_WIN)
152 // This fails on Windows if the file is not closed.
153 EXPECT_FALSE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
154#endif
155
156 proxy.Close(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
157 MessageLoop::current()->Run();
158 EXPECT_EQ(File::FILE_OK, error_);
159 EXPECT_FALSE(proxy.IsValid());
160
161 // Now it should pass on all platforms.
162 EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
163}
164
165TEST_F(FileProxyTest, CreateTemporary) {
166 {
167 FileProxy proxy(file_task_runner());
168 proxy.CreateTemporary(
169 0 /* additional_file_flags */,
170 Bind(&FileProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
171 MessageLoop::current()->Run();
172
173 EXPECT_TRUE(proxy.IsValid());
174 EXPECT_EQ(File::FILE_OK, error_);
175 EXPECT_TRUE(PathExists(path_));
176
177 // The file should be writable.
178 proxy.Write(0, "test", 4,
179 Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
180 MessageLoop::current()->Run();
181 EXPECT_EQ(File::FILE_OK, error_);
182 EXPECT_EQ(4, bytes_written_);
183 }
184
185 // Make sure the written data can be read from the returned path.
186 std::string data;
187 EXPECT_TRUE(ReadFileToString(path_, &data));
188 EXPECT_EQ("test", data);
189
190 // Make sure we can & do delete the created file to prevent leaks on the bots.
191 EXPECT_TRUE(base::DeleteFile(path_, false));
192}
193
194TEST_F(FileProxyTest, GetInfo) {
195 // Setup.
196 ASSERT_EQ(4, base::WriteFile(test_path(), "test", 4));
197 File::Info expected_info;
198 GetFileInfo(test_path(), &expected_info);
199
200 // Run.
201 FileProxy proxy(file_task_runner());
202 CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
203 proxy.GetInfo(
204 Bind(&FileProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
205 MessageLoop::current()->Run();
206
207 // Verify.
208 EXPECT_EQ(File::FILE_OK, error_);
209 EXPECT_EQ(expected_info.size, file_info_.size);
210 EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
211 EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
212
213 File file = proxy.TakeFile();
214 EXPECT_TRUE(file.GetInfo(&expected_info));
215 EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
216 EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
217}
218
219TEST_F(FileProxyTest, Read) {
220 // Setup.
221 const char expected_data[] = "bleh";
222 int expected_bytes = arraysize(expected_data);
223 ASSERT_EQ(expected_bytes,
224 base::WriteFile(test_path(), expected_data, expected_bytes));
225
226 // Run.
227 FileProxy proxy(file_task_runner());
228 CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
229
230 proxy.Read(0, 128, Bind(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr()));
231 MessageLoop::current()->Run();
232
233 // Verify.
234 EXPECT_EQ(File::FILE_OK, error_);
235 EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
236 for (size_t i = 0; i < buffer_.size(); ++i) {
237 EXPECT_EQ(expected_data[i], buffer_[i]);
238 }
239}
240
241TEST_F(FileProxyTest, WriteAndFlush) {
242 FileProxy proxy(file_task_runner());
243 CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
244
245 const char data[] = "foo!";
246 int data_bytes = ARRAYSIZE_UNSAFE(data);
247 proxy.Write(0, data, data_bytes,
248 Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
249 MessageLoop::current()->Run();
250 EXPECT_EQ(File::FILE_OK, error_);
251 EXPECT_EQ(data_bytes, bytes_written_);
252
253 // Flush the written data. (So that the following read should always
254 // succeed. On some platforms it may work with or without this flush.)
255 proxy.Flush(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
256 MessageLoop::current()->Run();
257 EXPECT_EQ(File::FILE_OK, error_);
258
259 // Verify the written data.
260 char buffer[10];
261 EXPECT_EQ(data_bytes, base::ReadFile(test_path(), buffer, data_bytes));
262 for (int i = 0; i < data_bytes; ++i) {
263 EXPECT_EQ(data[i], buffer[i]);
264 }
265}
266
267TEST_F(FileProxyTest, SetTimes) {
268 FileProxy proxy(file_task_runner());
269 CreateProxy(
270 File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES,
271 &proxy);
272
273 Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
274 Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
275
276 proxy.SetTimes(last_accessed_time, last_modified_time,
277 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
278 MessageLoop::current()->Run();
279 EXPECT_EQ(File::FILE_OK, error_);
280
281 File::Info info;
282 GetFileInfo(test_path(), &info);
283
284 // The returned values may only have the seconds precision, so we cast
285 // the double values to int here.
286 EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
287 static_cast<int>(info.last_modified.ToDoubleT()));
288 EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
289 static_cast<int>(info.last_accessed.ToDoubleT()));
290}
291
292TEST_F(FileProxyTest, SetLength_Shrink) {
293 // Setup.
294 const char kTestData[] = "0123456789";
295 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
296 File::Info info;
297 GetFileInfo(test_path(), &info);
298 ASSERT_EQ(10, info.size);
299
300 // Run.
301 FileProxy proxy(file_task_runner());
302 CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
303 proxy.SetLength(7,
304 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
305 MessageLoop::current()->Run();
306
307 // Verify.
308 GetFileInfo(test_path(), &info);
309 ASSERT_EQ(7, info.size);
310
311 char buffer[7];
312 EXPECT_EQ(7, base::ReadFile(test_path(), buffer, 7));
313 int i = 0;
314 for (; i < 7; ++i)
315 EXPECT_EQ(kTestData[i], buffer[i]);
316}
317
318TEST_F(FileProxyTest, SetLength_Expand) {
319 // Setup.
320 const char kTestData[] = "9876543210";
321 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
322 File::Info info;
323 GetFileInfo(test_path(), &info);
324 ASSERT_EQ(10, info.size);
325
326 // Run.
327 FileProxy proxy(file_task_runner());
328 CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
329 proxy.SetLength(53,
330 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
331 MessageLoop::current()->Run();
332
333 // Verify.
334 GetFileInfo(test_path(), &info);
335 ASSERT_EQ(53, info.size);
336
337 char buffer[53];
338 EXPECT_EQ(53, base::ReadFile(test_path(), buffer, 53));
339 int i = 0;
340 for (; i < 10; ++i)
341 EXPECT_EQ(kTestData[i], buffer[i]);
342 for (; i < 53; ++i)
343 EXPECT_EQ(0, buffer[i]);
344}
345
346} // namespace base