[libc] Convert readv, writev, and read_write tests to use pipes (#210725)

Using a pipe avoids races between "hermetic" and "unit" versions of the
same test and avoids leaving filesystem artifacts around if the test
fails. If I'm successful, we won't have the worry about the first
problem anymore, but I think it's still a nice cleanup.

Assisted by Gemini.
This commit is contained in:
Pavel Labath 2026-07-24 10:34:52 +02:00 committed by GitHub
parent 9f426801ba
commit 35368cb5dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 39 additions and 58 deletions

View file

@ -1,6 +1,6 @@
add_custom_target(libc_sys_uio_unittests)
add_libc_unittest(
add_libc_test(
writev_test
SUITE
libc_sys_uio_unittests
@ -10,14 +10,14 @@ add_libc_unittest(
libc.hdr.types.struct_iovec
libc.src.__support.common
libc.src.errno.errno
libc.src.fcntl.open
libc.src.sys.uio.writev
libc.src.unistd.close
libc.src.unistd.unlink
libc.src.unistd.pipe
libc.src.unistd.read
libc.test.UnitTest.ErrnoSetterMatcher
)
add_libc_unittest(
add_libc_test(
readv_test
SUITE
libc_sys_uio_unittests
@ -27,10 +27,9 @@ add_libc_unittest(
libc.hdr.types.struct_iovec
libc.src.__support.common
libc.src.errno.errno
libc.src.fcntl.open
libc.src.sys.uio.readv
libc.src.unistd.close
libc.src.unistd.unlink
libc.src.unistd.pipe
libc.src.unistd.write
libc.test.UnitTest.ErrnoSetterMatcher
)

View file

@ -7,10 +7,9 @@
//===----------------------------------------------------------------------===//
#include "hdr/types/struct_iovec.h"
#include "src/fcntl/open.h"
#include "src/sys/uio/readv.h"
#include "src/unistd/close.h"
#include "src/unistd/unlink.h"
#include "src/unistd/pipe.h"
#include "src/unistd/write.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@ -18,16 +17,14 @@
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
TEST(LlvmLibcSysUioReadvTest, SmokeTest) {
const char *filename = "./LlvmLibcSysUioReadvTest";
int fd = LIBC_NAMESPACE::open(filename, O_WRONLY | O_CREAT, 0644);
ASSERT_THAT(fd, returns(GT(0)).with_errno(EQ(0)));
const char data[] = "Hello, World!\n";
ASSERT_THAT(LIBC_NAMESPACE::write(fd, data, sizeof(data)),
returns(EQ(sizeof(data))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
int pipefd[2];
ASSERT_THAT(LIBC_NAMESPACE::pipe(pipefd), Succeeds());
const char data[] = "Hello, World!\n";
ASSERT_THAT(LIBC_NAMESPACE::write(pipefd[1], data, sizeof(data)),
returns(EQ(sizeof(data))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[1]), Succeeds());
fd = LIBC_NAMESPACE::open(filename, O_RDONLY);
ASSERT_THAT(fd, returns(GT(0)).with_errno(EQ(0)));
char buf0[2];
char buf1[3];
struct iovec iov[2];
@ -35,9 +32,7 @@ TEST(LlvmLibcSysUioReadvTest, SmokeTest) {
iov[0].iov_len = 1;
iov[1].iov_base = buf1;
iov[1].iov_len = 2;
ASSERT_THAT(LIBC_NAMESPACE::readv(fd, iov, 2),
ASSERT_THAT(LIBC_NAMESPACE::readv(pipefd[0], iov, 2),
returns(EQ(ssize_t(3))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::unlink(filename),
returns(EQ(ssize_t(0))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[0]), Succeeds());
}

View file

@ -7,28 +7,33 @@
//===----------------------------------------------------------------------===//
#include "hdr/types/struct_iovec.h"
#include "src/fcntl/open.h"
#include "src/sys/uio/writev.h"
#include "src/unistd/close.h"
#include "src/unistd/unlink.h"
#include "src/unistd/pipe.h"
#include "src/unistd/read.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
TEST(LlvmLibcSysUioWritevTest, SmokeTest) {
const char *filename = "./LlvmLibcSysUioWritevTest";
int fd = LIBC_NAMESPACE::open(filename, O_WRONLY | O_CREAT, 0644);
ASSERT_THAT(fd, returns(GT(0)).with_errno(EQ(0)));
int pipefd[2];
ASSERT_THAT(LIBC_NAMESPACE::pipe(pipefd), Succeeds());
const char *data = "Hello, World!\n";
struct iovec iov[2];
iov[0].iov_base = const_cast<char *>(data);
iov[0].iov_len = 7;
iov[1].iov_base = const_cast<char *>(data + 7);
iov[1].iov_len = 8;
ASSERT_THAT(LIBC_NAMESPACE::writev(fd, iov, 2),
ASSERT_THAT(LIBC_NAMESPACE::writev(pipefd[1], iov, 2),
returns(EQ(ssize_t(15))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::unlink(filename),
returns(EQ(ssize_t(0))).with_errno(EQ(0)));
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[1]), Succeeds());
char buf[16];
ASSERT_THAT(LIBC_NAMESPACE::read(pipefd[0], buf, 15),
returns(EQ(ssize_t(15))).with_errno(EQ(0)));
buf[15] = '\0';
EXPECT_STREQ(buf, data);
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[0]), Succeeds());
}

View file

@ -230,22 +230,19 @@ add_libc_unittest(
libc.test.UnitTest.ErrnoSetterMatcher
)
add_libc_unittest(
add_libc_test(
read_write_test
SUITE
libc_unistd_unittests
SRCS
read_write_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
libc.include.unistd
libc.src.errno.errno
libc.src.fcntl.open
libc.src.unistd.close
libc.src.unistd.fsync
libc.src.unistd.pipe
libc.src.unistd.read
libc.src.unistd.write
libc.src.stdio.remove
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)

View file

@ -6,11 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "hdr/sys_stat_macros.h"
#include "src/fcntl/open.h"
#include "src/stdio/remove.h"
#include "src/unistd/close.h"
#include "src/unistd/fsync.h"
#include "src/unistd/pipe.h"
#include "src/unistd/read.h"
#include "src/unistd/write.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
@ -21,29 +18,20 @@ using LlvmLibcUniStd = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcUniStd, WriteAndReadBackTest) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *FILENAME = "__unistd_read_write.test";
auto TEST_FILE = libc_make_test_file_path(FILENAME);
int pipefd[2];
ASSERT_THAT(LIBC_NAMESPACE::pipe(pipefd), Succeeds(0));
int write_fd = LIBC_NAMESPACE::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(write_fd, 0);
constexpr const char HELLO[] = "hello";
constexpr ssize_t HELLO_SIZE = sizeof(HELLO);
ASSERT_THAT(LIBC_NAMESPACE::write(write_fd, HELLO, HELLO_SIZE),
ASSERT_THAT(LIBC_NAMESPACE::write(pipefd[1], HELLO, HELLO_SIZE),
Succeeds(HELLO_SIZE));
ASSERT_THAT(LIBC_NAMESPACE::fsync(write_fd), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(write_fd), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[1]), Succeeds(0));
int read_fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDONLY);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(read_fd, 0);
char read_buf[10];
ASSERT_THAT(LIBC_NAMESPACE::read(read_fd, read_buf, HELLO_SIZE),
ASSERT_THAT(LIBC_NAMESPACE::read(pipefd[0], read_buf, HELLO_SIZE),
Succeeds(HELLO_SIZE));
EXPECT_STREQ(read_buf, HELLO);
ASSERT_THAT(LIBC_NAMESPACE::close(read_fd), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::remove(TEST_FILE), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(pipefd[0]), Succeeds(0));
}
TEST_F(LlvmLibcUniStd, WriteFails) {

View file

@ -107,11 +107,8 @@ libc_test(
srcs = ["read_write_test.cpp"],
deps = [
"//libc:close",
"//libc:fsync",
"//libc:hdr_sys_stat_macros",
"//libc:open",
"//libc:pipe",
"//libc:read",
"//libc:remove",
"//libc:write",
],
)