Add five targeted test cases for the new qio_channel_pread{v,}_all()
and preadv_all_eof() helpers introduced earlier in this series:
preadv_all: read from a non-zero offset into two iovecs
pread_all: single-buffer wrapper smoke test
preadv_all_eof/clean: clean EOF (offset == file length) returns 0
preadv_all_eof/partial: partial data then EOF returns -1
preadv_all/eof-is-error: strict wrapper turns clean EOF into -1
All tests create a 16-byte file with known content and exercise the
read helpers against it, verifying return values, error state, and
(where applicable) buffer contents. The tests are guarded by
CONFIG_PREADV since the underlying preadv support is optional.
Signed-off-by: Junjie Cao <junjie.cao@intel.com>
---
tests/unit/test-io-channel-file.c | 137 ++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
diff --git a/tests/unit/test-io-channel-file.c b/tests/unit/test-io-channel-file.c
index 1977006ce9..97a2a5b5cb 100644
--- a/tests/unit/test-io-channel-file.c
+++ b/tests/unit/test-io-channel-file.c
@@ -102,6 +102,131 @@ static void test_io_channel_fd(void)
}
+#ifdef CONFIG_PREADV
+#define TEST_PREAD_FILE "tests/test-io-channel-pread.txt"
+#define TEST_PREAD_PATTERN "ABCDEFGHIJKLMNOP" /* 16 bytes */
+#define TEST_PREAD_LEN 16
+
+static QIOChannel *create_pread_test_file(void)
+{
+ int fd;
+
+ fd = open(TEST_PREAD_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ g_assert_cmpint(fd, >=, 0);
+ g_assert_cmpint(write(fd, TEST_PREAD_PATTERN, TEST_PREAD_LEN),
+ ==, TEST_PREAD_LEN);
+ close(fd);
+
+ return QIO_CHANNEL(qio_channel_file_new_path(
+ TEST_PREAD_FILE, O_RDONLY, 0,
+ &error_abort));
+}
+
+static void test_io_channel_preadv_all(void)
+{
+ QIOChannel *ioc;
+ char buf1[4], buf2[4];
+ struct iovec iov[2] = {
+ { .iov_base = buf1, .iov_len = sizeof(buf1) },
+ { .iov_base = buf2, .iov_len = sizeof(buf2) },
+ };
+ int ret;
+
+ ioc = create_pread_test_file();
+
+ /* Read 8 bytes from offset 4 into two iovecs: "EFGH" + "IJKL" */
+ ret = qio_channel_preadv_all(ioc, iov, 2, 4, &error_abort);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpmem(buf1, 4, "EFGH", 4);
+ g_assert_cmpmem(buf2, 4, "IJKL", 4);
+
+ unlink(TEST_PREAD_FILE);
+ object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_pread_all(void)
+{
+ QIOChannel *ioc;
+ char buf[8];
+ int ret;
+
+ ioc = create_pread_test_file();
+
+ /* Read 8 bytes from offset 8: "IJKLMNOP" */
+ ret = qio_channel_pread_all(ioc, buf, sizeof(buf), 8, &error_abort);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_cmpmem(buf, 8, "IJKLMNOP", 8);
+
+ unlink(TEST_PREAD_FILE);
+ object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_preadv_all_eof_clean(void)
+{
+ QIOChannel *ioc;
+ Error *err = NULL;
+ char buf[8];
+ struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
+ int ret;
+
+ ioc = create_pread_test_file();
+
+ /* Read from offset == file length: clean EOF, expect 0 and no error */
+ ret = qio_channel_preadv_all_eof(ioc, &iov, 1, TEST_PREAD_LEN, &err);
+ g_assert_cmpint(ret, ==, 0);
+ g_assert_null(err);
+
+ unlink(TEST_PREAD_FILE);
+ object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_preadv_all_eof_partial(void)
+{
+ QIOChannel *ioc;
+ Error *err = NULL;
+ char buf[8];
+ struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
+ int ret;
+
+ ioc = create_pread_test_file();
+
+ /*
+ * Read 8 bytes from offset 12: only 4 bytes available before EOF.
+ * Expect -1 (partial data then EOF is an error) and err set.
+ */
+ ret = qio_channel_preadv_all_eof(ioc, &iov, 1, 12, &err);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_nonnull(err);
+ error_free(err);
+
+ unlink(TEST_PREAD_FILE);
+ object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_preadv_all_eof_is_error(void)
+{
+ QIOChannel *ioc;
+ Error *err = NULL;
+ char buf[8];
+ struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
+ int ret;
+
+ ioc = create_pread_test_file();
+
+ /*
+ * Clean EOF through the strict wrapper: should be translated to -1.
+ */
+ ret = qio_channel_preadv_all(ioc, &iov, 1, TEST_PREAD_LEN, &err);
+ g_assert_cmpint(ret, ==, -1);
+ g_assert_nonnull(err);
+ error_free(err);
+
+ unlink(TEST_PREAD_FILE);
+ object_unref(OBJECT(ioc));
+}
+#endif /* CONFIG_PREADV */
+
+
#ifndef _WIN32
static void test_io_channel_pipe(bool async)
{
@@ -147,6 +272,18 @@ int main(int argc, char **argv)
g_test_add_func("/io/channel/file", test_io_channel_file);
g_test_add_func("/io/channel/file/rdwr", test_io_channel_file_rdwr);
g_test_add_func("/io/channel/file/fd", test_io_channel_fd);
+#ifdef CONFIG_PREADV
+ g_test_add_func("/io/channel/file/preadv-all",
+ test_io_channel_preadv_all);
+ g_test_add_func("/io/channel/file/pread-all",
+ test_io_channel_pread_all);
+ g_test_add_func("/io/channel/file/preadv-all-eof/clean",
+ test_io_channel_preadv_all_eof_clean);
+ g_test_add_func("/io/channel/file/preadv-all-eof/partial",
+ test_io_channel_preadv_all_eof_partial);
+ g_test_add_func("/io/channel/file/preadv-all/eof-is-error",
+ test_io_channel_preadv_all_eof_is_error);
+#endif
#ifndef _WIN32
g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
--
2.43.0
© 2016 - 2026 Red Hat, Inc.