1 // 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.
5 #include "base/files/file.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/time/time.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 TEST(FileTest
, Create
) {
16 base::ScopedTempDir temp_dir
;
17 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
18 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
21 // Don't create a File at all.
23 EXPECT_FALSE(file
.IsValid());
24 EXPECT_EQ(base::File::FILE_ERROR_FAILED
, file
.error_details());
26 File
file2(base::File::FILE_ERROR_TOO_MANY_OPENED
);
27 EXPECT_FALSE(file2
.IsValid());
28 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED
, file2
.error_details());
32 // Open a file that doesn't exist.
33 File
file(file_path
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
34 EXPECT_FALSE(file
.IsValid());
35 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND
, file
.error_details());
39 // Open or create a file.
40 File
file(file_path
, base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_READ
);
41 EXPECT_TRUE(file
.IsValid());
42 EXPECT_TRUE(file
.created());
43 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
47 // Open an existing file.
48 File
file(file_path
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
49 EXPECT_TRUE(file
.IsValid());
50 EXPECT_FALSE(file
.created());
51 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
53 // This time verify closing the file.
55 EXPECT_FALSE(file
.IsValid());
59 // Open an existing file through Initialize
61 file
.Initialize(file_path
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
62 EXPECT_TRUE(file
.IsValid());
63 EXPECT_FALSE(file
.created());
64 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
66 // This time verify closing the file.
68 EXPECT_FALSE(file
.IsValid());
72 // Create a file that exists.
73 File
file(file_path
, base::File::FLAG_CREATE
| base::File::FLAG_READ
);
74 EXPECT_FALSE(file
.IsValid());
75 EXPECT_FALSE(file
.created());
76 EXPECT_EQ(base::File::FILE_ERROR_EXISTS
, file
.error_details());
80 // Create or overwrite a file.
82 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
);
83 EXPECT_TRUE(file
.IsValid());
84 EXPECT_TRUE(file
.created());
85 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
89 // Create a delete-on-close file.
90 file_path
= temp_dir
.path().AppendASCII("create_file_2");
92 base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_READ
|
93 base::File::FLAG_DELETE_ON_CLOSE
);
94 EXPECT_TRUE(file
.IsValid());
95 EXPECT_TRUE(file
.created());
96 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
99 EXPECT_FALSE(base::PathExists(file_path
));
102 TEST(FileTest
, Async
) {
103 base::ScopedTempDir temp_dir
;
104 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
105 FilePath file_path
= temp_dir
.path().AppendASCII("create_file");
108 File
file(file_path
, base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_ASYNC
);
109 EXPECT_TRUE(file
.IsValid());
110 EXPECT_TRUE(file
.async());
114 File
file(file_path
, base::File::FLAG_OPEN_ALWAYS
);
115 EXPECT_TRUE(file
.IsValid());
116 EXPECT_FALSE(file
.async());
120 TEST(FileTest
, DeleteOpenFile
) {
121 base::ScopedTempDir temp_dir
;
122 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
123 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
127 base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_READ
|
128 base::File::FLAG_SHARE_DELETE
);
129 EXPECT_TRUE(file
.IsValid());
130 EXPECT_TRUE(file
.created());
131 EXPECT_EQ(base::File::FILE_OK
, file
.error_details());
133 // Open an existing file and mark it as delete on close.
134 File
same_file(file_path
,
135 base::File::FLAG_OPEN
| base::File::FLAG_DELETE_ON_CLOSE
|
136 base::File::FLAG_READ
);
137 EXPECT_TRUE(file
.IsValid());
138 EXPECT_FALSE(same_file
.created());
139 EXPECT_EQ(base::File::FILE_OK
, same_file
.error_details());
141 // Close both handles and check that the file is gone.
144 EXPECT_FALSE(base::PathExists(file_path
));
147 TEST(FileTest
, ReadWrite
) {
148 base::ScopedTempDir temp_dir
;
149 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
150 FilePath file_path
= temp_dir
.path().AppendASCII("read_write_file");
152 base::File::FLAG_CREATE
| base::File::FLAG_READ
|
153 base::File::FLAG_WRITE
);
154 ASSERT_TRUE(file
.IsValid());
156 char data_to_write
[] = "test";
157 const int kTestDataSize
= 4;
159 // Write 0 bytes to the file.
160 int bytes_written
= file
.Write(0, data_to_write
, 0);
161 EXPECT_EQ(0, bytes_written
);
163 // Write "test" to the file.
164 bytes_written
= file
.Write(0, data_to_write
, kTestDataSize
);
165 EXPECT_EQ(kTestDataSize
, bytes_written
);
168 char data_read_1
[32];
169 int bytes_read
= file
.Read(kTestDataSize
, data_read_1
, kTestDataSize
);
170 EXPECT_EQ(0, bytes_read
);
172 // Read from somewhere in the middle of the file.
173 const int kPartialReadOffset
= 1;
174 bytes_read
= file
.Read(kPartialReadOffset
, data_read_1
, kTestDataSize
);
175 EXPECT_EQ(kTestDataSize
- kPartialReadOffset
, bytes_read
);
176 for (int i
= 0; i
< bytes_read
; i
++)
177 EXPECT_EQ(data_to_write
[i
+ kPartialReadOffset
], data_read_1
[i
]);
180 bytes_read
= file
.Read(0, data_read_1
, 0);
181 EXPECT_EQ(0, bytes_read
);
183 // Read the entire file.
184 bytes_read
= file
.Read(0, data_read_1
, kTestDataSize
);
185 EXPECT_EQ(kTestDataSize
, bytes_read
);
186 for (int i
= 0; i
< bytes_read
; i
++)
187 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
189 // Read again, but using the trivial native wrapper.
190 bytes_read
= file
.ReadNoBestEffort(0, data_read_1
, kTestDataSize
);
191 EXPECT_LE(bytes_read
, kTestDataSize
);
192 for (int i
= 0; i
< bytes_read
; i
++)
193 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
195 // Write past the end of the file.
196 const int kOffsetBeyondEndOfFile
= 10;
197 const int kPartialWriteLength
= 2;
198 bytes_written
= file
.Write(kOffsetBeyondEndOfFile
,
199 data_to_write
, kPartialWriteLength
);
200 EXPECT_EQ(kPartialWriteLength
, bytes_written
);
202 // Make sure the file was extended.
204 EXPECT_TRUE(GetFileSize(file_path
, &file_size
));
205 EXPECT_EQ(kOffsetBeyondEndOfFile
+ kPartialWriteLength
, file_size
);
207 // Make sure the file was zero-padded.
208 char data_read_2
[32];
209 bytes_read
= file
.Read(0, data_read_2
, static_cast<int>(file_size
));
210 EXPECT_EQ(file_size
, bytes_read
);
211 for (int i
= 0; i
< kTestDataSize
; i
++)
212 EXPECT_EQ(data_to_write
[i
], data_read_2
[i
]);
213 for (int i
= kTestDataSize
; i
< kOffsetBeyondEndOfFile
; i
++)
214 EXPECT_EQ(0, data_read_2
[i
]);
215 for (int i
= kOffsetBeyondEndOfFile
; i
< file_size
; i
++)
216 EXPECT_EQ(data_to_write
[i
- kOffsetBeyondEndOfFile
], data_read_2
[i
]);
219 TEST(FileTest
, Append
) {
220 base::ScopedTempDir temp_dir
;
221 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
222 FilePath file_path
= temp_dir
.path().AppendASCII("append_file");
223 File
file(file_path
, base::File::FLAG_CREATE
| base::File::FLAG_APPEND
);
224 ASSERT_TRUE(file
.IsValid());
226 char data_to_write
[] = "test";
227 const int kTestDataSize
= 4;
229 // Write 0 bytes to the file.
230 int bytes_written
= file
.Write(0, data_to_write
, 0);
231 EXPECT_EQ(0, bytes_written
);
233 // Write "test" to the file.
234 bytes_written
= file
.Write(0, data_to_write
, kTestDataSize
);
235 EXPECT_EQ(kTestDataSize
, bytes_written
);
238 File
file2(file_path
,
239 base::File::FLAG_OPEN
| base::File::FLAG_READ
|
240 base::File::FLAG_APPEND
);
241 ASSERT_TRUE(file2
.IsValid());
243 // Test passing the file around.
245 EXPECT_FALSE(file2
.IsValid());
246 ASSERT_TRUE(file
.IsValid());
248 char append_data_to_write
[] = "78";
249 const int kAppendDataSize
= 2;
251 // Append "78" to the file.
252 bytes_written
= file
.Write(0, append_data_to_write
, kAppendDataSize
);
253 EXPECT_EQ(kAppendDataSize
, bytes_written
);
255 // Read the entire file.
256 char data_read_1
[32];
257 int bytes_read
= file
.Read(0, data_read_1
,
258 kTestDataSize
+ kAppendDataSize
);
259 EXPECT_EQ(kTestDataSize
+ kAppendDataSize
, bytes_read
);
260 for (int i
= 0; i
< kTestDataSize
; i
++)
261 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
262 for (int i
= 0; i
< kAppendDataSize
; i
++)
263 EXPECT_EQ(append_data_to_write
[i
], data_read_1
[kTestDataSize
+ i
]);
267 TEST(FileTest
, Length
) {
268 base::ScopedTempDir temp_dir
;
269 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
270 FilePath file_path
= temp_dir
.path().AppendASCII("truncate_file");
272 base::File::FLAG_CREATE
| base::File::FLAG_READ
|
273 base::File::FLAG_WRITE
);
274 ASSERT_TRUE(file
.IsValid());
275 EXPECT_EQ(0, file
.GetLength());
277 // Write "test" to the file.
278 char data_to_write
[] = "test";
279 int kTestDataSize
= 4;
280 int bytes_written
= file
.Write(0, data_to_write
, kTestDataSize
);
281 EXPECT_EQ(kTestDataSize
, bytes_written
);
284 const int kExtendedFileLength
= 10;
286 EXPECT_TRUE(file
.SetLength(kExtendedFileLength
));
287 EXPECT_EQ(kExtendedFileLength
, file
.GetLength());
288 EXPECT_TRUE(GetFileSize(file_path
, &file_size
));
289 EXPECT_EQ(kExtendedFileLength
, file_size
);
291 // Make sure the file was zero-padded.
293 int bytes_read
= file
.Read(0, data_read
, static_cast<int>(file_size
));
294 EXPECT_EQ(file_size
, bytes_read
);
295 for (int i
= 0; i
< kTestDataSize
; i
++)
296 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
297 for (int i
= kTestDataSize
; i
< file_size
; i
++)
298 EXPECT_EQ(0, data_read
[i
]);
300 // Truncate the file.
301 const int kTruncatedFileLength
= 2;
302 EXPECT_TRUE(file
.SetLength(kTruncatedFileLength
));
303 EXPECT_EQ(kTruncatedFileLength
, file
.GetLength());
304 EXPECT_TRUE(GetFileSize(file_path
, &file_size
));
305 EXPECT_EQ(kTruncatedFileLength
, file_size
);
307 // Make sure the file was truncated.
308 bytes_read
= file
.Read(0, data_read
, kTestDataSize
);
309 EXPECT_EQ(file_size
, bytes_read
);
310 for (int i
= 0; i
< file_size
; i
++)
311 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
314 // Flakily fails: http://crbug.com/86494
315 #if defined(OS_ANDROID)
316 TEST(FileTest
, TouchGetInfo
) {
318 TEST(FileTest
, DISABLED_TouchGetInfo
) {
320 base::ScopedTempDir temp_dir
;
321 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
322 File
file(temp_dir
.path().AppendASCII("touch_get_info_file"),
323 base::File::FLAG_CREATE
| base::File::FLAG_WRITE
|
324 base::File::FLAG_WRITE_ATTRIBUTES
);
325 ASSERT_TRUE(file
.IsValid());
327 // Get info for a newly created file.
328 base::File::Info info
;
329 EXPECT_TRUE(file
.GetInfo(&info
));
331 // Add 2 seconds to account for possible rounding errors on
332 // filesystems that use a 1s or 2s timestamp granularity.
333 base::Time now
= base::Time::Now() + base::TimeDelta::FromSeconds(2);
334 EXPECT_EQ(0, info
.size
);
335 EXPECT_FALSE(info
.is_directory
);
336 EXPECT_FALSE(info
.is_symbolic_link
);
337 EXPECT_LE(info
.last_accessed
.ToInternalValue(), now
.ToInternalValue());
338 EXPECT_LE(info
.last_modified
.ToInternalValue(), now
.ToInternalValue());
339 EXPECT_LE(info
.creation_time
.ToInternalValue(), now
.ToInternalValue());
340 base::Time creation_time
= info
.creation_time
;
342 // Write "test" to the file.
343 char data
[] = "test";
344 const int kTestDataSize
= 4;
345 int bytes_written
= file
.Write(0, data
, kTestDataSize
);
346 EXPECT_EQ(kTestDataSize
, bytes_written
);
348 // Change the last_accessed and last_modified dates.
349 // It's best to add values that are multiples of 2 (in seconds)
350 // to the current last_accessed and last_modified times, because
351 // FATxx uses a 2s timestamp granularity.
352 base::Time new_last_accessed
=
353 info
.last_accessed
+ base::TimeDelta::FromSeconds(234);
354 base::Time new_last_modified
=
355 info
.last_modified
+ base::TimeDelta::FromMinutes(567);
357 EXPECT_TRUE(file
.SetTimes(new_last_accessed
, new_last_modified
));
359 // Make sure the file info was updated accordingly.
360 EXPECT_TRUE(file
.GetInfo(&info
));
361 EXPECT_EQ(info
.size
, kTestDataSize
);
362 EXPECT_FALSE(info
.is_directory
);
363 EXPECT_FALSE(info
.is_symbolic_link
);
365 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
366 #if defined(OS_POSIX)
367 EXPECT_EQ(info
.last_accessed
.ToTimeVal().tv_sec
,
368 new_last_accessed
.ToTimeVal().tv_sec
);
369 EXPECT_EQ(info
.last_modified
.ToTimeVal().tv_sec
,
370 new_last_modified
.ToTimeVal().tv_sec
);
372 EXPECT_EQ(info
.last_accessed
.ToInternalValue(),
373 new_last_accessed
.ToInternalValue());
374 EXPECT_EQ(info
.last_modified
.ToInternalValue(),
375 new_last_modified
.ToInternalValue());
378 EXPECT_EQ(info
.creation_time
.ToInternalValue(),
379 creation_time
.ToInternalValue());
382 TEST(FileTest
, ReadAtCurrentPosition
) {
383 base::ScopedTempDir temp_dir
;
384 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
385 FilePath file_path
= temp_dir
.path().AppendASCII("read_at_current_position");
387 base::File::FLAG_CREATE
| base::File::FLAG_READ
|
388 base::File::FLAG_WRITE
);
389 EXPECT_TRUE(file
.IsValid());
391 const char kData
[] = "test";
392 const int kDataSize
= sizeof(kData
) - 1;
393 EXPECT_EQ(kDataSize
, file
.Write(0, kData
, kDataSize
));
395 EXPECT_EQ(0, file
.Seek(base::File::FROM_BEGIN
, 0));
397 char buffer
[kDataSize
];
398 int first_chunk_size
= kDataSize
/ 2;
399 EXPECT_EQ(first_chunk_size
, file
.ReadAtCurrentPos(buffer
, first_chunk_size
));
400 EXPECT_EQ(kDataSize
- first_chunk_size
,
401 file
.ReadAtCurrentPos(buffer
+ first_chunk_size
,
402 kDataSize
- first_chunk_size
));
403 EXPECT_EQ(std::string(buffer
, buffer
+ kDataSize
), std::string(kData
));
406 TEST(FileTest
, WriteAtCurrentPosition
) {
407 base::ScopedTempDir temp_dir
;
408 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
409 FilePath file_path
= temp_dir
.path().AppendASCII("write_at_current_position");
411 base::File::FLAG_CREATE
| base::File::FLAG_READ
|
412 base::File::FLAG_WRITE
);
413 EXPECT_TRUE(file
.IsValid());
415 const char kData
[] = "test";
416 const int kDataSize
= sizeof(kData
) - 1;
418 int first_chunk_size
= kDataSize
/ 2;
419 EXPECT_EQ(first_chunk_size
, file
.WriteAtCurrentPos(kData
, first_chunk_size
));
420 EXPECT_EQ(kDataSize
- first_chunk_size
,
421 file
.WriteAtCurrentPos(kData
+ first_chunk_size
,
422 kDataSize
- first_chunk_size
));
424 char buffer
[kDataSize
];
425 EXPECT_EQ(kDataSize
, file
.Read(0, buffer
, kDataSize
));
426 EXPECT_EQ(std::string(buffer
, buffer
+ kDataSize
), std::string(kData
));
429 TEST(FileTest
, Seek
) {
430 base::ScopedTempDir temp_dir
;
431 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
432 FilePath file_path
= temp_dir
.path().AppendASCII("seek_file");
434 base::File::FLAG_CREATE
| base::File::FLAG_READ
|
435 base::File::FLAG_WRITE
);
436 ASSERT_TRUE(file
.IsValid());
438 const int64 kOffset
= 10;
439 EXPECT_EQ(kOffset
, file
.Seek(base::File::FROM_BEGIN
, kOffset
));
440 EXPECT_EQ(2 * kOffset
, file
.Seek(base::File::FROM_CURRENT
, kOffset
));
441 EXPECT_EQ(kOffset
, file
.Seek(base::File::FROM_CURRENT
, -kOffset
));
442 EXPECT_TRUE(file
.SetLength(kOffset
* 2));
443 EXPECT_EQ(kOffset
, file
.Seek(base::File::FROM_END
, -kOffset
));
447 TEST(FileTest
, GetInfoForDirectory
) {
448 base::ScopedTempDir temp_dir
;
449 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
450 FilePath empty_dir
= temp_dir
.path().Append(FILE_PATH_LITERAL("gpfi_test"));
451 ASSERT_TRUE(CreateDirectory(empty_dir
));
454 ::CreateFile(empty_dir
.value().c_str(),
456 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
459 FILE_FLAG_BACKUP_SEMANTICS
, // Needed to open a directory.
461 ASSERT_TRUE(dir
.IsValid());
463 base::File::Info info
;
464 EXPECT_TRUE(dir
.GetInfo(&info
));
465 EXPECT_TRUE(info
.is_directory
);
466 EXPECT_FALSE(info
.is_symbolic_link
);
467 EXPECT_EQ(0, info
.size
);
469 #endif // defined(OS_WIN)
471 #if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
472 TEST(FileTest
, MemoryCorruption
) {
474 // Test that changing the checksum value is detected.
476 EXPECT_NE(file
.file_
.file_memory_checksum_
,
477 implicit_cast
<unsigned int>(file
.GetPlatformFile()));
478 file
.file_
.file_memory_checksum_
= file
.GetPlatformFile();
479 EXPECT_DEATH(file
.IsValid(), "");
481 file
.file_
.UpdateChecksum(); // Do not crash on File::~File().
485 // Test that changing the file descriptor value is detected.
487 file
.file_
.file_
.reset(17);
488 EXPECT_DEATH(file
.IsValid(), "");
490 // Do not crash on File::~File().
491 ignore_result(file
.file_
.file_
.release());
492 file
.file_
.UpdateChecksum();
496 // Test that GetPlatformFile() checks for corruption.
498 file
.file_
.file_memory_checksum_
= file
.GetPlatformFile();
499 EXPECT_DEATH(file
.GetPlatformFile(), "");
501 file
.file_
.UpdateChecksum(); // Do not crash on File::~File().
505 // Test that the base::File destructor checks for corruption.
506 scoped_ptr
<base::File
> file(new File());
507 file
->file_
.file_memory_checksum_
= file
->GetPlatformFile();
508 EXPECT_DEATH(file
.reset(), "");
510 // Do not crash on this thread's destructor call.
511 file
->file_
.UpdateChecksum();
515 // Test that the base::File constructor checks for corruption.
517 file
.file_
.file_memory_checksum_
= file
.GetPlatformFile();
518 EXPECT_DEATH(File
f(file
.Pass()), "");
520 file
.file_
.UpdateChecksum(); // Do not crash on File::~File().
524 // Test that doing IO checks for corruption.
526 file
.file_
.file_
.reset(17); // A fake open FD value.
528 EXPECT_DEATH(file
.Seek(File::FROM_BEGIN
, 0), "");
529 EXPECT_DEATH(file
.Read(0, NULL
, 0), "");
530 EXPECT_DEATH(file
.ReadAtCurrentPos(NULL
, 0), "");
531 EXPECT_DEATH(file
.Write(0, NULL
, 0), "");
533 ignore_result(file
.file_
.file_
.release());
534 file
.file_
.UpdateChecksum();
537 #endif // defined(OS_POSIX)