blob: 2621dcf1280500b1e4160ffe3d553ac807f74e17 [file] [log] [blame]
// 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 "services/files/files_test_base.h"
namespace mojo {
namespace files {
namespace {
using DirectoryImplTest = FilesTestBase;
TEST_F(DirectoryImplTest, Read) {
SynchronousInterfacePtr<Directory> 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;
ASSERT_TRUE(directory->OpenFile(files_to_create[i].name, nullptr,
files_to_create[i].open_flags, &error));
EXPECT_EQ(Error::OK, error);
}
// Make a directory.
error = Error::INTERNAL;
ASSERT_TRUE(directory->OpenDirectory(
"my_dir", nullptr, kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate,
&error));
EXPECT_EQ(Error::OK, error);
error = Error::INTERNAL;
Array<DirectoryEntryPtr> directory_contents;
ASSERT_TRUE(directory->Read(&error, &directory_contents));
EXPECT_EQ(Error::OK, error);
// Expected contents of the directory.
std::map<std::string, FileType> expected_contents;
expected_contents["my_file1"] = FileType::REGULAR_FILE;
expected_contents["my_file2"] = FileType::REGULAR_FILE;
expected_contents["my_file3"] = FileType::REGULAR_FILE;
expected_contents["my_file4"] = FileType::REGULAR_FILE;
expected_contents["my_dir"] = FileType::DIRECTORY;
expected_contents["."] = FileType::DIRECTORY;
expected_contents[".."] = FileType::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) {
SynchronousInterfacePtr<Directory> directory;
GetTemporaryRoot(&directory);
Error error;
// Stat it.
error = Error::INTERNAL;
FileInformationPtr file_info;
ASSERT_TRUE(directory->Stat(&error, &file_info));
EXPECT_EQ(Error::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(FileType::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;
ASSERT_TRUE(directory->Touch(t.Pass(), nullptr, &error));
EXPECT_EQ(Error::OK, error);
// Stat again.
error = Error::INTERNAL;
file_info.reset();
ASSERT_TRUE(directory->Stat(&error, &file_info));
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;
ASSERT_TRUE(directory->Touch(nullptr, t.Pass(), &error));
EXPECT_EQ(Error::OK, error);
// Stat again.
error = Error::INTERNAL;
file_info.reset();
ASSERT_TRUE(directory->Stat(&error, &file_info));
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) {
SynchronousInterfacePtr<Directory> directory;
GetTemporaryRoot(&directory);
Error error;
// Create my_file.
error = Error::INTERNAL;
ASSERT_TRUE(directory->OpenFile("my_file", nullptr,
kOpenFlagWrite | kOpenFlagCreate, &error));
EXPECT_EQ(Error::OK, error);
// Opening my_file should succeed.
error = Error::INTERNAL;
ASSERT_TRUE(directory->OpenFile("my_file", nullptr, kOpenFlagRead, &error));
EXPECT_EQ(Error::OK, error);
// Rename my_file to my_new_file.
error = Error::INTERNAL;
ASSERT_TRUE(directory->Rename("my_file", "my_new_file", &error));
EXPECT_EQ(Error::OK, error);
// Opening my_file should fail.
error = Error::INTERNAL;
ASSERT_TRUE(directory->OpenFile("my_file", nullptr, kOpenFlagRead, &error));
EXPECT_EQ(Error::UNKNOWN, error);
// Opening my_new_file should succeed.
error = Error::INTERNAL;
ASSERT_TRUE(
directory->OpenFile("my_new_file", nullptr, kOpenFlagRead, &error));
EXPECT_EQ(Error::OK, error);
// Delete my_new_file (no flags).
error = Error::INTERNAL;
ASSERT_TRUE(directory->Delete("my_new_file", 0u, &error));
EXPECT_EQ(Error::OK, error);
// Opening my_new_file should fail.
error = Error::INTERNAL;
ASSERT_TRUE(
directory->OpenFile("my_new_file", nullptr, kOpenFlagRead, &error));
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.
// TODO(vtl): Strictly speaking, this is a test of |FilesImpl|, but we need
// |Directory| to do anything, so it lives here.
TEST_F(DirectoryImplTest, AppPersistentCache) {
{
SynchronousInterfacePtr<Directory> directory;
GetAppPersistentCacheRoot(&directory);
// Create my_file.
Error error = Error::INTERNAL;
ASSERT_TRUE(directory->OpenFile("my_file", nullptr,
kOpenFlagCreate | kOpenFlagWrite, &error));
EXPECT_EQ(Error::OK, error);
}
{
SynchronousInterfacePtr<Directory> directory;
GetAppPersistentCacheRoot(&directory);
// We should be in the same directory and my_file should still exist, so we
// should be able to delete it.
Error error = Error::INTERNAL;
ASSERT_TRUE(directory->Delete("my_file", kDeleteFlagFileOnly, &error));
EXPECT_EQ(Error::OK, error);
}
}
} // namespace
} // namespace files
} // namespace mojo