diff options
Diffstat (limited to 'na/test/test_pipe_devfs.cc')
| -rw-r--r-- | na/test/test_pipe_devfs.cc | 420 |
1 files changed, 0 insertions, 420 deletions
diff --git a/na/test/test_pipe_devfs.cc b/na/test/test_pipe_devfs.cc deleted file mode 100644 index ed375ed..0000000 --- a/na/test/test_pipe_devfs.cc +++ /dev/null @@ -1,420 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -/* - * test_pipe_devfs.cc — Self-tests for pipe, /dev/null, /dev/zero, fcntl - */ - -#include <lume/selftest.h> -#include <lume/errno.h> -#include <lume/file.h> -#include <lume/fs.h> -#include <lume/fs_types.h> -#include <lume/task.h> -#include <lume/fdtable.h> -#include <lume/pipe.h> - -/* Syscall entry points */ -int64 sys_openat(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_close(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_read(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_write(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_pipe2(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_fcntl(uint64, uint64, uint64, uint64, uint64, uint64); -int64 sys_fstat_wrapper(uint64, uint64, uint64, uint64, uint64, uint64); - -/* ================================================================== */ -/* Helpers */ -/* ================================================================== */ - -static int64 open_dev(const char* path, int flags) -{ - return sys_openat( - static_cast<uint64>(-100), /* AT_FDCWD */ - reinterpret_cast<uint64>(path), - static_cast<uint64>(flags), - 0, 0, 0); -} - -static int64 do_close(int64 fd) -{ - return sys_close(static_cast<uint64>(fd), 0, 0, 0, 0, 0); -} - -static int64 do_read(int64 fd, void* buf, uint64 count) -{ - return sys_read(static_cast<uint64>(fd), - reinterpret_cast<uint64>(buf), count, 0, 0, 0); -} - -static int64 do_write(int64 fd, const void* buf, uint64 count) -{ - return sys_write(static_cast<uint64>(fd), - reinterpret_cast<uint64>(buf), count, 0, 0, 0); -} - -/* fcntl command constants — must match sys_fs.cc */ -inline constexpr int F_DUPFD = 0; -inline constexpr int F_GETFD = 1; -inline constexpr int F_SETFD = 2; -inline constexpr int F_GETFL = 3; -inline constexpr int F_SETFL = 4; -inline constexpr int F_DUPFD_CLOEXEC = 1030; -inline constexpr int FD_CLOEXEC = 1; - -/* ================================================================== */ -/* /dev/null tests */ -/* ================================================================== */ - -void selftest_devfs() -{ - /* ---- /dev/null: read returns EOF ---- */ - st_begin("devfs: /dev/null read returns 0 (EOF)"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - char buf[16]; - int64 n = do_read(fd, buf, sizeof(buf)); - ST_ASSERT_EQ(n, (int64)0); - do_close(fd); - } - st_pass(); - - /* ---- /dev/null: write discards data ---- */ - st_begin("devfs: /dev/null write discards data"); - { - int64 fd = open_dev("/dev/null", O_WRONLY); - ST_ASSERT(fd >= 0); - - const char* msg = "discarded"; - int64 n = do_write(fd, msg, 9); - ST_ASSERT_EQ(n, (int64)9); - do_close(fd); - } - st_pass(); - - /* ---- /dev/null: fstat reports S_IFCHR ---- */ - st_begin("devfs: /dev/null fstat is S_IFCHR"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - kstat st{}; - int64 ret = sys_fstat_wrapper( - static_cast<uint64>(fd), - reinterpret_cast<uint64>(&st), 0, 0, 0, 0); - ST_ASSERT_EQ(ret, (int64)0); - ST_ASSERT(S_ISCHR(st.st_mode)); - do_close(fd); - } - st_pass(); - - /* ---- /dev/zero: read returns zeros ---- */ - st_begin("devfs: /dev/zero read returns zeros"); - { - int64 fd = open_dev("/dev/zero", O_RDONLY); - ST_ASSERT(fd >= 0); - - char buf[32]; - /* Pre-fill with non-zero */ - for (int i = 0; i < 32; i++) buf[i] = 0xFF; - - int64 n = do_read(fd, buf, 32); - ST_ASSERT_EQ(n, (int64)32); - - bool all_zero = true; - for (int i = 0; i < 32; i++) { - if (buf[i] != 0) { all_zero = false; break; } - } - ST_ASSERT(all_zero); - do_close(fd); - } - st_pass(); - - /* ---- /dev/zero: write discards data ---- */ - st_begin("devfs: /dev/zero write discards data"); - { - int64 fd = open_dev("/dev/zero", O_WRONLY); - ST_ASSERT(fd >= 0); - - char buf[16] = {1, 2, 3}; - int64 n = do_write(fd, buf, 16); - ST_ASSERT_EQ(n, (int64)16); - do_close(fd); - } - st_pass(); -} - -/* ================================================================== */ -/* Pipe tests */ -/* ================================================================== */ - -void selftest_pipe() -{ - /* ---- pipe2: basic creation ---- */ - st_begin("pipe: pipe2 creates two valid fds"); - { - int fds[2] = {-1, -1}; - int64 ret = sys_pipe2( - reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - ST_ASSERT_EQ(ret, (int64)0); - ST_ASSERT(fds[0] >= 0); - ST_ASSERT(fds[1] >= 0); - ST_ASSERT_NE(fds[0], fds[1]); - - do_close(fds[0]); - do_close(fds[1]); - } - st_pass(); - - /* ---- pipe: write then read ---- */ - st_begin("pipe: write then read returns correct data"); - { - int fds[2]; - sys_pipe2(reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - - const char* msg = "pipe_test"; - int64 w = do_write(fds[1], msg, 9); - ST_ASSERT_EQ(w, (int64)9); - - char buf[16] = {}; - int64 r = do_read(fds[0], buf, 16); - ST_ASSERT_EQ(r, (int64)9); - - bool match = true; - for (int i = 0; i < 9; i++) { - if (buf[i] != msg[i]) { match = false; break; } - } - ST_ASSERT(match); - - do_close(fds[0]); - do_close(fds[1]); - } - st_pass(); - - /* ---- pipe: read from closed write end returns EOF ---- */ - st_begin("pipe: read after writer close returns EOF"); - { - int fds[2]; - sys_pipe2(reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - - /* Write some data, then close write end */ - const char* msg = "eof"; - do_write(fds[1], msg, 3); - do_close(fds[1]); - - /* Read the data */ - char buf[16]; - int64 r1 = do_read(fds[0], buf, 16); - ST_ASSERT_EQ(r1, (int64)3); - - /* Next read should return 0 (EOF) */ - int64 r2 = do_read(fds[0], buf, 16); - ST_ASSERT_EQ(r2, (int64)0); - - do_close(fds[0]); - } - st_pass(); - - /* ---- pipe: write to closed read end returns -EPIPE ---- */ - st_begin("pipe: write after reader close returns -EPIPE"); - { - int fds[2]; - sys_pipe2(reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - - /* Close read end */ - do_close(fds[0]); - - /* Write should fail */ - const char* msg = "broken"; - int64 w = do_write(fds[1], msg, 6); - ST_ASSERT_EQ(w, (int64)-EPIPE); - - do_close(fds[1]); - } - st_pass(); - - /* ---- pipe: multiple writes accumulate ---- */ - st_begin("pipe: multiple writes accumulate in buffer"); - { - int fds[2]; - sys_pipe2(reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - - do_write(fds[1], "AAA", 3); - do_write(fds[1], "BBB", 3); - - char buf[16] = {}; - int64 r = do_read(fds[0], buf, 16); - ST_ASSERT_EQ(r, (int64)6); - ST_ASSERT_EQ(buf[0], 'A'); - ST_ASSERT_EQ(buf[3], 'B'); - - do_close(fds[0]); - do_close(fds[1]); - } - st_pass(); - - /* ---- pipe: read partial ---- */ - st_begin("pipe: partial read leaves remainder"); - { - int fds[2]; - sys_pipe2(reinterpret_cast<uint64>(fds), 0, 0, 0, 0, 0); - - do_write(fds[1], "ABCDEF", 6); - - char buf[3] = {}; - int64 r1 = do_read(fds[0], buf, 3); - ST_ASSERT_EQ(r1, (int64)3); - ST_ASSERT_EQ(buf[0], 'A'); - ST_ASSERT_EQ(buf[2], 'C'); - - int64 r2 = do_read(fds[0], buf, 3); - ST_ASSERT_EQ(r2, (int64)3); - ST_ASSERT_EQ(buf[0], 'D'); - ST_ASSERT_EQ(buf[2], 'F'); - - do_close(fds[0]); - do_close(fds[1]); - } - st_pass(); -} - -/* ================================================================== */ -/* fcntl tests */ -/* ================================================================== */ - -void selftest_fcntl() -{ - /* ---- fcntl F_DUPFD ---- */ - st_begin("fcntl: F_DUPFD duplicates fd"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - int64 fd2 = sys_fcntl(static_cast<uint64>(fd), F_DUPFD, 0, 0, 0, 0); - ST_ASSERT(fd2 >= 0); - ST_ASSERT_NE(fd, fd2); - - /* Both should be valid reads */ - char buf[4]; - int64 r = do_read(fd2, buf, 4); - ST_ASSERT_EQ(r, (int64)0); /* /dev/null → EOF */ - - do_close(fd); - do_close(fd2); - } - st_pass(); - - /* ---- fcntl F_DUPFD with min_fd ---- */ - st_begin("fcntl: F_DUPFD respects min_fd"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - int64 fd2 = sys_fcntl(static_cast<uint64>(fd), F_DUPFD, 100, 0, 0, 0); - ST_ASSERT(fd2 >= 100); - - do_close(fd); - do_close(fd2); - } - st_pass(); - - /* ---- fcntl F_GETFD / F_SETFD ---- */ - st_begin("fcntl: F_GETFD/F_SETFD cloexec"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - /* Initially no CLOEXEC */ - int64 flags = sys_fcntl(static_cast<uint64>(fd), F_GETFD, 0, 0, 0, 0); - ST_ASSERT_EQ(flags, (int64)0); - - /* Set CLOEXEC */ - int64 ret = sys_fcntl(static_cast<uint64>(fd), F_SETFD, FD_CLOEXEC, 0, 0, 0); - ST_ASSERT_EQ(ret, (int64)0); - - /* Verify it was set */ - flags = sys_fcntl(static_cast<uint64>(fd), F_GETFD, 0, 0, 0, 0); - ST_ASSERT_EQ(flags, (int64)FD_CLOEXEC); - - /* Clear it */ - sys_fcntl(static_cast<uint64>(fd), F_SETFD, 0, 0, 0, 0); - flags = sys_fcntl(static_cast<uint64>(fd), F_GETFD, 0, 0, 0, 0); - ST_ASSERT_EQ(flags, (int64)0); - - do_close(fd); - } - st_pass(); - - /* ---- fcntl F_GETFL ---- */ - st_begin("fcntl: F_GETFL returns open flags"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - int64 fl = sys_fcntl(static_cast<uint64>(fd), F_GETFL, 0, 0, 0, 0); - /* O_RDONLY == 0, so result should have no write bits */ - ST_ASSERT_EQ(fl & O_WRONLY, (int64)0); - - do_close(fd); - } - st_pass(); - - /* ---- fcntl F_SETFL O_NONBLOCK ---- */ - st_begin("fcntl: F_SETFL toggles O_NONBLOCK"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - /* Set O_NONBLOCK */ - sys_fcntl(static_cast<uint64>(fd), F_SETFL, O_NONBLOCK, 0, 0, 0); - int64 fl = sys_fcntl(static_cast<uint64>(fd), F_GETFL, 0, 0, 0, 0); - ST_ASSERT(fl & O_NONBLOCK); - - /* Clear it */ - sys_fcntl(static_cast<uint64>(fd), F_SETFL, 0, 0, 0, 0); - fl = sys_fcntl(static_cast<uint64>(fd), F_GETFL, 0, 0, 0, 0); - ST_ASSERT_EQ(fl & O_NONBLOCK, (int64)0); - - do_close(fd); - } - st_pass(); - - /* ---- fcntl F_DUPFD_CLOEXEC ---- */ - st_begin("fcntl: F_DUPFD_CLOEXEC sets cloexec"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - int64 fd2 = sys_fcntl(static_cast<uint64>(fd), F_DUPFD_CLOEXEC, 0, 0, 0, 0); - ST_ASSERT(fd2 >= 0); - - int64 flags = sys_fcntl(static_cast<uint64>(fd2), F_GETFD, 0, 0, 0, 0); - ST_ASSERT_EQ(flags, (int64)FD_CLOEXEC); - - do_close(fd); - do_close(fd2); - } - st_pass(); - - /* ---- fcntl bad fd ---- */ - st_begin("fcntl: bad fd returns -EBADF"); - { - int64 ret = sys_fcntl(999, F_GETFD, 0, 0, 0, 0); - ST_ASSERT_EQ(ret, (int64)-EBADF); - } - st_pass(); - - /* ---- fcntl unknown cmd ---- */ - st_begin("fcntl: unknown cmd returns -EINVAL"); - { - int64 fd = open_dev("/dev/null", O_RDONLY); - ST_ASSERT(fd >= 0); - - int64 ret = sys_fcntl(static_cast<uint64>(fd), 9999, 0, 0, 0, 0); - ST_ASSERT_EQ(ret, (int64)-EINVAL); - do_close(fd); - } - st_pass(); -} |
