zlib / tests /tests_gzlib_gzoffset64.c
AryaWu's picture
Upload folder using huggingface_hub
e996a55 verified
#include "unity/unity.h"
#include "zlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
/* Helpers to create and clean up temporary files */
static char *make_temp_path(void) {
char tmpl[] = "/tmp/zlib_gzoffset64_XXXXXX";
int fd = mkstemp(tmpl);
if (fd == -1) {
return NULL;
}
close(fd); /* We'll reopen as needed */
char *path = (char *)malloc(strlen(tmpl) + 1);
if (!path) return NULL;
strcpy(path, tmpl);
return path;
}
static size_t file_size(const char *path) {
struct stat st;
if (stat(path, &st) != 0) return 0;
return (size_t)st.st_size;
}
/* Write a gzip file with given data bytes */
static int write_gz_file(const char *path, const unsigned char *data, size_t len) {
gzFile gz = gzopen(path, "wb");
if (!gz) return -1;
size_t total = 0;
while (total < len) {
unsigned chunk = (unsigned)((len - total) > 4096 ? 4096 : (len - total));
int wrote = gzwrite(gz, data + total, chunk);
if (wrote <= 0) {
gzclose(gz);
return -1;
}
total += (size_t)wrote;
}
int rc = gzclose(gz);
return rc == Z_OK ? 0 : -1;
}
/* Generate repetitive data */
static unsigned char *make_data(size_t len) {
unsigned char *buf = (unsigned char *)malloc(len);
if (!buf) return NULL;
for (size_t i = 0; i < len; i++) {
buf[i] = (unsigned char)(i * 1315423911u + 0x5bd1e995u); /* simple pattern */
}
return buf;
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Test cases */
void test_gzoffset64_null_returns_minus1(void) {
z_off64_t off = gzoffset64(NULL);
TEST_ASSERT_EQUAL_INT64(-1, off);
}
void test_gzoffset64_write_mode_zero_and_increases_after_flush(void) {
char *path = make_temp_path();
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp path");
gzFile gz = gzopen(path, "wb");
TEST_ASSERT_NOT_NULL_MESSAGE(gz, "gzopen failed for write");
/* Initially zero */
z_off64_t off0 = gzoffset64(gz);
TEST_ASSERT_EQUAL_INT64(0, off0);
/* Write some data */
const char *msg1 = "The quick brown fox jumps over the lazy dog.\n";
int w1 = gzwrite(gz, msg1, (unsigned)strlen(msg1));
TEST_ASSERT_TRUE(w1 > 0);
/* Before flush, offset may still be 0 due to buffering; don't assert > 0 yet */
z_off64_t off_pre = gzoffset64(gz);
TEST_ASSERT_TRUE(off_pre >= 0);
/* Flush to force writes to underlying fd */
int fr = gzflush(gz, Z_SYNC_FLUSH);
TEST_ASSERT_TRUE(fr == Z_OK || fr == Z_BUF_ERROR); /* Z_BUF_ERROR means nothing to flush */
z_off64_t off1 = gzoffset64(gz);
TEST_ASSERT_TRUE_MESSAGE(off1 >= 0, "gzoffset64 should be non-negative after flush");
/* With some data written and flushed, we expect some bytes written */
TEST_ASSERT_TRUE_MESSAGE(off1 > 0, "gzoffset64 should be > 0 after writing and flushing");
/* Write more and flush again */
const char *msg2 = "Pack my box with five dozen liquor jugs.\n";
int w2 = gzwrite(gz, msg2, (unsigned)strlen(msg2));
TEST_ASSERT_TRUE(w2 > 0);
fr = gzflush(gz, Z_SYNC_FLUSH);
TEST_ASSERT_TRUE(fr == Z_OK || fr == Z_BUF_ERROR);
z_off64_t off2 = gzoffset64(gz);
TEST_ASSERT_TRUE_MESSAGE(off2 >= off1, "Offset should be non-decreasing after additional writes");
/* Close and check final size is at least as large as last observed offset */
int rc = gzclose(gz);
TEST_ASSERT_EQUAL_INT(Z_OK, rc);
size_t final_size = file_size(path);
TEST_ASSERT_TRUE_MESSAGE((z_off64_t)final_size >= off2,
"Final file size should be >= offset observed before close");
/* Cleanup */
remove(path);
free(path);
}
void test_gzoffset64_read_mode_initial_fd_position_via_gzdopen(void) {
char *path = make_temp_path();
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp path");
/* Create a regular file with some content */
int fd_create = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
TEST_ASSERT_TRUE_MESSAGE(fd_create >= 0, "open for create failed");
unsigned char zeros[1024];
memset(zeros, 0, sizeof(zeros));
ssize_t wr = write(fd_create, zeros, sizeof(zeros));
TEST_ASSERT_TRUE_MESSAGE(wr == (ssize_t)sizeof(zeros), "write failed");
close(fd_create);
/* Reopen for read and position to 123 */
int fd = open(path, O_RDONLY);
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "open for read failed");
off_t want = 123;
off_t pos = lseek(fd, want, SEEK_SET);
TEST_ASSERT_EQUAL_INT64((long long)want, (long long)pos);
/* Wrap with gzdopen in read mode */
gzFile gz = gzdopen(fd, "rb");
TEST_ASSERT_NOT_NULL_MESSAGE(gz, "gzdopen failed");
/* Before any reads, avail_in == 0, so gzoffset64 should reflect current fd pos */
z_off64_t off = gzoffset64(gz);
TEST_ASSERT_EQUAL_INT64((long long)want, (long long)off);
int rc = gzclose(gz); /* closes fd as well */
TEST_ASSERT_EQUAL_INT(Z_OK, rc);
remove(path);
free(path);
}
void test_gzoffset64_read_mode_not_greater_than_raw_fd_position_after_read(void) {
char *path = make_temp_path();
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp path");
/* Create a valid gzip file with some data */
size_t data_len = 20000;
unsigned char *data = make_data(data_len);
TEST_ASSERT_NOT_NULL_MESSAGE(data, "Failed to allocate data");
TEST_ASSERT_EQUAL_INT(0, write_gz_file(path, data, data_len));
free(data);
/* Open raw fd and wrap with gzdopen */
int fd = open(path, O_RDONLY);
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "open gzip for read failed");
gzFile gz = gzdopen(fd, "rb");
TEST_ASSERT_NOT_NULL_MESSAGE(gz, "gzdopen failed");
/* Initial checks */
off_t raw0 = lseek(fd, 0, SEEK_CUR);
TEST_ASSERT_EQUAL_INT64(0, (long long)raw0);
z_off64_t off0 = gzoffset64(gz);
TEST_ASSERT_EQUAL_INT64(0, (long long)off0);
unsigned char buf[128];
int rd1 = gzread(gz, buf, sizeof(buf));
TEST_ASSERT_TRUE_MESSAGE(rd1 > 0, "gzread should read some bytes");
off_t raw1 = lseek(fd, 0, SEEK_CUR);
z_off64_t off1 = gzoffset64(gz);
TEST_ASSERT_TRUE_MESSAGE(off1 >= 0, "gzoffset64 should be non-negative");
TEST_ASSERT_TRUE_MESSAGE(off1 <= (z_off64_t)raw1, "gzoffset64 should be <= raw fd position after read");
/* Read more and verify monotonicity and <= raw fd pos */
int rd2 = gzread(gz, buf, sizeof(buf));
TEST_ASSERT_TRUE_MESSAGE(rd2 >= 0, "gzread should not error");
off_t raw2 = lseek(fd, 0, SEEK_CUR);
z_off64_t off2 = gzoffset64(gz);
TEST_ASSERT_TRUE_MESSAGE(off2 >= off1, "gzoffset64 should be non-decreasing after additional reads");
TEST_ASSERT_TRUE_MESSAGE(off2 <= (z_off64_t)raw2, "gzoffset64 should be <= raw fd position after more reads");
int rc = gzclose(gz);
TEST_ASSERT_EQUAL_INT(Z_OK, rc);
remove(path);
free(path);
}
void test_gzoffset64_unchanged_by_pending_seek_request(void) {
/* Prepare gzip file */
char *path = make_temp_path();
TEST_ASSERT_NOT_NULL_MESSAGE(path, "Failed to create temp path");
size_t data_len = 10000;
unsigned char *data = make_data(data_len);
TEST_ASSERT_NOT_NULL_MESSAGE(data, "Failed to allocate data");
TEST_ASSERT_EQUAL_INT(0, write_gz_file(path, data, data_len));
free(data);
/* Open via fd and wrap in gzdopen */
int fd = open(path, O_RDONLY);
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "open for read failed");
gzFile gz = gzdopen(fd, "rb");
TEST_ASSERT_NOT_NULL_MESSAGE(gz, "gzdopen failed");
/* Read a bit to ensure buffers are initialized */
unsigned char tmp[64];
int rd = gzread(gz, tmp, sizeof(tmp));
TEST_ASSERT_TRUE_MESSAGE(rd >= 0, "gzread should not fail");
z_off64_t before = gzoffset64(gz);
/* Issue a pending relative seek (SEEK_CUR) which sets state->seek without moving OS fd immediately */
z_off64_t newpos = gzseek64(gz, 10, SEEK_CUR);
TEST_ASSERT_TRUE_MESSAGE(newpos >= 0, "gzseek64 should succeed");
z_off64_t after = gzoffset64(gz);
/* gzoffset64 should reflect current fd - avail_in, not the pending skip */
TEST_ASSERT_EQUAL_INT64((long long)before, (long long)after);
int rc = gzclose(gz);
TEST_ASSERT_EQUAL_INT(Z_OK, rc);
remove(path);
free(path);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_gzoffset64_null_returns_minus1);
RUN_TEST(test_gzoffset64_write_mode_zero_and_increases_after_flush);
RUN_TEST(test_gzoffset64_read_mode_initial_fd_position_via_gzdopen);
RUN_TEST(test_gzoffset64_read_mode_not_greater_than_raw_fd_position_after_read);
RUN_TEST(test_gzoffset64_unchanged_by_pending_seek_request);
return UNITY_END();
}