#include "unity/unity.h" #include "zlib.h" #include #include #include #include #include #include #include /* Unity fixtures */ void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* Helpers */ static int make_temp_file(char *out_path, size_t out_size) { if (out_size < 32) { return -1; } /* Create a template for mkstemp */ snprintf(out_path, out_size, "/tmp/zlib_gzdopen_ut_%ld_XXXXXX", (long)getpid()); int fd = mkstemp(out_path); return fd; } static int write_string_gz(const char *path, const char *s) { gzFile g = gzopen(path, "wb"); if (g == NULL) return -1; int w = gzwrite(g, s, (unsigned)strlen(s)); int zc = gzclose(g); if (w <= 0 || zc != Z_OK) return -1; return 0; } static int read_all_gz(const char *path, char *buf, size_t buf_size, int *out_len) { *out_len = 0; gzFile g = gzopen(path, "rb"); if (g == NULL) return -1; int total = 0; for (;;) { int n = gzread(g, buf + total, (unsigned)(buf_size - (size_t)total)); if (n < 0) { gzclose(g); return -1; } if (n == 0) break; total += n; if ((size_t)total >= buf_size) break; } int zc = gzclose(g); if (zc != Z_OK) return -1; *out_len = total; return 0; } /* Tests */ void test_gzdopen_invalid_fd_returns_null(void) { gzFile g = gzdopen(-1, "rb"); TEST_ASSERT_NULL(g); } void test_gzdopen_write_and_close_closes_fd(void) { char path[128]; int fd = make_temp_file(path, sizeof(path)); TEST_ASSERT_NOT_EQUAL(-1, fd); /* Open gzip on provided fd and write some data */ gzFile g = gzdopen(fd, "wb"); TEST_ASSERT_NOT_NULL(g); const char *msg = "hello world"; int w = gzwrite(g, msg, (unsigned)strlen(msg)); TEST_ASSERT_TRUE(w > 0); int zc = gzclose(g); TEST_ASSERT_EQUAL_INT(Z_OK, zc); /* After gzclose, the provided fd should be closed by zlib */ errno = 0; ssize_t wr = write(fd, "X", 1); TEST_ASSERT_EQUAL_INT(-1, (int)wr); /* Cleanup */ unlink(path); } void test_gzdopen_read_existing_gz_file(void) { char path[128]; int fd_tmp = make_temp_file(path, sizeof(path)); TEST_ASSERT_NOT_EQUAL(-1, fd_tmp); close(fd_tmp); const char *payload = "abcdef"; TEST_ASSERT_EQUAL_INT(0, write_string_gz(path, payload)); int fd = open(path, O_RDONLY); TEST_ASSERT_NOT_EQUAL(-1, fd); gzFile g = gzdopen(fd, "rb"); TEST_ASSERT_NOT_NULL(g); char buf[64]; int total = 0; for (;;) { int n = gzread(g, buf + total, (unsigned)(sizeof(buf) - (size_t)total)); TEST_ASSERT_TRUE(n >= 0); if (n == 0) break; total += n; if ((size_t)total >= sizeof(buf)) break; } TEST_ASSERT_EQUAL_INT((int)strlen(payload), total); TEST_ASSERT_EQUAL_INT(0, memcmp(buf, payload, (size_t)total)); int zc = gzclose(g); TEST_ASSERT_EQUAL_INT(Z_OK, zc); unlink(path); } void test_gzdopen_plus_mode_rejected_fd_not_closed(void) { char path[128]; int fd = make_temp_file(path, sizeof(path)); TEST_ASSERT_NOT_EQUAL(-1, fd); gzFile g = gzdopen(fd, "wb+"); /* '+' is not allowed */ TEST_ASSERT_NULL(g); /* Ensure fd remains open (write should succeed) */ errno = 0; const char c = 'Z'; ssize_t wr = write(fd, &c, 1); TEST_ASSERT_EQUAL_INT(1, (int)wr); close(fd); unlink(path); } void test_gzdopen_append_mode_appends_and_can_be_read_as_concatenated_streams(void) { char path[128]; int fd_tmp = make_temp_file(path, sizeof(path)); TEST_ASSERT_NOT_EQUAL(-1, fd_tmp); close(fd_tmp); const char *first = "first"; const char *second = "second"; TEST_ASSERT_EQUAL_INT(0, write_string_gz(path, first)); int fd = open(path, O_WRONLY); TEST_ASSERT_NOT_EQUAL(-1, fd); gzFile g = gzdopen(fd, "ab"); TEST_ASSERT_NOT_NULL(g); int w = gzwrite(g, second, (unsigned)strlen(second)); TEST_ASSERT_TRUE(w > 0); int zc = gzclose(g); TEST_ASSERT_EQUAL_INT(Z_OK, zc); char buf[128]; int len = 0; TEST_ASSERT_EQUAL_INT(0, read_all_gz(path, buf, sizeof(buf), &len)); TEST_ASSERT_EQUAL_INT((int)(strlen(first) + strlen(second)), len); TEST_ASSERT_EQUAL_INT(0, memcmp(buf, "firstsecond", (size_t)len)); unlink(path); } void test_gzdopen_invalid_mode_without_r_w_a_returns_null_and_fd_open(void) { char path[128]; int fd = make_temp_file(path, sizeof(path)); TEST_ASSERT_NOT_EQUAL(-1, fd); gzFile g = gzdopen(fd, "q"); /* no r/w/a, should be rejected */ TEST_ASSERT_NULL(g); /* Ensure fd remains open */ const char c = 'Y'; ssize_t wr = write(fd, &c, 1); TEST_ASSERT_EQUAL_INT(1, (int)wr); close(fd); unlink(path); } /* Test runner */ int main(void) { UNITY_BEGIN(); RUN_TEST(test_gzdopen_invalid_fd_returns_null); RUN_TEST(test_gzdopen_write_and_close_closes_fd); RUN_TEST(test_gzdopen_read_existing_gz_file); RUN_TEST(test_gzdopen_plus_mode_rejected_fd_not_closed); RUN_TEST(test_gzdopen_append_mode_appends_and_can_be_read_as_concatenated_streams); RUN_TEST(test_gzdopen_invalid_mode_without_r_w_a_returns_null_and_fd_open); return UNITY_END(); }