[fzl] Make FdioCaller movable, add tests
Change-Id: Ic07d237e894317e2a7c12d7bf4b9759eba8e916a
diff --git a/zircon/system/ulib/fzl/include/lib/fzl/fdio.h b/zircon/system/ulib/fzl/include/lib/fzl/fdio.h
index 204d882..f2f3ff5 100644
--- a/zircon/system/ulib/fzl/include/lib/fzl/fdio.h
+++ b/zircon/system/ulib/fzl/include/lib/fzl/fdio.h
@@ -18,6 +18,8 @@
//
// FdioCaller consumes |fd|, but the same |fd| may be re-acquired by
// calling "release()" on the FdioCaller object.
+//
+// This class is movable, but not copyable.
class FdioCaller {
public:
FdioCaller() : io_(nullptr) {}
@@ -25,6 +27,18 @@
explicit FdioCaller(fbl::unique_fd fd) :
fd_(std::move(fd)), io_(fdio_unsafe_fd_to_io(fd_.get())) {}
+ FdioCaller& operator=(FdioCaller&& o) {
+ fd_ = std::move(o.fd_);
+ io_ = o.io_;
+ o.io_ = nullptr;
+ return *this;
+ }
+ FdioCaller(FdioCaller&& o) : fd_(std::move(o.fd_)), io_(o.io_) {
+ o.io_ = nullptr;
+ }
+ FdioCaller(const FdioCaller&) = delete;
+ FdioCaller& operator=(const FdioCaller&) = delete;
+
~FdioCaller() {
release();
}
@@ -64,11 +78,6 @@
return fdio_unsafe_borrow_channel(io_);
}
- FdioCaller& operator=(FdioCaller&& o) = delete;
- FdioCaller(FdioCaller&& o) = delete;
- FdioCaller(const FdioCaller&) = delete;
- FdioCaller& operator=(const FdioCaller&) = delete;
-
private:
fbl::unique_fd fd_;
fdio_t* io_;
diff --git a/zircon/system/ulib/fzl/test/BUILD.gn b/zircon/system/ulib/fzl/test/BUILD.gn
index 3242b77..e91858e 100644
--- a/zircon/system/ulib/fzl/test/BUILD.gn
+++ b/zircon/system/ulib/fzl/test/BUILD.gn
@@ -31,6 +31,7 @@
"$zx/system/ulib/fdio",
"$zx/system/ulib/fzl",
"$zx/system/ulib/memfs",
+ "$zx/system/ulib/sync",
"$zx/system/ulib/unittest",
"$zx/system/ulib/zircon",
"$zx/system/ulib/zx",
diff --git a/zircon/system/ulib/fzl/test/fdio.cpp b/zircon/system/ulib/fzl/test/fdio.cpp
index 396bdc8..7dfdf2c 100644
--- a/zircon/system/ulib/fzl/test/fdio.cpp
+++ b/zircon/system/ulib/fzl/test/fdio.cpp
@@ -8,6 +8,7 @@
#include <fbl/unique_fd.h>
#include <fuchsia/io/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
+#include <lib/fdio/fd.h>
#include <lib/memfs/memfs.h>
#include <lib/fzl/fdio.h>
#include <unittest/unittest.h>
@@ -16,48 +17,77 @@
namespace {
-bool fdio_call_io() {
- BEGIN_TEST;
-
- // Create a Memfs filesystem.
- async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
- ASSERT_EQ(loop.StartThread(), ZX_OK);
- ASSERT_EQ(memfs_install_at(loop.dispatcher(), "/my-tmp"), ZX_OK);
- fbl::unique_fd dir(open("/my-tmp", O_DIRECTORY | O_RDONLY));
- ASSERT_TRUE(dir);
-
- // Open a file within the filesystem.
- fbl::unique_fd fd(openat(dir.get(), "my-file", O_CREAT | O_RDWR));
- ASSERT_TRUE(fd);
-
- // Try some filesystem operations natively:
- fzl::FdioCaller caller(std::move(fd));
- ASSERT_TRUE(caller);
+bool TryFilesystemOperations(const fzl::FdioCaller& caller) {
+ BEGIN_HELPER;
const char* golden = "foobar";
zx_status_t status;
uint64_t actual;
- ASSERT_EQ(fuchsia_io_FileWrite(caller.borrow_channel(),
- reinterpret_cast<const uint8_t*>(golden),
- strlen(golden), &status, &actual),
+ ASSERT_EQ(fuchsia_io_FileWriteAt(caller.borrow_channel(),
+ reinterpret_cast<const uint8_t*>(golden),
+ strlen(golden), 0, &status, &actual),
ZX_OK);
ASSERT_EQ(status, ZX_OK);
ASSERT_EQ(actual, strlen(golden));
- ASSERT_EQ(fuchsia_io_FileSeek(caller.borrow_channel(), 0L, fuchsia_io_SeekOrigin_START,
- &status, &actual),
- ZX_OK);
- ASSERT_EQ(status, ZX_OK);
- ASSERT_EQ(actual, 0);
-
char buf[256];
- ASSERT_EQ(fuchsia_io_FileRead(caller.borrow_channel(), static_cast<uint64_t>(sizeof(buf)),
+ ASSERT_EQ(fuchsia_io_FileReadAt(caller.borrow_channel(), static_cast<uint64_t>(sizeof(buf)), 0,
&status, reinterpret_cast<uint8_t*>(buf), sizeof(buf), &actual),
ZX_OK);
ASSERT_EQ(status, ZX_OK);
ASSERT_EQ(actual, strlen(golden));
ASSERT_EQ(memcmp(buf, golden, strlen(golden)), 0);
+ END_HELPER;
+}
+
+class Harness {
+public:
+ Harness() {}
+
+ ~Harness() {
+ if (memfs_) {
+ sync_completion_t unmounted;
+ memfs_free_filesystem(memfs_, &unmounted);
+ sync_completion_wait(&unmounted, ZX_SEC(3));
+ }
+ }
+
+ bool Setup() {
+ BEGIN_HELPER;
+ ASSERT_EQ(loop_.StartThread(), ZX_OK);
+ zx_handle_t root;
+ ASSERT_EQ(memfs_create_filesystem(loop_.dispatcher(), &memfs_, &root), ZX_OK);
+ int fd;
+ ASSERT_EQ(fdio_fd_create(root, &fd), ZX_OK);
+ fbl::unique_fd dir(fd);
+ ASSERT_TRUE(dir);
+ fd_.reset(openat(dir.get(), "my-file", O_CREAT | O_RDWR));
+ ASSERT_TRUE(fd_);
+
+ END_HELPER;
+ }
+
+ fbl::unique_fd fd() { return std::move(fd_); }
+
+private:
+ async::Loop loop_ = async::Loop(&kAsyncLoopConfigNoAttachToThread);
+ memfs_filesystem_t* memfs_ = nullptr;
+ fbl::unique_fd fd_;
+};
+
+bool FdioCallerFile() {
+ BEGIN_TEST;
+
+ Harness harness;
+ ASSERT_TRUE(harness.Setup());
+ auto fd = harness.fd();
+
+ // Try some filesystem operations.
+ fzl::FdioCaller caller(std::move(fd));
+ ASSERT_TRUE(caller);
+ ASSERT_TRUE(TryFilesystemOperations(caller));
+
// Re-acquire the underlying fd.
fd = caller.release();
ASSERT_EQ(close(fd.release()), 0);
@@ -65,9 +95,43 @@
END_TEST;
}
+bool FdioCallerMoveAssignment() {
+ BEGIN_TEST;
+
+ Harness harness;
+ ASSERT_TRUE(harness.Setup());
+ auto fd = harness.fd();
+
+ fzl::FdioCaller caller(std::move(fd));
+ fzl::FdioCaller move_assignment_caller = std::move(caller);
+ ASSERT_TRUE(move_assignment_caller);
+ ASSERT_FALSE(caller);
+ ASSERT_TRUE(TryFilesystemOperations(move_assignment_caller));
+
+ END_TEST;
+}
+
+bool FdioCallerMoveConstructor() {
+ BEGIN_TEST;
+
+ Harness harness;
+ ASSERT_TRUE(harness.Setup());
+ auto fd = harness.fd();
+
+ fzl::FdioCaller caller(std::move(fd));
+ fzl::FdioCaller move_ctor_caller(std::move(caller));
+ ASSERT_TRUE(move_ctor_caller);
+ ASSERT_FALSE(caller);
+ ASSERT_TRUE(TryFilesystemOperations(move_ctor_caller));
+
+ END_TEST;
+}
+
} // namespace
-BEGIN_TEST_CASE(fdio_call_tests)
-RUN_TEST(fdio_call_io)
-END_TEST_CASE(fdio_call_tests)
+BEGIN_TEST_CASE(FdioCallTests)
+RUN_TEST(FdioCallerFile)
+RUN_TEST(FdioCallerMoveAssignment)
+RUN_TEST(FdioCallerMoveConstructor)
+END_TEST_CASE(FdioCallTests)