Index: components/filesystem/directory_impl_unittest.cc |
diff --git a/components/filesystem/directory_impl_unittest.cc b/components/filesystem/directory_impl_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b043e4bc8e9902942191685df3a37f4346cdf920 |
--- /dev/null |
+++ b/components/filesystem/directory_impl_unittest.cc |
@@ -0,0 +1,200 @@ |
+// 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 <map> |
+#include <string> |
+ |
+#include "components/filesystem/files_test_base.h" |
+ |
+namespace mojo { |
+namespace files { |
+namespace { |
+ |
+using DirectoryImplTest = FilesTestBase; |
+ |
+TEST_F(DirectoryImplTest, Read) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Make some files. |
+ const struct { |
+ const char* name; |
+ uint32_t open_flags; |
+ } files_to_create[] = { |
+ {"my_file1", kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate}, |
+ {"my_file2", kOpenFlagWrite | kOpenFlagCreate | kOpenFlagExclusive}, |
+ {"my_file3", kOpenFlagWrite | kOpenFlagCreate | kOpenFlagAppend}, |
+ {"my_file4", kOpenFlagWrite | kOpenFlagCreate | kOpenFlagTruncate}}; |
+ for (size_t i = 0; i < arraysize(files_to_create); i++) { |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile(files_to_create[i].name, nullptr, |
+ files_to_create[i].open_flags, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ } |
+ // Make a directory. |
+ error = ERROR_INTERNAL; |
+ directory->OpenDirectory("my_dir", nullptr, |
+ kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ error = ERROR_INTERNAL; |
+ Array<DirectoryEntryPtr> directory_contents; |
+ directory->Read(Capture(&error, &directory_contents)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Expected contents of the directory. |
+ std::map<std::string, FileType> expected_contents; |
+ expected_contents["my_file1"] = FILE_TYPE_REGULAR_FILE; |
+ expected_contents["my_file2"] = FILE_TYPE_REGULAR_FILE; |
+ expected_contents["my_file3"] = FILE_TYPE_REGULAR_FILE; |
+ expected_contents["my_file4"] = FILE_TYPE_REGULAR_FILE; |
+ expected_contents["my_dir"] = FILE_TYPE_DIRECTORY; |
+ expected_contents["."] = FILE_TYPE_DIRECTORY; |
+ expected_contents[".."] = FILE_TYPE_DIRECTORY; |
+ |
+ EXPECT_EQ(expected_contents.size(), directory_contents.size()); |
+ for (size_t i = 0; i < directory_contents.size(); i++) { |
+ ASSERT_TRUE(directory_contents[i]); |
+ ASSERT_TRUE(directory_contents[i]->name); |
+ auto it = expected_contents.find(directory_contents[i]->name.get()); |
+ ASSERT_TRUE(it != expected_contents.end()); |
+ EXPECT_EQ(it->second, directory_contents[i]->type); |
+ expected_contents.erase(it); |
+ } |
+} |
+ |
+// Note: Ignore nanoseconds, since it may not always be supported. We expect at |
+// least second-resolution support though. |
+// TODO(vtl): Maybe share this with |FileImplTest.StatTouch| ... but then it'd |
+// be harder to split this file. |
+TEST_F(DirectoryImplTest, StatTouch) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Stat it. |
+ error = ERROR_INTERNAL; |
+ FileInformationPtr file_info; |
+ directory->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ ASSERT_FALSE(file_info.is_null()); |
+ EXPECT_EQ(FILE_TYPE_DIRECTORY, 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; |
+ directory->Touch(t.Pass(), nullptr, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat again. |
+ error = ERROR_INTERNAL; |
+ file_info.reset(); |
+ directory->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(directory.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; |
+ directory->Touch(nullptr, t.Pass(), Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Stat again. |
+ error = ERROR_INTERNAL; |
+ file_info.reset(); |
+ directory->Stat(Capture(&error, &file_info)); |
+ ASSERT_TRUE(directory.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 Touch() "now" options. |
+ // TODO(vtl): Also test touching both atime and mtime. |
+} |
+ |
+// TODO(vtl): Properly test OpenFile() and OpenDirectory() (including flags). |
+ |
+TEST_F(DirectoryImplTest, BasicRenameDelete) { |
+ DirectoryPtr directory; |
+ GetTemporaryRoot(&directory); |
+ Error error; |
+ |
+ // Create my_file. |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", nullptr, kOpenFlagWrite | kOpenFlagCreate, |
+ Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Opening my_file should succeed. |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", nullptr, kOpenFlagRead, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Rename my_file to my_new_file. |
+ directory->Rename("my_file", "my_new_file", Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Opening my_file should fail. |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_file", nullptr, kOpenFlagRead, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_UNKNOWN, error); |
+ |
+ // Opening my_new_file should succeed. |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_new_file", nullptr, kOpenFlagRead, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Delete my_new_file (no flags). |
+ directory->Delete("my_new_file", 0, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_OK, error); |
+ |
+ // Opening my_new_file should fail. |
+ error = ERROR_INTERNAL; |
+ directory->OpenFile("my_new_file", nullptr, kOpenFlagRead, Capture(&error)); |
+ ASSERT_TRUE(directory.WaitForIncomingMethodCall()); |
+ EXPECT_EQ(ERROR_UNKNOWN, error); |
+} |
+ |
+// TODO(vtl): Test that an open file can be moved (by someone else) without |
+// operations on it being affected. |
+// TODO(vtl): Test delete flags. |
+ |
+} // namespace |
+} // namespace files |
+} // namespace mojo |