zlib / tests /tests_gzread_gz_avail.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 <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Include zlib's internal definitions to access gz_statep and fields.
We do not redefine any structs or macros; we merely use existing ones. */
#include "gzguts.h"
/* Wrapper provided in the module for testing the local function */
extern int test_gz_avail(gz_statep state);
/* Helpers */
static gzFile gzfile_from_bytes(const unsigned char *data, size_t len) {
char path[] = "/tmp/gzread_test_XXXXXX";
int fd = mkstemp(path);
TEST_ASSERT_MESSAGE(fd != -1, "mkstemp failed");
ssize_t w = write(fd, data, len);
TEST_ASSERT_MESSAGE(w >= 0, "write failed");
TEST_ASSERT_EQUAL_UINT32((uint32_t)len, (uint32_t)w);
/* rewind for reading */
off_t off = lseek(fd, 0, SEEK_SET);
TEST_ASSERT_MESSAGE(off == 0, "lseek failed");
/* wrap the fd as a gzFile */
gzFile f = gzdopen(fd, "rb");
TEST_ASSERT_NOT_NULL_MESSAGE(f, "gzdopen failed");
/* Unlink the path so it is cleaned up automatically after close */
unlink(path);
return f;
}
/* Prepare the input buffer and minimal state fields expected by gz_avail.
This allocates state->in and sets state->size = want. */
static void prepare_in_buffer(gz_statep s, unsigned want) {
s->want = want;
s->in = (unsigned char *)malloc(want);
TEST_ASSERT_NOT_NULL(s->in);
s->size = want;
/* Initialize stream input pointers */
s->strm.avail_in = 0;
s->strm.next_in = s->in;
/* Ensure readable state */
s->eof = 0;
s->err = Z_OK;
}
/* Cleanup allocated input buffer and neutralize so gzclose_r doesn't free or
call inflateEnd on a "live" buffer. */
static void free_reset_buffers(gz_statep s) {
if (s->in) {
free(s->in);
s->in = NULL;
}
s->size = 0;
s->strm.avail_in = 0;
s->strm.next_in = NULL;
}
/* Unity fixtures */
void setUp(void) {
/* empty */
}
void tearDown(void) {
/* empty */
}
/* Tests */
void test_gz_avail_reads_into_empty_buffer_and_sets_eof(void) {
const unsigned char data[] = "Hello, zlib gz_avail!";
const size_t len = sizeof(data) - 1;
gzFile f = gzfile_from_bytes(data, len);
gz_statep s = (gz_statep)f;
/* Prepare a buffer larger than file size to force EOF on load */
prepare_in_buffer(s, 64);
int rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_PTR(s->in, s->strm.next_in);
TEST_ASSERT_EQUAL_UINT((unsigned)len, s->strm.avail_in);
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, s->in, len);
TEST_ASSERT_EQUAL_INT(1, s->eof);
free_reset_buffers(s);
/* close gz */
int cr = gzclose_r(f);
(void)cr; /* ignore code path-specific errors */
}
void test_gz_avail_moves_existing_and_loads_more(void) {
const unsigned char data[] = "ABCDEFGH"; /* 8 bytes */
const size_t len = sizeof(data) - 1;
gzFile f = gzfile_from_bytes(data, len);
gz_statep s = (gz_statep)f;
/* Small buffer so loads happen in chunks */
prepare_in_buffer(s, 4);
/* First load: should read "ABCD", not at EOF */
int rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_UINT(4u, s->strm.avail_in);
TEST_ASSERT_EQUAL_UINT8_ARRAY("ABCD", s->in, 4);
TEST_ASSERT_EQUAL_INT(0, s->eof);
/* Simulate consuming two bytes: remaining "CD" */
s->strm.next_in = s->in + 2;
s->strm.avail_in = 2;
/* Second load: should move "CD" to start, then read "EF" -> "CDEF" */
rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_PTR(s->in, s->strm.next_in);
TEST_ASSERT_EQUAL_UINT(4u, s->strm.avail_in);
TEST_ASSERT_EQUAL_UINT8_ARRAY("CDEF", s->in, 4);
TEST_ASSERT_EQUAL_INT(0, s->eof); /* still have "GH" left in file */
free_reset_buffers(s);
int cr = gzclose_r(f);
(void)cr;
}
void test_gz_avail_sets_eof_when_end_reached(void) {
const unsigned char data[] = "XY"; /* 2 bytes */
const size_t len = sizeof(data) - 1;
gzFile f = gzfile_from_bytes(data, len);
gz_statep s = (gz_statep)f;
/* Buffer larger than file forces EOF set */
prepare_in_buffer(s, 8);
int rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_UINT((unsigned)len, s->strm.avail_in);
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, s->in, len);
TEST_ASSERT_EQUAL_INT(1, s->eof);
free_reset_buffers(s);
int cr = gzclose_r(f);
(void)cr;
}
void test_gz_avail_returns_minus1_on_error_state(void) {
const unsigned char data[] = "ABC";
const size_t len = sizeof(data) - 1;
gzFile f = gzfile_from_bytes(data, len);
gz_statep s = (gz_statep)f;
prepare_in_buffer(s, 4);
/* Seed some existing input to verify it remains unchanged */
s->strm.avail_in = 1;
s->in[0] = 0x42;
s->strm.next_in = s->in;
/* Set an error different from Z_OK/Z_BUF_ERROR */
s->err = Z_STREAM_ERROR;
int rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(-1, rc);
TEST_ASSERT_EQUAL_UINT(1u, s->strm.avail_in);
TEST_ASSERT_EQUAL_UINT8(0x42, s->in[0]); /* unchanged */
/* eof must not be set by early return */
TEST_ASSERT_EQUAL_INT(0, s->eof);
free_reset_buffers(s);
int cr = gzclose_r(f);
(void)cr;
}
void test_gz_avail_noop_when_eof_already_set(void) {
const unsigned char data[] = "ABCDEF";
const size_t len = sizeof(data) - 1;
gzFile f = gzfile_from_bytes(data, len);
gz_statep s = (gz_statep)f;
prepare_in_buffer(s, 4);
/* Preload some dummy existing data into the buffer */
s->in[0] = 'Q';
s->in[1] = 'R';
s->in[2] = 'S';
s->in[3] = 'T';
s->strm.next_in = s->in + 1; /* pretend "RS" remaining */
s->strm.avail_in = 2;
s->eof = 1; /* already at EOF; gz_avail should do nothing */
unsigned char before0 = s->in[0];
unsigned char before1 = s->in[1];
unsigned char before2 = s->in[2];
unsigned char before3 = s->in[3];
unsigned prev_avail = s->strm.avail_in;
unsigned char *prev_next = s->strm.next_in;
int rc = test_gz_avail(s);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_UINT(prev_avail, s->strm.avail_in);
TEST_ASSERT_EQUAL_PTR(prev_next, s->strm.next_in);
TEST_ASSERT_EQUAL_UINT8(before0, s->in[0]);
TEST_ASSERT_EQUAL_UINT8(before1, s->in[1]);
TEST_ASSERT_EQUAL_UINT8(before2, s->in[2]);
TEST_ASSERT_EQUAL_UINT8(before3, s->in[3]);
TEST_ASSERT_EQUAL_INT(1, s->eof);
free_reset_buffers(s);
int cr = gzclose_r(f);
(void)cr;
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_gz_avail_reads_into_empty_buffer_and_sets_eof);
RUN_TEST(test_gz_avail_moves_existing_and_loads_more);
RUN_TEST(test_gz_avail_sets_eof_when_end_reached);
RUN_TEST(test_gz_avail_returns_minus1_on_error_state);
RUN_TEST(test_gz_avail_noop_when_eof_already_set);
return UNITY_END();
}