|
|
#include "unity/unity.h" |
|
|
#include "zlib.h" |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <fcntl.h> |
|
|
#include <unistd.h> |
|
|
#include <errno.h> |
|
|
#include <sys/stat.h> |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static int make_temp_file(char *out_path, size_t out_size) { |
|
|
if (out_size < 32) { |
|
|
return -1; |
|
|
} |
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
errno = 0; |
|
|
ssize_t wr = write(fd, "X", 1); |
|
|
TEST_ASSERT_EQUAL_INT(-1, (int)wr); |
|
|
|
|
|
|
|
|
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+"); |
|
|
TEST_ASSERT_NULL(g); |
|
|
|
|
|
|
|
|
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"); |
|
|
TEST_ASSERT_NULL(g); |
|
|
|
|
|
|
|
|
const char c = 'Y'; |
|
|
ssize_t wr = write(fd, &c, 1); |
|
|
TEST_ASSERT_EQUAL_INT(1, (int)wr); |
|
|
|
|
|
close(fd); |
|
|
unlink(path); |
|
|
} |
|
|
|
|
|
|
|
|
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(); |
|
|
} |