1 // 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.
5 #include "base/files/file_proxy.h"
8 #include "base/files/file.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "testing/gtest/include/gtest/gtest.h"
19 class FileProxyTest
: public testing::Test
{
22 : file_thread_("FileProxyTestFileThread"),
23 error_(File::FILE_OK
),
25 weak_factory_(this) {}
27 virtual void SetUp() OVERRIDE
{
28 ASSERT_TRUE(dir_
.CreateUniqueTempDir());
29 ASSERT_TRUE(file_thread_
.Start());
32 void DidFinish(File::Error error
) {
34 MessageLoop::current()->QuitWhenIdle();
37 void DidCreateOrOpen(File::Error error
) {
39 MessageLoop::current()->QuitWhenIdle();
42 void DidCreateTemporary(File::Error error
,
43 const FilePath
& path
) {
46 MessageLoop::current()->QuitWhenIdle();
49 void DidGetFileInfo(File::Error error
,
50 const File::Info
& file_info
) {
52 file_info_
= file_info
;
53 MessageLoop::current()->QuitWhenIdle();
56 void DidRead(File::Error error
,
60 buffer_
.resize(bytes_read
);
61 memcpy(&buffer_
[0], data
, bytes_read
);
62 MessageLoop::current()->QuitWhenIdle();
65 void DidWrite(File::Error error
,
68 bytes_written_
= bytes_written
;
69 MessageLoop::current()->QuitWhenIdle();
73 void CreateProxy(uint32 flags
, FileProxy
* proxy
) {
76 Bind(&FileProxyTest::DidCreateOrOpen
, weak_factory_
.GetWeakPtr()));
77 MessageLoop::current()->Run();
78 EXPECT_TRUE(proxy
->IsValid());
81 TaskRunner
* file_task_runner() const {
82 return file_thread_
.message_loop_proxy().get();
84 const FilePath
& test_dir_path() const { return dir_
.path(); }
85 const FilePath
test_path() const { return dir_
.path().AppendASCII("test"); }
87 MessageLoopForIO message_loop_
;
93 File::Info file_info_
;
94 std::vector
<char> buffer_
;
96 WeakPtrFactory
<FileProxyTest
> weak_factory_
;
99 TEST_F(FileProxyTest
, CreateOrOpen_Create
) {
100 FileProxy
proxy(file_task_runner());
103 File::FLAG_CREATE
| File::FLAG_READ
,
104 Bind(&FileProxyTest::DidCreateOrOpen
, weak_factory_
.GetWeakPtr()));
105 MessageLoop::current()->Run();
107 EXPECT_EQ(File::FILE_OK
, error_
);
108 EXPECT_TRUE(proxy
.IsValid());
109 EXPECT_TRUE(proxy
.created());
110 EXPECT_TRUE(PathExists(test_path()));
113 TEST_F(FileProxyTest
, CreateOrOpen_Open
) {
115 base::WriteFile(test_path(), NULL
, 0);
116 ASSERT_TRUE(PathExists(test_path()));
118 // Opens the created file.
119 FileProxy
proxy(file_task_runner());
122 File::FLAG_OPEN
| File::FLAG_READ
,
123 Bind(&FileProxyTest::DidCreateOrOpen
, weak_factory_
.GetWeakPtr()));
124 MessageLoop::current()->Run();
126 EXPECT_EQ(File::FILE_OK
, error_
);
127 EXPECT_TRUE(proxy
.IsValid());
128 EXPECT_FALSE(proxy
.created());
131 TEST_F(FileProxyTest
, CreateOrOpen_OpenNonExistent
) {
132 FileProxy
proxy(file_task_runner());
135 File::FLAG_OPEN
| File::FLAG_READ
,
136 Bind(&FileProxyTest::DidCreateOrOpen
, weak_factory_
.GetWeakPtr()));
137 MessageLoop::current()->Run();
138 EXPECT_EQ(File::FILE_ERROR_NOT_FOUND
, error_
);
139 EXPECT_FALSE(proxy
.IsValid());
140 EXPECT_FALSE(proxy
.created());
141 EXPECT_FALSE(PathExists(test_path()));
144 TEST_F(FileProxyTest
, CreateOrOpen_AbandonedCreate
) {
145 bool prev
= ThreadRestrictions::SetIOAllowed(false);
147 FileProxy
proxy(file_task_runner());
150 File::FLAG_CREATE
| File::FLAG_READ
,
151 Bind(&FileProxyTest::DidCreateOrOpen
, weak_factory_
.GetWeakPtr()));
153 MessageLoop::current()->Run();
154 ThreadRestrictions::SetIOAllowed(prev
);
156 EXPECT_TRUE(PathExists(test_path()));
159 TEST_F(FileProxyTest
, Close
) {
161 FileProxy
proxy(file_task_runner());
162 CreateProxy(File::FLAG_CREATE
| File::FLAG_WRITE
, &proxy
);
165 // This fails on Windows if the file is not closed.
166 EXPECT_FALSE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
169 proxy
.Close(Bind(&FileProxyTest::DidFinish
, weak_factory_
.GetWeakPtr()));
170 MessageLoop::current()->Run();
171 EXPECT_EQ(File::FILE_OK
, error_
);
172 EXPECT_FALSE(proxy
.IsValid());
174 // Now it should pass on all platforms.
175 EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
178 TEST_F(FileProxyTest
, CreateTemporary
) {
180 FileProxy
proxy(file_task_runner());
181 proxy
.CreateTemporary(
182 0 /* additional_file_flags */,
183 Bind(&FileProxyTest::DidCreateTemporary
, weak_factory_
.GetWeakPtr()));
184 MessageLoop::current()->Run();
186 EXPECT_TRUE(proxy
.IsValid());
187 EXPECT_EQ(File::FILE_OK
, error_
);
188 EXPECT_TRUE(PathExists(path_
));
190 // The file should be writable.
191 proxy
.Write(0, "test", 4,
192 Bind(&FileProxyTest::DidWrite
, weak_factory_
.GetWeakPtr()));
193 MessageLoop::current()->Run();
194 EXPECT_EQ(File::FILE_OK
, error_
);
195 EXPECT_EQ(4, bytes_written_
);
198 // Make sure the written data can be read from the returned path.
200 EXPECT_TRUE(ReadFileToString(path_
, &data
));
201 EXPECT_EQ("test", data
);
203 // Make sure we can & do delete the created file to prevent leaks on the bots.
204 EXPECT_TRUE(base::DeleteFile(path_
, false));
207 TEST_F(FileProxyTest
, SetAndTake
) {
208 File
file(test_path(), File::FLAG_CREATE
| File::FLAG_READ
);
209 ASSERT_TRUE(file
.IsValid());
210 FileProxy
proxy(file_task_runner());
211 EXPECT_FALSE(proxy
.IsValid());
212 proxy
.SetFile(file
.Pass());
213 EXPECT_TRUE(proxy
.IsValid());
214 EXPECT_FALSE(file
.IsValid());
216 file
= proxy
.TakeFile();
217 EXPECT_FALSE(proxy
.IsValid());
218 EXPECT_TRUE(file
.IsValid());
221 TEST_F(FileProxyTest
, GetInfo
) {
223 ASSERT_EQ(4, base::WriteFile(test_path(), "test", 4));
224 File::Info expected_info
;
225 GetFileInfo(test_path(), &expected_info
);
228 FileProxy
proxy(file_task_runner());
229 CreateProxy(File::FLAG_OPEN
| File::FLAG_READ
, &proxy
);
231 Bind(&FileProxyTest::DidGetFileInfo
, weak_factory_
.GetWeakPtr()));
232 MessageLoop::current()->Run();
235 EXPECT_EQ(File::FILE_OK
, error_
);
236 EXPECT_EQ(expected_info
.size
, file_info_
.size
);
237 EXPECT_EQ(expected_info
.is_directory
, file_info_
.is_directory
);
238 EXPECT_EQ(expected_info
.is_symbolic_link
, file_info_
.is_symbolic_link
);
239 EXPECT_EQ(expected_info
.last_modified
, file_info_
.last_modified
);
240 EXPECT_EQ(expected_info
.creation_time
, file_info_
.creation_time
);
243 TEST_F(FileProxyTest
, Read
) {
245 const char expected_data
[] = "bleh";
246 int expected_bytes
= arraysize(expected_data
);
247 ASSERT_EQ(expected_bytes
,
248 base::WriteFile(test_path(), expected_data
, expected_bytes
));
251 FileProxy
proxy(file_task_runner());
252 CreateProxy(File::FLAG_OPEN
| File::FLAG_READ
, &proxy
);
254 proxy
.Read(0, 128, Bind(&FileProxyTest::DidRead
, weak_factory_
.GetWeakPtr()));
255 MessageLoop::current()->Run();
258 EXPECT_EQ(File::FILE_OK
, error_
);
259 EXPECT_EQ(expected_bytes
, static_cast<int>(buffer_
.size()));
260 for (size_t i
= 0; i
< buffer_
.size(); ++i
) {
261 EXPECT_EQ(expected_data
[i
], buffer_
[i
]);
265 TEST_F(FileProxyTest
, WriteAndFlush
) {
266 FileProxy
proxy(file_task_runner());
267 CreateProxy(File::FLAG_CREATE
| File::FLAG_WRITE
, &proxy
);
269 const char data
[] = "foo!";
270 int data_bytes
= ARRAYSIZE_UNSAFE(data
);
271 proxy
.Write(0, data
, data_bytes
,
272 Bind(&FileProxyTest::DidWrite
, weak_factory_
.GetWeakPtr()));
273 MessageLoop::current()->Run();
274 EXPECT_EQ(File::FILE_OK
, error_
);
275 EXPECT_EQ(data_bytes
, bytes_written_
);
277 // Flush the written data. (So that the following read should always
278 // succeed. On some platforms it may work with or without this flush.)
279 proxy
.Flush(Bind(&FileProxyTest::DidFinish
, weak_factory_
.GetWeakPtr()));
280 MessageLoop::current()->Run();
281 EXPECT_EQ(File::FILE_OK
, error_
);
283 // Verify the written data.
285 EXPECT_EQ(data_bytes
, base::ReadFile(test_path(), buffer
, data_bytes
));
286 for (int i
= 0; i
< data_bytes
; ++i
) {
287 EXPECT_EQ(data
[i
], buffer
[i
]);
291 TEST_F(FileProxyTest
, SetTimes
) {
292 FileProxy
proxy(file_task_runner());
294 File::FLAG_CREATE
| File::FLAG_WRITE
| File::FLAG_WRITE_ATTRIBUTES
,
297 Time last_accessed_time
= Time::Now() - TimeDelta::FromDays(12345);
298 Time last_modified_time
= Time::Now() - TimeDelta::FromHours(98765);
300 proxy
.SetTimes(last_accessed_time
, last_modified_time
,
301 Bind(&FileProxyTest::DidFinish
, weak_factory_
.GetWeakPtr()));
302 MessageLoop::current()->Run();
303 EXPECT_EQ(File::FILE_OK
, error_
);
306 GetFileInfo(test_path(), &info
);
308 // The returned values may only have the seconds precision, so we cast
309 // the double values to int here.
310 EXPECT_EQ(static_cast<int>(last_modified_time
.ToDoubleT()),
311 static_cast<int>(info
.last_modified
.ToDoubleT()));
312 EXPECT_EQ(static_cast<int>(last_accessed_time
.ToDoubleT()),
313 static_cast<int>(info
.last_accessed
.ToDoubleT()));
316 TEST_F(FileProxyTest
, SetLength_Shrink
) {
318 const char kTestData
[] = "0123456789";
319 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData
, 10));
321 GetFileInfo(test_path(), &info
);
322 ASSERT_EQ(10, info
.size
);
325 FileProxy
proxy(file_task_runner());
326 CreateProxy(File::FLAG_OPEN
| File::FLAG_WRITE
, &proxy
);
328 Bind(&FileProxyTest::DidFinish
, weak_factory_
.GetWeakPtr()));
329 MessageLoop::current()->Run();
332 GetFileInfo(test_path(), &info
);
333 ASSERT_EQ(7, info
.size
);
336 EXPECT_EQ(7, base::ReadFile(test_path(), buffer
, 7));
339 EXPECT_EQ(kTestData
[i
], buffer
[i
]);
342 TEST_F(FileProxyTest
, SetLength_Expand
) {
344 const char kTestData
[] = "9876543210";
345 ASSERT_EQ(10, base::WriteFile(test_path(), kTestData
, 10));
347 GetFileInfo(test_path(), &info
);
348 ASSERT_EQ(10, info
.size
);
351 FileProxy
proxy(file_task_runner());
352 CreateProxy(File::FLAG_OPEN
| File::FLAG_WRITE
, &proxy
);
354 Bind(&FileProxyTest::DidFinish
, weak_factory_
.GetWeakPtr()));
355 MessageLoop::current()->Run();
358 GetFileInfo(test_path(), &info
);
359 ASSERT_EQ(53, info
.size
);
362 EXPECT_EQ(53, base::ReadFile(test_path(), buffer
, 53));
365 EXPECT_EQ(kTestData
[i
], buffer
[i
]);
367 EXPECT_EQ(0, buffer
[i
]);