zlib / tests /tests_gzread_gz_load.c
AryaWu's picture
Upload folder using huggingface_hub
e996a55 verified
#include "unity/unity.h"
#include "zlib.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Declare the provided test wrapper without relying on internal types */
int test_gz_load(void *state, unsigned char *buf, unsigned len, unsigned *have);
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Helper: create a temporary file with given data, return fd and path.
The caller is responsible for unlinking the path and closing/unwrapping fd. */
static int make_temp_file_with_data(const unsigned char *data, size_t len, char *out_path, size_t out_path_size) {
const char *tmpdir = getenv("TMPDIR");
if (!tmpdir) tmpdir = "/tmp";
snprintf(out_path, out_path_size, "%s/gzread_test_%ld_%d_XXXXXX", tmpdir, (long)getpid(), rand());
int fd = mkstemp(out_path);
if (fd == -1) {
return -1;
}
ssize_t w = write(fd, data, len);
if (w < 0 || (size_t)w != len) {
close(fd);
unlink(out_path);
return -1;
}
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
close(fd);
unlink(out_path);
return -1;
}
return fd;
}
/* Helper: open a gzFile for reading using gzdopen() on an existing fd */
static gzFile open_gzfile_from_fd_for_reading(int fd) {
/* gzdopen takes ownership of fd and will close it on gzclose_r */
gzFile file = gzdopen(fd, "rb");
return file;
}
/* Test 1: Basic sequential reads and EOF behavior on a regular file */
void test_gz_load_basic_sequential_reads(void) {
const unsigned char content[] = "ABCDEFGHIJ"; /* 10 bytes */
char path[256];
int fd = make_temp_file_with_data(content, sizeof(content) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd != -1, "Failed to create temp file");
gzFile file = open_gzfile_from_fd_for_reading(fd);
TEST_ASSERT_MESSAGE(file != NULL, "gzdopen failed");
/* Unlink immediately; fd remains valid until gzclose_r */
unlink(path);
unsigned char buf[8];
unsigned have = 123; /* ensure function resets it */
int ret;
/* Read first 4 bytes */
ret = test_gz_load((void*)file, buf, 4U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(4U, have);
TEST_ASSERT_EQUAL_UINT8_ARRAY(content + 0, buf, 4);
/* Read next 4 bytes */
have = 0;
ret = test_gz_load((void*)file, buf, 4U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(4U, have);
TEST_ASSERT_EQUAL_UINT8_ARRAY(content + 4, buf, 4);
/* Request 4 more, but only 2 remain */
have = 0;
ret = test_gz_load((void*)file, buf, 4U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(2U, have);
TEST_ASSERT_EQUAL_UINT8_ARRAY(content + 8, buf, 2);
/* Next call at EOF should return 0 with have==0 */
have = 777;
ret = test_gz_load((void*)file, buf, 4U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0U, have);
/* Cleanup */
int c = gzclose_r(file);
TEST_ASSERT_MESSAGE(c == Z_OK || c == Z_BUF_ERROR, "gzclose_r failed");
}
/* Test 2: Partial read and EOF via a pipe (writer provides fewer bytes than requested) */
void test_gz_load_handles_partial_read_with_pipe(void) {
int pfd[2];
int r = pipe(pfd);
TEST_ASSERT_MESSAGE(r == 0, "pipe() failed");
const unsigned char msg[] = "hello"; /* 5 bytes */
ssize_t w = write(pfd[1], msg, sizeof(msg) - 1);
TEST_ASSERT_MESSAGE(w == (ssize_t)(sizeof(msg) - 1), "write to pipe failed");
close(pfd[1]); /* Ensure EOF after available data */
gzFile file = open_gzfile_from_fd_for_reading(pfd[0]);
TEST_ASSERT_MESSAGE(file != NULL, "gzdopen failed on pipe");
unsigned char buf[16];
unsigned have = 0;
int ret = test_gz_load((void*)file, buf, 10U, &have); /* request more than available */
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(5U, have);
TEST_ASSERT_EQUAL_UINT8_ARRAY(msg, buf, 5);
int c = gzclose_r(file);
TEST_ASSERT_MESSAGE(c == Z_OK || c == Z_BUF_ERROR, "gzclose_r failed");
}
/* Test 3: Error path - use a write-only file descriptor to force read() error (EBADF) */
void test_gz_load_returns_error_on_unreadable_fd(void) {
const unsigned char content[] = "data";
char path[256];
int fdw = make_temp_file_with_data(content, sizeof(content) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(fdw != -1, "Failed to create temp file for error test");
close(fdw);
/* Open write-only to make read() fail with EBADF */
int fd = open(path, O_WRONLY);
TEST_ASSERT_MESSAGE(fd != -1, "Failed to reopen temp file write-only");
/* Unlink immediately; fd remains valid until gzclose_r */
unlink(path);
gzFile file = open_gzfile_from_fd_for_reading(fd);
TEST_ASSERT_MESSAGE(file != NULL, "gzdopen failed on write-only fd");
unsigned char buf[8];
unsigned have = 42;
int ret = test_gz_load((void*)file, buf, 5U, &have);
TEST_ASSERT_EQUAL_INT(-1, ret);
TEST_ASSERT_EQUAL_UINT(0U, have);
int c = gzclose_r(file);
TEST_ASSERT_MESSAGE(c == Z_OK || c == Z_BUF_ERROR, "gzclose_r failed");
}
/* Test 4: Zero-length request returns 0 and does not consume data */
void test_gz_load_zero_length_request(void) {
const unsigned char content[] = "WXYZ"; /* 4 bytes */
char path[256];
int fd = make_temp_file_with_data(content, sizeof(content) - 1, path, sizeof(path));
TEST_ASSERT_MESSAGE(fd != -1, "Failed to create temp file");
gzFile file = open_gzfile_from_fd_for_reading(fd);
TEST_ASSERT_MESSAGE(file != NULL, "gzdopen failed");
unlink(path);
unsigned char buf[8];
unsigned have = 99;
/* len == 0 should return 0 and set have == 0 */
int ret = test_gz_load((void*)file, buf, 0U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(0U, have);
/* Subsequent normal read should still return initial data */
have = 0;
ret = test_gz_load((void*)file, buf, 4U, &have);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_UINT(4U, have);
TEST_ASSERT_EQUAL_UINT8_ARRAY(content, buf, 4);
int c = gzclose_r(file);
TEST_ASSERT_MESSAGE(c == Z_OK || c == Z_BUF_ERROR, "gzclose_r failed");
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_gz_load_basic_sequential_reads);
RUN_TEST(test_gz_load_handles_partial_read_with_pipe);
RUN_TEST(test_gz_load_returns_error_on_unreadable_fd);
RUN_TEST(test_gz_load_zero_length_request);
return UNITY_END();
}