#include "unity/unity.h" #include "zlib.h" #include #include #include #include /* Unity required hooks */ void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* Helpers */ static void make_temp_filename(char *out, size_t out_size) { /* Create a reasonably unique temp filename in the current directory */ unsigned r1 = (unsigned)rand(); unsigned r2 = (unsigned)time(NULL); #if !defined(_WIN32) (void)snprintf(out, out_size, "gztell64_test_%u_%u.gz", r1, r2); #else (void)_snprintf(out, out_size, "gztell64_test_%u_%u.gz", r1, r2); #endif } static int write_gzip_file(const char *path, const void *data, size_t len) { gzFile gz = gzopen(path, "wb"); if (gz == NULL) return -1; int wrote = gzwrite(gz, data, (unsigned)len); int clos = gzclose(gz); if (wrote != (int)len) return -1; if (clos != Z_OK) return -1; return 0; } /* Tests */ void test_gztell64_null_input(void) { z_off64_t ret = gztell64(NULL); TEST_ASSERT_EQUAL_INT64(-1, (long long)ret); } void test_gztell64_write_basic_progress(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); gzFile gz = gzopen(fname, "wb"); TEST_ASSERT_NOT_NULL(gz); TEST_ASSERT_EQUAL_INT64(0, (long long)gztell64(gz)); const char *p1 = "hello"; int w = gzwrite(gz, p1, (unsigned)strlen(p1)); TEST_ASSERT_EQUAL_INT((int)strlen(p1), w); TEST_ASSERT_EQUAL_INT64((long long)strlen(p1), (long long)gztell64(gz)); const char *p2 = " world!"; w = gzwrite(gz, p2, (unsigned)strlen(p2)); TEST_ASSERT_EQUAL_INT((int)strlen(p2), w); TEST_ASSERT_EQUAL_INT64((long long)(strlen(p1) + strlen(p2)), (long long)gztell64(gz)); TEST_ASSERT_EQUAL_INT(Z_OK, gzclose(gz)); remove(fname); } void test_gztell64_read_basic_progress(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); const char *msg = "The quick brown fox jumps over the lazy dog."; size_t msg_len = strlen(msg); /* Write two copies to have enough to read */ char buffer[256]; memset(buffer, 0, sizeof(buffer)); memcpy(buffer, msg, msg_len); memcpy(buffer + msg_len, msg, msg_len); size_t total_len = msg_len * 2; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(fname, buffer, total_len)); gzFile gz = gzopen(fname, "rb"); TEST_ASSERT_NOT_NULL(gz); TEST_ASSERT_EQUAL_INT64(0, (long long)gztell64(gz)); char rd[32]; int need = 13; int got = gzread(gz, rd, need); TEST_ASSERT_EQUAL_INT(need, got); TEST_ASSERT_EQUAL_INT64((long long)need, (long long)gztell64(gz)); /* Read some more and check cumulative position */ need = 7; got = gzread(gz, rd, need); TEST_ASSERT_EQUAL_INT(need, got); TEST_ASSERT_EQUAL_INT64(13 + 7, (long long)gztell64(gz)); gzclose(gz); remove(fname); } void test_gztell64_reflects_pending_seek_read_cur(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); const char *msg = "abcdefghijklmnopqrstuvwxyz"; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(fname, msg, strlen(msg))); gzFile gz = gzopen(fname, "rb"); TEST_ASSERT_NOT_NULL(gz); TEST_ASSERT_EQUAL_INT64(0, (long long)gztell64(gz)); /* Request a pending seek of +10 from current position (0) */ z_off64_t sret = gzseek64(gz, 10, SEEK_CUR); TEST_ASSERT_EQUAL_INT64(10, (long long)sret); /* gztell64 should reflect pos + pending skip */ TEST_ASSERT_EQUAL_INT64(10, (long long)gztell64(gz)); gzclose(gz); remove(fname); } void test_gztell64_reflects_pending_seek_read_set(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); const char *msg = "abcdefghijklmnopqrstuvwxyz"; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(fname, msg, strlen(msg))); gzFile gz = gzopen(fname, "rb"); TEST_ASSERT_NOT_NULL(gz); /* First, request a CUR seek to set a non-zero pending skip */ z_off64_t s1 = gzseek64(gz, 12, SEEK_CUR); TEST_ASSERT_EQUAL_INT64(12, (long long)s1); TEST_ASSERT_EQUAL_INT64(12, (long long)gztell64(gz)); /* Now override with an absolute position using SEEK_SET to 5 */ z_off64_t s2 = gzseek64(gz, 5, SEEK_SET); TEST_ASSERT_EQUAL_INT64(5, (long long)s2); TEST_ASSERT_EQUAL_INT64(5, (long long)gztell64(gz)); gzclose(gz); remove(fname); } void test_gztell64_reflects_pending_seek_write(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); gzFile gz = gzopen(fname, "wb"); TEST_ASSERT_NOT_NULL(gz); const char *msg = "1234567"; int w = gzwrite(gz, msg, (unsigned)strlen(msg)); TEST_ASSERT_EQUAL_INT((int)strlen(msg), w); TEST_ASSERT_EQUAL_INT64((long long)strlen(msg), (long long)gztell64(gz)); /* Large forward seek while writing */ z_off64_t ofs = 10000000000LL; /* 10^10 */ z_off64_t sret = gzseek64(gz, ofs, SEEK_CUR); TEST_ASSERT_EQUAL_INT64((long long)strlen(msg) + ofs, (long long)sret); TEST_ASSERT_EQUAL_INT64((long long)strlen(msg) + ofs, (long long)gztell64(gz)); gzclose(gz); remove(fname); } void test_gztell64_large_pending_seek_read(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); const char *msg = "data"; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(fname, msg, strlen(msg))); gzFile gz = gzopen(fname, "rb"); TEST_ASSERT_NOT_NULL(gz); z_off64_t big = ((z_off64_t)1 << 33); /* 8 GiB */ z_off64_t sret = gzseek64(gz, big, SEEK_CUR); TEST_ASSERT_EQUAL_INT64((long long)big, (long long)sret); TEST_ASSERT_EQUAL_INT64((long long)big, (long long)gztell64(gz)); gzclose(gz); remove(fname); } void test_gztell64_after_read_then_seek(void) { char fname[256]; make_temp_filename(fname, sizeof(fname)); const char *msg = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; TEST_ASSERT_EQUAL_INT(0, write_gzip_file(fname, msg, strlen(msg))); gzFile gz = gzopen(fname, "rb"); TEST_ASSERT_NOT_NULL(gz); char rd[8]; int got = gzread(gz, rd, 3); TEST_ASSERT_EQUAL_INT(3, got); TEST_ASSERT_EQUAL_INT64(3, (long long)gztell64(gz)); z_off64_t sret = gzseek64(gz, 4, SEEK_CUR); TEST_ASSERT_EQUAL_INT64(7, (long long)sret); TEST_ASSERT_EQUAL_INT64(7, (long long)gztell64(gz)); gzclose(gz); remove(fname); } /* Main */ int main(void) { srand((unsigned)time(NULL)); UNITY_BEGIN(); RUN_TEST(test_gztell64_null_input); RUN_TEST(test_gztell64_write_basic_progress); RUN_TEST(test_gztell64_read_basic_progress); RUN_TEST(test_gztell64_reflects_pending_seek_read_cur); RUN_TEST(test_gztell64_reflects_pending_seek_read_set); RUN_TEST(test_gztell64_reflects_pending_seek_write); RUN_TEST(test_gztell64_large_pending_seek_read); RUN_TEST(test_gztell64_after_read_then_seek); return UNITY_END(); }