diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-06-21 12:20:34 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-06-21 12:20:34 +0100 |
| commit | 8a36eb498e1a1c2cf2e886356faa4ce67e52e874 (patch) | |
| tree | 92e44b4d4ddef68ff91d35f44ca57a9d45e7f879 /tests/fd.cc | |
| download | nihil-8a36eb498e1a1c2cf2e886356faa4ce67e52e874.tar.gz nihil-8a36eb498e1a1c2cf2e886356faa4ce67e52e874.tar.bz2 | |
initial commit
Diffstat (limited to 'tests/fd.cc')
| -rw-r--r-- | tests/fd.cc | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/tests/fd.cc b/tests/fd.cc new file mode 100644 index 0000000..fbf353e --- /dev/null +++ b/tests/fd.cc @@ -0,0 +1,200 @@ +/* + * This source code is released into the public domain. + */ + +#include <span> + +#include <stdio.h> +#include <fcntl.h> + +#include <catch2/catch_test_macros.hpp> + +import nihil; + +using namespace std::literals; + +namespace { + +// Test if an fd is open. +auto fd_is_open(int fd) -> bool { + auto const ret = ::fcntl(fd, F_GETFL); + return ret == 0; +} + +} // anonymous namespace + +TEST_CASE("fd: construct empty", "[fd]") { + nihil::fd fd; + + REQUIRE(!fd); + REQUIRE_THROWS_AS(fd.get(), nihil::fd_logic_error); +} + +TEST_CASE("fd: construct from fd", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + { + auto fd = nihil::fd(file); + REQUIRE(fd_is_open(fd.get())); + } + + REQUIRE(!fd_is_open(file)); +} + +TEST_CASE("fd: close", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd = nihil::fd(file); + REQUIRE(fd); + + auto const ret = fd.close(); + REQUIRE(ret); + REQUIRE(!fd_is_open(file)); +} + +TEST_CASE("fd: move construct", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd1 = nihil::fd(file); + REQUIRE(fd_is_open(fd1.get())); + + auto fd2(std::move(fd1)); + REQUIRE(!fd1); + REQUIRE(fd2); + REQUIRE(fd2.get() == file); + REQUIRE(fd_is_open(file)); +} + +TEST_CASE("fd: move assign", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd1 = nihil::fd(file); + REQUIRE(fd_is_open(fd1.get())); + + auto fd2 = nihil::fd(); + REQUIRE(!fd2); + + fd2 = std::move(fd1); + + REQUIRE(!fd1); + REQUIRE(fd2); + REQUIRE(fd2.get() == file); + REQUIRE(fd_is_open(file)); +} + +TEST_CASE("fd: release", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd = nihil::fd(file); + auto fdesc = std::move(fd).release(); + REQUIRE(!fd); + REQUIRE(fdesc == file); +} + +TEST_CASE("fd: dup", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd = nihil::fd(file); + REQUIRE(fd); + + auto fd2 = dup(fd); + REQUIRE(fd2); + REQUIRE(fd.get() != fd2->get()); +} + +TEST_CASE("fd: dup2", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + REQUIRE(!fd_is_open(666)); + + auto fd = nihil::fd(file); + auto fd2 = dup(fd, 666); + + REQUIRE(fd); + REQUIRE(fd2); + REQUIRE(fd2->get() == 666); +} + +TEST_CASE("fd: flags", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd = nihil::fd(file); + + { + auto const ret = replaceflags(fd, 0); + REQUIRE(ret); + REQUIRE(getflags(fd) == 0); + } + + { + auto const ret = setflags(fd, O_NONBLOCK); + REQUIRE(ret == O_NONBLOCK); + REQUIRE(getflags(fd) == O_NONBLOCK); + } + + { + auto const ret = setflags(fd, O_SYNC); + REQUIRE(ret == (O_NONBLOCK|O_SYNC)); + REQUIRE(getflags(fd) == (O_NONBLOCK|O_SYNC)); + } + + { + auto const ret = clearflags(fd, O_NONBLOCK); + REQUIRE(ret == O_SYNC); + REQUIRE(getflags(fd) == O_SYNC); + } +} + +TEST_CASE("fd: fdflags", "[fd]") { + auto file = ::open("/dev/null", O_RDONLY); + REQUIRE(file > 0); + + auto fd = nihil::fd(file); + + { + auto const ret = replacefdflags(fd, 0); + REQUIRE(ret); + REQUIRE(getfdflags(fd) == 0); + } + + { + auto const ret = setfdflags(fd, FD_CLOEXEC); + REQUIRE(ret == FD_CLOEXEC); + REQUIRE(getfdflags(fd) == FD_CLOEXEC); + } + + { + auto const ret = clearfdflags(fd, FD_CLOEXEC); + REQUIRE(ret == 0); + REQUIRE(getfdflags(fd) == 0); + } +} + +TEST_CASE("fd: pipe, read, write", "[fd]") { + auto fds = nihil::pipe(); + REQUIRE(fds); + + auto [fd1, fd2] = std::move(*fds); + + auto constexpr test_string = "test string"sv; + + auto ret = write(fd1, test_string); + REQUIRE(ret); + REQUIRE(*ret == test_string.size()); + + auto readbuf = std::array<char, test_string.size() * 2>{}; + ret = read(fd2, readbuf); + REQUIRE(ret); + REQUIRE(*ret == test_string.size()); + + auto read_string = std::string_view(std::span(readbuf).subspan(0, *ret)); + REQUIRE(read_string == test_string); +} |
