Index: components/filesystem/file_impl_unittest.cc |
diff --git a/components/filesystem/file_impl_unittest.cc b/components/filesystem/file_impl_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8add60aa120c17333f4e5f19738ed21392d75b20 |
--- /dev/null |
+++ b/components/filesystem/file_impl_unittest.cc |
@@ -0,0 +1,693 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <vector> |
+ |
+#include "components/filesystem/files_test_base.h" |
+#include "mojo/public/cpp/bindings/interface_request.h" |
+#include "mojo/public/cpp/bindings/type_converter.h" |
+ |
+namespace mojo { |
+namespace files { |
+namespace { |
+ |
+using FileImplTest = FilesTestBase; |
+ |
+TEST_F(FileImplTest, CreateWriteCloseRenameOpenRead) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ { |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('h')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ // Rename it. |
+ error = ERROR_INTERNAL; |
+ directory->Rename("my_file", "your_file", Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ { |
+ // Open my_file again. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("your_file", GetProxy(&file), kOpenFlagRead, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Read from it. |
+ Array<uint8_t> bytes_read; |
+ error = ERROR_INTERNAL; |
+ file->Read(3, 1, WHENCE_FROM_START, Capture(&error, &bytes_read)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_EQ(3u, bytes_read.size()); |
+ EXPECT_EQ(static_cast<uint8_t>('e'), bytes_read[0]); |
+ EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[1]); |
+ EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[2]); |
+ } |
+ |
+ // TODO(vtl): Test read/write offset options. |
+} |
+ |
+TEST_F(FileImplTest, CantWriteInReadMode) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('h')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ |
+ { |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Open my_file again, this time with read only mode. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), kOpenFlagRead, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Try to write in read mode; it should fail. |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_UNKNOWN, error); |
+ EXPECT_EQ(0u, num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+} |
+ |
+TEST_F(FileImplTest, OpenExclusive) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ { |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("temp_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate |kOpenFlagExclusive, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Try to open my_file again in exclusive mode; it should fail. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("temp_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate | kOpenFlagExclusive, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_UNKNOWN, error); |
+ } |
+} |
+ |
+TEST_F(FileImplTest, OpenInAppendMode) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ { |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('h')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Append to my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagAppend, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('g')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('d')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('b')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('y')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Open my_file again. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), kOpenFlagRead, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Read from it. |
+ Array<uint8_t> bytes_read; |
+ error = ERROR_INTERNAL; |
+ file->Read(12, 0, WHENCE_FROM_START, Capture(&error, &bytes_read)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_EQ(12u, bytes_read.size()); |
+ EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[3]); |
+ EXPECT_EQ(static_cast<uint8_t>('o'), bytes_read[4]); |
+ EXPECT_EQ(static_cast<uint8_t>('g'), bytes_read[5]); |
+ EXPECT_EQ(static_cast<uint8_t>('o'), bytes_read[6]); |
+ } |
+} |
+ |
+TEST_F(FileImplTest, OpenInTruncateMode) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ { |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('h')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Append to my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagTruncate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('g')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('d')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('b')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('y')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ |
+ // Close it. |
+ error = ERROR_INTERNAL; |
+ file->Close(Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ |
+ { |
+ // Open my_file again. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), kOpenFlagRead, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Read from it. |
+ Array<uint8_t> bytes_read; |
+ error = ERROR_INTERNAL; |
+ file->Read(7, 0, WHENCE_FROM_START, Capture(&error, &bytes_read)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_EQ(7u, bytes_read.size()); |
+ EXPECT_EQ(static_cast<uint8_t>('g'), bytes_read[0]); |
+ EXPECT_EQ(static_cast<uint8_t>('o'), bytes_read[1]); |
+ EXPECT_EQ(static_cast<uint8_t>('o'), bytes_read[2]); |
+ EXPECT_EQ(static_cast<uint8_t>('d'), bytes_read[3]); |
+ } |
+} |
+ |
+// Note: Ignore nanoseconds, since it may not always be supported. We expect at |
+// least second-resolution support though. |
+TEST_F(FileImplTest, StatTouch) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat it. |
+ error = ERROR_INTERNAL; |
+ FileInformationPtr file_info; |
+ file->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ EXPECT_EQ(FILE_TYPE_REGULAR_FILE, file_info->type); |
+ EXPECT_EQ(0, file_info->size); |
+ ASSERT_FALSE(file_info->atime.is_null()); |
+ EXPECT_GT(file_info->atime->seconds, 0); // Expect that it's not 1970-01-01. |
+ ASSERT_FALSE(file_info->mtime.is_null()); |
+ EXPECT_GT(file_info->mtime->seconds, 0); |
+ int64_t first_mtime = file_info->mtime->seconds; |
+ |
+ // Touch only the atime. |
+ error = ERROR_INTERNAL; |
+ TimespecOrNowPtr t(TimespecOrNow::New()); |
+ t->now = false; |
+ t->timespec = Timespec::New(); |
+ const int64_t kPartyTime1 = 1234567890; // Party like it's 2009-02-13. |
+ t->timespec->seconds = kPartyTime1; |
+ file->Touch(t.Pass(), nullptr, Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat again. |
+ error = ERROR_INTERNAL; |
+ file_info.reset(); |
+ file->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ ASSERT_FALSE(file_info->atime.is_null()); |
+ EXPECT_EQ(kPartyTime1, file_info->atime->seconds); |
+ ASSERT_FALSE(file_info->mtime.is_null()); |
+ EXPECT_EQ(first_mtime, file_info->mtime->seconds); |
+ |
+ // Touch only the mtime. |
+ t = TimespecOrNow::New(); |
+ t->now = false; |
+ t->timespec = Timespec::New(); |
+ const int64_t kPartyTime2 = 1425059525; // No time like the present. |
+ t->timespec->seconds = kPartyTime2; |
+ file->Touch(nullptr, t.Pass(), Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat again. |
+ error = ERROR_INTERNAL; |
+ file_info.reset(); |
+ file->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ ASSERT_FALSE(file_info->atime.is_null()); |
+ EXPECT_EQ(kPartyTime1, file_info->atime->seconds); |
+ ASSERT_FALSE(file_info->mtime.is_null()); |
+ EXPECT_EQ(kPartyTime2, file_info->mtime->seconds); |
+ |
+ // TODO(vtl): Also test non-zero file size. |
+ // TODO(vtl): Also test Touch() "now" options. |
+ // TODO(vtl): Also test touching both atime and mtime. |
+} |
+ |
+TEST_F(FileImplTest, TellSeek) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write(1000, '!'); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ const int size = static_cast<int>(num_bytes_written); |
+ |
+ // Tell. |
+ error = ERROR_INTERNAL; |
+ int64_t position = -1; |
+ file->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ // Should be at the end. |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(size, position); |
+ |
+ // Seek back 100. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Seek(-100, WHENCE_FROM_CURRENT, Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(size - 100, position); |
+ |
+ // Tell. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(size - 100, position); |
+ |
+ // Seek to 123 from start. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Seek(123, WHENCE_FROM_START, Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(123, position); |
+ |
+ // Tell. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(123, position); |
+ |
+ // Seek to 123 back from end. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Seek(-123, WHENCE_FROM_END, Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(size - 123, position); |
+ |
+ // Tell. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(size - 123, position); |
+ |
+ // TODO(vtl): Check that seeking actually affects reading/writing. |
+ // TODO(vtl): Check that seeking can extend the file? |
+} |
+ |
+TEST_F(FileImplTest, Dup) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ FilePtr file1; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file1), |
+ kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write; |
+ bytes_to_write.push_back(static_cast<uint8_t>('h')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('e')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file1->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file1.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(bytes_to_write.size(), num_bytes_written); |
+ const int end_hello_pos = static_cast<int>(num_bytes_written); |
+ |
+ // Dup it. |
+ FilePtr file2; |
+ error = ERROR_INTERNAL; |
+ file1->Dup(GetProxy(&file2), Capture(&error)); |
+ ASSERT_TRUE(file1.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // |file2| should have the same position. |
+ error = ERROR_INTERNAL; |
+ int64_t position = -1; |
+ file2->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file2.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(end_hello_pos, position); |
+ |
+ // Write using |file2|. |
+ std::vector<uint8_t> more_bytes_to_write; |
+ more_bytes_to_write.push_back(static_cast<uint8_t>('w')); |
+ more_bytes_to_write.push_back(static_cast<uint8_t>('o')); |
+ more_bytes_to_write.push_back(static_cast<uint8_t>('r')); |
+ more_bytes_to_write.push_back(static_cast<uint8_t>('l')); |
+ more_bytes_to_write.push_back(static_cast<uint8_t>('d')); |
+ error = ERROR_INTERNAL; |
+ num_bytes_written = 0; |
+ file2->Write(Array<uint8_t>::From(more_bytes_to_write), 0, |
+ WHENCE_FROM_CURRENT, Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file2.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(more_bytes_to_write.size(), num_bytes_written); |
+ const int end_world_pos = end_hello_pos + static_cast<int>(num_bytes_written); |
+ |
+ // |file1| should have the same position. |
+ error = ERROR_INTERNAL; |
+ position = -1; |
+ file1->Tell(Capture(&error, &position)); |
+ ASSERT_TRUE(file1.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(end_world_pos, position); |
+ |
+ // Close |file1|. |
+ error = ERROR_INTERNAL; |
+ file1->Close(Capture(&error)); |
+ ASSERT_TRUE(file1.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Read everything using |file2|. |
+ Array<uint8_t> bytes_read; |
+ error = ERROR_INTERNAL; |
+ file2->Read(1000, 0, WHENCE_FROM_START, Capture(&error, &bytes_read)); |
+ ASSERT_TRUE(file2.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_EQ(static_cast<size_t>(end_world_pos), bytes_read.size()); |
+ // Just check the first and last bytes. |
+ EXPECT_EQ(static_cast<uint8_t>('h'), bytes_read[0]); |
+ EXPECT_EQ(static_cast<uint8_t>('d'), bytes_read[end_world_pos - 1]); |
+ |
+ // TODO(vtl): Test that |file2| has the same open options as |file1|. |
+} |
+ |
+TEST_F(FileImplTest, Truncate) { |
+ const uint32_t kInitialSize = 1000; |
+ const uint32_t kTruncatedSize = 654; |
+ |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagWrite | kOpenFlagCreate, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write(kInitialSize, '!'); |
+ error = ERROR_INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(Array<uint8_t>::From(bytes_to_write), 0, WHENCE_FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ EXPECT_EQ(kInitialSize, num_bytes_written); |
+ |
+ // Stat it. |
+ error = ERROR_INTERNAL; |
+ FileInformationPtr file_info; |
+ file->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ EXPECT_EQ(kInitialSize, file_info->size); |
+ |
+ // Truncate it. |
+ error = ERROR_INTERNAL; |
+ file->Truncate(kTruncatedSize, Capture(&error)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat again. |
+ error = ERROR_INTERNAL; |
+ file_info.reset(); |
+ file->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ EXPECT_EQ(kTruncatedSize, file_info->size); |
+} |
+ |
+TEST_F(FileImplTest, Ioctl) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ FilePtr file; |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", GetProxy(&file), |
+ kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Normal files don't support any ioctls. |
+ Array<uint32_t> out_values; |
+ file->Ioctl(0, Array<uint32_t>(), Capture(&error, &out_values)); |
+ ASSERT_TRUE(file.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_UNAVAILABLE, error); |
+ EXPECT_TRUE(out_values.is_null()); |
+} |
+ |
+} // namespace |
+} // namespace files |
+} // namespace mojo |