blob: 2cf5b2534c573053891a7ceb17929c253e109660 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <fuchsia/io/cpp/fidl.h>
#include <lib/vfs/cpp/testing/dir_test_util.h>
#include <zircon/status.h>
// TODO(b/293936429): Remove use of deprecated `vdirent_t` when transitioning ReadDir to Enumerate
// as part of io2 migration.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
namespace vfs_tests {
Dirent Dirent::DirentForDot() { return DirentForDirectory("."); }
Dirent Dirent::DirentForDirectory(const std::string& name) {
return Dirent(fuchsia::io::INO_UNKNOWN, fuchsia::io::DirentType::DIRECTORY, name);
}
Dirent Dirent::DirentForFile(const std::string& name) {
return Dirent(fuchsia::io::INO_UNKNOWN, fuchsia::io::DirentType::FILE, name);
}
Dirent Dirent::DirentForService(const std::string& name) {
return Dirent(fuchsia::io::INO_UNKNOWN, fuchsia::io::DirentType::SERVICE, name);
}
std::string Dirent::String() {
return "Dirent:\nino: " + std ::to_string(ino_) + "\ntype: " + std ::to_string(type_) +
"\nsize: " + std ::to_string(size_) + "\nname: " + name_;
}
Dirent::Dirent(uint64_t ino, fuchsia::io::DirentType type, const std::string& name)
: ino_(ino),
type_(static_cast<uint8_t>(type)),
size_(static_cast<uint8_t>(name.length())),
name_(name),
size_in_bytes_(sizeof(vdirent_t) + size_) {
ZX_DEBUG_ASSERT(name.length() <= static_cast<uint64_t>(NAME_MAX));
}
void DirConnection::AssertOpen(async_dispatcher_t* dispatcher, fuchsia::io::OpenFlags flags,
zx_status_t expected_status, bool test_on_open_event) {
fuchsia::io::NodePtr node_ptr;
if (test_on_open_event) {
flags |= fuchsia::io::OpenFlags::DESCRIBE;
}
EXPECT_EQ(expected_status,
GetDirectoryNode()->Serve(flags, node_ptr.NewRequest().TakeChannel(), dispatcher));
if (test_on_open_event) {
bool on_open_called = false;
node_ptr.events().OnOpen = [&](zx_status_t status,
std::unique_ptr<fuchsia::io::NodeInfoDeprecated> info) {
EXPECT_FALSE(on_open_called); // should be called only once
on_open_called = true;
EXPECT_EQ(expected_status, status);
if (expected_status == ZX_OK) {
ASSERT_NE(info.get(), nullptr);
EXPECT_TRUE(info->is_directory());
} else {
EXPECT_EQ(info.get(), nullptr);
}
};
RunLoopUntil([&]() { return on_open_called; }, zx::msec(1));
}
}
void DirConnection::AssertReadDirents(fuchsia::io::DirectorySyncPtr& ptr, uint64_t max_bytes,
std::vector<Dirent>& expected_dirents,
zx_status_t expected_status) {
std::vector<uint8_t> out_dirents;
zx_status_t status;
ptr->ReadDirents(max_bytes, &status, &out_dirents);
ASSERT_EQ(expected_status, status);
if (status != ZX_OK) {
return;
}
uint64_t expected_size = 0;
for (auto& d : expected_dirents) {
expected_size += d.size_in_bytes();
}
EXPECT_EQ(expected_size, out_dirents.size());
uint64_t offset = 0;
auto data_ptr = out_dirents.data();
for (auto& d : expected_dirents) {
SCOPED_TRACE(d.String());
ASSERT_LE(sizeof(vdirent_t), out_dirents.size() - offset);
vdirent_t* de = reinterpret_cast<vdirent_t*>(data_ptr + offset);
uint64_t ino;
memcpy(&ino, &de->ino, sizeof(ino));
EXPECT_EQ(d.ino(), ino);
uint8_t size, type;
memcpy(&size, &de->size, sizeof(size));
EXPECT_EQ(d.size(), size);
memcpy(&type, &de->type, sizeof(type));
EXPECT_EQ(d.type(), type);
ASSERT_LE(d.size_in_bytes(), out_dirents.size() - offset);
EXPECT_EQ(d.name(), std::string(de->name, size));
offset += sizeof(vdirent_t) + size;
}
}
void DirConnection::AssertRewind(fuchsia::io::DirectorySyncPtr& ptr, zx_status_t expected_status) {
zx_status_t status;
ptr->Rewind(&status);
ASSERT_EQ(expected_status, status);
}
void DirConnection::AssertRead(fuchsia::io::FileSyncPtr& file, int count,
const std::string& expected_str, zx_status_t expected_status) {
fuchsia::io::Readable_Read_Result result;
file->Read(count, &result);
if (expected_status == ZX_OK) {
ASSERT_TRUE(result.is_response()) << zx_status_get_string(result.err());
const std::vector<uint8_t>& data = result.response().data;
ASSERT_EQ(expected_str,
std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
} else {
ASSERT_TRUE(result.is_err());
ASSERT_EQ(expected_status, result.err());
}
}
} // namespace vfs_tests
#pragma clang diagnostic pop