blob: 7a26c5a6d0b933128895b0a30dbee41713dd0aa9 [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 <lib/async-loop/cpp/loop.h>
#include <lib/fdio/limits.h>
#include <lib/fdio/util.h>
#include <unistd.h>
#include <zircon/processargs.h>
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
#include "lib/vfs/cpp/file.h"
namespace {
class TestFile : public vfs::File {
public:
explicit TestFile(std::vector<uint8_t>* buffer) : buffer_(buffer) {}
~TestFile() override = default;
zx_status_t ReadAt(uint64_t count, uint64_t offset,
std::vector<uint8_t>* out_data) override {
if (offset >= buffer_->size()) {
return ZX_OK;
}
size_t actual = std::min(count, buffer_->size() - offset);
out_data->resize(actual);
std::copy_n(buffer_->begin() + offset, actual, out_data->begin());
return ZX_OK;
}
zx_status_t WriteAt(std::vector<uint8_t> data, uint64_t offset,
uint64_t* out_actual) override {
if (offset >= buffer_->size()) {
*out_actual = 0u;
return ZX_OK;
}
size_t actual = std::min(data.size(), buffer_->size() - offset);
std::copy_n(data.begin(), actual, buffer_->begin() + offset);
*out_actual = actual;
return ZX_OK;
}
uint64_t GetLength() override { return buffer_->size(); }
size_t GetCapacity() override { return buffer_->size(); }
private:
std::vector<uint8_t>* buffer_;
};
int OpenAsFD(vfs::Node* node, async_dispatcher_t* dispatcher) {
zx::channel local, remote;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &local, &remote));
EXPECT_EQ(ZX_OK, node->Serve(fuchsia::io::OPEN_RIGHT_READABLE |
fuchsia::io::OPEN_RIGHT_WRITABLE,
std::move(remote), dispatcher));
zx_handle_t handles = local.release();
uint32_t types = PA_FDIO_REMOTE;
int fd = -1;
EXPECT_EQ(ZX_OK, fdio_create_fd(&handles, &types, 1, &fd));
return fd;
}
TEST(File, Control) {
std::vector<uint8_t> store(12u);
TestFile file(&store);
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
loop.StartThread("vfs test thread");
int fd = OpenAsFD(&file, loop.dispatcher());
ASSERT_LE(0, fd);
ASSERT_EQ(4, write(fd, "abcd", 4));
EXPECT_EQ(0, strcmp("abcd", reinterpret_cast<char*>(store.data())));
ASSERT_EQ(5, write(fd, "exxxi", 5));
EXPECT_EQ(0, strcmp("abcdexxxi", reinterpret_cast<char*>(store.data())));
ASSERT_EQ(3, pwrite(fd, "fgh", 3, 5));
EXPECT_EQ(0, strcmp("abcdefghi", reinterpret_cast<char*>(store.data())));
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
ASSERT_EQ(7, pread(fd, buffer, 7, 1));
EXPECT_EQ(0, strcmp("bcdefgh", buffer));
ASSERT_EQ(3, write(fd, "jklmn", 5));
EXPECT_EQ('l', store[store.size() - 1]);
memset(buffer, 0, sizeof(buffer));
ASSERT_EQ(4, pread(fd, buffer, 10, 8));
EXPECT_EQ(0, strcmp("ijkl", buffer));
ASSERT_GE(0, close(fd));
}
TEST(File, Clone) {
std::vector<uint8_t> store(12u);
TestFile file(&store);
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
loop.StartThread("vfs test thread");
int fd = OpenAsFD(&file, loop.dispatcher());
ASSERT_LE(0, fd);
ASSERT_EQ(4, write(fd, "abcd", 4));
EXPECT_EQ(0, strcmp("abcd", reinterpret_cast<char*>(store.data())));
zx_handle_t handles[FDIO_MAX_HANDLES];
uint32_t types[FDIO_MAX_HANDLES];
ASSERT_EQ(1, fdio_clone_fd(fd, 0, handles, types));
int cloned = -1;
EXPECT_EQ(ZX_OK, fdio_create_fd(handles, types, 1, &cloned));
ASSERT_LE(0, cloned);
ASSERT_EQ(3, write(cloned, "xyz", 3));
EXPECT_EQ(0, strcmp("xyzd", reinterpret_cast<char*>(store.data())));
ASSERT_GE(0, close(fd));
ASSERT_GE(0, close(cloned));
}
} // namespace