| #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(); |
| } |