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/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/platform_file.h"
8 #include "base/time/time.h"
9 #include "testing/gtest/include/gtest/gtest.h"
15 // Reads from a file the given number of bytes, or until EOF is reached.
16 // Returns the number of bytes read.
17 int ReadFully(base::PlatformFile file
, int64 offset
, char* data
, int size
) {
18 return base::ReadPlatformFile(file
, offset
, data
, size
);
21 // Writes the given number of bytes to a file.
22 // Returns the number of bytes written.
23 int WriteFully(base::PlatformFile file
, int64 offset
,
24 const char* data
, int size
) {
25 return base::WritePlatformFile(file
, offset
, data
, size
);
30 TEST(PlatformFile
, CreatePlatformFile
) {
31 base::ScopedTempDir temp_dir
;
32 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
33 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
35 // Open a file that doesn't exist.
36 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
37 base::PlatformFile file
= base::CreatePlatformFile(
39 base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
42 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
43 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND
, error_code
);
45 // Open or create a file.
47 error_code
= base::PLATFORM_FILE_OK
;
48 file
= base::CreatePlatformFile(
50 base::PLATFORM_FILE_OPEN_ALWAYS
| base::PLATFORM_FILE_READ
,
53 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
55 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
56 base::ClosePlatformFile(file
);
58 // Open an existing file.
60 file
= base::CreatePlatformFile(
62 base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
,
65 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
66 EXPECT_FALSE(created
);
67 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
68 base::ClosePlatformFile(file
);
70 // Create a file that exists.
71 file
= base::CreatePlatformFile(
73 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_READ
,
76 EXPECT_EQ(base::kInvalidPlatformFileValue
, file
);
77 EXPECT_FALSE(created
);
78 EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS
, error_code
);
80 // Create or overwrite a file.
81 error_code
= base::PLATFORM_FILE_OK
;
82 file
= base::CreatePlatformFile(
84 base::PLATFORM_FILE_CREATE_ALWAYS
| base::PLATFORM_FILE_READ
,
87 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
89 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
90 base::ClosePlatformFile(file
);
92 // Create a delete-on-close file.
94 file_path
= temp_dir
.path().AppendASCII("create_file_2");
95 file
= base::CreatePlatformFile(
97 base::PLATFORM_FILE_OPEN_ALWAYS
| base::PLATFORM_FILE_DELETE_ON_CLOSE
|
98 base::PLATFORM_FILE_READ
,
101 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
102 EXPECT_TRUE(created
);
103 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
105 EXPECT_TRUE(base::ClosePlatformFile(file
));
106 EXPECT_FALSE(base::PathExists(file_path
));
109 TEST(PlatformFile
, DeleteOpenFile
) {
110 base::ScopedTempDir temp_dir
;
111 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
112 FilePath file_path
= temp_dir
.path().AppendASCII("create_file_1");
115 bool created
= false;
116 base::PlatformFileError error_code
= base::PLATFORM_FILE_OK
;
117 base::PlatformFile file
= base::CreatePlatformFile(
119 base::PLATFORM_FILE_OPEN_ALWAYS
| base::PLATFORM_FILE_READ
|
120 base::PLATFORM_FILE_SHARE_DELETE
,
123 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
124 EXPECT_TRUE(created
);
125 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
127 // Open an existing file and mark it as delete on close.
129 base::PlatformFile same_file
= base::CreatePlatformFile(
131 base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_DELETE_ON_CLOSE
|
132 base::PLATFORM_FILE_READ
,
135 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
136 EXPECT_FALSE(created
);
137 EXPECT_EQ(base::PLATFORM_FILE_OK
, error_code
);
139 // Close both handles and check that the file is gone.
140 base::ClosePlatformFile(file
);
141 base::ClosePlatformFile(same_file
);
142 EXPECT_FALSE(base::PathExists(file_path
));
145 TEST(PlatformFile
, ReadWritePlatformFile
) {
146 base::ScopedTempDir temp_dir
;
147 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
148 FilePath file_path
= temp_dir
.path().AppendASCII("read_write_file");
149 base::PlatformFile file
= base::CreatePlatformFile(
151 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_READ
|
152 base::PLATFORM_FILE_WRITE
,
155 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
157 char data_to_write
[] = "test";
158 const int kTestDataSize
= 4;
160 // Write 0 bytes to the file.
161 int bytes_written
= WriteFully(file
, 0, data_to_write
, 0);
162 EXPECT_EQ(0, bytes_written
);
164 // Write "test" to the file.
165 bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
166 EXPECT_EQ(kTestDataSize
, bytes_written
);
169 char data_read_1
[32];
170 int bytes_read
= ReadFully(file
, kTestDataSize
, data_read_1
, kTestDataSize
);
171 EXPECT_EQ(0, bytes_read
);
173 // Read from somewhere in the middle of the file.
174 const int kPartialReadOffset
= 1;
175 bytes_read
= ReadFully(file
, kPartialReadOffset
, data_read_1
, kTestDataSize
);
176 EXPECT_EQ(kTestDataSize
- kPartialReadOffset
, bytes_read
);
177 for (int i
= 0; i
< bytes_read
; i
++)
178 EXPECT_EQ(data_to_write
[i
+ kPartialReadOffset
], data_read_1
[i
]);
181 bytes_read
= ReadFully(file
, 0, data_read_1
, 0);
182 EXPECT_EQ(0, bytes_read
);
184 // Read the entire file.
185 bytes_read
= ReadFully(file
, 0, data_read_1
, kTestDataSize
);
186 EXPECT_EQ(kTestDataSize
, bytes_read
);
187 for (int i
= 0; i
< bytes_read
; i
++)
188 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
190 // Read again, but using the trivial native wrapper.
191 bytes_read
= base::ReadPlatformFileNoBestEffort(file
, 0, data_read_1
,
193 EXPECT_LE(bytes_read
, kTestDataSize
);
194 for (int i
= 0; i
< bytes_read
; i
++)
195 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
197 // Write past the end of the file.
198 const int kOffsetBeyondEndOfFile
= 10;
199 const int kPartialWriteLength
= 2;
200 bytes_written
= WriteFully(file
, kOffsetBeyondEndOfFile
,
201 data_to_write
, kPartialWriteLength
);
202 EXPECT_EQ(kPartialWriteLength
, bytes_written
);
204 // Make sure the file was extended.
206 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
207 EXPECT_EQ(kOffsetBeyondEndOfFile
+ kPartialWriteLength
, file_size
);
209 // Make sure the file was zero-padded.
210 char data_read_2
[32];
211 bytes_read
= ReadFully(file
, 0, data_read_2
, static_cast<int>(file_size
));
212 EXPECT_EQ(file_size
, bytes_read
);
213 for (int i
= 0; i
< kTestDataSize
; i
++)
214 EXPECT_EQ(data_to_write
[i
], data_read_2
[i
]);
215 for (int i
= kTestDataSize
; i
< kOffsetBeyondEndOfFile
; i
++)
216 EXPECT_EQ(0, data_read_2
[i
]);
217 for (int i
= kOffsetBeyondEndOfFile
; i
< file_size
; i
++)
218 EXPECT_EQ(data_to_write
[i
- kOffsetBeyondEndOfFile
], data_read_2
[i
]);
220 // Close the file handle to allow the temp directory to be deleted.
221 base::ClosePlatformFile(file
);
224 TEST(PlatformFile
, AppendPlatformFile
) {
225 base::ScopedTempDir temp_dir
;
226 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
227 FilePath file_path
= temp_dir
.path().AppendASCII("append_file");
228 base::PlatformFile file
= base::CreatePlatformFile(
230 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_APPEND
,
233 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
235 char data_to_write
[] = "test";
236 const int kTestDataSize
= 4;
238 // Write 0 bytes to the file.
239 int bytes_written
= WriteFully(file
, 0, data_to_write
, 0);
240 EXPECT_EQ(0, bytes_written
);
242 // Write "test" to the file.
243 bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
244 EXPECT_EQ(kTestDataSize
, bytes_written
);
246 base::ClosePlatformFile(file
);
247 file
= base::CreatePlatformFile(
249 base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
|
250 base::PLATFORM_FILE_APPEND
,
253 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
255 char append_data_to_write
[] = "78";
256 const int kAppendDataSize
= 2;
258 // Append "78" to the file.
259 bytes_written
= WriteFully(file
, 0, append_data_to_write
, kAppendDataSize
);
260 EXPECT_EQ(kAppendDataSize
, bytes_written
);
262 // Read the entire file.
263 char data_read_1
[32];
264 int bytes_read
= ReadFully(file
, 0, data_read_1
,
265 kTestDataSize
+ kAppendDataSize
);
266 EXPECT_EQ(kTestDataSize
+ kAppendDataSize
, bytes_read
);
267 for (int i
= 0; i
< kTestDataSize
; i
++)
268 EXPECT_EQ(data_to_write
[i
], data_read_1
[i
]);
269 for (int i
= 0; i
< kAppendDataSize
; i
++)
270 EXPECT_EQ(append_data_to_write
[i
], data_read_1
[kTestDataSize
+ i
]);
272 // Close the file handle to allow the temp directory to be deleted.
273 base::ClosePlatformFile(file
);
277 TEST(PlatformFile
, TruncatePlatformFile
) {
278 base::ScopedTempDir temp_dir
;
279 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
280 FilePath file_path
= temp_dir
.path().AppendASCII("truncate_file");
281 base::PlatformFile file
= base::CreatePlatformFile(
283 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_READ
|
284 base::PLATFORM_FILE_WRITE
,
287 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
289 // Write "test" to the file.
290 char data_to_write
[] = "test";
291 int kTestDataSize
= 4;
292 int bytes_written
= WriteFully(file
, 0, data_to_write
, kTestDataSize
);
293 EXPECT_EQ(kTestDataSize
, bytes_written
);
296 const int kExtendedFileLength
= 10;
298 EXPECT_TRUE(base::TruncatePlatformFile(file
, kExtendedFileLength
));
299 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
300 EXPECT_EQ(kExtendedFileLength
, file_size
);
302 // Make sure the file was zero-padded.
304 int bytes_read
= ReadFully(file
, 0, data_read
, static_cast<int>(file_size
));
305 EXPECT_EQ(file_size
, bytes_read
);
306 for (int i
= 0; i
< kTestDataSize
; i
++)
307 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
308 for (int i
= kTestDataSize
; i
< file_size
; i
++)
309 EXPECT_EQ(0, data_read
[i
]);
311 // Truncate the file.
312 const int kTruncatedFileLength
= 2;
313 EXPECT_TRUE(base::TruncatePlatformFile(file
, kTruncatedFileLength
));
314 EXPECT_TRUE(file_util::GetFileSize(file_path
, &file_size
));
315 EXPECT_EQ(kTruncatedFileLength
, file_size
);
317 // Make sure the file was truncated.
318 bytes_read
= ReadFully(file
, 0, data_read
, kTestDataSize
);
319 EXPECT_EQ(file_size
, bytes_read
);
320 for (int i
= 0; i
< file_size
; i
++)
321 EXPECT_EQ(data_to_write
[i
], data_read
[i
]);
323 // Close the file handle to allow the temp directory to be deleted.
324 base::ClosePlatformFile(file
);
327 // Flakily fails: http://crbug.com/86494
328 #if defined(OS_ANDROID)
329 TEST(PlatformFile
, TouchGetInfoPlatformFile
) {
331 TEST(PlatformFile
, DISABLED_TouchGetInfoPlatformFile
) {
333 base::ScopedTempDir temp_dir
;
334 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
335 base::PlatformFile file
= base::CreatePlatformFile(
336 temp_dir
.path().AppendASCII("touch_get_info_file"),
337 base::PLATFORM_FILE_CREATE
| base::PLATFORM_FILE_WRITE
|
338 base::PLATFORM_FILE_WRITE_ATTRIBUTES
,
341 EXPECT_NE(base::kInvalidPlatformFileValue
, file
);
343 // Get info for a newly created file.
344 base::PlatformFileInfo info
;
345 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
347 // Add 2 seconds to account for possible rounding errors on
348 // filesystems that use a 1s or 2s timestamp granularity.
349 base::Time now
= base::Time::Now() + base::TimeDelta::FromSeconds(2);
350 EXPECT_EQ(0, info
.size
);
351 EXPECT_FALSE(info
.is_directory
);
352 EXPECT_FALSE(info
.is_symbolic_link
);
353 EXPECT_LE(info
.last_accessed
.ToInternalValue(), now
.ToInternalValue());
354 EXPECT_LE(info
.last_modified
.ToInternalValue(), now
.ToInternalValue());
355 EXPECT_LE(info
.creation_time
.ToInternalValue(), now
.ToInternalValue());
356 base::Time creation_time
= info
.creation_time
;
358 // Write "test" to the file.
359 char data
[] = "test";
360 const int kTestDataSize
= 4;
361 int bytes_written
= WriteFully(file
, 0, data
, kTestDataSize
);
362 EXPECT_EQ(kTestDataSize
, bytes_written
);
364 // Change the last_accessed and last_modified dates.
365 // It's best to add values that are multiples of 2 (in seconds)
366 // to the current last_accessed and last_modified times, because
367 // FATxx uses a 2s timestamp granularity.
368 base::Time new_last_accessed
=
369 info
.last_accessed
+ base::TimeDelta::FromSeconds(234);
370 base::Time new_last_modified
=
371 info
.last_modified
+ base::TimeDelta::FromMinutes(567);
373 EXPECT_TRUE(base::TouchPlatformFile(file
, new_last_accessed
,
376 // Make sure the file info was updated accordingly.
377 EXPECT_TRUE(base::GetPlatformFileInfo(file
, &info
));
378 EXPECT_EQ(info
.size
, kTestDataSize
);
379 EXPECT_FALSE(info
.is_directory
);
380 EXPECT_FALSE(info
.is_symbolic_link
);
382 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
383 #if defined(OS_POSIX)
384 EXPECT_EQ(info
.last_accessed
.ToTimeVal().tv_sec
,
385 new_last_accessed
.ToTimeVal().tv_sec
);
386 EXPECT_EQ(info
.last_modified
.ToTimeVal().tv_sec
,
387 new_last_modified
.ToTimeVal().tv_sec
);
389 EXPECT_EQ(info
.last_accessed
.ToInternalValue(),
390 new_last_accessed
.ToInternalValue());
391 EXPECT_EQ(info
.last_modified
.ToInternalValue(),
392 new_last_modified
.ToInternalValue());
395 EXPECT_EQ(info
.creation_time
.ToInternalValue(),
396 creation_time
.ToInternalValue());
398 // Close the file handle to allow the temp directory to be deleted.
399 base::ClosePlatformFile(file
);