blob: e8680bbce6bbad4d492f534cb7fc3b2582480b5c [file] [log] [blame]
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +09001// 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
brettw@chromium.org06a553b2013-01-26 09:21:58 +09005#include "base/files/file_util_proxy.h"
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +09006
7#include <map>
8
9#include "base/bind.h"
thestig@chromium.org1b6e1b72013-05-14 19:12:56 +090010#include "base/file_util.h"
brettw@chromium.org091db522012-11-17 05:34:23 +090011#include "base/files/scoped_temp_dir.h"
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090012#include "base/logging.h"
13#include "base/memory/weak_ptr.h"
14#include "base/message_loop.h"
15#include "base/platform_file.h"
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090016#include "base/threading/thread.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace base {
20
21class FileUtilProxyTest : public testing::Test {
22 public:
23 FileUtilProxyTest()
24 : message_loop_(MessageLoop::TYPE_IO),
25 file_thread_("FileUtilProxyTestFileThread"),
26 error_(PLATFORM_FILE_OK),
27 created_(false),
28 file_(kInvalidPlatformFileValue),
29 bytes_written_(-1),
tfarina@chromium.org506c2082013-04-25 21:17:15 +090030 weak_factory_(this) {}
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090031
32 virtual void SetUp() OVERRIDE {
33 ASSERT_TRUE(dir_.CreateUniqueTempDir());
34 ASSERT_TRUE(file_thread_.Start());
35 }
36
37 virtual void TearDown() OVERRIDE {
38 if (file_ != kInvalidPlatformFileValue)
39 ClosePlatformFile(file_);
40 }
41
42 void DidFinish(PlatformFileError error) {
43 error_ = error;
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090044 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090045 }
46
47 void DidCreateOrOpen(PlatformFileError error,
48 PassPlatformFile file,
49 bool created) {
50 error_ = error;
51 file_ = file.ReleaseValue();
52 created_ = created;
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090053 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090054 }
55
56 void DidCreateTemporary(PlatformFileError error,
57 PassPlatformFile file,
58 const FilePath& path) {
59 error_ = error;
60 file_ = file.ReleaseValue();
61 path_ = path;
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090062 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090063 }
64
65 void DidGetFileInfo(PlatformFileError error,
66 const PlatformFileInfo& file_info) {
67 error_ = error;
68 file_info_ = file_info;
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090069 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090070 }
71
72 void DidRead(PlatformFileError error,
73 const char* data,
74 int bytes_read) {
75 error_ = error;
76 buffer_.resize(bytes_read);
77 memcpy(&buffer_[0], data, bytes_read);
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090078 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090079 }
80
81 void DidWrite(PlatformFileError error,
82 int bytes_written) {
83 error_ = error;
84 bytes_written_ = bytes_written;
tfarina@chromium.org3b5d1472013-01-10 23:56:17 +090085 MessageLoop::current()->QuitWhenIdle();
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +090086 }
87
88 protected:
89 PlatformFile GetTestPlatformFile(int flags) {
90 if (file_ != kInvalidPlatformFileValue)
91 return file_;
92 bool created;
93 PlatformFileError error;
94 file_ = CreatePlatformFile(test_path(), flags, &created, &error);
95 EXPECT_EQ(PLATFORM_FILE_OK, error);
96 EXPECT_NE(kInvalidPlatformFileValue, file_);
97 return file_;
98 }
99
100 TaskRunner* file_task_runner() const {
101 return file_thread_.message_loop_proxy().get();
102 }
103 const FilePath& test_dir_path() const { return dir_.path(); }
104 const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
105
106 MessageLoop message_loop_;
107 Thread file_thread_;
108
109 ScopedTempDir dir_;
110 PlatformFileError error_;
111 bool created_;
112 PlatformFile file_;
113 FilePath path_;
114 PlatformFileInfo file_info_;
115 std::vector<char> buffer_;
116 int bytes_written_;
117 WeakPtrFactory<FileUtilProxyTest> weak_factory_;
118};
119
120TEST_F(FileUtilProxyTest, CreateOrOpen_Create) {
121 FileUtilProxy::CreateOrOpen(
122 file_task_runner(),
123 test_path(),
124 PLATFORM_FILE_CREATE | PLATFORM_FILE_READ,
125 Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
126 MessageLoop::current()->Run();
127
128 EXPECT_EQ(PLATFORM_FILE_OK, error_);
129 EXPECT_TRUE(created_);
130 EXPECT_NE(kInvalidPlatformFileValue, file_);
brettw@chromium.org10b64122013-07-12 02:36:07 +0900131 EXPECT_TRUE(PathExists(test_path()));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900132}
133
134TEST_F(FileUtilProxyTest, CreateOrOpen_Open) {
135 // Creates a file.
136 file_util::WriteFile(test_path(), NULL, 0);
brettw@chromium.org10b64122013-07-12 02:36:07 +0900137 ASSERT_TRUE(PathExists(test_path()));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900138
139 // Opens the created file.
140 FileUtilProxy::CreateOrOpen(
141 file_task_runner(),
142 test_path(),
143 PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
144 Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
145 MessageLoop::current()->Run();
146
147 EXPECT_EQ(PLATFORM_FILE_OK, error_);
148 EXPECT_FALSE(created_);
149 EXPECT_NE(kInvalidPlatformFileValue, file_);
150}
151
152TEST_F(FileUtilProxyTest, CreateOrOpen_OpenNonExistent) {
153 FileUtilProxy::CreateOrOpen(
154 file_task_runner(),
155 test_path(),
156 PLATFORM_FILE_OPEN | PLATFORM_FILE_READ,
157 Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
158 MessageLoop::current()->Run();
159 EXPECT_EQ(PLATFORM_FILE_ERROR_NOT_FOUND, error_);
160 EXPECT_FALSE(created_);
161 EXPECT_EQ(kInvalidPlatformFileValue, file_);
brettw@chromium.org10b64122013-07-12 02:36:07 +0900162 EXPECT_FALSE(PathExists(test_path()));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900163}
164
165TEST_F(FileUtilProxyTest, Close) {
166 // Creates a file.
167 PlatformFile file = GetTestPlatformFile(
168 PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
169
170#if defined(OS_WIN)
171 // This fails on Windows if the file is not closed.
brettw@chromium.org0878fea2013-07-02 08:07:36 +0900172 EXPECT_FALSE(base::Move(test_path(),
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900173 test_dir_path().AppendASCII("new")));
174#endif
175
176 FileUtilProxy::Close(
177 file_task_runner(),
178 file,
179 Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
180 MessageLoop::current()->Run();
181 EXPECT_EQ(PLATFORM_FILE_OK, error_);
182
183 // Now it should pass on all platforms.
brettw@chromium.org0878fea2013-07-02 08:07:36 +0900184 EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900185}
186
187TEST_F(FileUtilProxyTest, CreateTemporary) {
188 FileUtilProxy::CreateTemporary(
189 file_task_runner(), 0 /* additional_file_flags */,
190 Bind(&FileUtilProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
191 MessageLoop::current()->Run();
192 EXPECT_EQ(PLATFORM_FILE_OK, error_);
brettw@chromium.org10b64122013-07-12 02:36:07 +0900193 EXPECT_TRUE(PathExists(path_));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900194 EXPECT_NE(kInvalidPlatformFileValue, file_);
195
196 // The file should be writable.
197#if defined(OS_WIN)
thestig@chromium.org1b6e1b72013-05-14 19:12:56 +0900198 HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
199 OVERLAPPED overlapped = {0};
200 overlapped.hEvent = hEvent;
201 DWORD bytes_written;
202 if (!::WriteFile(file_, "test", 4, &bytes_written, &overlapped)) {
203 // Temporary file is created with ASYNC flag, so WriteFile may return 0
204 // with ERROR_IO_PENDING.
205 EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
206 GetOverlappedResult(file_, &overlapped, &bytes_written, TRUE);
207 }
208 EXPECT_EQ(4, bytes_written);
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900209#else
210 // On POSIX ASYNC flag does not affect synchronous read/write behavior.
211 EXPECT_EQ(4, WritePlatformFile(file_, 0, "test", 4));
212#endif
213 EXPECT_TRUE(ClosePlatformFile(file_));
214 file_ = kInvalidPlatformFileValue;
215
216 // Make sure the written data can be read from the returned path.
217 std::string data;
218 EXPECT_TRUE(file_util::ReadFileToString(path_, &data));
219 EXPECT_EQ("test", data);
scr@chromium.org7a760d42012-06-01 18:25:32 +0900220
221 // Make sure we can & do delete the created file to prevent leaks on the bots.
brettw@chromium.orge9f99482013-07-02 04:41:02 +0900222 EXPECT_TRUE(base::Delete(path_, false));
kinuko@chromium.org20e2efc2012-04-24 03:40:57 +0900223}
224
225TEST_F(FileUtilProxyTest, GetFileInfo_File) {
226 // Setup.
227 ASSERT_EQ(4, file_util::WriteFile(test_path(), "test", 4));
228 PlatformFileInfo expected_info;
229 file_util::GetFileInfo(test_path(), &expected_info);
230
231 // Run.
232 FileUtilProxy::GetFileInfo(
233 file_task_runner(),
234 test_path(),
235 Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
236 MessageLoop::current()->Run();
237
238 // Verify.
239 EXPECT_EQ(PLATFORM_FILE_OK, error_);
240 EXPECT_EQ(expected_info.size, file_info_.size);
241 EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
242 EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
243 EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
244 EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
245 EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
246}
247
248TEST_F(FileUtilProxyTest, GetFileInfo_Directory) {
249 // Setup.
250 ASSERT_TRUE(file_util::CreateDirectory(test_path()));
251 PlatformFileInfo expected_info;
252 file_util::GetFileInfo(test_path(), &expected_info);
253
254 // Run.
255 FileUtilProxy::GetFileInfo(
256 file_task_runner(),
257 test_path(),
258 Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
259 MessageLoop::current()->Run();
260
261 // Verify.
262 EXPECT_EQ(PLATFORM_FILE_OK, error_);
263 EXPECT_EQ(expected_info.size, file_info_.size);
264 EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
265 EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
266 EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
267 EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
268 EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
269}
270
271TEST_F(FileUtilProxyTest, Read) {
272 // Setup.
273 const char expected_data[] = "bleh";
274 int expected_bytes = arraysize(expected_data);
275 ASSERT_EQ(expected_bytes,
276 file_util::WriteFile(test_path(), expected_data, expected_bytes));
277
278 // Run.
279 FileUtilProxy::Read(
280 file_task_runner(),
281 GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_READ),
282 0, // offset
283 128,
284 Bind(&FileUtilProxyTest::DidRead, weak_factory_.GetWeakPtr()));
285 MessageLoop::current()->Run();
286
287 // Verify.
288 EXPECT_EQ(PLATFORM_FILE_OK, error_);
289 EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
290 for (size_t i = 0; i < buffer_.size(); ++i) {
291 EXPECT_EQ(expected_data[i], buffer_[i]);
292 }
293}
294
295TEST_F(FileUtilProxyTest, WriteAndFlush) {
296 const char data[] = "foo!";
297 int data_bytes = ARRAYSIZE_UNSAFE(data);
298 PlatformFile file = GetTestPlatformFile(
299 PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE);
300
301 FileUtilProxy::Write(
302 file_task_runner(),
303 file,
304 0, // offset
305 data,
306 data_bytes,
307 Bind(&FileUtilProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
308 MessageLoop::current()->Run();
309 EXPECT_EQ(PLATFORM_FILE_OK, error_);
310 EXPECT_EQ(data_bytes, bytes_written_);
311
312 // Flush the written data. (So that the following read should always
313 // succeed. On some platforms it may work with or without this flush.)
314 FileUtilProxy::Flush(
315 file_task_runner(),
316 file,
317 Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
318 MessageLoop::current()->Run();
319 EXPECT_EQ(PLATFORM_FILE_OK, error_);
320
321 // Verify the written data.
322 char buffer[10];
323 EXPECT_EQ(data_bytes, file_util::ReadFile(test_path(), buffer, data_bytes));
324 for (int i = 0; i < data_bytes; ++i) {
325 EXPECT_EQ(data[i], buffer[i]);
326 }
327}
328
329TEST_F(FileUtilProxyTest, Touch) {
330 Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
331 Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
332
333 FileUtilProxy::Touch(
334 file_task_runner(),
335 GetTestPlatformFile(PLATFORM_FILE_CREATE |
336 PLATFORM_FILE_WRITE |
337 PLATFORM_FILE_WRITE_ATTRIBUTES),
338 last_accessed_time,
339 last_modified_time,
340 Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
341 MessageLoop::current()->Run();
342 EXPECT_EQ(PLATFORM_FILE_OK, error_);
343
344 PlatformFileInfo info;
345 file_util::GetFileInfo(test_path(), &info);
346
347 // The returned values may only have the seconds precision, so we cast
348 // the double values to int here.
349 EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
350 static_cast<int>(info.last_modified.ToDoubleT()));
351 EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
352 static_cast<int>(info.last_accessed.ToDoubleT()));
353}
354
355TEST_F(FileUtilProxyTest, Truncate_Shrink) {
356 // Setup.
357 const char kTestData[] = "0123456789";
358 ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
359 PlatformFileInfo info;
360 file_util::GetFileInfo(test_path(), &info);
361 ASSERT_EQ(10, info.size);
362
363 // Run.
364 FileUtilProxy::Truncate(
365 file_task_runner(),
366 GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
367 7,
368 Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
369 MessageLoop::current()->Run();
370
371 // Verify.
372 file_util::GetFileInfo(test_path(), &info);
373 ASSERT_EQ(7, info.size);
374
375 char buffer[7];
376 EXPECT_EQ(7, file_util::ReadFile(test_path(), buffer, 7));
377 int i = 0;
378 for (; i < 7; ++i)
379 EXPECT_EQ(kTestData[i], buffer[i]);
380}
381
382TEST_F(FileUtilProxyTest, Truncate_Expand) {
383 // Setup.
384 const char kTestData[] = "9876543210";
385 ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10));
386 PlatformFileInfo info;
387 file_util::GetFileInfo(test_path(), &info);
388 ASSERT_EQ(10, info.size);
389
390 // Run.
391 FileUtilProxy::Truncate(
392 file_task_runner(),
393 GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE),
394 53,
395 Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
396 MessageLoop::current()->Run();
397
398 // Verify.
399 file_util::GetFileInfo(test_path(), &info);
400 ASSERT_EQ(53, info.size);
401
402 char buffer[53];
403 EXPECT_EQ(53, file_util::ReadFile(test_path(), buffer, 53));
404 int i = 0;
405 for (; i < 10; ++i)
406 EXPECT_EQ(kTestData[i], buffer[i]);
407 for (; i < 53; ++i)
408 EXPECT_EQ(0, buffer[i]);
409}
410
411} // namespace base