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. 4 5#include "base/files/file.h" 6 7#include <stdint.h> 8 9#include <utility> 10 11#include "base/files/file_util.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/time/time.h" 14#include "build/build_config.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17using base::File; 18using base::FilePath; 19 20TEST(FileTest, Create) { 21 base::ScopedTempDir temp_dir; 22 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 23 FilePath file_path = temp_dir.path().AppendASCII("create_file_1"); 24 25 { 26 // Don't create a File at all. 27 File file; 28 EXPECT_FALSE(file.IsValid()); 29 EXPECT_EQ(base::File::FILE_ERROR_FAILED, file.error_details()); 30 31 File file2(base::File::FILE_ERROR_TOO_MANY_OPENED); 32 EXPECT_FALSE(file2.IsValid()); 33 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details()); 34 } 35 36 { 37 // Open a file that doesn't exist. 38 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 39 EXPECT_FALSE(file.IsValid()); 40 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details()); 41 } 42 43 { 44 // Open or create a file. 45 File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ); 46 EXPECT_TRUE(file.IsValid()); 47 EXPECT_TRUE(file.created()); 48 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 49 } 50 51 { 52 // Open an existing file. 53 File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 54 EXPECT_TRUE(file.IsValid()); 55 EXPECT_FALSE(file.created()); 56 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 57 58 // This time verify closing the file. 59 file.Close(); 60 EXPECT_FALSE(file.IsValid()); 61 } 62 63 { 64 // Open an existing file through Initialize 65 File file; 66 file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 67 EXPECT_TRUE(file.IsValid()); 68 EXPECT_FALSE(file.created()); 69 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 70 71 // This time verify closing the file. 72 file.Close(); 73 EXPECT_FALSE(file.IsValid()); 74 } 75 76 { 77 // Create a file that exists. 78 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ); 79 EXPECT_FALSE(file.IsValid()); 80 EXPECT_FALSE(file.created()); 81 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details()); 82 } 83 84 { 85 // Create or overwrite a file. 86 File file(file_path, 87 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 88 EXPECT_TRUE(file.IsValid()); 89 EXPECT_TRUE(file.created()); 90 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 91 } 92 93 { 94 // Create a delete-on-close file. 95 file_path = temp_dir.path().AppendASCII("create_file_2"); 96 File file(file_path, 97 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ | 98 base::File::FLAG_DELETE_ON_CLOSE); 99 EXPECT_TRUE(file.IsValid()); 100 EXPECT_TRUE(file.created()); 101 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 102 } 103 104 EXPECT_FALSE(base::PathExists(file_path)); 105} 106 107TEST(FileTest, Async) { 108 base::ScopedTempDir temp_dir; 109 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 110 FilePath file_path = temp_dir.path().AppendASCII("create_file"); 111 112 { 113 File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_ASYNC); 114 EXPECT_TRUE(file.IsValid()); 115 EXPECT_TRUE(file.async()); 116 } 117 118 { 119 File file(file_path, base::File::FLAG_OPEN_ALWAYS); 120 EXPECT_TRUE(file.IsValid()); 121 EXPECT_FALSE(file.async()); 122 } 123} 124 125TEST(FileTest, DeleteOpenFile) { 126 base::ScopedTempDir temp_dir; 127 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 128 FilePath file_path = temp_dir.path().AppendASCII("create_file_1"); 129 130 // Create a file. 131 File file(file_path, 132 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ | 133 base::File::FLAG_SHARE_DELETE); 134 EXPECT_TRUE(file.IsValid()); 135 EXPECT_TRUE(file.created()); 136 EXPECT_EQ(base::File::FILE_OK, file.error_details()); 137 138 // Open an existing file and mark it as delete on close. 139 File same_file(file_path, 140 base::File::FLAG_OPEN | base::File::FLAG_DELETE_ON_CLOSE | 141 base::File::FLAG_READ); 142 EXPECT_TRUE(file.IsValid()); 143 EXPECT_FALSE(same_file.created()); 144 EXPECT_EQ(base::File::FILE_OK, same_file.error_details()); 145 146 // Close both handles and check that the file is gone. 147 file.Close(); 148 same_file.Close(); 149 EXPECT_FALSE(base::PathExists(file_path)); 150} 151 152TEST(FileTest, ReadWrite) { 153 base::ScopedTempDir temp_dir; 154 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 155 FilePath file_path = temp_dir.path().AppendASCII("read_write_file"); 156 File file(file_path, 157 base::File::FLAG_CREATE | base::File::FLAG_READ | 158 base::File::FLAG_WRITE); 159 ASSERT_TRUE(file.IsValid()); 160 161 char data_to_write[] = "test"; 162 const int kTestDataSize = 4; 163 164 // Write 0 bytes to the file. 165 int bytes_written = file.Write(0, data_to_write, 0); 166 EXPECT_EQ(0, bytes_written); 167 168 // Write "test" to the file. 169 bytes_written = file.Write(0, data_to_write, kTestDataSize); 170 EXPECT_EQ(kTestDataSize, bytes_written); 171 172 // Read from EOF. 173 char data_read_1[32]; 174 int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize); 175 EXPECT_EQ(0, bytes_read); 176 177 // Read from somewhere in the middle of the file. 178 const int kPartialReadOffset = 1; 179 bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize); 180 EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read); 181 for (int i = 0; i < bytes_read; i++) 182 EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]); 183 184 // Read 0 bytes. 185 bytes_read = file.Read(0, data_read_1, 0); 186 EXPECT_EQ(0, bytes_read); 187 188 // Read the entire file. 189 bytes_read = file.Read(0, data_read_1, kTestDataSize); 190 EXPECT_EQ(kTestDataSize, bytes_read); 191 for (int i = 0; i < bytes_read; i++) 192 EXPECT_EQ(data_to_write[i], data_read_1[i]); 193 194 // Read again, but using the trivial native wrapper. 195 bytes_read = file.ReadNoBestEffort(0, data_read_1, kTestDataSize); 196 EXPECT_LE(bytes_read, kTestDataSize); 197 for (int i = 0; i < bytes_read; i++) 198 EXPECT_EQ(data_to_write[i], data_read_1[i]); 199 200 // Write past the end of the file. 201 const int kOffsetBeyondEndOfFile = 10; 202 const int kPartialWriteLength = 2; 203 bytes_written = file.Write(kOffsetBeyondEndOfFile, 204 data_to_write, kPartialWriteLength); 205 EXPECT_EQ(kPartialWriteLength, bytes_written); 206 207 // Make sure the file was extended. 208 int64_t file_size = 0; 209 EXPECT_TRUE(GetFileSize(file_path, &file_size)); 210 EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size); 211 212 // Make sure the file was zero-padded. 213 char data_read_2[32]; 214 bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size)); 215 EXPECT_EQ(file_size, bytes_read); 216 for (int i = 0; i < kTestDataSize; i++) 217 EXPECT_EQ(data_to_write[i], data_read_2[i]); 218 for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++) 219 EXPECT_EQ(0, data_read_2[i]); 220 for (int i = kOffsetBeyondEndOfFile; i < file_size; i++) 221 EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]); 222} 223 224TEST(FileTest, Append) { 225 base::ScopedTempDir temp_dir; 226 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 227 FilePath file_path = temp_dir.path().AppendASCII("append_file"); 228 File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND); 229 ASSERT_TRUE(file.IsValid()); 230 231 char data_to_write[] = "test"; 232 const int kTestDataSize = 4; 233 234 // Write 0 bytes to the file. 235 int bytes_written = file.Write(0, data_to_write, 0); 236 EXPECT_EQ(0, bytes_written); 237 238 // Write "test" to the file. 239 bytes_written = file.Write(0, data_to_write, kTestDataSize); 240 EXPECT_EQ(kTestDataSize, bytes_written); 241 242 file.Close(); 243 File file2(file_path, 244 base::File::FLAG_OPEN | base::File::FLAG_READ | 245 base::File::FLAG_APPEND); 246 ASSERT_TRUE(file2.IsValid()); 247 248 // Test passing the file around. 249 file = std::move(file2); 250 EXPECT_FALSE(file2.IsValid()); 251 ASSERT_TRUE(file.IsValid()); 252 253 char append_data_to_write[] = "78"; 254 const int kAppendDataSize = 2; 255 256 // Append "78" to the file. 257 bytes_written = file.Write(0, append_data_to_write, kAppendDataSize); 258 EXPECT_EQ(kAppendDataSize, bytes_written); 259 260 // Read the entire file. 261 char data_read_1[32]; 262 int bytes_read = file.Read(0, data_read_1, 263 kTestDataSize + kAppendDataSize); 264 EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read); 265 for (int i = 0; i < kTestDataSize; i++) 266 EXPECT_EQ(data_to_write[i], data_read_1[i]); 267 for (int i = 0; i < kAppendDataSize; i++) 268 EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]); 269} 270 271 272TEST(FileTest, Length) { 273 base::ScopedTempDir temp_dir; 274 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 275 FilePath file_path = temp_dir.path().AppendASCII("truncate_file"); 276 File file(file_path, 277 base::File::FLAG_CREATE | base::File::FLAG_READ | 278 base::File::FLAG_WRITE); 279 ASSERT_TRUE(file.IsValid()); 280 EXPECT_EQ(0, file.GetLength()); 281 282 // Write "test" to the file. 283 char data_to_write[] = "test"; 284 int kTestDataSize = 4; 285 int bytes_written = file.Write(0, data_to_write, kTestDataSize); 286 EXPECT_EQ(kTestDataSize, bytes_written); 287 288 // Extend the file. 289 const int kExtendedFileLength = 10; 290 int64_t file_size = 0; 291 EXPECT_TRUE(file.SetLength(kExtendedFileLength)); 292 EXPECT_EQ(kExtendedFileLength, file.GetLength()); 293 EXPECT_TRUE(GetFileSize(file_path, &file_size)); 294 EXPECT_EQ(kExtendedFileLength, file_size); 295 296 // Make sure the file was zero-padded. 297 char data_read[32]; 298 int bytes_read = file.Read(0, data_read, static_cast<int>(file_size)); 299 EXPECT_EQ(file_size, bytes_read); 300 for (int i = 0; i < kTestDataSize; i++) 301 EXPECT_EQ(data_to_write[i], data_read[i]); 302 for (int i = kTestDataSize; i < file_size; i++) 303 EXPECT_EQ(0, data_read[i]); 304 305 // Truncate the file. 306 const int kTruncatedFileLength = 2; 307 EXPECT_TRUE(file.SetLength(kTruncatedFileLength)); 308 EXPECT_EQ(kTruncatedFileLength, file.GetLength()); 309 EXPECT_TRUE(GetFileSize(file_path, &file_size)); 310 EXPECT_EQ(kTruncatedFileLength, file_size); 311 312 // Make sure the file was truncated. 313 bytes_read = file.Read(0, data_read, kTestDataSize); 314 EXPECT_EQ(file_size, bytes_read); 315 for (int i = 0; i < file_size; i++) 316 EXPECT_EQ(data_to_write[i], data_read[i]); 317} 318 319// Flakily fails: http://crbug.com/86494 320#if defined(OS_ANDROID) 321TEST(FileTest, TouchGetInfo) { 322#else 323TEST(FileTest, DISABLED_TouchGetInfo) { 324#endif 325 base::ScopedTempDir temp_dir; 326 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 327 File file(temp_dir.path().AppendASCII("touch_get_info_file"), 328 base::File::FLAG_CREATE | base::File::FLAG_WRITE | 329 base::File::FLAG_WRITE_ATTRIBUTES); 330 ASSERT_TRUE(file.IsValid()); 331 332 // Get info for a newly created file. 333 base::File::Info info; 334 EXPECT_TRUE(file.GetInfo(&info)); 335 336 // Add 2 seconds to account for possible rounding errors on 337 // filesystems that use a 1s or 2s timestamp granularity. 338 base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2); 339 EXPECT_EQ(0, info.size); 340 EXPECT_FALSE(info.is_directory); 341 EXPECT_FALSE(info.is_symbolic_link); 342 EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue()); 343 EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue()); 344 EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue()); 345 base::Time creation_time = info.creation_time; 346 347 // Write "test" to the file. 348 char data[] = "test"; 349 const int kTestDataSize = 4; 350 int bytes_written = file.Write(0, data, kTestDataSize); 351 EXPECT_EQ(kTestDataSize, bytes_written); 352 353 // Change the last_accessed and last_modified dates. 354 // It's best to add values that are multiples of 2 (in seconds) 355 // to the current last_accessed and last_modified times, because 356 // FATxx uses a 2s timestamp granularity. 357 base::Time new_last_accessed = 358 info.last_accessed + base::TimeDelta::FromSeconds(234); 359 base::Time new_last_modified = 360 info.last_modified + base::TimeDelta::FromMinutes(567); 361 362 EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified)); 363 364 // Make sure the file info was updated accordingly. 365 EXPECT_TRUE(file.GetInfo(&info)); 366 EXPECT_EQ(info.size, kTestDataSize); 367 EXPECT_FALSE(info.is_directory); 368 EXPECT_FALSE(info.is_symbolic_link); 369 370 // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s. 371#if defined(OS_POSIX) 372 EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec, 373 new_last_accessed.ToTimeVal().tv_sec); 374 EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec, 375 new_last_modified.ToTimeVal().tv_sec); 376#else 377 EXPECT_EQ(info.last_accessed.ToInternalValue(), 378 new_last_accessed.ToInternalValue()); 379 EXPECT_EQ(info.last_modified.ToInternalValue(), 380 new_last_modified.ToInternalValue()); 381#endif 382 383 EXPECT_EQ(info.creation_time.ToInternalValue(), 384 creation_time.ToInternalValue()); 385} 386 387TEST(FileTest, ReadAtCurrentPosition) { 388 base::ScopedTempDir temp_dir; 389 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 390 FilePath file_path = temp_dir.path().AppendASCII("read_at_current_position"); 391 File file(file_path, 392 base::File::FLAG_CREATE | base::File::FLAG_READ | 393 base::File::FLAG_WRITE); 394 EXPECT_TRUE(file.IsValid()); 395 396 const char kData[] = "test"; 397 const int kDataSize = sizeof(kData) - 1; 398 EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize)); 399 400 EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0)); 401 402 char buffer[kDataSize]; 403 int first_chunk_size = kDataSize / 2; 404 EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size)); 405 EXPECT_EQ(kDataSize - first_chunk_size, 406 file.ReadAtCurrentPos(buffer + first_chunk_size, 407 kDataSize - first_chunk_size)); 408 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData)); 409} 410 411TEST(FileTest, WriteAtCurrentPosition) { 412 base::ScopedTempDir temp_dir; 413 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 414 FilePath file_path = temp_dir.path().AppendASCII("write_at_current_position"); 415 File file(file_path, 416 base::File::FLAG_CREATE | base::File::FLAG_READ | 417 base::File::FLAG_WRITE); 418 EXPECT_TRUE(file.IsValid()); 419 420 const char kData[] = "test"; 421 const int kDataSize = sizeof(kData) - 1; 422 423 int first_chunk_size = kDataSize / 2; 424 EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size)); 425 EXPECT_EQ(kDataSize - first_chunk_size, 426 file.WriteAtCurrentPos(kData + first_chunk_size, 427 kDataSize - first_chunk_size)); 428 429 char buffer[kDataSize]; 430 EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize)); 431 EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData)); 432} 433 434TEST(FileTest, Seek) { 435 base::ScopedTempDir temp_dir; 436 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 437 FilePath file_path = temp_dir.path().AppendASCII("seek_file"); 438 File file(file_path, 439 base::File::FLAG_CREATE | base::File::FLAG_READ | 440 base::File::FLAG_WRITE); 441 ASSERT_TRUE(file.IsValid()); 442 443 const int64_t kOffset = 10; 444 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset)); 445 EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset)); 446 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset)); 447 EXPECT_TRUE(file.SetLength(kOffset * 2)); 448 EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset)); 449} 450 451TEST(FileTest, Duplicate) { 452 base::ScopedTempDir temp_dir; 453 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 454 FilePath file_path = temp_dir.path().AppendASCII("file"); 455 File file(file_path,(base::File::FLAG_CREATE | 456 base::File::FLAG_READ | 457 base::File::FLAG_WRITE)); 458 ASSERT_TRUE(file.IsValid()); 459 460 File file2(file.Duplicate()); 461 ASSERT_TRUE(file2.IsValid()); 462 463 // Write through one handle, close it, read through the other. 464 static const char kData[] = "now is a good time."; 465 static const int kDataLen = sizeof(kData) - 1; 466 467 ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0)); 468 ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0)); 469 ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen)); 470 ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0)); 471 ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0)); 472 file.Close(); 473 char buf[kDataLen]; 474 ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen)); 475 ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen)); 476} 477 478TEST(FileTest, DuplicateDeleteOnClose) { 479 base::ScopedTempDir temp_dir; 480 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 481 FilePath file_path = temp_dir.path().AppendASCII("file"); 482 File file(file_path,(base::File::FLAG_CREATE | 483 base::File::FLAG_READ | 484 base::File::FLAG_WRITE | 485 base::File::FLAG_DELETE_ON_CLOSE)); 486 ASSERT_TRUE(file.IsValid()); 487 File file2(file.Duplicate()); 488 ASSERT_TRUE(file2.IsValid()); 489 file.Close(); 490 file2.Close(); 491 ASSERT_FALSE(base::PathExists(file_path)); 492} 493 494#if defined(OS_WIN) 495TEST(FileTest, GetInfoForDirectory) { 496 base::ScopedTempDir temp_dir; 497 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 498 FilePath empty_dir = temp_dir.path().Append(FILE_PATH_LITERAL("gpfi_test")); 499 ASSERT_TRUE(CreateDirectory(empty_dir)); 500 501 base::File dir( 502 ::CreateFile(empty_dir.value().c_str(), 503 GENERIC_READ | GENERIC_WRITE, 504 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 505 NULL, 506 OPEN_EXISTING, 507 FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. 508 NULL)); 509 ASSERT_TRUE(dir.IsValid()); 510 511 base::File::Info info; 512 EXPECT_TRUE(dir.GetInfo(&info)); 513 EXPECT_TRUE(info.is_directory); 514 EXPECT_FALSE(info.is_symbolic_link); 515 EXPECT_EQ(0, info.size); 516} 517#endif // defined(OS_WIN) 518